@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.
@@ -307,6 +307,124 @@ async function executeFunction(client, ref, input = {}, timeout) {
307
307
  error: data.error
308
308
  };
309
309
  }
310
+ async function enqueueFunction(client, ref, input = {}, options = {}) {
311
+ const [ns, name] = parseRef2(ref);
312
+ const baseUrl = client.requireBaseUrl();
313
+ const body = { input };
314
+ if (options.triggerId !== void 0) body.trigger_id = options.triggerId;
315
+ if (options.delaySeconds !== void 0) body.delay_seconds = options.delaySeconds;
316
+ if (options.callbackUrl !== void 0) body.callback_url = options.callbackUrl;
317
+ const res = await client.fetch(`${baseUrl}/functions/${ns}/${name}/execute/async`, {
318
+ method: "POST",
319
+ body: JSON.stringify(body)
320
+ });
321
+ const data = await res.json();
322
+ return {
323
+ executionId: data.execution_id,
324
+ status: data.status
325
+ };
326
+ }
327
+ async function submitFunctionBatch(client, ref, inputs, options = {}) {
328
+ const [ns, name] = parseRef2(ref);
329
+ const baseUrl = client.requireBaseUrl();
330
+ const body = { inputs };
331
+ if (options.triggerIdPrefix !== void 0) body.trigger_id_prefix = options.triggerIdPrefix;
332
+ if (options.delaySeconds !== void 0) body.delay_seconds = options.delaySeconds;
333
+ if (options.callbackUrl !== void 0) body.callback_url = options.callbackUrl;
334
+ if (options.batchCallbackUrl !== void 0) body.batch_callback_url = options.batchCallbackUrl;
335
+ const res = await client.fetch(`${baseUrl}/functions/${ns}/${name}/execute/batch`, {
336
+ method: "POST",
337
+ body: JSON.stringify(body)
338
+ });
339
+ const data = await res.json();
340
+ return {
341
+ batchId: data.batch_id,
342
+ executionIds: data.execution_ids,
343
+ total: data.total,
344
+ status: data.status
345
+ };
346
+ }
347
+ async function submitAgentBatch(client, ref, inputs, options = {}) {
348
+ const [ns, name] = parseRef2(ref);
349
+ const baseUrl = client.requireBaseUrl();
350
+ const body = {
351
+ inputs: inputs.map((item) => ({
352
+ input_variables: item.inputVariables || {},
353
+ message: item.message
354
+ }))
355
+ };
356
+ if (options.triggerIdPrefix !== void 0) body.trigger_id_prefix = options.triggerIdPrefix;
357
+ if (options.callbackUrl !== void 0) body.callback_url = options.callbackUrl;
358
+ if (options.batchCallbackUrl !== void 0) body.batch_callback_url = options.batchCallbackUrl;
359
+ const res = await client.fetch(`${baseUrl}/agents/${ns}/${name}/chats/batch`, {
360
+ method: "POST",
361
+ body: JSON.stringify(body)
362
+ });
363
+ const data = await res.json();
364
+ return {
365
+ batchId: data.batch_id,
366
+ executionIds: data.execution_ids,
367
+ chatIds: data.chat_ids,
368
+ total: data.total,
369
+ status: data.status
370
+ };
371
+ }
372
+ async function getBatch(client, batchId) {
373
+ const baseUrl = client.requireBaseUrl();
374
+ const res = await client.fetch(`${baseUrl}/batches/${batchId}`);
375
+ const data = await res.json();
376
+ return {
377
+ batchId: data.batch_id,
378
+ kind: data.kind,
379
+ target: data.target,
380
+ userId: data.user_id,
381
+ total: data.total,
382
+ completed: data.completed,
383
+ failed: data.failed,
384
+ cancelled: data.cancelled,
385
+ running: data.running,
386
+ queued: data.queued,
387
+ status: data.status,
388
+ startedAt: data.started_at,
389
+ finishedAt: data.finished_at,
390
+ triggerIdPrefix: data.trigger_id_prefix
391
+ };
392
+ }
393
+ async function listBatchExecutions(client, batchId, options = {}) {
394
+ const baseUrl = client.requireBaseUrl();
395
+ const params = new URLSearchParams();
396
+ if (options.status) params.set("status", options.status);
397
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
398
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
399
+ const q = params.toString();
400
+ const res = await client.fetch(
401
+ `${baseUrl}/batches/${batchId}/executions${q ? "?" + q : ""}`
402
+ );
403
+ const data = await res.json();
404
+ return (data.executions || []).map((row) => ({
405
+ executionId: row.execution_id,
406
+ status: row.status,
407
+ functionName: row.function_name,
408
+ chatId: row.chat_id ?? null,
409
+ triggerId: row.trigger_id,
410
+ startedAt: row.started_at ?? null,
411
+ completedAt: row.completed_at ?? null,
412
+ durationMs: row.duration_ms ?? null,
413
+ error: row.error ?? null
414
+ }));
415
+ }
416
+ async function cancelBatch(client, batchId) {
417
+ const baseUrl = client.requireBaseUrl();
418
+ const res = await client.fetch(`${baseUrl}/batches/${batchId}/cancel`, {
419
+ method: "POST"
420
+ });
421
+ const data = await res.json();
422
+ return {
423
+ batchId: data.batch_id,
424
+ status: data.status,
425
+ cancelledChildren: data.cancelled_children
426
+ };
427
+ }
310
428
 
