npm package: @lambdacurry/currychat
Description: OpenClaw SDK plugin for the Curry Chat app
Latest version: 0.0.1

# @currychat/currychat

MVP OpenClaw SDK plugin for the Curry Chat app.

## What this plugin does today

This first pass follows the OpenClaw plugin SDK pattern and exposes a small app-facing gateway surface:

- `currychat.bootstrap`
  - returns plugin metadata
  - returns visible agents for the app
  - returns visible models for the app
  - advertises the currently supported Curry Chat methods
- `currychat.sessions.create`
  - creates a lightweight OpenClaw session store entry
  - returns the new session key, summary, and routing info
  - does not own or enforce app auth
  - does not inject the first message into the transcript yet
- `currychat.sessions.get`
  - returns a lightweight session summary by `sessionKey`
- `currychat.sessions.patch`
  - updates session `label`
  - updates session `modelOverride`
- `currychat.sessions.history`
  - returns transcript/history items for a session
  - includes simple cursor + limit pagination
  - mirrors OpenClaw transcript ordering and `__openclaw.seq` metadata
- `currychat.chat.send`
  - validates and normalizes an app send request against plugin-owned session state
  - returns the upstream `chat.send` gateway request to execute
  - declares the websocket stream contract the app should expect
  - leaves auth / ACL / buffering / reconnect handling in the app-owned proxy

The app remains responsible for:

- login and employee auth
- ACL / tenant policy
- UI / UX
- deciding when to call these methods

## Plugin config

Configured under `plugins.entries.currychat.config` in the OpenClaw config.

Supported keys:

- `agentAllowlist?: string[]`
- `bootstrapIncludeSessionSummary?: boolean`

## Contract notes

### `currychat.chat.send`

Input:

- `sessionKey: string`
- `message: string`
- `idempotencyKey?: string`
- `senderId?: string`
- `senderName?: string`
- `senderEmail?: string`
- `attachments?: Array<{ type: "image", mimeType: string, content: string }>`

Output:

- `session`
- `gatewayRequest.method === "chat.send"`
- `gatewayRequest.params.sessionKey`
- `gatewayRequest.params.message`
- `gatewayRequest.params.idempotencyKey`
- `gatewayRequest.params.attachments?`
- `stream.transport === "websocket"`
- `stream.gatewayChatEvent === "chat"`
- `stream.gatewayToolEvent === "agent"`
- `stream.runIdSource === "gateway-response"`
- `stream.resume.method === "run.resume"`
- `stream.resume.primaryKey === "runId"`
- `stream.resume.fallbackKey === "idempotencyKey"`
- `stream.resume.bufferedBy === "app-proxy"`

The intended runtime flow is:

1. the app websocket proxy authenticates the browser request and enforces ACL
2. the app calls `currychat.chat.send`
3. the plugin returns the normalized upstream `chat.send` request + stream metadata
4. the app proxy sends `chat.send` to the gateway hub
5. the app proxy buffers and resumes by `runId`, with `idempotencyKey` as the fallback lookup while the run id is still unknown

### `currychat.sessions.create`

Input:

- `appUserId: string`
- `agentId: string`
- `model: string`
- `firstMessage: string`
- `title?: string`
- `metadata?: Record<string, unknown>`
- `sessionKey?: string` (optional override, mainly for migrations/imports)

Output:

- `session.sessionKey`
- `session.sessionId`
- session summary fields (`label`, `displayName`, `modelOverride`, `model`, `modelProvider`, `updatedAt`)
- `routing.agentId`
- echoed request context under `request`

### `currychat.sessions.history`

Input:

- `sessionKey: string`
- `limit?: number`
- `cursor?: string` (`seq` or `seq:<n>`)

Output:

- `session`
- `items: Array<{ seq, message }>`
- `messages: unknown[]`
- `hasMore: boolean`
- `nextCursor?: string`

## Not implemented yet

The following are intentionally left for later iterations:

- actually sending the first message as part of session creation
- plugin-emitted streaming events beyond the normalized send/start contract
- server-driven chat/session creation workflows beyond the session store entry
- tool invocation proxying
- richer per-agent capability metadata
- app-specific auth handoff or ACL enforcement
- a dedicated HTTP route surface if the app prefers HTTP over gateway RPC
- transcript sanitization/redaction policies tuned for app consumers

## SDK references used

This package was shaped against the OpenClaw plugin docs:

- `docs/plugins/sdk-overview.md`
- `docs/plugins/sdk-channel-plugins.md`
- `docs/plugins/building-plugins.md`
- `docs/plugins/sdk-entrypoints.md`
- `docs/plugins/sdk-runtime.md`