@beanx/cathygo-protocol 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # @beanx/cathygo-protocol
2
+
3
+ Public TypeScript protocol package for CathyGO Web/iOS clients.
4
+
5
+ Current active upgrade plan:
6
+
7
+ - [`../../docs/session-runtime-vnext-upgrade-plan.md`](../../docs/session-runtime-vnext-upgrade-plan.md)
8
+
9
+ ## vNext Role
10
+
11
+ This package owns the typed client contract for:
12
+
13
+ - request/response multiplexing over local WebSocket or BeanX Relay transport
14
+ - `session.input` with `client_input_id`
15
+ - `session.stop`
16
+ - `session.resume`
17
+ - `session.subscribe(session_id, after_seq, follow=true)`
18
+ - stable event names for user messages, session loop lifecycle, assistant
19
+ deltas, terminal events, and replay
20
+
21
+ It must not own product rendering state. Session view state and rendering
22
+ helpers belong in `@beanx/cathygo-web-core`.
23
+
24
+ ## First vNext Deliverables
25
+
26
+ - Add event/request/result types from the upgrade plan.
27
+ - Update `CathyGOProtocolClient` methods.
28
+ - Add tests for input idempotency fields, stop payloads, removed legacy command
29
+ rejection, and event typing.
30
+ - Bump to `0.2.0` only after local Web validates the new runtime path.
package/dist/index.d.ts CHANGED
@@ -48,15 +48,25 @@ type CathyGOResponse = {
48
48
  type LearningTurnEventPayload = {
49
49
  session_id?: string;
50
50
  turn_id?: string;
51
+ turn_ids?: string[];
52
+ client_input_id?: string;
53
+ client_turn_id?: string;
54
+ interrupted_turn_id?: string;
55
+ interrupted_turn_ids?: string[];
56
+ same_session_policy?: SameSessionPolicy;
51
57
  capability?: "chat" | "photo_question";
52
58
  input_summary?: string;
53
59
  input_mode?: "text" | "image" | "text_image" | string;
54
60
  required_model_capabilities?: string[];
55
61
  message_id?: string;
62
+ role?: "user" | "assistant" | "system";
56
63
  delta?: string;
57
64
  message?: string;
65
+ parts?: ConversationMessagePart[];
66
+ metadata?: Record<string, unknown>;
67
+ created_at?: string;
58
68
  blocks?: unknown[];
59
- status?: "running" | "completed" | "failed" | "cancelled";
69
+ status?: "accepted" | "idle" | "running" | "stopping" | "completed" | "failed" | "cancelled" | string;
60
70
  reason?: string;
61
71
  phase?: "queued" | "model" | "reasoning" | "tool" | "generating" | string;
62
72
  source?: "provider_reasoning_summary" | "public_progress" | "system_progress" | "hidden_reasoning" | string;
@@ -72,7 +82,7 @@ type LearningTurnEventPayload = {
72
82
  };
73
83
  type LearningTurnEvent = {
74
84
  type: "event";
75
- event: "turn.started" | "assistant.delta" | "assistant.completed" | "turn.completed" | "turn.failed" | "turn.cancelled" | "agent.activity.started" | "agent.activity.updated" | "agent.activity.completed" | "agent.progress.delta" | `debug.${string}` | `experimental.${string}`;
85
+ event: "session.created" | "session.deleted" | "session.input.accepted" | "session.stop.requested" | "user.message.created" | "turn.started" | "assistant.delta" | "assistant.completed" | "turn.completed" | "turn.failed" | "turn.cancelled" | "agent.activity.started" | "agent.activity.updated" | "agent.activity.completed" | "agent.progress.delta" | `debug.${string}` | `experimental.${string}`;
76
86
  seq: number;
77
87
  payload: LearningTurnEventPayload;
78
88
  };
@@ -113,14 +123,39 @@ type MultimodalTurnInput = {
113
123
  attachments?: AttachmentInput[];
114
124
  };
115
125
  type TurnInput = TextTurnInput | MultimodalTurnInput;
116
- type TurnStartOptions = {
126
+ type SameSessionPolicy = "interrupt" | "reject";
127
+ type SessionInputOptions = {
117
128
  capability?: "chat" | "photo_question";
118
129
  metadata?: Record<string, unknown>;
130
+ clientInputId?: string;
131
+ clientTurnId?: string;
132
+ sameSessionPolicy?: SameSessionPolicy;
119
133
  };
120
- type TurnStartResult = {
134
+ type SessionInputResult = {
121
135
  session_id: string;
122
136
  turn_id: string;
123
- status: string;
137
+ status: "accepted" | "running" | "completed" | "failed" | "cancelled" | string;
138
+ client_input_id?: string;
139
+ client_turn_id?: string;
140
+ same_session_policy?: SameSessionPolicy;
141
+ interrupted_turn_id?: string;
142
+ interrupted_turn_ids?: string[];
143
+ idempotent_replay?: boolean;
144
+ };
145
+ type SessionStopResult = {
146
+ session_id: string;
147
+ status: "stopping" | "idle" | string;
148
+ turn_id?: string;
149
+ turn_ids?: string[];
150
+ };
151
+ type SessionRuntimeSnapshot = {
152
+ status: "idle" | "running" | "stopping" | string;
153
+ active_turn_id?: string | null;
154
+ active_turn_ids?: string[];
155
+ active_client_input_id?: string | null;
156
+ active_client_turn_id?: string | null;
157
+ last_event_seq: number;
158
+ last_durable_seq?: number;
124
159
  };
125
160
  type UploadScope = {
126
161
  sessionId?: string;
@@ -135,6 +170,7 @@ interface ConversationSummary {
135
170
  updated_at: string;
136
171
  created_at: string;
137
172
  metadata?: Record<string, unknown>;
173
+ runtime?: SessionRuntimeSnapshot;
138
174
  }
139
175
  interface ConversationMessage {
140
176
  id: string;
@@ -143,11 +179,15 @@ interface ConversationMessage {
143
179
  parts?: ConversationMessagePart[];
144
180
  turn_id?: string | null;
145
181
  created_at: string;
182
+ metadata?: Record<string, unknown>;
146
183
  }
147
184
  interface ConversationDetail {
148
- session: ConversationSummary;
185
+ session: ConversationSummary & {
186
+ runtime?: SessionRuntimeSnapshot;
187
+ };
149
188
  messages: ConversationMessage[];
150
189
  activities?: AgentActivity[];
190
+ runtime?: SessionRuntimeSnapshot;
151
191
  }
152
192
  interface AgentActivity {
153
193
  activity_id: string;
@@ -176,6 +216,13 @@ interface GatewayAttachment {
176
216
  width?: number | null;
177
217
  height?: number | null;
178
218
  created_at?: string | null;
219
+ thumbnail?: GatewayAttachmentThumbnail | null;
220
+ }
221
+ interface GatewayAttachmentThumbnail {
222
+ mime_type: string;
223
+ data_base64: string;
224
+ width?: number | null;
225
+ height?: number | null;
179
226
  }
180
227
  interface ConversationMessagePart {
181
228
  id?: string;
@@ -356,11 +403,11 @@ declare class CathyGOProtocolClient {
356
403
  listSessions(limit?: number): Promise<ConversationSummary[]>;
357
404
  getSession(sessionId: string): Promise<ConversationDetail>;
358
405
  deleteSession(sessionId: string): Promise<void>;
359
- startTurn(sessionId: string, input: TurnInput, options?: TurnStartOptions): Promise<TurnStartResult>;
360
- subscribeTurn(turnId: string, afterSeq?: number): Promise<void>;
406
+ inputSession(sessionId: string, input: TurnInput, options?: SessionInputOptions): Promise<SessionInputResult>;
361
407
  subscribeSession(sessionId: string, afterSeq?: number): Promise<void>;
362
- cancelTurn(turnId: string): Promise<void>;
363
- regenerateLastTurn(sessionId: string): Promise<TurnStartResult>;
408
+ stopSession(sessionId: string): Promise<SessionStopResult>;
409
+ resumeSession(sessionId: string, afterSeq?: number): Promise<ConversationDetail>;
410
+ regenerateSession(sessionId: string): Promise<SessionInputResult>;
364
411
  commitAttachment(params: AttachmentCommitParams): Promise<GatewayAttachment>;
365
412
  getSettings(): Promise<GatewayVisibleSettings>;
366
413
  updateSettings(settings: Record<string, unknown>): Promise<GatewayVisibleSettings>;
@@ -377,10 +424,10 @@ declare function parseConnectPayload(payload: Record<string, unknown>): CathyGOC
377
424
  declare function settingsFromPayload(payload: Record<string, unknown>): GatewayVisibleSettings;
378
425
  declare function isLearningTurnEvent(frame: CathyGOIncomingFrame): frame is LearningTurnEvent;
379
426
 
380
- type LearningCapability = NonNullable<TurnStartOptions["capability"]>;
427
+ type LearningCapability = NonNullable<SessionInputOptions["capability"]>;
381
428
  declare function textTurnInput(text: string): TurnInput;
382
429
  declare function photoQuestionTurnInput(text: string, attachments: GatewayAttachment[]): TurnInput;
383
430
  declare function capabilityForTurn(attachments: GatewayAttachment[]): LearningCapability;
384
431
  declare function learningTurnInput(text: string, attachments: GatewayAttachment[]): TurnInput;
385
432
 
386
- export { type AgentActivity, type AgentPresenceEvent, type AttachmentCommitBlob, type AttachmentCommitParams, type AttachmentInput, type BeanXAccountRuntimeConfig, CathyGOClientError, type CathyGOClientRole, type CathyGOConnectOptions, type CathyGOConnectResult, type CathyGODeviceContext, type CathyGOFrame, type CathyGOIncomingFrame, CathyGOProtocolClient, type CathyGOProtocolClientCallbacks, type CathyGOProtocolClientOptions, type CathyGORequest, type CathyGOResponse, type CathyGOTransport, type CathyGOTransportEventHandler, type CathyGOTransportFrameHandler, type ConversationDetail, type ConversationMessage, type ConversationMessagePart, type ConversationSummary, type GatewayAgentProfile, type GatewayAttachment, type GatewayModelConfig, type GatewayModelConfigUpdate, type GatewayModelOption, type GatewayModelStatus, type GatewayVisibleSettings, type LearningCapability, type LearningTurnEvent, type LearningTurnEventHandler, type LearningTurnEventPayload, type ListResponse, type MessagePartInput, type MultimodalTurnInput, type SettingsItem, type SettingsItemKind, type SettingsSection, type TextTurnInput, type TurnInput, type TurnStartOptions, type TurnStartResult, type UploadScope, capabilityForTurn, connectPayload, isLearningTurnEvent, learningTurnInput, parseConnectPayload, photoQuestionTurnInput, settingsFromPayload, textTurnInput };
433
+ export { type AgentActivity, type AgentPresenceEvent, type AttachmentCommitBlob, type AttachmentCommitParams, type AttachmentInput, type BeanXAccountRuntimeConfig, CathyGOClientError, type CathyGOClientRole, type CathyGOConnectOptions, type CathyGOConnectResult, type CathyGODeviceContext, type CathyGOFrame, type CathyGOIncomingFrame, CathyGOProtocolClient, type CathyGOProtocolClientCallbacks, type CathyGOProtocolClientOptions, type CathyGORequest, type CathyGOResponse, type CathyGOTransport, type CathyGOTransportEventHandler, type CathyGOTransportFrameHandler, type ConversationDetail, type ConversationMessage, type ConversationMessagePart, type ConversationSummary, type GatewayAgentProfile, type GatewayAttachment, type GatewayModelConfig, type GatewayModelConfigUpdate, type GatewayModelOption, type GatewayModelStatus, type GatewayVisibleSettings, type LearningCapability, type LearningTurnEvent, type LearningTurnEventHandler, type LearningTurnEventPayload, type ListResponse, type MessagePartInput, type MultimodalTurnInput, type SameSessionPolicy, type SessionInputOptions, type SessionInputResult, type SessionRuntimeSnapshot, type SessionStopResult, type SettingsItem, type SettingsItemKind, type SettingsSection, type TextTurnInput, type TurnInput, type UploadScope, capabilityForTurn, connectPayload, isLearningTurnEvent, learningTurnInput, parseConnectPayload, photoQuestionTurnInput, settingsFromPayload, textTurnInput };
package/dist/index.js CHANGED
@@ -88,24 +88,20 @@ var CathyGOProtocolClient = class {
88
88
  async deleteSession(sessionId) {
89
89
  await this.request("session.delete", { session_id: sessionId });
90
90
  }
91
- async startTurn(sessionId, input, options = {}) {
92
- const payload = await this.request("turn.start", {
93
- session_id: sessionId,
94
- capability: options.capability,
95
- input,
96
- metadata: options.metadata
97
- });
98
- return {
99
- session_id: String(payload.session_id ?? sessionId),
100
- turn_id: String(payload.turn_id ?? ""),
101
- status: String(payload.status ?? "accepted")
102
- };
103
- }
104
- async subscribeTurn(turnId, afterSeq) {
105
- await this.request("turn.subscribe", {
106
- turn_id: turnId,
107
- after_seq: afterSeq ?? this.lastEventSeq
108
- });
91
+ async inputSession(sessionId, input, options = {}) {
92
+ const payload = await this.request(
93
+ "session.input",
94
+ compactParams({
95
+ session_id: sessionId,
96
+ capability: options.capability,
97
+ input,
98
+ metadata: options.metadata,
99
+ client_input_id: options.clientInputId,
100
+ client_turn_id: options.clientTurnId,
101
+ same_session_policy: options.sameSessionPolicy
102
+ })
103
+ );
104
+ return turnStartResultFromPayload(payload, sessionId);
109
105
  }
110
106
  async subscribeSession(sessionId, afterSeq) {
111
107
  await this.request("session.subscribe", {
@@ -113,11 +109,25 @@ var CathyGOProtocolClient = class {
113
109
  after_seq: afterSeq ?? this.lastEventSeq
114
110
  });
115
111
  }
116
- async cancelTurn(turnId) {
117
- await this.request("turn.cancel", { turn_id: turnId });
112
+ async stopSession(sessionId) {
113
+ const payload = await this.request("session.stop", { session_id: sessionId });
114
+ return {
115
+ session_id: String(payload.session_id ?? sessionId),
116
+ status: String(payload.status ?? "idle"),
117
+ turn_id: optionalString(payload.turn_id),
118
+ turn_ids: Array.isArray(payload.turn_ids) ? payload.turn_ids.map((value) => String(value)) : void 0
119
+ };
118
120
  }
119
- async regenerateLastTurn(sessionId) {
120
- const payload = await this.request("turn.regenerate", { session_id: sessionId });
121
+ async resumeSession(sessionId, afterSeq) {
122
+ const detail = await this.getSession(sessionId);
123
+ await this.subscribeSession(
124
+ sessionId,
125
+ afterSeq ?? detail.runtime?.last_event_seq ?? detail.session.runtime?.last_event_seq
126
+ );
127
+ return detail;
128
+ }
129
+ async regenerateSession(sessionId) {
130
+ const payload = await this.request("session.regenerate", { session_id: sessionId });
121
131
  return {
122
132
  session_id: String(payload.session_id ?? sessionId),
123
133
  turn_id: String(payload.turn_id ?? ""),
@@ -242,7 +252,32 @@ function settingsFromPayload(payload) {
242
252
  };
243
253
  }
244
254
  function isLearningTurnEvent(frame) {
245
- return frame.type === "event" && (frame.event.startsWith("turn.") || frame.event.startsWith("agent.activity.") || frame.event.startsWith("agent.progress.") || frame.event.startsWith("assistant.") || frame.event.startsWith("debug.") || frame.event.startsWith("experimental."));
255
+ return frame.type === "event" && (frame.event.startsWith("session.") || frame.event.startsWith("turn.") || frame.event.startsWith("agent.activity.") || frame.event.startsWith("agent.progress.") || frame.event.startsWith("assistant.") || frame.event.startsWith("debug.") || frame.event.startsWith("experimental."));
256
+ }
257
+ function turnStartResultFromPayload(payload, fallbackSessionId) {
258
+ return {
259
+ session_id: String(payload.session_id ?? fallbackSessionId),
260
+ turn_id: String(payload.turn_id ?? ""),
261
+ status: String(payload.status ?? "accepted"),
262
+ client_input_id: optionalString(payload.client_input_id),
263
+ client_turn_id: optionalString(payload.client_turn_id),
264
+ same_session_policy: sameSessionPolicy(payload.same_session_policy),
265
+ interrupted_turn_id: optionalString(payload.interrupted_turn_id),
266
+ interrupted_turn_ids: Array.isArray(payload.interrupted_turn_ids) ? payload.interrupted_turn_ids.map((value) => String(value)) : void 0,
267
+ idempotent_replay: payload.idempotent_replay === true
268
+ };
269
+ }
270
+ function optionalString(value) {
271
+ if (value === void 0 || value === null) return void 0;
272
+ const text = String(value).trim();
273
+ return text || void 0;
274
+ }
275
+ function sameSessionPolicy(value) {
276
+ if (value === "interrupt" || value === "reject") return value;
277
+ return void 0;
278
+ }
279
+ function compactParams(params) {
280
+ return Object.fromEntries(Object.entries(params).filter(([, value]) => value !== void 0));
246
281
  }
247
282
 
248
283
  // src/turn-input.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beanx/cathygo-protocol",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"