311
429
  // src/client/states.ts
312
430
  async function stateGet(client, ns, key) {
@@ -340,12 +458,111 @@ async function stateList(client, ns) {
340
458
  return res.json();
341
459
  }
342
460
 
461
+ // src/client/chatEvents.ts
462
+ var isObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
463
+ var str = (v) => typeof v === "string" ? v : null;
464
+ var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
465
+ var optionsOf = (v) => Array.isArray(v) && v.length > 0 && v.every((o) => typeof o === "string") ? v : null;
466
+ function parsePendingInput(raw) {
467
+ if (!isObject(raw)) return null;
468
+ if (typeof raw.tool_call_id !== "string" || !raw.tool_call_id) return null;
469
+ return {
470
+ toolCallId: raw.tool_call_id,
471
+ question: str(raw.question) ?? "",
472
+ options: optionsOf(raw.options),
473
+ expiresAt: str(raw.expires_at),
474
+ createdAt: str(raw.created_at)
475
+ };
476
+ }
477
+ function parsePendingInputs(raw) {
478
+ return Array.isArray(raw) ? raw.map(parsePendingInput).filter((p) => p !== null) : [];
479
+ }
480
+ function pendingInputFromChunk(chunk) {
481
+ if (chunk.event !== "input_required" && chunk.event !== "message") return null;
482
+ let parsed;
483
+ try {
484
+ parsed = JSON.parse(chunk.data);
485
+ } catch {
486
+ return null;
487
+ }
488
+ if (chunk.event === "message" && (!isObject(parsed) || parsed.type !== "input_required")) return null;
489
+ return parsePendingInput(parsed);
490
+ }
491
+ function parseApproval(raw) {
492
+ if (!isObject(raw) || typeof raw.tool_call_id !== "string") return null;
493
+ return {
494
+ type: str(raw.type) ?? "approval_required",
495
+ toolCallId: raw.tool_call_id,
496
+ functionNamespace: str(raw.function_namespace) ?? "",
497
+ functionName: str(raw.function_name) ?? "",
498
+ arguments: isObject(raw.arguments) ? raw.arguments : {}
499
+ };
500
+ }
501
+ function parseUsage(raw) {
502
+ if (!isObject(raw)) return null;
503
+ return {
504
+ calls: num(raw.calls),
505
+ promptTokens: num(raw.prompt_tokens),
506
+ completionTokens: num(raw.completion_tokens),
507
+ totalTokens: num(raw.total_tokens),
508
+ cacheReadTokens: num(raw.cache_read_tokens),
509
+ cacheWriteTokens: num(raw.cache_write_tokens),
510
+ costUsd: typeof raw.cost_usd === "number" ? raw.cost_usd : null,
511
+ unpricedCalls: num(raw.unpriced_calls),
512
+ errors: num(raw.errors)
513
+ };
514
+ }
515
+ var TURN_STATUSES = ["completed", "input_required", "in_progress", "injected"];
516
+ function parseTurnState(raw) {
517
+ const status = TURN_STATUSES.includes(raw.status) ? raw.status : "completed";
518
+ return {
519
+ status,
520
+ pendingInputs: parsePendingInputs(raw.pending_inputs),
521
+ channelId: str(raw.channel_id),
522
+ usage: parseUsage(raw.usage)
523
+ };
524
+ }
525
+ function parseMessage(data) {
526
+ const toolCalls = data.tool_calls;
527
+ return {
528
+ id: data.id,
529
+ chatId: data.chat_id,
530
+ role: data.role,
531
+ content: data.content ?? null,
532
+ toolCalls: toolCalls ?? null,
533
+ toolCallId: data.tool_call_id ?? null,
534
+ name: data.name ?? null,
535
+ createdAt: data.created_at
536
+ };
537
+ }
538
+ function parseDone(data) {
539
+ try {
540
+ const parsed = JSON.parse(data);
541
+ if (isObject(parsed) && typeof parsed.status === "string") return { status: parsed.status };
542
+ } catch {
543
+ }
544
+ return { status: "completed" };
545
+ }
546
+ function approvalResumeChannel(result, approved = true) {
547
+ if (result.resume === "waiting") return null;
548
+ if (result.resume === void 0 && !approved) return null;
549
+ return result.channelId || null;
550
+ }
551
+ function answerResumeChannel(result) {
552
+ if (!result.resumed && !result.resumePending) return null;
553
+ return result.channelId || null;
554
+ }
555
+
343
556
  // src/client/chat.ts
344
- async function createChat(client, agentRef, input) {
557
+ function splitAgentRef(agentRef) {
345
558
  const [ns, name] = agentRef.split("/");
346
559
  if (!ns || !name) {
347
560
  throw new Error(`Invalid agent ref "${agentRef}": expected "namespace/name"`);
348
561
  }
562
+ return [ns, name];
563
+ }
564
+ async function createChat(client, agentRef, input) {
565
+ const [ns, name] = splitAgentRef(agentRef);
349
566
  const config = client.getConfig();
350
567
  const res = await client.fetch(`${config.apiBase}/agents/${ns}/${name}/chats`, {
351
568
  method: "POST",
@@ -371,66 +588,117 @@ async function sendMessage(client, chatId, content) {
371
588
  chatId: data.chat_id,
372
589
  role: data.role,
373
590
  content: data.content,
374
- createdAt: data.created_at
591
+ createdAt: data.created_at,
592
+ ...parseTurnState(data)
375
593
  };
376
594
  }
377
- function mapMessage(data) {
378
- const toolCalls = data.tool_calls;
595
+ async function invokeAgent(client, agentRef, message, options = {}) {
596
+ const [ns, name] = splitAgentRef(agentRef);
597
+ const config = client.getConfig();
598
+ const body = { message };
599
+ if (options.sessionKey !== void 0) body.session_key = options.sessionKey;
600
+ if (options.reset !== void 0) body.reset = options.reset;
601
+ if (options.input !== void 0) body.input = options.input;
602
+ const res = await client.fetch(`${config.apiBase}/agents/${ns}/${name}/invoke`, {
603
+ method: "POST",
604
+ body: JSON.stringify(body)
605
+ });
606
+ const data = await res.json();
379
607
  return {
380
- id: data.id,
608
+ reply: typeof data.reply === "string" ? data.reply : "",
381
609
  chatId: data.chat_id,
382
- role: data.role,
383
- content: data.content ?? null,
384
- toolCalls: toolCalls ?? null,
385
- toolCallId: data.tool_call_id ?? null,
386
- name: data.name ?? null,
387
- createdAt: data.created_at
610
+ sessionKey: data.session_key ?? null,
611
+ ...parseTurnState(data)
388
612
  };
389
613
  }
390
614
  async function getChat(client, chatId) {
391
615
  const config = client.getConfig();
392
616
  const res = await client.fetch(`${config.apiBase}/chats/${chatId}`);
393
617
  const data = await res.json();
394
- return {
618
+ const detail = {
395
619
  id: data.id,
396
620
  agentNamespace: data.agent_namespace,
397
621
  agentName: data.agent_name,
398
622
  title: data.title,
399
- messages: (data.messages || []).map(mapMessage),
400
- pendingApprovals: (data.pending_approvals || []).map((pa) => ({
401
- type: "approval_required",
402
- toolCallId: pa.tool_call_id,
403
- functionNamespace: pa.function_namespace,
404
- functionName: pa.function_name,
405
- arguments: pa.arguments || {}
406
- }))
623
+ messages: (data.messages || []).map(parseMessage),
624
+ pendingApprovals: (data.pending_approvals || []).map(parseApproval).filter((a) => a !== null)
407
625
  };
626
+ if (Array.isArray(data.pending_inputs)) {
627
+ detail.pendingInputs = parsePendingInputs(data.pending_inputs);
628
+ }
629
+ return detail;
408
630
  }
409
- async function approveToolCall(client, chatId, toolCallId, approved) {
631
+ async function approveToolCall(client, chatId, toolCallId, approved, options = {}) {
410
632
  const config = client.getConfig();
633
+ const body = { approved };
634
+ if (approved && options.alwaysAllow) body.always_allow = true;
411
635
  const res = await client.fetch(
412
- `${config.apiBase}/chats/${chatId}/approve-tool/${toolCallId}`,
413
- { method: "POST", body: JSON.stringify({ approved }) }
636
+ `${config.apiBase}/chats/${chatId}/approve-tool/${encodeURIComponent(toolCallId)}`,
637
+ { method: "POST", body: JSON.stringify(body) }
414
638
  );
415
639
  const data = await res.json();
416
- return {
640
+ const result = {
417
641
  status: data.status,
418
642
  toolCallId: data.tool_call_id,
419
643
  channelId: data.channel_id
420
644
  };
645
+ if (data.resume === "waiting" || data.resume === "queued") result.resume = data.resume;
646
+ if (typeof data.message === "string") result.message = data.message;
647
+ return result;
421
648
  }
422
- function streamFromChannel(client, chatId, channelId, onChunk, onDone, onError) {
423
- const controller = new AbortController();
649
+ async function listPendingInputs(client, chatId) {
650
+ const config = client.getConfig();
651
+ const res = await client.fetch(`${config.apiBase}/chats/${chatId}/pending-input`);
652
+ return parsePendingInputs(await res.json());
653
+ }
654
+ async function answerPendingInput(client, chatId, toolCallId, answer, options = {}) {
655
+ const config = client.getConfig();
656
+ const body = { answer };
657
+ if (options.wait) body.wait = true;
658
+ const res = await client.fetch(
659
+ `${config.apiBase}/chats/${chatId}/pending-input/${encodeURIComponent(toolCallId)}`,
660
+ { method: "POST", body: JSON.stringify(body) }
661
+ );
662
+ const data = await res.json();
663
+ if (options.wait) {
664
+ return {
665
+ toolCallId: data.tool_call_id,
666
+ chatId: data.chat_id,
667
+ reply: typeof data.reply === "string" ? data.reply : "",
668
+ message: data.message && typeof data.message === "object" ? parseMessage(data.message) : null,
669
+ ...parseTurnState(data)
670
+ };
671
+ }
672
+ return {
673
+ status: "answered",
674
+ toolCallId: data.tool_call_id,
675
+ resumed: !!data.resumed,
676
+ resumePending: !!data.resume_pending,
677
+ channelId: data.channel_id ?? null,
678
+ message: typeof data.message === "string" ? data.message : ""
679
+ };
680
+ }
681
+ function streamFromChannel(client, chatId, channelId, onChunk, onDone, onError, options = {}) {
424
682
  const config = client.getConfig();
683
+ const params = new URLSearchParams({ last_id: options.lastId ?? "0" });
684
+ if (options.includeThinking) params.set("include_thinking", "true");
685
+ return runSSE(
686
+ `${config.apiBase}/chats/${chatId}/stream/${encodeURIComponent(channelId)}?${params}`,
687
+ (signal) => ({ headers: client.getAuthHeaders(), signal }),
688
+ "Stream reconnect failed",
689
+ onChunk,
690
+ onDone,
691
+ onError
692
+ );
693
+ }
694
+ function runSSE(url, init, failure, onChunk, onDone, onError) {
695
+ const controller = new AbortController();
425
696
  (async () => {
426
697
  try {
427
- const res = await fetch(
428
- `${config.apiBase}/chats/${chatId}/stream/${channelId}?last_id=0`,
429
- { headers: client.getAuthHeaders(), signal: controller.signal }
430
- );
698
+ const res = await fetch(url, init(controller.signal));
431
699
  if (!res.ok) {
432
700
  const body = await res.json().catch(() => ({ detail: res.statusText }));
433
- throw new Error(body.detail || "Stream reconnect failed");
701
+ throw new Error(body.detail || failure);
434
702
  }
435
703
  const reader = res.body.getReader();
436
704
  const decoder = new TextDecoder();
@@ -444,7 +712,7 @@ function streamFromChannel(client, chatId, channelId, onChunk, onDone, onError)
444
712
  for (const chunk of chunks) {
445
713
  onChunk(chunk);
446
714
  if (chunk.event === "done") {
447
- onDone?.();
715
+ onDone?.(parseDone(chunk.data));
448
716
  return;
449
717
  }
450
718
  }
@@ -453,9 +721,13 @@ function streamFromChannel(client, chatId, channelId, onChunk, onDone, onError)
453
721
  const { chunks } = parseSSE(buffer + "\n\n");
454
722
  for (const chunk of chunks) {
455
723
  onChunk(chunk);
724
+ if (chunk.event === "done") {
725
+ onDone?.(parseDone(chunk.data));
726
+ return;
727
+ }
456
728
  }
457
729
  }
458
- onDone?.();
730
+ onDone?.({ status: "closed" });
459
731
  } catch (err) {
460
732
  if (err.name === "AbortError") return;
461
733
  onError?.(err);
@@ -466,75 +738,33 @@ function streamFromChannel(client, chatId, channelId, onChunk, onDone, onError)
466
738
  function parseSSE(buffer) {
467
739
  const chunks = [];
468
740
  const normalized = buffer.replace(/\r\n/g, "\n");
469
- const lines = normalized.split("\n");
470
- let event = "";
471
- let data = "";
472
- let remaining = "";
473
- for (let i = 0; i < lines.length; i++) {
474
- const line = lines[i];
475
- if (i === lines.length - 1 && !normalized.endsWith("\n")) {
476
- remaining = line;
477
- break;
478
- }
479
- if (line.startsWith("event:")) {
480
- event = line.slice(6).trim();
481
- } else if (line.startsWith("data:")) {
482
- data = line.slice(5).trim();
483
- } else if (line === "") {
484
- if (event || data) {
485
- chunks.push({ event: event || "message", data });
486
- event = "";
487
- data = "";
488
- }
741
+ let start = 0;
742
+ let end;
743
+ while ((end = normalized.indexOf("\n\n", start)) !== -1) {
744
+ const block = normalized.slice(start, end);
745
+ start = end + 2;
746
+ let event = "";
747
+ const data = [];
748
+ for (const line of block.split("\n")) {
749
+ if (line.startsWith("event:")) event = line.slice(6).trim();
750
+ else if (line.startsWith("data:")) data.push(line.slice(5).trim());
489
751
  }
752
+ if (event || data.length) chunks.push({ event: event || "message", data: data.join("\n") });
490
753
  }
491
- return { chunks, remaining };
754
+ return { chunks, remaining: normalized.slice(start) };
492
755
  }
493
- function streamMessage(client, chatId, content, onChunk, onDone, onError) {
494
- const controller = new AbortController();
756
+ function streamMessage(client, chatId, content, onChunk, onDone, onError, options = {}) {
495
757
  const config = client.getConfig();
496
- (async () => {
497
- try {
498
- const res = await fetch(`${config.apiBase}/chats/${chatId}/messages/stream`, {
499
- method: "POST",
500
- headers: client.getAuthHeaders(),
501
- body: JSON.stringify({ content }),
502
- signal: controller.signal
503
- });
504
- if (!res.ok) {
505
- const body = await res.json().catch(() => ({ detail: res.statusText }));
506
- throw new Error(body.detail || "Stream request failed");
507
- }
508
- const reader = res.body.getReader();
509
- const decoder = new TextDecoder();
510
- let buffer = "";
511
- while (true) {
512
- const { done, value } = await reader.read();
513
- if (done) break;
514
- buffer += decoder.decode(value, { stream: true });
515
- const { chunks, remaining } = parseSSE(buffer);
516
- buffer = remaining;
517
- for (const chunk of chunks) {
518
- onChunk(chunk);
519
- if (chunk.event === "done") {
520
- onDone?.();
521
- return;
522
- }
523
- }
524
- }
525
- if (buffer.trim()) {
526
- const { chunks } = parseSSE(buffer + "\n\n");
527
- for (const chunk of chunks) {
528
- onChunk(chunk);
529
- }
530
- }
531
- onDone?.();
532
- } catch (err) {
533
- if (err.name === "AbortError") return;
534
- onError?.(err);
535
- }
536
- })();
537
- return controller;
758
+ const body = { content };
759
+ if (options.includeThinking) body.include_thinking = true;
760
+ return runSSE(
761
+ `${config.apiBase}/chats/${chatId}/messages/stream`,
762
+ (signal) => ({ method: "POST", headers: client.getAuthHeaders(), body: JSON.stringify(body), signal }),
763
+ "Stream request failed",
764
+ onChunk,
765
+ onDone,
766
+ onError
767
+ );
538
768
  }
539
769
 
540
770
  // src/client/collections.ts
@@ -585,14 +815,29 @@ export {
585
815
  SinasClient,
586
816
  executeQuery,
587
817
  executeFunction,
818
+ enqueueFunction,
819
+ submitFunctionBatch,
820
+ submitAgentBatch,
821
+ getBatch,
822
+ listBatchExecutions,
823
+ cancelBatch,
588
824
  stateGet,
589
825
  stateSet,
590
826
  stateDelete,
591
827
  stateList,
828
+ parsePendingInput,
829
+ parsePendingInputs,
830
+ pendingInputFromChunk,
831
+ parseApproval,
832
+ approvalResumeChannel,
833
+ answerResumeChannel,
592
834
  createChat,
593
835
  sendMessage,
836
+ invokeAgent,
594
837
  getChat,
595
838
  approveToolCall,
839
+ listPendingInputs,
840
+ answerPendingInput,
596
841
  streamFromChannel,
597
842
  streamMessage,
598
843
  listCollections,
@@ -600,4 +845,4 @@ export {
600
845
  uploadFile,
601
846
  generateFileUrl
602
847
  };
603
- //# sourceMappingURL=chunk-IABVF56L.js.map
848
+ //# sourceMappingURL=chunk-RHQVV5O6.js.map