@beanx/cathygo-protocol 0.1.0

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.
@@ -0,0 +1,386 @@
1
+ type CathyGOClientRole = "parent" | "child" | "developer";
2
+ type CathyGODeviceContext = {
3
+ deviceId: string;
4
+ displayName?: string;
5
+ platform: string;
6
+ appVersion?: string;
7
+ };
8
+ type CathyGOConnectOptions = {
9
+ authToken: string;
10
+ device?: CathyGODeviceContext;
11
+ clientId?: string;
12
+ clientVersion?: string;
13
+ role?: CathyGOClientRole;
14
+ scopes?: string[];
15
+ };
16
+ type CathyGOConnectResult = {
17
+ protocol: {
18
+ name: "cathygo.vnext";
19
+ version: number;
20
+ };
21
+ features: {
22
+ methods: string[];
23
+ events: string[];
24
+ };
25
+ limits: {
26
+ max_payload_bytes: number;
27
+ max_upload_bytes: number;
28
+ heartbeat_interval_ms: number;
29
+ };
30
+ };
31
+ type CathyGORequest = {
32
+ type: "req";
33
+ id: string;
34
+ method: string;
35
+ params?: Record<string, unknown>;
36
+ };
37
+ type CathyGOResponse = {
38
+ type: "res";
39
+ id: string;
40
+ status: "ok" | "error";
41
+ payload?: Record<string, unknown>;
42
+ error?: {
43
+ code: string;
44
+ message: string;
45
+ retryable?: boolean;
46
+ };
47
+ };
48
+ type LearningTurnEventPayload = {
49
+ session_id?: string;
50
+ turn_id?: string;
51
+ capability?: "chat" | "photo_question";
52
+ input_summary?: string;
53
+ input_mode?: "text" | "image" | "text_image" | string;
54
+ required_model_capabilities?: string[];
55
+ message_id?: string;
56
+ delta?: string;
57
+ message?: string;
58
+ blocks?: unknown[];
59
+ status?: "running" | "completed" | "failed" | "cancelled";
60
+ reason?: string;
61
+ phase?: "queued" | "model" | "reasoning" | "tool" | "generating" | string;
62
+ source?: "provider_reasoning_summary" | "public_progress" | "system_progress" | "hidden_reasoning" | string;
63
+ text_delta?: string;
64
+ text?: string;
65
+ durable?: boolean;
66
+ error?: {
67
+ code?: string;
68
+ message?: string;
69
+ retryable?: boolean;
70
+ };
71
+ [key: string]: unknown;
72
+ };
73
+ type LearningTurnEvent = {
74
+ 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}`;
76
+ seq: number;
77
+ payload: LearningTurnEventPayload;
78
+ };
79
+ type AgentPresenceEvent = {
80
+ type: "event";
81
+ event: "agent.online" | "agent.offline";
82
+ seq: number;
83
+ cursor?: string;
84
+ payload: {
85
+ agent_id: string;
86
+ status: "online" | "offline";
87
+ [key: string]: unknown;
88
+ };
89
+ };
90
+ type CathyGOIncomingFrame = CathyGOResponse | LearningTurnEvent | AgentPresenceEvent;
91
+ type CathyGOFrame = CathyGORequest | CathyGOIncomingFrame;
92
+ type TextTurnInput = {
93
+ text: string;
94
+ };
95
+ type MessagePartInput = {
96
+ type: "text";
97
+ text: string;
98
+ metadata?: Record<string, unknown>;
99
+ } | {
100
+ type: "image";
101
+ attachment_id: string;
102
+ metadata?: Record<string, unknown>;
103
+ };
104
+ type AttachmentInput = {
105
+ attachment_id: string;
106
+ kind: "image";
107
+ mime_type?: string | null;
108
+ uri?: string | null;
109
+ metadata?: Record<string, unknown>;
110
+ };
111
+ type MultimodalTurnInput = {
112
+ parts: MessagePartInput[];
113
+ attachments?: AttachmentInput[];
114
+ };
115
+ type TurnInput = TextTurnInput | MultimodalTurnInput;
116
+ type TurnStartOptions = {
117
+ capability?: "chat" | "photo_question";
118
+ metadata?: Record<string, unknown>;
119
+ };
120
+ type TurnStartResult = {
121
+ session_id: string;
122
+ turn_id: string;
123
+ status: string;
124
+ };
125
+ type UploadScope = {
126
+ sessionId?: string;
127
+ ownerId?: string;
128
+ };
129
+ interface ConversationSummary {
130
+ session_id: string;
131
+ title: string;
132
+ preview: string;
133
+ status: "active" | "archived";
134
+ message_count: number;
135
+ updated_at: string;
136
+ created_at: string;
137
+ metadata?: Record<string, unknown>;
138
+ }
139
+ interface ConversationMessage {
140
+ id: string;
141
+ role: "user" | "assistant" | "system";
142
+ content: string;
143
+ parts?: ConversationMessagePart[];
144
+ turn_id?: string | null;
145
+ created_at: string;
146
+ }
147
+ interface ConversationDetail {
148
+ session: ConversationSummary;
149
+ messages: ConversationMessage[];
150
+ activities?: AgentActivity[];
151
+ }
152
+ interface AgentActivity {
153
+ activity_id: string;
154
+ session_id: string;
155
+ turn_id: string;
156
+ kind: "model" | "tool" | "skill" | "vision" | "memory" | "system";
157
+ status: "running" | "completed" | "failed" | "cancelled";
158
+ title: string;
159
+ summary?: string;
160
+ detail?: string;
161
+ started_at?: string;
162
+ completed_at?: string;
163
+ error?: {
164
+ code?: string;
165
+ message: string;
166
+ };
167
+ }
168
+ interface GatewayAttachment {
169
+ id: string;
170
+ kind: "image";
171
+ uri: string;
172
+ original_name?: string | null;
173
+ mime_type?: string | null;
174
+ size_bytes?: number | null;
175
+ sha256?: string | null;
176
+ width?: number | null;
177
+ height?: number | null;
178
+ created_at?: string | null;
179
+ }
180
+ interface ConversationMessagePart {
181
+ id?: string;
182
+ type: "text" | "image";
183
+ text?: string | null;
184
+ attachment_id?: string | null;
185
+ attachment?: GatewayAttachment;
186
+ }
187
+ interface GatewayAgentProfile {
188
+ agent_instance_id?: string;
189
+ display_name?: string;
190
+ grade?: number | null;
191
+ default_subject?: string | null;
192
+ default_goal?: string | null;
193
+ locale?: string;
194
+ timezone?: string;
195
+ }
196
+ interface GatewayVisibleSettings {
197
+ app_name?: string;
198
+ shell?: string;
199
+ gateway_url?: string;
200
+ token?: string;
201
+ editable?: boolean;
202
+ protocol_version?: number;
203
+ gateway_version?: string;
204
+ mode?: string;
205
+ device_context?: Record<string, unknown>;
206
+ agent_profile?: GatewayAgentProfile | null;
207
+ model?: GatewayModelStatus;
208
+ model_config?: GatewayModelConfig;
209
+ model_options?: GatewayModelOption[];
210
+ beanx_account?: BeanXAccountRuntimeConfig;
211
+ settings_schema_version?: number;
212
+ sections?: SettingsSection[];
213
+ }
214
+ interface BeanXAccountRuntimeConfig {
215
+ api_url?: string | null;
216
+ supabase_url?: string | null;
217
+ supabase_anon_key?: string | null;
218
+ configured?: boolean;
219
+ }
220
+ interface GatewayModelStatus {
221
+ provider: string;
222
+ requested_provider?: string;
223
+ display_name?: string;
224
+ model?: string | null;
225
+ base_url?: string | null;
226
+ configured: boolean;
227
+ capabilities?: string[];
228
+ missing_config_keys: string[];
229
+ error?: string | null;
230
+ }
231
+ interface GatewayModelConfig {
232
+ provider: string;
233
+ model?: string | null;
234
+ base_url?: string | null;
235
+ api_key_status: "set" | "missing" | "not_required" | string;
236
+ routing_mode?: string;
237
+ model_selection_label?: string;
238
+ source?: string | null;
239
+ reasoning_effort?: string;
240
+ }
241
+ interface GatewayModelConfigUpdate {
242
+ provider: string;
243
+ model?: string;
244
+ base_url?: string;
245
+ api_key?: string;
246
+ clear_api_key?: boolean;
247
+ reasoning_effort?: string;
248
+ }
249
+ interface GatewayModelOption {
250
+ id: string;
251
+ label: string;
252
+ description?: string;
253
+ requires_api_key: boolean;
254
+ api_key_status?: "set" | "missing" | "not_required" | string;
255
+ selected?: boolean;
256
+ capabilities?: string[];
257
+ model?: string;
258
+ base_url?: string;
259
+ reasoning_effort?: string;
260
+ supports_reasoning?: boolean;
261
+ }
262
+ type SettingsItemKind = "readonly_text" | "text" | "password" | "select" | "toggle" | "number" | "status" | "secret_status" | "key_value" | "list" | "json";
263
+ interface SettingsSection {
264
+ id: string;
265
+ title: string;
266
+ status: string;
267
+ description?: string | null;
268
+ items: SettingsItem[];
269
+ }
270
+ interface SettingsItem {
271
+ id: string;
272
+ label: string;
273
+ kind: SettingsItemKind;
274
+ value?: unknown;
275
+ display_value?: string | null;
276
+ source?: string | null;
277
+ editable?: boolean;
278
+ sensitive?: boolean;
279
+ requires_restart?: boolean;
280
+ visibility?: "normal" | "advanced" | "developer" | string;
281
+ read_only_reason?: string | null;
282
+ }
283
+ interface ListResponse<T> {
284
+ has_more: boolean;
285
+ [key: string]: T[] | boolean;
286
+ }
287
+ type AttachmentCommitBlob = {
288
+ blob_id?: string;
289
+ data_base64?: string;
290
+ mime_type?: string;
291
+ size_bytes?: number;
292
+ sha256?: string;
293
+ };
294
+ type AttachmentCommitParams = {
295
+ session_id?: string;
296
+ attachment_id?: string;
297
+ blob_id?: string;
298
+ kind?: "image";
299
+ mime_type?: string;
300
+ original_name?: string;
301
+ blob?: AttachmentCommitBlob;
302
+ metadata?: Record<string, unknown>;
303
+ };
304
+ type LearningTurnEventHandler = (event: LearningTurnEvent) => void;
305
+ type CathyGOProtocolClientCallbacks = {
306
+ onOpen?: () => void;
307
+ onClose?: () => void;
308
+ onError?: () => void;
309
+ onFrame?: (frame: CathyGOIncomingFrame) => void;
310
+ onTurnEvent?: LearningTurnEventHandler;
311
+ };
312
+
313
+ type CathyGOTransportFrameHandler = (frame: CathyGOIncomingFrame) => void;
314
+ type CathyGOTransportEventHandler = () => void;
315
+ type CathyGOTransport = {
316
+ connect(): Promise<void>;
317
+ sendFrame(frame: CathyGORequest): void;
318
+ onFrame(handler: CathyGOTransportFrameHandler): () => void;
319
+ onClose?(handler: CathyGOTransportEventHandler): () => void;
320
+ onError?(handler: CathyGOTransportEventHandler): () => void;
321
+ close(): void;
322
+ isOpen(): boolean;
323
+ };
324
+
325
+ declare class CathyGOClientError extends Error {
326
+ readonly code?: string | undefined;
327
+ constructor(message: string, code?: string | undefined);
328
+ }
329
+ type CathyGOProtocolClientOptions = {
330
+ connect: CathyGOConnectOptions;
331
+ callbacks?: CathyGOProtocolClientCallbacks;
332
+ };
333
+ declare class CathyGOProtocolClient {
334
+ private readonly transport;
335
+ private requestSeq;
336
+ private pending;
337
+ private turnHandlers;
338
+ private lastConnect?;
339
+ private lastEventSeq;
340
+ private connectOptions;
341
+ private callbacks;
342
+ constructor(transport: CathyGOTransport, options: CathyGOProtocolClientOptions);
343
+ updateConnectOptions(patch: Partial<CathyGOConnectOptions>): void;
344
+ updateCallbacks(callbacks: CathyGOProtocolClientCallbacks): void;
345
+ onTurnEvent(handler: LearningTurnEventHandler): () => void;
346
+ connect(): Promise<CathyGOConnectResult>;
347
+ reconnect(options?: Partial<CathyGOConnectOptions>): Promise<CathyGOConnectResult>;
348
+ disconnect(): void;
349
+ isConnected(): boolean;
350
+ getLimits(): {
351
+ max_payload_bytes: number;
352
+ max_upload_bytes: number;
353
+ heartbeat_interval_ms: number;
354
+ } | undefined;
355
+ createSession(metadata?: Record<string, unknown>): Promise<string>;
356
+ listSessions(limit?: number): Promise<ConversationSummary[]>;
357
+ getSession(sessionId: string): Promise<ConversationDetail>;
358
+ deleteSession(sessionId: string): Promise<void>;
359
+ startTurn(sessionId: string, input: TurnInput, options?: TurnStartOptions): Promise<TurnStartResult>;
360
+ subscribeTurn(turnId: string, afterSeq?: number): Promise<void>;
361
+ subscribeSession(sessionId: string, afterSeq?: number): Promise<void>;
362
+ cancelTurn(turnId: string): Promise<void>;
363
+ regenerateLastTurn(sessionId: string): Promise<TurnStartResult>;
364
+ commitAttachment(params: AttachmentCommitParams): Promise<GatewayAttachment>;
365
+ getSettings(): Promise<GatewayVisibleSettings>;
366
+ updateSettings(settings: Record<string, unknown>): Promise<GatewayVisibleSettings>;
367
+ updateModelConfig(modelConfig: GatewayModelConfigUpdate): Promise<GatewayVisibleSettings>;
368
+ request(method: string, params?: Record<string, unknown>): Promise<Record<string, unknown>>;
369
+ private sendRequest;
370
+ private send;
371
+ private rejectPending;
372
+ private unwrap;
373
+ private handleFrame;
374
+ }
375
+ declare function connectPayload(options: CathyGOConnectOptions): Record<string, unknown>;
376
+ declare function parseConnectPayload(payload: Record<string, unknown>): CathyGOConnectResult;
377
+ declare function settingsFromPayload(payload: Record<string, unknown>): GatewayVisibleSettings;
378
+ declare function isLearningTurnEvent(frame: CathyGOIncomingFrame): frame is LearningTurnEvent;
379
+
380
+ type LearningCapability = NonNullable<TurnStartOptions["capability"]>;
381
+ declare function textTurnInput(text: string): TurnInput;
382
+ declare function photoQuestionTurnInput(text: string, attachments: GatewayAttachment[]): TurnInput;
383
+ declare function capabilityForTurn(attachments: GatewayAttachment[]): LearningCapability;
384
+ declare function learningTurnInput(text: string, attachments: GatewayAttachment[]): TurnInput;
385
+
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 };
package/dist/index.js ADDED
@@ -0,0 +1,289 @@
1
+ // src/client.ts
2
+ var CathyGOClientError = class extends Error {
3
+ constructor(message, code) {
4
+ super(message);
5
+ this.code = code;
6
+ this.name = "CathyGOClientError";
7
+ }
8
+ code;
9
+ };
10
+ var CathyGOProtocolClient = class {
11
+ constructor(transport, options) {
12
+ this.transport = transport;
13
+ this.connectOptions = options.connect;
14
+ this.callbacks = options.callbacks ?? {};
15
+ this.transport.onFrame((frame) => this.handleFrame(frame));
16
+ this.transport.onClose?.(() => {
17
+ this.rejectPending("CathyGO socket closed");
18
+ this.callbacks.onClose?.();
19
+ });
20
+ this.transport.onError?.(() => {
21
+ this.rejectPending("CathyGO socket error");
22
+ this.callbacks.onError?.();
23
+ });
24
+ }
25
+ transport;
26
+ requestSeq = 1;
27
+ pending = /* @__PURE__ */ new Map();
28
+ turnHandlers = /* @__PURE__ */ new Set();
29
+ lastConnect;
30
+ lastEventSeq = 0;
31
+ connectOptions;
32
+ callbacks;
33
+ updateConnectOptions(patch) {
34
+ this.connectOptions = { ...this.connectOptions, ...patch };
35
+ }
36
+ updateCallbacks(callbacks) {
37
+ this.callbacks = callbacks;
38
+ }
39
+ onTurnEvent(handler) {
40
+ this.turnHandlers.add(handler);
41
+ return () => this.turnHandlers.delete(handler);
42
+ }
43
+ async connect() {
44
+ if (this.isConnected() && this.lastConnect) {
45
+ return this.lastConnect;
46
+ }
47
+ this.lastConnect = void 0;
48
+ this.transport.close();
49
+ await this.transport.connect();
50
+ this.callbacks.onOpen?.();
51
+ const response = await this.sendRequest(
52
+ "client.connect",
53
+ connectPayload(this.connectOptions),
54
+ "cathygo_connect"
55
+ );
56
+ this.lastConnect = parseConnectPayload(this.unwrap(response, "client.connect"));
57
+ return this.lastConnect;
58
+ }
59
+ async reconnect(options) {
60
+ if (options) this.updateConnectOptions(options);
61
+ this.disconnect();
62
+ return this.connect();
63
+ }
64
+ disconnect() {
65
+ this.transport.close();
66
+ this.lastConnect = void 0;
67
+ this.lastEventSeq = 0;
68
+ this.rejectPending("CathyGO socket closed");
69
+ }
70
+ isConnected() {
71
+ return this.transport.isOpen();
72
+ }
73
+ getLimits() {
74
+ return this.lastConnect?.limits;
75
+ }
76
+ async createSession(metadata = {}) {
77
+ const payload = await this.request("session.create", { metadata });
78
+ return String(payload.session_id ?? "");
79
+ }
80
+ async listSessions(limit = 50) {
81
+ const payload = await this.request("session.list", { limit });
82
+ return payload.sessions ?? [];
83
+ }
84
+ async getSession(sessionId) {
85
+ const payload = await this.request("session.get", { session_id: sessionId });
86
+ return payload;
87
+ }
88
+ async deleteSession(sessionId) {
89
+ await this.request("session.delete", { session_id: sessionId });
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
+ });
109
+ }
110
+ async subscribeSession(sessionId, afterSeq) {
111
+ await this.request("session.subscribe", {
112
+ session_id: sessionId,
113
+ after_seq: afterSeq ?? this.lastEventSeq
114
+ });
115
+ }
116
+ async cancelTurn(turnId) {
117
+ await this.request("turn.cancel", { turn_id: turnId });
118
+ }
119
+ async regenerateLastTurn(sessionId) {
120
+ const payload = await this.request("turn.regenerate", { session_id: sessionId });
121
+ return {
122
+ session_id: String(payload.session_id ?? sessionId),
123
+ turn_id: String(payload.turn_id ?? ""),
124
+ status: String(payload.status ?? "accepted")
125
+ };
126
+ }
127
+ async commitAttachment(params) {
128
+ const payload = await this.request("attachment.commit", params);
129
+ return payload.attachment ?? payload;
130
+ }
131
+ async getSettings() {
132
+ return settingsFromPayload(await this.request("settings.get"));
133
+ }
134
+ async updateSettings(settings) {
135
+ return settingsFromPayload(await this.request("settings.update", { settings }));
136
+ }
137
+ async updateModelConfig(modelConfig) {
138
+ return this.updateSettings({ model_config: modelConfig });
139
+ }
140
+ async request(method, params = {}) {
141
+ if (!this.isConnected() || !this.lastConnect) {
142
+ await this.connect();
143
+ }
144
+ const response = await this.sendRequest(method, params);
145
+ return this.unwrap(response, method);
146
+ }
147
+ sendRequest(method, params = {}, id) {
148
+ const requestId = id ?? `cathygo_req_${this.requestSeq++}`;
149
+ const response = new Promise((resolve, reject) => {
150
+ this.pending.set(requestId, { resolve, reject });
151
+ });
152
+ this.send(method, params, requestId);
153
+ return response;
154
+ }
155
+ send(method, params, id) {
156
+ const requestId = id ?? `cathygo_req_${this.requestSeq++}`;
157
+ const frame = {
158
+ type: "req",
159
+ id: requestId,
160
+ method,
161
+ params
162
+ };
163
+ this.transport.sendFrame(frame);
164
+ return requestId;
165
+ }
166
+ rejectPending(message) {
167
+ for (const pending of this.pending.values()) {
168
+ pending.reject(new Error(message));
169
+ }
170
+ this.pending.clear();
171
+ }
172
+ unwrap(response, method) {
173
+ if (response.status !== "ok") {
174
+ throw new CathyGOClientError(
175
+ response.error?.message ?? `${method} failed`,
176
+ response.error?.code
177
+ );
178
+ }
179
+ return response.payload ?? {};
180
+ }
181
+ handleFrame(frame) {
182
+ if (frame.type === "res") {
183
+ const pending = this.pending.get(frame.id);
184
+ if (pending) {
185
+ this.pending.delete(frame.id);
186
+ pending.resolve(frame);
187
+ }
188
+ }
189
+ if (isLearningTurnEvent(frame)) {
190
+ if (typeof frame.seq === "number" && frame.seq > this.lastEventSeq) {
191
+ this.lastEventSeq = frame.seq;
192
+ }
193
+ this.callbacks.onTurnEvent?.(frame);
194
+ for (const handler of this.turnHandlers) {
195
+ handler(frame);
196
+ }
197
+ }
198
+ this.callbacks.onFrame?.(frame);
199
+ }
200
+ };
201
+ function connectPayload(options) {
202
+ return {
203
+ protocol: { name: "cathygo.vnext", version: 1 },
204
+ client: {
205
+ id: options.clientId ?? "cathygo-web-shell",
206
+ version: options.clientVersion ?? "0.1.0",
207
+ platform: options.device?.platform ?? "web"
208
+ },
209
+ role: options.role ?? "child",
210
+ scopes: options.scopes ?? ["learning.write", "session.read", "session.write", "settings.write"],
211
+ device: options.device ? {
212
+ id: options.device.deviceId,
213
+ name: options.device.displayName ?? options.device.platform,
214
+ platform: options.device.platform,
215
+ app_version: options.device.appVersion
216
+ } : { id: "cathygo-web-shell", name: "CathyGO Web", platform: "web" },
217
+ auth: { token: options.authToken }
218
+ };
219
+ }
220
+ function parseConnectPayload(payload) {
221
+ const protocol = payload.protocol;
222
+ const features = payload.features ?? {
223
+ methods: [],
224
+ events: []
225
+ };
226
+ const limits = payload.limits ?? {
227
+ max_payload_bytes: 262144,
228
+ max_upload_bytes: 10 * 1024 * 1024,
229
+ heartbeat_interval_ms: 15e3
230
+ };
231
+ return {
232
+ protocol: protocol ?? { name: "cathygo.vnext", version: 1 },
233
+ features,
234
+ limits
235
+ };
236
+ }
237
+ function settingsFromPayload(payload) {
238
+ return {
239
+ ...payload.settings ?? {},
240
+ settings_schema_version: Number(payload.settings_schema_version ?? 0) || void 0,
241
+ sections: payload.sections
242
+ };
243
+ }
244
+ 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."));
246
+ }
247
+
248
+ // src/turn-input.ts
249
+ function textTurnInput(text) {
250
+ return { text };
251
+ }
252
+ function photoQuestionTurnInput(text, attachments) {
253
+ return {
254
+ parts: [
255
+ ...text ? [{ type: "text", text }] : [],
256
+ ...attachments.map((attachment) => ({
257
+ type: "image",
258
+ attachment_id: attachment.id
259
+ }))
260
+ ],
261
+ attachments: attachments.map((attachment) => ({
262
+ attachment_id: attachment.id,
263
+ kind: "image",
264
+ mime_type: attachment.mime_type,
265
+ uri: attachment.uri
266
+ }))
267
+ };
268
+ }
269
+ function capabilityForTurn(attachments) {
270
+ return attachments.length ? "photo_question" : "chat";
271
+ }
272
+ function learningTurnInput(text, attachments) {
273
+ if (attachments.length === 0) {
274
+ return textTurnInput(text);
275
+ }
276
+ return photoQuestionTurnInput(text, attachments);
277
+ }
278
+ export {
279
+ CathyGOClientError,
280
+ CathyGOProtocolClient,
281
+ capabilityForTurn,
282
+ connectPayload,
283
+ isLearningTurnEvent,
284
+ learningTurnInput,
285
+ parseConnectPayload,
286
+ photoQuestionTurnInput,
287
+ settingsFromPayload,
288
+ textTurnInput
289
+ };
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@beanx/cathygo-protocol",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "sideEffects": false,
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsup src/index.ts --format esm --dts --clean",
17
+ "test": "vitest run"
18
+ },
19
+ "publishConfig": {
20
+ "access": "public"
21
+ }
22
+ }