@sinas/sdk 0.5.0 → 0.8.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.
- package/dist/{chunk-IABVF56L.js → chunk-RHQVV5O6.js} +344 -99
- package/dist/chunk-RHQVV5O6.js.map +1 -0
- package/dist/client.cjs +356 -98
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +330 -5
- package/dist/client.d.ts +330 -5
- package/dist/client.js +29 -1
- package/dist/index.cjs +624 -244
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -4
- package/dist/index.d.ts +62 -4
- package/dist/index.js +298 -147
- package/dist/index.js.map +1 -1
- package/dist/sinas-sdk.umd.js +610 -244
- package/dist/sinas-sdk.umd.js.map +1 -1
- package/package.json +6 -3
- package/dist/chunk-IABVF56L.js.map +0 -1
package/dist/client.cjs
CHANGED
|
@@ -27,19 +27,31 @@ __export(client_exports, {
|
|
|
27
27
|
SinasNotFoundError: () => SinasNotFoundError,
|
|
28
28
|
SinasPermissionError: () => SinasPermissionError,
|
|
29
29
|
SinasTimeoutError: () => SinasTimeoutError,
|
|
30
|
+
answerPendingInput: () => answerPendingInput,
|
|
31
|
+
answerResumeChannel: () => answerResumeChannel,
|
|
32
|
+
approvalResumeChannel: () => approvalResumeChannel,
|
|
30
33
|
approveToolCall: () => approveToolCall,
|
|
34
|
+
cancelBatch: () => cancelBatch,
|
|
31
35
|
checkPermissions: () => checkPermissions,
|
|
32
36
|
createChat: () => createChat,
|
|
37
|
+
enqueueFunction: () => enqueueFunction,
|
|
33
38
|
executeFunction: () => executeFunction,
|
|
34
39
|
executeQuery: () => executeQuery,
|
|
35
40
|
generateFileUrl: () => generateFileUrl,
|
|
41
|
+
getBatch: () => getBatch,
|
|
36
42
|
getChat: () => getChat,
|
|
37
43
|
getInfo: () => getInfo,
|
|
38
44
|
getMe: () => getMe,
|
|
45
|
+
invokeAgent: () => invokeAgent,
|
|
46
|
+
listBatchExecutions: () => listBatchExecutions,
|
|
39
47
|
listCollections: () => listCollections,
|
|
40
48
|
listFiles: () => listFiles,
|
|
49
|
+
listPendingInputs: () => listPendingInputs,
|
|
41
50
|
login: () => login,
|
|
42
51
|
logout: () => logout,
|
|
52
|
+
parsePendingInput: () => parsePendingInput,
|
|
53
|
+
parsePendingInputs: () => parsePendingInputs,
|
|
54
|
+
pendingInputFromChunk: () => pendingInputFromChunk,
|
|
43
55
|
refresh: () => refresh,
|
|
44
56
|
sendMessage: () => sendMessage,
|
|
45
57
|
stateDelete: () => stateDelete,
|
|
@@ -48,6 +60,8 @@ __export(client_exports, {
|
|
|
48
60
|
stateSet: () => stateSet,
|
|
49
61
|
streamFromChannel: () => streamFromChannel,
|
|
50
62
|
streamMessage: () => streamMessage,
|
|
63
|
+
submitAgentBatch: () => submitAgentBatch,
|
|
64
|
+
submitFunctionBatch: () => submitFunctionBatch,
|
|
51
65
|
uploadFile: () => uploadFile,
|
|
52
66
|
verifyOTP: () => verifyOTP
|
|
53
67
|
});
|
|
@@ -362,6 +376,124 @@ async function executeFunction(client, ref, input = {}, timeout) {
|
|
|
362
376
|
error: data.error
|
|
363
377
|
};
|
|
364
378
|
}
|
|
379
|
+
async function enqueueFunction(client, ref, input = {}, options = {}) {
|
|
380
|
+
const [ns, name] = parseRef2(ref);
|
|
381
|
+
const baseUrl = client.requireBaseUrl();
|
|
382
|
+
const body = { input };
|
|
383
|
+
if (options.triggerId !== void 0) body.trigger_id = options.triggerId;
|
|
384
|
+
if (options.delaySeconds !== void 0) body.delay_seconds = options.delaySeconds;
|
|
385
|
+
if (options.callbackUrl !== void 0) body.callback_url = options.callbackUrl;
|
|
386
|
+
const res = await client.fetch(`${baseUrl}/functions/${ns}/${name}/execute/async`, {
|
|
387
|
+
method: "POST",
|
|
388
|
+
body: JSON.stringify(body)
|
|
389
|
+
});
|
|
390
|
+
const data = await res.json();
|
|
391
|
+
return {
|
|
392
|
+
executionId: data.execution_id,
|
|
393
|
+
status: data.status
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
async function submitFunctionBatch(client, ref, inputs, options = {}) {
|
|
397
|
+
const [ns, name] = parseRef2(ref);
|
|
398
|
+
const baseUrl = client.requireBaseUrl();
|
|
399
|
+
const body = { inputs };
|
|
400
|
+
if (options.triggerIdPrefix !== void 0) body.trigger_id_prefix = options.triggerIdPrefix;
|
|
401
|
+
if (options.delaySeconds !== void 0) body.delay_seconds = options.delaySeconds;
|
|
402
|
+
if (options.callbackUrl !== void 0) body.callback_url = options.callbackUrl;
|
|
403
|
+
if (options.batchCallbackUrl !== void 0) body.batch_callback_url = options.batchCallbackUrl;
|
|
404
|
+
const res = await client.fetch(`${baseUrl}/functions/${ns}/${name}/execute/batch`, {
|
|
405
|
+
method: "POST",
|
|
406
|
+
body: JSON.stringify(body)
|
|
407
|
+
});
|
|
408
|
+
const data = await res.json();
|
|
409
|
+
return {
|
|
410
|
+
batchId: data.batch_id,
|
|
411
|
+
executionIds: data.execution_ids,
|
|
412
|
+
total: data.total,
|
|
413
|
+
status: data.status
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
async function submitAgentBatch(client, ref, inputs, options = {}) {
|
|
417
|
+
const [ns, name] = parseRef2(ref);
|
|
418
|
+
const baseUrl = client.requireBaseUrl();
|
|
419
|
+
const body = {
|
|
420
|
+
inputs: inputs.map((item) => ({
|
|
421
|
+
input_variables: item.inputVariables || {},
|
|
422
|
+
message: item.message
|
|
423
|
+
}))
|
|
424
|
+
};
|
|
425
|
+
if (options.triggerIdPrefix !== void 0) body.trigger_id_prefix = options.triggerIdPrefix;
|
|
426
|
+
if (options.callbackUrl !== void 0) body.callback_url = options.callbackUrl;
|
|
427
|
+
if (options.batchCallbackUrl !== void 0) body.batch_callback_url = options.batchCallbackUrl;
|
|
428
|
+
const res = await client.fetch(`${baseUrl}/agents/${ns}/${name}/chats/batch`, {
|
|
429
|
+
method: "POST",
|
|
430
|
+
body: JSON.stringify(body)
|
|
431
|
+
});
|
|
432
|
+
const data = await res.json();
|
|
433
|
+
return {
|
|
434
|
+
batchId: data.batch_id,
|
|
435
|
+
executionIds: data.execution_ids,
|
|
436
|
+
chatIds: data.chat_ids,
|
|
437
|
+
total: data.total,
|
|
438
|
+
status: data.status
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
async function getBatch(client, batchId) {
|
|
442
|
+
const baseUrl = client.requireBaseUrl();
|
|
443
|
+
const res = await client.fetch(`${baseUrl}/batches/${batchId}`);
|
|
444
|
+
const data = await res.json();
|
|
445
|
+
return {
|
|
446
|
+
batchId: data.batch_id,
|
|
447
|
+
kind: data.kind,
|
|
448
|
+
target: data.target,
|
|
449
|
+
userId: data.user_id,
|
|
450
|
+
total: data.total,
|
|
451
|
+
completed: data.completed,
|
|
452
|
+
failed: data.failed,
|
|
453
|
+
cancelled: data.cancelled,
|
|
454
|
+
running: data.running,
|
|
455
|
+
queued: data.queued,
|
|
456
|
+
status: data.status,
|
|
457
|
+
startedAt: data.started_at,
|
|
458
|
+
finishedAt: data.finished_at,
|
|
459
|
+
triggerIdPrefix: data.trigger_id_prefix
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
async function listBatchExecutions(client, batchId, options = {}) {
|
|
463
|
+
const baseUrl = client.requireBaseUrl();
|
|
464
|
+
const params = new URLSearchParams();
|
|
465
|
+
if (options.status) params.set("status", options.status);
|
|
466
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
467
|
+
if (options.offset !== void 0) params.set("offset", String(options.offset));
|
|
468
|
+
const q = params.toString();
|
|
469
|
+
const res = await client.fetch(
|
|
470
|
+
`${baseUrl}/batches/${batchId}/executions${q ? "?" + q : ""}`
|
|
471
|
+
);
|
|
472
|
+
const data = await res.json();
|
|
473
|
+
return (data.executions || []).map((row) => ({
|
|
474
|
+
executionId: row.execution_id,
|
|
475
|
+
status: row.status,
|
|
476
|
+
functionName: row.function_name,
|
|
477
|
+
chatId: row.chat_id ?? null,
|
|
478
|
+
triggerId: row.trigger_id,
|
|
479
|
+
startedAt: row.started_at ?? null,
|
|
480
|
+
completedAt: row.completed_at ?? null,
|
|
481
|
+
durationMs: row.duration_ms ?? null,
|
|
482
|
+
error: row.error ?? null
|
|
483
|
+
}));
|
|
484
|
+
}
|
|
485
|
+
async function cancelBatch(client, batchId) {
|
|
486
|
+
const baseUrl = client.requireBaseUrl();
|
|
487
|
+
const res = await client.fetch(`${baseUrl}/batches/${batchId}/cancel`, {
|
|
488
|
+
method: "POST"
|
|
489
|
+
});
|
|
490
|
+
const data = await res.json();
|
|
491
|
+
return {
|
|
492
|
+
batchId: data.batch_id,
|
|
493
|
+
status: data.status,
|
|
494
|
+
cancelledChildren: data.cancelled_children
|
|
495
|
+
};
|
|
496
|
+
}
|
|
365
497
|
|
|
366
498
|
// src/client/states.ts
|
|
367
499
|
async function stateGet(client, ns, key) {
|
|
@@ -395,12 +527,111 @@ async function stateList(client, ns) {
|
|
|
395
527
|
return res.json();
|
|
396
528
|
}
|
|
397
529
|
|
|
530
|
+
// src/client/chatEvents.ts
|
|
531
|
+
var isObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
532
|
+
var str = (v) => typeof v === "string" ? v : null;
|
|
533
|
+
var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
534
|
+
var optionsOf = (v) => Array.isArray(v) && v.length > 0 && v.every((o) => typeof o === "string") ? v : null;
|
|
535
|
+
function parsePendingInput(raw) {
|
|
536
|
+
if (!isObject(raw)) return null;
|
|
537
|
+
if (typeof raw.tool_call_id !== "string" || !raw.tool_call_id) return null;
|
|
538
|
+
return {
|
|
539
|
+
toolCallId: raw.tool_call_id,
|
|
540
|
+
question: str(raw.question) ?? "",
|
|
541
|
+
options: optionsOf(raw.options),
|
|
542
|
+
expiresAt: str(raw.expires_at),
|
|
543
|
+
createdAt: str(raw.created_at)
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
function parsePendingInputs(raw) {
|
|
547
|
+
return Array.isArray(raw) ? raw.map(parsePendingInput).filter((p) => p !== null) : [];
|
|
548
|
+
}
|
|
549
|
+
function pendingInputFromChunk(chunk) {
|
|
550
|
+
if (chunk.event !== "input_required" && chunk.event !== "message") return null;
|
|
551
|
+
let parsed;
|
|
552
|
+
try {
|
|
553
|
+
parsed = JSON.parse(chunk.data);
|
|
554
|
+
} catch {
|
|
555
|
+
return null;
|
|
556
|
+
}
|
|
557
|
+
if (chunk.event === "message" && (!isObject(parsed) || parsed.type !== "input_required")) return null;
|
|
558
|
+
return parsePendingInput(parsed);
|
|
559
|
+
}
|
|
560
|
+
function parseApproval(raw) {
|
|
561
|
+
if (!isObject(raw) || typeof raw.tool_call_id !== "string") return null;
|
|
562
|
+
return {
|
|
563
|
+
type: str(raw.type) ?? "approval_required",
|
|
564
|
+
toolCallId: raw.tool_call_id,
|
|
565
|
+
functionNamespace: str(raw.function_namespace) ?? "",
|
|
566
|
+
functionName: str(raw.function_name) ?? "",
|
|
567
|
+
arguments: isObject(raw.arguments) ? raw.arguments : {}
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
function parseUsage(raw) {
|
|
571
|
+
if (!isObject(raw)) return null;
|
|
572
|
+
return {
|
|
573
|
+
calls: num(raw.calls),
|
|
574
|
+
promptTokens: num(raw.prompt_tokens),
|
|
575
|
+
completionTokens: num(raw.completion_tokens),
|
|
576
|
+
totalTokens: num(raw.total_tokens),
|
|
577
|
+
cacheReadTokens: num(raw.cache_read_tokens),
|
|
578
|
+
cacheWriteTokens: num(raw.cache_write_tokens),
|
|
579
|
+
costUsd: typeof raw.cost_usd === "number" ? raw.cost_usd : null,
|
|
580
|
+
unpricedCalls: num(raw.unpriced_calls),
|
|
581
|
+
errors: num(raw.errors)
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
var TURN_STATUSES = ["completed", "input_required", "in_progress", "injected"];
|
|
585
|
+
function parseTurnState(raw) {
|
|
586
|
+
const status = TURN_STATUSES.includes(raw.status) ? raw.status : "completed";
|
|
587
|
+
return {
|
|
588
|
+
status,
|
|
589
|
+
pendingInputs: parsePendingInputs(raw.pending_inputs),
|
|
590
|
+
channelId: str(raw.channel_id),
|
|
591
|
+
usage: parseUsage(raw.usage)
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
function parseMessage(data) {
|
|
595
|
+
const toolCalls = data.tool_calls;
|
|
596
|
+
return {
|
|
597
|
+
id: data.id,
|
|
598
|
+
chatId: data.chat_id,
|
|
599
|
+
role: data.role,
|
|
600
|
+
content: data.content ?? null,
|
|
601
|
+
toolCalls: toolCalls ?? null,
|
|
602
|
+
toolCallId: data.tool_call_id ?? null,
|
|
603
|
+
name: data.name ?? null,
|
|
604
|
+
createdAt: data.created_at
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
function parseDone(data) {
|
|
608
|
+
try {
|
|
609
|
+
const parsed = JSON.parse(data);
|
|
610
|
+
if (isObject(parsed) && typeof parsed.status === "string") return { status: parsed.status };
|
|
611
|
+
} catch {
|
|
612
|
+
}
|
|
613
|
+
return { status: "completed" };
|
|
614
|
+
}
|
|
615
|
+
function approvalResumeChannel(result, approved = true) {
|
|
616
|
+
if (result.resume === "waiting") return null;
|
|
617
|
+
if (result.resume === void 0 && !approved) return null;
|
|
618
|
+
return result.channelId || null;
|
|
619
|
+
}
|
|
620
|
+
function answerResumeChannel(result) {
|
|
621
|
+
if (!result.resumed && !result.resumePending) return null;
|
|
622
|
+
return result.channelId || null;
|
|
623
|
+
}
|
|
624
|
+
|
|
398
625
|
// src/client/chat.ts
|
|
399
|
-
|
|
626
|
+
function splitAgentRef(agentRef) {
|
|
400
627
|
const [ns, name] = agentRef.split("/");
|
|
401
628
|
if (!ns || !name) {
|
|
402
629
|
throw new Error(`Invalid agent ref "${agentRef}": expected "namespace/name"`);
|
|
403
630
|
}
|
|
631
|
+
return [ns, name];
|
|
632
|
+
}
|
|
633
|
+
async function createChat(client, agentRef, input) {
|
|
634
|
+
const [ns, name] = splitAgentRef(agentRef);
|
|
404
635
|
const config = client.getConfig();
|
|
405
636
|
const res = await client.fetch(`${config.apiBase}/agents/${ns}/${name}/chats`, {
|
|
406
637
|
method: "POST",
|
|
@@ -426,66 +657,117 @@ async function sendMessage(client, chatId, content) {
|
|
|
426
657
|
chatId: data.chat_id,
|
|
427
658
|
role: data.role,
|
|
428
659
|
content: data.content,
|
|
429
|
-
createdAt: data.created_at
|
|
660
|
+
createdAt: data.created_at,
|
|
661
|
+
...parseTurnState(data)
|
|
430
662
|
};
|
|
431
663
|
}
|
|
432
|
-
function
|
|
433
|
-
const
|
|
664
|
+
async function invokeAgent(client, agentRef, message, options = {}) {
|
|
665
|
+
const [ns, name] = splitAgentRef(agentRef);
|
|
666
|
+
const config = client.getConfig();
|
|
667
|
+
const body = { message };
|
|
668
|
+
if (options.sessionKey !== void 0) body.session_key = options.sessionKey;
|
|
669
|
+
if (options.reset !== void 0) body.reset = options.reset;
|
|
670
|
+
if (options.input !== void 0) body.input = options.input;
|
|
671
|
+
const res = await client.fetch(`${config.apiBase}/agents/${ns}/${name}/invoke`, {
|
|
672
|
+
method: "POST",
|
|
673
|
+
body: JSON.stringify(body)
|
|
674
|
+
});
|
|
675
|
+
const data = await res.json();
|
|
434
676
|
return {
|
|
435
|
-
|
|
677
|
+
reply: typeof data.reply === "string" ? data.reply : "",
|
|
436
678
|
chatId: data.chat_id,
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
toolCalls: toolCalls ?? null,
|
|
440
|
-
toolCallId: data.tool_call_id ?? null,
|
|
441
|
-
name: data.name ?? null,
|
|
442
|
-
createdAt: data.created_at
|
|
679
|
+
sessionKey: data.session_key ?? null,
|
|
680
|
+
...parseTurnState(data)
|
|
443
681
|
};
|
|
444
682
|
}
|
|
445
683
|
async function getChat(client, chatId) {
|
|
446
684
|
const config = client.getConfig();
|
|
447
685
|
const res = await client.fetch(`${config.apiBase}/chats/${chatId}`);
|
|
448
686
|
const data = await res.json();
|
|
449
|
-
|
|
687
|
+
const detail = {
|
|
450
688
|
id: data.id,
|
|
451
689
|
agentNamespace: data.agent_namespace,
|
|
452
690
|
agentName: data.agent_name,
|
|
453
691
|
title: data.title,
|
|
454
|
-
messages: (data.messages || []).map(
|
|
455
|
-
pendingApprovals: (data.pending_approvals || []).map((
|
|
456
|
-
type: "approval_required",
|
|
457
|
-
toolCallId: pa.tool_call_id,
|
|
458
|
-
functionNamespace: pa.function_namespace,
|
|
459
|
-
functionName: pa.function_name,
|
|
460
|
-
arguments: pa.arguments || {}
|
|
461
|
-
}))
|
|
692
|
+
messages: (data.messages || []).map(parseMessage),
|
|
693
|
+
pendingApprovals: (data.pending_approvals || []).map(parseApproval).filter((a) => a !== null)
|
|
462
694
|
};
|
|
695
|
+
if (Array.isArray(data.pending_inputs)) {
|
|
696
|
+
detail.pendingInputs = parsePendingInputs(data.pending_inputs);
|
|
697
|
+
}
|
|
698
|
+
return detail;
|
|
463
699
|
}
|
|
464
|
-
async function approveToolCall(client, chatId, toolCallId, approved) {
|
|
700
|
+
async function approveToolCall(client, chatId, toolCallId, approved, options = {}) {
|
|
465
701
|
const config = client.getConfig();
|
|
702
|
+
const body = { approved };
|
|
703
|
+
if (approved && options.alwaysAllow) body.always_allow = true;
|
|
466
704
|
const res = await client.fetch(
|
|
467
|
-
`${config.apiBase}/chats/${chatId}/approve-tool/${toolCallId}`,
|
|
468
|
-
{ method: "POST", body: JSON.stringify(
|
|
705
|
+
`${config.apiBase}/chats/${chatId}/approve-tool/${encodeURIComponent(toolCallId)}`,
|
|
706
|
+
{ method: "POST", body: JSON.stringify(body) }
|
|
469
707
|
);
|
|
470
708
|
const data = await res.json();
|
|
471
|
-
|
|
709
|
+
const result = {
|
|
472
710
|
status: data.status,
|
|
473
711
|
toolCallId: data.tool_call_id,
|
|
474
712
|
channelId: data.channel_id
|
|
475
713
|
};
|
|
714
|
+
if (data.resume === "waiting" || data.resume === "queued") result.resume = data.resume;
|
|
715
|
+
if (typeof data.message === "string") result.message = data.message;
|
|
716
|
+
return result;
|
|
476
717
|
}
|
|
477
|
-
function
|
|
478
|
-
const
|
|
718
|
+
async function listPendingInputs(client, chatId) {
|
|
719
|
+
const config = client.getConfig();
|
|
720
|
+
const res = await client.fetch(`${config.apiBase}/chats/${chatId}/pending-input`);
|
|
721
|
+
return parsePendingInputs(await res.json());
|
|
722
|
+
}
|
|
723
|
+
async function answerPendingInput(client, chatId, toolCallId, answer, options = {}) {
|
|
724
|
+
const config = client.getConfig();
|
|
725
|
+
const body = { answer };
|
|
726
|
+
if (options.wait) body.wait = true;
|
|
727
|
+
const res = await client.fetch(
|
|
728
|
+
`${config.apiBase}/chats/${chatId}/pending-input/${encodeURIComponent(toolCallId)}`,
|
|
729
|
+
{ method: "POST", body: JSON.stringify(body) }
|
|
730
|
+
);
|
|
731
|
+
const data = await res.json();
|
|
732
|
+
if (options.wait) {
|
|
733
|
+
return {
|
|
734
|
+
toolCallId: data.tool_call_id,
|
|
735
|
+
chatId: data.chat_id,
|
|
736
|
+
reply: typeof data.reply === "string" ? data.reply : "",
|
|
737
|
+
message: data.message && typeof data.message === "object" ? parseMessage(data.message) : null,
|
|
738
|
+
...parseTurnState(data)
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
return {
|
|
742
|
+
status: "answered",
|
|
743
|
+
toolCallId: data.tool_call_id,
|
|
744
|
+
resumed: !!data.resumed,
|
|
745
|
+
resumePending: !!data.resume_pending,
|
|
746
|
+
channelId: data.channel_id ?? null,
|
|
747
|
+
message: typeof data.message === "string" ? data.message : ""
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
function streamFromChannel(client, chatId, channelId, onChunk, onDone, onError, options = {}) {
|
|
479
751
|
const config = client.getConfig();
|
|
752
|
+
const params = new URLSearchParams({ last_id: options.lastId ?? "0" });
|
|
753
|
+
if (options.includeThinking) params.set("include_thinking", "true");
|
|
754
|
+
return runSSE(
|
|
755
|
+
`${config.apiBase}/chats/${chatId}/stream/${encodeURIComponent(channelId)}?${params}`,
|
|
756
|
+
(signal) => ({ headers: client.getAuthHeaders(), signal }),
|
|
757
|
+
"Stream reconnect failed",
|
|
758
|
+
onChunk,
|
|
759
|
+
onDone,
|
|
760
|
+
onError
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
function runSSE(url, init, failure, onChunk, onDone, onError) {
|
|
764
|
+
const controller = new AbortController();
|
|
480
765
|
(async () => {
|
|
481
766
|
try {
|
|
482
|
-
const res = await fetch(
|
|
483
|
-
`${config.apiBase}/chats/${chatId}/stream/${channelId}?last_id=0`,
|
|
484
|
-
{ headers: client.getAuthHeaders(), signal: controller.signal }
|
|
485
|
-
);
|
|
767
|
+
const res = await fetch(url, init(controller.signal));
|
|
486
768
|
if (!res.ok) {
|
|
487
769
|
const body = await res.json().catch(() => ({ detail: res.statusText }));
|
|
488
|
-
throw new Error(body.detail ||
|
|
770
|
+
throw new Error(body.detail || failure);
|
|
489
771
|
}
|
|
490
772
|
const reader = res.body.getReader();
|
|
491
773
|
const decoder = new TextDecoder();
|
|
@@ -499,7 +781,7 @@ function streamFromChannel(client, chatId, channelId, onChunk, onDone, onError)
|
|
|
499
781
|
for (const chunk of chunks) {
|
|
500
782
|
onChunk(chunk);
|
|
501
783
|
if (chunk.event === "done") {
|
|
502
|
-
onDone?.();
|
|
784
|
+
onDone?.(parseDone(chunk.data));
|
|
503
785
|
return;
|
|
504
786
|
}
|
|
505
787
|
}
|
|
@@ -508,9 +790,13 @@ function streamFromChannel(client, chatId, channelId, onChunk, onDone, onError)
|
|
|
508
790
|
const { chunks } = parseSSE(buffer + "\n\n");
|
|
509
791
|
for (const chunk of chunks) {
|
|
510
792
|
onChunk(chunk);
|
|
793
|
+
if (chunk.event === "done") {
|
|
794
|
+
onDone?.(parseDone(chunk.data));
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
511
797
|
}
|
|
512
798
|
}
|
|
513
|
-
onDone?.();
|
|
799
|
+
onDone?.({ status: "closed" });
|
|
514
800
|
} catch (err) {
|
|
515
801
|
if (err.name === "AbortError") return;
|
|
516
802
|
onError?.(err);
|
|
@@ -521,75 +807,33 @@ function streamFromChannel(client, chatId, channelId, onChunk, onDone, onError)
|
|
|
521
807
|
function parseSSE(buffer) {
|
|
522
808
|
const chunks = [];
|
|
523
809
|
const normalized = buffer.replace(/\r\n/g, "\n");
|
|
524
|
-
|
|
525
|
-
let
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
if (line.startsWith("event:")) {
|
|
535
|
-
event = line.slice(6).trim();
|
|
536
|
-
} else if (line.startsWith("data:")) {
|
|
537
|
-
data = line.slice(5).trim();
|
|
538
|
-
} else if (line === "") {
|
|
539
|
-
if (event || data) {
|
|
540
|
-
chunks.push({ event: event || "message", data });
|
|
541
|
-
event = "";
|
|
542
|
-
data = "";
|
|
543
|
-
}
|
|
810
|
+
let start = 0;
|
|
811
|
+
let end;
|
|
812
|
+
while ((end = normalized.indexOf("\n\n", start)) !== -1) {
|
|
813
|
+
const block = normalized.slice(start, end);
|
|
814
|
+
start = end + 2;
|
|
815
|
+
let event = "";
|
|
816
|
+
const data = [];
|
|
817
|
+
for (const line of block.split("\n")) {
|
|
818
|
+
if (line.startsWith("event:")) event = line.slice(6).trim();
|
|
819
|
+
else if (line.startsWith("data:")) data.push(line.slice(5).trim());
|
|
544
820
|
}
|
|
821
|
+
if (event || data.length) chunks.push({ event: event || "message", data: data.join("\n") });
|
|
545
822
|
}
|
|
546
|
-
return { chunks, remaining };
|
|
823
|
+
return { chunks, remaining: normalized.slice(start) };
|
|
547
824
|
}
|
|
548
|
-
function streamMessage(client, chatId, content, onChunk, onDone, onError) {
|
|
549
|
-
const controller = new AbortController();
|
|
825
|
+
function streamMessage(client, chatId, content, onChunk, onDone, onError, options = {}) {
|
|
550
826
|
const config = client.getConfig();
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
throw new Error(body.detail || "Stream request failed");
|
|
562
|
-
}
|
|
563
|
-
const reader = res.body.getReader();
|
|
564
|
-
const decoder = new TextDecoder();
|
|
565
|
-
let buffer = "";
|
|
566
|
-
while (true) {
|
|
567
|
-
const { done, value } = await reader.read();
|
|
568
|
-
if (done) break;
|
|
569
|
-
buffer += decoder.decode(value, { stream: true });
|
|
570
|
-
const { chunks, remaining } = parseSSE(buffer);
|
|
571
|
-
buffer = remaining;
|
|
572
|
-
for (const chunk of chunks) {
|
|
573
|
-
onChunk(chunk);
|
|
574
|
-
if (chunk.event === "done") {
|
|
575
|
-
onDone?.();
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
if (buffer.trim()) {
|
|
581
|
-
const { chunks } = parseSSE(buffer + "\n\n");
|
|
582
|
-
for (const chunk of chunks) {
|
|
583
|
-
onChunk(chunk);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
onDone?.();
|
|
587
|
-
} catch (err) {
|
|
588
|
-
if (err.name === "AbortError") return;
|
|
589
|
-
onError?.(err);
|
|
590
|
-
}
|
|
591
|
-
})();
|
|
592
|
-
return controller;
|
|
827
|
+
const body = { content };
|
|
828
|
+
if (options.includeThinking) body.include_thinking = true;
|
|
829
|
+
return runSSE(
|
|
830
|
+
`${config.apiBase}/chats/${chatId}/messages/stream`,
|
|
831
|
+
(signal) => ({ method: "POST", headers: client.getAuthHeaders(), body: JSON.stringify(body), signal }),
|
|
832
|
+
"Stream request failed",
|
|
833
|
+
onChunk,
|
|
834
|
+
onDone,
|
|
835
|
+
onError
|
|
836
|
+
);
|
|
593
837
|
}
|
|
594
838
|
|
|
595
839
|
// src/client/collections.ts
|
|
@@ -631,19 +875,31 @@ async function generateFileUrl(client, namespace, collection, filename, expiresI
|
|
|
631
875
|
SinasNotFoundError,
|
|
632
876
|
SinasPermissionError,
|
|
633
877
|
SinasTimeoutError,
|
|
878
|
+
answerPendingInput,
|
|
879
|
+
answerResumeChannel,
|
|
880
|
+
approvalResumeChannel,
|
|
634
881
|
approveToolCall,
|
|
882
|
+
cancelBatch,
|
|
635
883
|
checkPermissions,
|
|
636
884
|
createChat,
|
|
885
|
+
enqueueFunction,
|
|
637
886
|
executeFunction,
|
|
638
887
|
executeQuery,
|
|
639
888
|
generateFileUrl,
|
|
889
|
+
getBatch,
|
|
640
890
|
getChat,
|
|
641
891
|
getInfo,
|
|
642
892
|
getMe,
|
|
893
|
+
invokeAgent,
|
|
894
|
+
listBatchExecutions,
|
|
643
895
|
listCollections,
|
|
644
896
|
listFiles,
|
|
897
|
+
listPendingInputs,
|
|
645
898
|
login,
|
|
646
899
|
logout,
|
|
900
|
+
parsePendingInput,
|
|
901
|
+
parsePendingInputs,
|
|
902
|
+
pendingInputFromChunk,
|
|
647
903
|
refresh,
|
|
648
904
|
sendMessage,
|
|
649
905
|
stateDelete,
|
|
@@ -652,6 +908,8 @@ async function generateFileUrl(client, namespace, collection, filename, expiresI
|
|
|
652
908
|
stateSet,
|
|
653
909
|
streamFromChannel,
|
|
654
910
|
streamMessage,
|
|
911
|
+
submitAgentBatch,
|
|
912
|
+
submitFunctionBatch,
|
|
655
913
|
uploadFile,
|
|
656
914
|
verifyOTP
|
|
657
915
|
});
|