@beanx/cathygo-protocol 0.1.4 → 0.1.6

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/dist/index.d.ts CHANGED
@@ -66,6 +66,9 @@ type LearningTurnEventPayload = {
66
66
  message_id?: string;
67
67
  role?: "user" | "assistant" | "system";
68
68
  delta?: string;
69
+ content?: string;
70
+ content_revision?: number;
71
+ persisted_message_id?: string;
69
72
  message?: string;
70
73
  parts?: ConversationMessagePart[];
71
74
  metadata?: Record<string, unknown>;
@@ -87,7 +90,7 @@ type LearningTurnEventPayload = {
87
90
  };
88
91
  type LearningTurnEvent = {
89
92
  type: "event";
90
- 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}`;
93
+ event: "session.created" | "session.deleted" | "session.input.accepted" | "session.stop.requested" | "user.message.created" | "turn.started" | "assistant.delta" | "assistant.message" | "assistant.completed" | "turn.completed" | "turn.failed" | "turn.cancelled" | "agent.activity.started" | "agent.activity.updated" | "agent.activity.completed" | "agent.progress.delta" | `debug.${string}` | `experimental.${string}`;
91
94
  seq: number;
92
95
  payload: LearningTurnEventPayload;
93
96
  };
@@ -197,6 +200,8 @@ interface ConversationMessage {
197
200
  content: string;
198
201
  parts?: ConversationMessagePart[];
199
202
  turn_id?: string | null;
203
+ status?: "streaming" | "completed" | "failed" | "aborted" | "superseded";
204
+ content_revision?: number;
200
205
  created_at: string;
201
206
  metadata?: Record<string, unknown>;
202
207
  }
@@ -390,6 +395,31 @@ type CathyGOTransport = {
390
395
  isOpen(): boolean;
391
396
  };
392
397
 
398
+ declare class SessionEventCursorStore {
399
+ private readonly cursors;
400
+ private readonly turnStartSeq;
401
+ getAfterSeq(sessionId: string): number;
402
+ getTurnStartSeq(sessionId: string): number | undefined;
403
+ observeEvent(event: LearningTurnEvent): void;
404
+ setAfterSeq(sessionId: string, seq: number): void;
405
+ clear(): void;
406
+ }
407
+ declare function resolveSubscribeAfterSeq(cursorStore: SessionEventCursorStore, sessionId: string, runtime?: SessionRuntimeSnapshot | null): number;
408
+ type SessionSubscriptionClient = {
409
+ getSession(sessionId: string): Promise<ConversationDetail>;
410
+ subscribeSession(sessionId: string, afterSeq: number): Promise<void>;
411
+ };
412
+ declare class SessionSubscriptionManager {
413
+ private readonly client;
414
+ readonly cursorStore: SessionEventCursorStore;
415
+ private activeSessionId;
416
+ constructor(client: SessionSubscriptionClient, cursorStore: SessionEventCursorStore);
417
+ get activeSession(): string | null;
418
+ activateSession(sessionId: string, afterSeq?: number): Promise<ConversationDetail>;
419
+ deactivate(): void;
420
+ markActive(sessionId: string): void;
421
+ }
422
+
393
423
  declare class CathyGOClientError extends Error {
394
424
  readonly code?: string | undefined;
395
425
  constructor(message: string, code?: string | undefined);
@@ -405,7 +435,8 @@ declare class CathyGOProtocolClient {
405
435
  private turnHandlers;
406
436
  private attachmentRelayProgressHandlers;
407
437
  private lastConnect?;
408
- private lastEventSeq;
438
+ private readonly cursorStore;
439
+ private readonly subscriptionManager;
409
440
  private connectOptions;
410
441
  private callbacks;
411
442
  constructor(transport: CathyGOTransport, options: CathyGOProtocolClientOptions);
@@ -427,6 +458,13 @@ declare class CathyGOProtocolClient {
427
458
  attachment_relay_max_file_bytes?: number;
428
459
  attachment_relay_progress_min_interval_ms?: number;
429
460
  } | undefined;
461
+ getConnectResult(): CathyGOConnectResult | undefined;
462
+ getSessionEventCursorStore(): SessionEventCursorStore;
463
+ getLastEventSeq(sessionId: string): number;
464
+ resolveSubscribeAfterSeq(sessionId: string, detail: ConversationDetail): number;
465
+ getActiveSubscriptionSessionId(): string | null;
466
+ activateSession(sessionId: string, afterSeq?: number): Promise<ConversationDetail>;
467
+ deactivateSessionSubscription(): void;
430
468
  createSession(metadata?: Record<string, unknown>): Promise<string>;
431
469
  listSessions(limit?: number): Promise<ConversationSummary[]>;
432
470
  getSession(sessionId: string): Promise<ConversationDetail>;
@@ -469,4 +507,4 @@ declare function photoQuestionTurnInput(text: string, attachments: GatewayAttach
469
507
  declare function capabilityForTurn(attachments: GatewayAttachment[]): LearningCapability;
470
508
  declare function learningTurnInput(text: string, attachments: GatewayAttachment[]): TurnInput;
471
509
 
472
- export { type AgentActivity, type AgentPresenceEvent, type AttachmentCommitBlob, type AttachmentCommitParams, type AttachmentInput, type AttachmentRelayProgress, type AttachmentRelayProgressEvent, type AttachmentRelayProgressHandler, 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 UploadAttachmentViaRelayOptions, type UploadScope, capabilityForTurn, connectPayload, isAttachmentRelayProgressEvent, isLearningTurnEvent, learningTurnInput, parseConnectPayload, photoQuestionTurnInput, settingsFromPayload, textTurnInput, uploadAttachmentViaRelay };
510
+ export { type AgentActivity, type AgentPresenceEvent, type AttachmentCommitBlob, type AttachmentCommitParams, type AttachmentInput, type AttachmentRelayProgress, type AttachmentRelayProgressEvent, type AttachmentRelayProgressHandler, 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, SessionEventCursorStore, type SessionInputOptions, type SessionInputResult, type SessionRuntimeSnapshot, type SessionStopResult, type SessionSubscriptionClient, SessionSubscriptionManager, type SettingsItem, type SettingsItemKind, type SettingsSection, type TextTurnInput, type TurnInput, type UploadAttachmentViaRelayOptions, type UploadScope, capabilityForTurn, connectPayload, isAttachmentRelayProgressEvent, isLearningTurnEvent, learningTurnInput, parseConnectPayload, photoQuestionTurnInput, resolveSubscribeAfterSeq, settingsFromPayload, textTurnInput, uploadAttachmentViaRelay };
package/dist/index.js CHANGED
@@ -1,3 +1,82 @@
1
+ // src/session-subscription.ts
2
+ var TERMINAL_TURN_EVENTS = /* @__PURE__ */ new Set(["turn.completed", "turn.failed", "turn.cancelled"]);
3
+ var SessionEventCursorStore = class {
4
+ cursors = /* @__PURE__ */ new Map();
5
+ turnStartSeq = /* @__PURE__ */ new Map();
6
+ getAfterSeq(sessionId) {
7
+ return this.cursors.get(sessionId) ?? 0;
8
+ }
9
+ getTurnStartSeq(sessionId) {
10
+ return this.turnStartSeq.get(sessionId);
11
+ }
12
+ observeEvent(event) {
13
+ const sessionId = sessionIdFromEvent(event);
14
+ if (!sessionId || !event.seq || event.seq <= 0) return;
15
+ const current = this.cursors.get(sessionId) ?? 0;
16
+ if (event.seq > current) {
17
+ this.cursors.set(sessionId, event.seq);
18
+ }
19
+ if (event.event === "turn.started") {
20
+ this.turnStartSeq.set(sessionId, event.seq);
21
+ return;
22
+ }
23
+ if (TERMINAL_TURN_EVENTS.has(event.event)) {
24
+ this.turnStartSeq.delete(sessionId);
25
+ }
26
+ }
27
+ setAfterSeq(sessionId, seq) {
28
+ if (seq > 0) {
29
+ this.cursors.set(sessionId, seq);
30
+ }
31
+ }
32
+ clear() {
33
+ this.cursors.clear();
34
+ this.turnStartSeq.clear();
35
+ }
36
+ };
37
+ function resolveSubscribeAfterSeq(cursorStore, sessionId, runtime) {
38
+ const lastEventSeq = runtime?.last_event_seq ?? 0;
39
+ if (!runtime?.active_turn_id) {
40
+ return lastEventSeq;
41
+ }
42
+ const turnStartSeq = cursorStore.getTurnStartSeq(sessionId);
43
+ if (turnStartSeq != null && turnStartSeq > 0) {
44
+ return Math.max(0, turnStartSeq - 1);
45
+ }
46
+ return 0;
47
+ }
48
+ var SessionSubscriptionManager = class {
49
+ constructor(client, cursorStore) {
50
+ this.client = client;
51
+ this.cursorStore = cursorStore;
52
+ }
53
+ client;
54
+ cursorStore;
55
+ activeSessionId = null;
56
+ get activeSession() {
57
+ return this.activeSessionId;
58
+ }
59
+ async activateSession(sessionId, afterSeq) {
60
+ this.activeSessionId = sessionId;
61
+ const detail = await this.client.getSession(sessionId);
62
+ const runtime = detail.runtime ?? detail.session.runtime;
63
+ const subscribeFrom = afterSeq ?? resolveSubscribeAfterSeq(this.cursorStore, sessionId, runtime);
64
+ await this.client.subscribeSession(sessionId, subscribeFrom);
65
+ return detail;
66
+ }
67
+ deactivate() {
68
+ this.activeSessionId = null;
69
+ }
70
+ markActive(sessionId) {
71
+ this.activeSessionId = sessionId;
72
+ }
73
+ };
74
+ function sessionIdFromEvent(event) {
75
+ const sessionId = event.payload.session_id;
76
+ if (typeof sessionId !== "string" || !sessionId.trim()) return void 0;
77
+ return sessionId.trim();
78
+ }
79
+
1
80
  // src/client.ts
2
81
  var CathyGOClientError = class extends Error {
3
82
  constructor(message, code) {
@@ -12,6 +91,7 @@ var CathyGOProtocolClient = class {
12
91
  this.transport = transport;
13
92
  this.connectOptions = options.connect;
14
93
  this.callbacks = options.callbacks ?? {};
94
+ this.subscriptionManager = new SessionSubscriptionManager(this, this.cursorStore);
15
95
  this.transport.onFrame((frame) => this.handleFrame(frame));
16
96
  this.transport.onClose?.(() => {
17
97
  this.rejectPending("CathyGO socket closed");
@@ -28,7 +108,8 @@ var CathyGOProtocolClient = class {
28
108
  turnHandlers = /* @__PURE__ */ new Set();
29
109
  attachmentRelayProgressHandlers = /* @__PURE__ */ new Set();
30
110
  lastConnect;
31
- lastEventSeq = 0;
111
+ cursorStore = new SessionEventCursorStore();
112
+ subscriptionManager;
32
113
  connectOptions;
33
114
  callbacks;
34
115
  updateConnectOptions(patch) {
@@ -69,7 +150,8 @@ var CathyGOProtocolClient = class {
69
150
  disconnect() {
70
151
  this.transport.close();
71
152
  this.lastConnect = void 0;
72
- this.lastEventSeq = 0;
153
+ this.cursorStore.clear();
154
+ this.subscriptionManager.deactivate();
73
155
  this.rejectPending("CathyGO socket closed");
74
156
  }
75
157
  isConnected() {
@@ -78,6 +160,28 @@ var CathyGOProtocolClient = class {
78
160
  getLimits() {
79
161
  return this.lastConnect?.limits;
80
162
  }
163
+ getConnectResult() {
164
+ return this.lastConnect;
165
+ }
166
+ getSessionEventCursorStore() {
167
+ return this.cursorStore;
168
+ }
169
+ getLastEventSeq(sessionId) {
170
+ return this.cursorStore.getAfterSeq(sessionId);
171
+ }
172
+ resolveSubscribeAfterSeq(sessionId, detail) {
173
+ const runtime = detail.runtime ?? detail.session.runtime;
174
+ return resolveSubscribeAfterSeq(this.cursorStore, sessionId, runtime);
175
+ }
176
+ getActiveSubscriptionSessionId() {
177
+ return this.subscriptionManager.activeSession;
178
+ }
179
+ async activateSession(sessionId, afterSeq) {
180
+ return this.subscriptionManager.activateSession(sessionId, afterSeq);
181
+ }
182
+ deactivateSessionSubscription() {
183
+ this.subscriptionManager.deactivate();
184
+ }
81
185
  async createSession(metadata = {}) {
82
186
  const payload = await this.request("session.create", { metadata });
83
187
  return String(payload.session_id ?? "");
@@ -109,9 +213,11 @@ var CathyGOProtocolClient = class {
109
213
  return turnStartResultFromPayload(payload, sessionId);
110
214
  }
111
215
  async subscribeSession(sessionId, afterSeq) {
216
+ this.subscriptionManager.markActive(sessionId);
217
+ const resolvedAfterSeq = afterSeq ?? this.cursorStore.getAfterSeq(sessionId);
112
218
  await this.request("session.subscribe", {
113
219
  session_id: sessionId,
114
- after_seq: afterSeq ?? this.lastEventSeq
220
+ after_seq: resolvedAfterSeq
115
221
  });
116
222
  }
117
223
  async stopSession(sessionId) {
@@ -124,12 +230,7 @@ var CathyGOProtocolClient = class {
124
230
  };
125
231
  }
126
232
  async resumeSession(sessionId, afterSeq) {
127
- const detail = await this.getSession(sessionId);
128
- await this.subscribeSession(
129
- sessionId,
130
- afterSeq ?? detail.runtime?.last_event_seq ?? detail.session.runtime?.last_event_seq
131
- );
132
- return detail;
233
+ return this.subscriptionManager.activateSession(sessionId, afterSeq);
133
234
  }
134
235
  async regenerateSession(sessionId) {
135
236
  const payload = await this.request("session.regenerate", { session_id: sessionId });
@@ -202,9 +303,7 @@ var CathyGOProtocolClient = class {
202
303
  }
203
304
  }
204
305
  if (isLearningTurnEvent(frame)) {
205
- if (typeof frame.seq === "number" && frame.seq > this.lastEventSeq) {
206
- this.lastEventSeq = frame.seq;
207
- }
306
+ this.cursorStore.observeEvent(frame);
208
307
  this.callbacks.onTurnEvent?.(frame);
209
308
  for (const handler of this.turnHandlers) {
210
309
  handler(frame);
@@ -461,6 +560,8 @@ function learningTurnInput(text, attachments) {
461
560
  export {
462
561
  CathyGOClientError,
463
562
  CathyGOProtocolClient,
563
+ SessionEventCursorStore,
564
+ SessionSubscriptionManager,
464
565
  capabilityForTurn,
465
566
  connectPayload,
466
567
  isAttachmentRelayProgressEvent,
@@ -468,6 +569,7 @@ export {
468
569
  learningTurnInput,
469
570
  parseConnectPayload,
470
571
  photoQuestionTurnInput,
572
+ resolveSubscribeAfterSeq,
471
573
  settingsFromPayload,
472
574
  textTurnInput,
473
575
  uploadAttachmentViaRelay
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beanx/cathygo-protocol",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"