@beanx/cathygo-protocol 0.1.1 → 0.1.3
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 +54 -3
- package/dist/index.js +137 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,11 @@ type CathyGOConnectResult = {
|
|
|
26
26
|
max_payload_bytes: number;
|
|
27
27
|
max_upload_bytes: number;
|
|
28
28
|
heartbeat_interval_ms: number;
|
|
29
|
+
attachment_relay_max_files_per_send?: number;
|
|
30
|
+
attachment_relay_max_concurrent_transfers?: number;
|
|
31
|
+
attachment_relay_chunk_bytes?: number;
|
|
32
|
+
attachment_relay_max_file_bytes?: number;
|
|
33
|
+
attachment_relay_progress_min_interval_ms?: number;
|
|
29
34
|
};
|
|
30
35
|
};
|
|
31
36
|
type CathyGORequest = {
|
|
@@ -59,8 +64,12 @@ type LearningTurnEventPayload = {
|
|
|
59
64
|
input_mode?: "text" | "image" | "text_image" | string;
|
|
60
65
|
required_model_capabilities?: string[];
|
|
61
66
|
message_id?: string;
|
|
67
|
+
role?: "user" | "assistant" | "system";
|
|
62
68
|
delta?: string;
|
|
63
69
|
message?: string;
|
|
70
|
+
parts?: ConversationMessagePart[];
|
|
71
|
+
metadata?: Record<string, unknown>;
|
|
72
|
+
created_at?: string;
|
|
64
73
|
blocks?: unknown[];
|
|
65
74
|
status?: "accepted" | "idle" | "running" | "stopping" | "completed" | "failed" | "cancelled" | string;
|
|
66
75
|
reason?: string;
|
|
@@ -78,7 +87,7 @@ type LearningTurnEventPayload = {
|
|
|
78
87
|
};
|
|
79
88
|
type LearningTurnEvent = {
|
|
80
89
|
type: "event";
|
|
81
|
-
event: "session.created" | "session.deleted" | "session.input.accepted" | "session.stop.requested" | "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}`;
|
|
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}`;
|
|
82
91
|
seq: number;
|
|
83
92
|
payload: LearningTurnEventPayload;
|
|
84
93
|
};
|
|
@@ -93,7 +102,21 @@ type AgentPresenceEvent = {
|
|
|
93
102
|
[key: string]: unknown;
|
|
94
103
|
};
|
|
95
104
|
};
|
|
96
|
-
type
|
|
105
|
+
type AttachmentRelayProgress = {
|
|
106
|
+
transfer_id: string;
|
|
107
|
+
received_bytes: number;
|
|
108
|
+
total_bytes: number;
|
|
109
|
+
percent: number;
|
|
110
|
+
batch_id?: string;
|
|
111
|
+
index?: number;
|
|
112
|
+
};
|
|
113
|
+
type AttachmentRelayProgressEvent = {
|
|
114
|
+
type: "event";
|
|
115
|
+
event: "attachment.relay.progress";
|
|
116
|
+
seq?: number;
|
|
117
|
+
payload: AttachmentRelayProgress;
|
|
118
|
+
};
|
|
119
|
+
type CathyGOIncomingFrame = CathyGOResponse | LearningTurnEvent | AgentPresenceEvent | AttachmentRelayProgressEvent;
|
|
97
120
|
type CathyGOFrame = CathyGORequest | CathyGOIncomingFrame;
|
|
98
121
|
type TextTurnInput = {
|
|
99
122
|
text: string;
|
|
@@ -175,6 +198,7 @@ interface ConversationMessage {
|
|
|
175
198
|
parts?: ConversationMessagePart[];
|
|
176
199
|
turn_id?: string | null;
|
|
177
200
|
created_at: string;
|
|
201
|
+
metadata?: Record<string, unknown>;
|
|
178
202
|
}
|
|
179
203
|
interface ConversationDetail {
|
|
180
204
|
session: ConversationSummary & {
|
|
@@ -211,6 +235,13 @@ interface GatewayAttachment {
|
|
|
211
235
|
width?: number | null;
|
|
212
236
|
height?: number | null;
|
|
213
237
|
created_at?: string | null;
|
|
238
|
+
thumbnail?: GatewayAttachmentThumbnail | null;
|
|
239
|
+
}
|
|
240
|
+
interface GatewayAttachmentThumbnail {
|
|
241
|
+
mime_type: string;
|
|
242
|
+
data_base64: string;
|
|
243
|
+
width?: number | null;
|
|
244
|
+
height?: number | null;
|
|
214
245
|
}
|
|
215
246
|
interface ConversationMessagePart {
|
|
216
247
|
id?: string;
|
|
@@ -336,6 +367,7 @@ type AttachmentCommitParams = {
|
|
|
336
367
|
blob?: AttachmentCommitBlob;
|
|
337
368
|
metadata?: Record<string, unknown>;
|
|
338
369
|
};
|
|
370
|
+
type AttachmentRelayProgressHandler = (progress: AttachmentRelayProgress) => void;
|
|
339
371
|
type LearningTurnEventHandler = (event: LearningTurnEvent) => void;
|
|
340
372
|
type CathyGOProtocolClientCallbacks = {
|
|
341
373
|
onOpen?: () => void;
|
|
@@ -343,6 +375,7 @@ type CathyGOProtocolClientCallbacks = {
|
|
|
343
375
|
onError?: () => void;
|
|
344
376
|
onFrame?: (frame: CathyGOIncomingFrame) => void;
|
|
345
377
|
onTurnEvent?: LearningTurnEventHandler;
|
|
378
|
+
onAttachmentRelayProgress?: AttachmentRelayProgressHandler;
|
|
346
379
|
};
|
|
347
380
|
|
|
348
381
|
type CathyGOTransportFrameHandler = (frame: CathyGOIncomingFrame) => void;
|
|
@@ -370,6 +403,7 @@ declare class CathyGOProtocolClient {
|
|
|
370
403
|
private requestSeq;
|
|
371
404
|
private pending;
|
|
372
405
|
private turnHandlers;
|
|
406
|
+
private attachmentRelayProgressHandlers;
|
|
373
407
|
private lastConnect?;
|
|
374
408
|
private lastEventSeq;
|
|
375
409
|
private connectOptions;
|
|
@@ -378,6 +412,7 @@ declare class CathyGOProtocolClient {
|
|
|
378
412
|
updateConnectOptions(patch: Partial<CathyGOConnectOptions>): void;
|
|
379
413
|
updateCallbacks(callbacks: CathyGOProtocolClientCallbacks): void;
|
|
380
414
|
onTurnEvent(handler: LearningTurnEventHandler): () => void;
|
|
415
|
+
onAttachmentRelayProgress(handler: AttachmentRelayProgressHandler): () => void;
|
|
381
416
|
connect(): Promise<CathyGOConnectResult>;
|
|
382
417
|
reconnect(options?: Partial<CathyGOConnectOptions>): Promise<CathyGOConnectResult>;
|
|
383
418
|
disconnect(): void;
|
|
@@ -386,6 +421,11 @@ declare class CathyGOProtocolClient {
|
|
|
386
421
|
max_payload_bytes: number;
|
|
387
422
|
max_upload_bytes: number;
|
|
388
423
|
heartbeat_interval_ms: number;
|
|
424
|
+
attachment_relay_max_files_per_send?: number;
|
|
425
|
+
attachment_relay_max_concurrent_transfers?: number;
|
|
426
|
+
attachment_relay_chunk_bytes?: number;
|
|
427
|
+
attachment_relay_max_file_bytes?: number;
|
|
428
|
+
attachment_relay_progress_min_interval_ms?: number;
|
|
389
429
|
} | undefined;
|
|
390
430
|
createSession(metadata?: Record<string, unknown>): Promise<string>;
|
|
391
431
|
listSessions(limit?: number): Promise<ConversationSummary[]>;
|
|
@@ -411,6 +451,17 @@ declare function connectPayload(options: CathyGOConnectOptions): Record<string,
|
|
|
411
451
|
declare function parseConnectPayload(payload: Record<string, unknown>): CathyGOConnectResult;
|
|
412
452
|
declare function settingsFromPayload(payload: Record<string, unknown>): GatewayVisibleSettings;
|
|
413
453
|
declare function isLearningTurnEvent(frame: CathyGOIncomingFrame): frame is LearningTurnEvent;
|
|
454
|
+
declare function isAttachmentRelayProgressEvent(frame: CathyGOIncomingFrame): frame is AttachmentRelayProgressEvent;
|
|
455
|
+
|
|
456
|
+
type UploadAttachmentViaRelayOptions = {
|
|
457
|
+
transferId?: string;
|
|
458
|
+
sessionId?: string;
|
|
459
|
+
metadata?: Record<string, unknown>;
|
|
460
|
+
chunkBytes?: number;
|
|
461
|
+
onProgress?: (progress: AttachmentRelayProgress) => void;
|
|
462
|
+
signal?: AbortSignal;
|
|
463
|
+
};
|
|
464
|
+
declare function uploadAttachmentViaRelay(client: CathyGOProtocolClient, file: File, options?: UploadAttachmentViaRelayOptions): Promise<GatewayAttachment>;
|
|
414
465
|
|
|
415
466
|
type LearningCapability = NonNullable<SessionInputOptions["capability"]>;
|
|
416
467
|
declare function textTurnInput(text: string): TurnInput;
|
|
@@ -418,4 +469,4 @@ declare function photoQuestionTurnInput(text: string, attachments: GatewayAttach
|
|
|
418
469
|
declare function capabilityForTurn(attachments: GatewayAttachment[]): LearningCapability;
|
|
419
470
|
declare function learningTurnInput(text: string, attachments: GatewayAttachment[]): TurnInput;
|
|
420
471
|
|
|
421
|
-
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 };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ var CathyGOProtocolClient = class {
|
|
|
26
26
|
requestSeq = 1;
|
|
27
27
|
pending = /* @__PURE__ */ new Map();
|
|
28
28
|
turnHandlers = /* @__PURE__ */ new Set();
|
|
29
|
+
attachmentRelayProgressHandlers = /* @__PURE__ */ new Set();
|
|
29
30
|
lastConnect;
|
|
30
31
|
lastEventSeq = 0;
|
|
31
32
|
connectOptions;
|
|
@@ -40,6 +41,10 @@ var CathyGOProtocolClient = class {
|
|
|
40
41
|
this.turnHandlers.add(handler);
|
|
41
42
|
return () => this.turnHandlers.delete(handler);
|
|
42
43
|
}
|
|
44
|
+
onAttachmentRelayProgress(handler) {
|
|
45
|
+
this.attachmentRelayProgressHandlers.add(handler);
|
|
46
|
+
return () => this.attachmentRelayProgressHandlers.delete(handler);
|
|
47
|
+
}
|
|
43
48
|
async connect() {
|
|
44
49
|
if (this.isConnected() && this.lastConnect) {
|
|
45
50
|
return this.lastConnect;
|
|
@@ -205,6 +210,12 @@ var CathyGOProtocolClient = class {
|
|
|
205
210
|
handler(frame);
|
|
206
211
|
}
|
|
207
212
|
}
|
|
213
|
+
if (isAttachmentRelayProgressEvent(frame)) {
|
|
214
|
+
this.callbacks.onAttachmentRelayProgress?.(frame.payload);
|
|
215
|
+
for (const handler of this.attachmentRelayProgressHandlers) {
|
|
216
|
+
handler(frame.payload);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
208
219
|
this.callbacks.onFrame?.(frame);
|
|
209
220
|
}
|
|
210
221
|
};
|
|
@@ -254,6 +265,9 @@ function settingsFromPayload(payload) {
|
|
|
254
265
|
function isLearningTurnEvent(frame) {
|
|
255
266
|
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
267
|
}
|
|
268
|
+
function isAttachmentRelayProgressEvent(frame) {
|
|
269
|
+
return frame.type === "event" && frame.event === "attachment.relay.progress";
|
|
270
|
+
}
|
|
257
271
|
function turnStartResultFromPayload(payload, fallbackSessionId) {
|
|
258
272
|
return {
|
|
259
273
|
session_id: String(payload.session_id ?? fallbackSessionId),
|
|
@@ -280,6 +294,126 @@ function compactParams(params) {
|
|
|
280
294
|
return Object.fromEntries(Object.entries(params).filter(([, value]) => value !== void 0));
|
|
281
295
|
}
|
|
282
296
|
|
|
297
|
+
// src/relay-attachment-upload.ts
|
|
298
|
+
async function uploadAttachmentViaRelay(client, file, options = {}) {
|
|
299
|
+
const transferId = options.transferId ?? createTransferId();
|
|
300
|
+
const mimeType = file.type || "application/octet-stream";
|
|
301
|
+
const buffer = await file.arrayBuffer();
|
|
302
|
+
const bytes = new Uint8Array(buffer);
|
|
303
|
+
const sha256 = await sha256Hex(buffer);
|
|
304
|
+
const limits = client.getLimits();
|
|
305
|
+
const chunkBytes = options.chunkBytes ?? Number(limits?.attachment_relay_chunk_bytes ?? DEFAULT_RELAY_CHUNK_BYTES);
|
|
306
|
+
if (options.signal?.aborted) {
|
|
307
|
+
throw new DOMException("Attachment relay upload aborted.", "AbortError");
|
|
308
|
+
}
|
|
309
|
+
const openPayload = await client.request("attachment.relay.open", {
|
|
310
|
+
transfer_id: transferId,
|
|
311
|
+
session_id: options.sessionId,
|
|
312
|
+
mime_type: mimeType,
|
|
313
|
+
size_bytes: bytes.byteLength,
|
|
314
|
+
sha256,
|
|
315
|
+
original_name: file.name || void 0,
|
|
316
|
+
metadata: options.metadata
|
|
317
|
+
});
|
|
318
|
+
const negotiatedChunkBytes = Number(openPayload.chunk_bytes ?? chunkBytes) || chunkBytes;
|
|
319
|
+
try {
|
|
320
|
+
let seq = 0;
|
|
321
|
+
for (let offset = 0; offset < bytes.byteLength; offset += negotiatedChunkBytes) {
|
|
322
|
+
if (options.signal?.aborted) {
|
|
323
|
+
await client.request("attachment.relay.abort", { transfer_id: transferId });
|
|
324
|
+
throw new DOMException("Attachment relay upload aborted.", "AbortError");
|
|
325
|
+
}
|
|
326
|
+
const chunk = bytes.subarray(offset, offset + negotiatedChunkBytes);
|
|
327
|
+
const pushPayload = await client.request("attachment.relay.push", {
|
|
328
|
+
transfer_id: transferId,
|
|
329
|
+
seq,
|
|
330
|
+
data_base64: bytesToBase64(chunk)
|
|
331
|
+
});
|
|
332
|
+
seq += 1;
|
|
333
|
+
options.onProgress?.({
|
|
334
|
+
transfer_id: transferId,
|
|
335
|
+
received_bytes: Number(pushPayload.received_bytes ?? offset + chunk.byteLength),
|
|
336
|
+
total_bytes: Number(pushPayload.total_bytes ?? bytes.byteLength),
|
|
337
|
+
percent: percent(
|
|
338
|
+
Number(pushPayload.received_bytes ?? offset + chunk.byteLength),
|
|
339
|
+
Number(pushPayload.total_bytes ?? bytes.byteLength)
|
|
340
|
+
),
|
|
341
|
+
batch_id: stringOrUndefined(options.metadata?.batch_id),
|
|
342
|
+
index: numberOrUndefined(options.metadata?.index)
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
const closePayload = await client.request("attachment.relay.close", {
|
|
346
|
+
transfer_id: transferId
|
|
347
|
+
});
|
|
348
|
+
return normalizeGatewayAttachment(closePayload.attachment);
|
|
349
|
+
} catch (error) {
|
|
350
|
+
if (!(error instanceof DOMException && error.name === "AbortError")) {
|
|
351
|
+
try {
|
|
352
|
+
await client.request("attachment.relay.abort", { transfer_id: transferId });
|
|
353
|
+
} catch {
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
var DEFAULT_RELAY_CHUNK_BYTES = 65536;
|
|
360
|
+
function createTransferId() {
|
|
361
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
362
|
+
return `xfer_${crypto.randomUUID().replace(/-/g, "").slice(0, 16)}`;
|
|
363
|
+
}
|
|
364
|
+
return `xfer_${Date.now().toString(36)}`;
|
|
365
|
+
}
|
|
366
|
+
function percent(receivedBytes, totalBytes) {
|
|
367
|
+
if (totalBytes <= 0) return 0;
|
|
368
|
+
return Math.min(100, Math.max(0, Math.round(receivedBytes * 100 / totalBytes)));
|
|
369
|
+
}
|
|
370
|
+
function bytesToBase64(bytes) {
|
|
371
|
+
let binary = "";
|
|
372
|
+
for (let index = 0; index < bytes.length; index += 1) {
|
|
373
|
+
binary += String.fromCharCode(bytes[index] ?? 0);
|
|
374
|
+
}
|
|
375
|
+
return btoa(binary);
|
|
376
|
+
}
|
|
377
|
+
async function sha256Hex(buffer) {
|
|
378
|
+
const digest = await crypto.subtle.digest("SHA-256", buffer);
|
|
379
|
+
return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
380
|
+
}
|
|
381
|
+
function normalizeGatewayAttachment(value) {
|
|
382
|
+
const attachment = value ?? {};
|
|
383
|
+
const id = String(attachment.id ?? attachment.attachment_id ?? "");
|
|
384
|
+
if (!id) {
|
|
385
|
+
throw new Error("attachment.relay.close did not return an attachment id.");
|
|
386
|
+
}
|
|
387
|
+
return {
|
|
388
|
+
id,
|
|
389
|
+
kind: "image",
|
|
390
|
+
uri: String(attachment.uri ?? ""),
|
|
391
|
+
original_name: stringOrNull(attachment.original_name),
|
|
392
|
+
mime_type: stringOrNull(attachment.mime_type),
|
|
393
|
+
size_bytes: numberOrNull(attachment.size_bytes),
|
|
394
|
+
sha256: stringOrNull(attachment.sha256),
|
|
395
|
+
width: numberOrNull(attachment.width),
|
|
396
|
+
height: numberOrNull(attachment.height),
|
|
397
|
+
created_at: stringOrNull(attachment.created_at),
|
|
398
|
+
thumbnail: attachment.thumbnail
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
function stringOrUndefined(value) {
|
|
402
|
+
if (typeof value !== "string") return void 0;
|
|
403
|
+
const text = value.trim();
|
|
404
|
+
return text || void 0;
|
|
405
|
+
}
|
|
406
|
+
function stringOrNull(value) {
|
|
407
|
+
return stringOrUndefined(value) ?? null;
|
|
408
|
+
}
|
|
409
|
+
function numberOrUndefined(value) {
|
|
410
|
+
if (typeof value !== "number" || Number.isNaN(value)) return void 0;
|
|
411
|
+
return value;
|
|
412
|
+
}
|
|
413
|
+
function numberOrNull(value) {
|
|
414
|
+
return numberOrUndefined(value) ?? null;
|
|
415
|
+
}
|
|
416
|
+
|
|
283
417
|
// src/turn-input.ts
|
|
284
418
|
function textTurnInput(text) {
|
|
285
419
|
return { text };
|
|
@@ -315,10 +449,12 @@ export {
|
|
|
315
449
|
CathyGOProtocolClient,
|
|
316
450
|
capabilityForTurn,
|
|
317
451
|
connectPayload,
|
|
452
|
+
isAttachmentRelayProgressEvent,
|
|
318
453
|
isLearningTurnEvent,
|
|
319
454
|
learningTurnInput,
|
|
320
455
|
parseConnectPayload,
|
|
321
456
|
photoQuestionTurnInput,
|
|
322
457
|
settingsFromPayload,
|
|
323
|
-
textTurnInput
|
|
458
|
+
textTurnInput,
|
|
459
|
+
uploadAttachmentViaRelay
|
|
324
460
|
};
|