Files
claw-code-parity/ts-worker/protocol.ts
Wylabb f7c23fb325
Build Claw Telegram / build (push) Successful in 5m26s
Build Claw Telegram / cleanup (push) Successful in 0s
Replace Rust worker with TS worker in single image
Add ts-worker/ with the Bun/TypeScript worker that replaces
claw-profile-worker. The Dockerfile now builds a single image
containing both the Rust gateway (claw-telegram) and the TS worker.

The image defaults to worker mode (bun run ts-worker/main.ts).
The gateway Unraid XML overrides with --entrypoint claw-telegram.
Worker containers use the same image with the default CMD.

- Add ts-worker/ (12 files): HTTP/SSE server, Anthropic SDK engine,
  approval broker, event translator, state stores
- Add package.json with @anthropic-ai/sdk dependency
- Rewrite Dockerfile: three-stage build (Rust + Bun + runtime)
- Revert CLAW_GATEWAY_WORKER_IMAGE to claw-telegram:latest
- Remove image pull from docker_worker_manager (same image, already local)
- Add ts-worker paths to CI trigger

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 23:44:57 +02:00

204 lines
4.8 KiB
TypeScript

/**
* Worker protocol types — mirrors worker-protocol/openapi.yaml.
*
* These are the wire types the Rust gateway expects. The TS worker
* translates internal QueryEngine / SDKMessage events into these shapes
* before sending them over SSE.
*/
// ── Turn request ──────────────────────────────────────────────────────
export type TurnSource = {
channel: string
sender_id: string
chat_id?: string
display_name?: string
}
export type InboundAttachment = {
file_name: string
kind: 'photo' | 'document'
media_type?: string
data_base64: string
}
export type WorkerTurnRequest = {
prompt: string
source: TurnSource
attachments?: InboundAttachment[]
}
export type WorkerTurnAccepted = {
turn_id: string
}
// ── SSE events ────────────────────────────────────────────────────────
export type AssistantTextDelta = {
type: 'assistant_text_delta'
delta: string
}
export type ToolUseEvent = {
type: 'tool_use'
id: string
name: string
input: string
}
export type ToolResultEvent = {
type: 'tool_result'
tool_use_id: string
tool_name: string
output: string
is_error: boolean
}
export type ApprovalRequestPayload = {
approval_id: string
tool_name: string
input: string
current_mode: string
required_mode: string
reason?: string
}
export type ApprovalRequestedEvent = {
type: 'approval_requested'
request: ApprovalRequestPayload
}
export type AutoCompactionEvent = {
type: 'auto_compaction'
removed_message_count: number
}
export type GeneratedFileDescriptor = {
file_id: string
file_name: string
media_type?: string
size_bytes: number
is_image: boolean
}
export type CompletedEvent = {
type: 'completed'
final_text: string
iterations: number
input_tokens: number
output_tokens: number
generated_files: GeneratedFileDescriptor[]
}
export type FailedEvent = {
type: 'failed'
message: string
}
export type TaskCreatedEvent = {
type: 'task_created'
task_list_id: string
task: TaskListRecord
}
export type TaskUpdatedEvent = {
type: 'task_updated'
task_list_id: string
task: TaskListRecord
}
export type TaskStoppedEvent = {
type: 'task_stopped'
task: RuntimeTaskRecord
}
export type AgentSpawnedEvent = {
type: 'agent_spawned'
agent: RuntimeTaskRecord
}
export type TeamCreatedEvent = {
type: 'team_created'
team: WorkerTeamCreatedPayload
}
export type TeamDeletedEvent = {
type: 'team_deleted'
team_name: string
}
export type MailboxMessageEvent = {
type: 'mailbox_message'
message: WorkerMailboxMessagePayload
}
export type WorkerTurnEvent =
| AssistantTextDelta
| ToolUseEvent
| ToolResultEvent
| ApprovalRequestedEvent
| AutoCompactionEvent
| TaskCreatedEvent
| TaskUpdatedEvent
| TaskStoppedEvent
| AgentSpawnedEvent
| TeamCreatedEvent
| TeamDeletedEvent
| MailboxMessageEvent
| CompletedEvent
| FailedEvent
// ── Approval decision ─────────────────────────────────────────────────
export type ApprovalDecision =
| { decision: 'approve_once' }
| { decision: 'approve_tool_for_session' }
| { decision: 'approve_all_for_session' }
| { decision: 'cancel_turn' }
| { decision: 'deny'; reason: string }
export type TurnApprovalRequest = {
approval_id: string
decision: ApprovalDecision
}
// ── Domain records (opaque pass-through for now) ──────────────────────
export type TaskListRecord = Record<string, unknown>
export type RuntimeTaskRecord = Record<string, unknown>
export type TeamRecord = Record<string, unknown>
export type MailboxMessage = Record<string, unknown>
export type MailboxSummary = Record<string, unknown>
export type BackgroundApprovalRecord = Record<string, unknown>
export type FeedItemRecord = Record<string, unknown>
export type LibraryAppRecord = Record<string, unknown>
export type LibraryAppVersionRecord = Record<string, unknown>
export type AppWorkspaceRecord = Record<string, unknown>
// ── Composite response types ──────────────────────────────────────────
export type WorkerStatusResponse = {
profile_id: string
message_count: number
model: string
permission_mode: string
default_cwd: string
busy: boolean
task_list_id: string
active_team?: string
}
export type WorkerTeamCreatedPayload = {
team: TeamRecord
task_list_id: string
team_file_path: string
}
export type WorkerMailboxMessagePayload = {
team_name: string
sender: string
count: number
recipients?: string[]
summary?: string
}