@xiashe/sdk 0.1.0 → 0.1.5

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.
Files changed (2) hide show
  1. package/index.mjs +82 -17
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -6,7 +6,7 @@ import path from 'node:path';
6
6
  import { ConvexHttpClient } from 'convex/browser';
7
7
  import { anyApi as api } from 'convex/server';
8
8
 
9
- export const VERSION = '0.1.0';
9
+ export const VERSION = '0.1.3';
10
10
 
11
11
  export const DEFAULTS = {
12
12
  cn: {
@@ -38,6 +38,7 @@ const CONFIG_DIR = process.env.XIASHE_CONFIG_DIR || path.join(os.homedir(), DEFA
38
38
  const CONFIG_PATH = process.env.XIASHE_CONFIG_PATH || path.join(CONFIG_DIR, 'config.json');
39
39
  const DEFAULT_PROFILE = 'default';
40
40
  const HTTP_TIMEOUT_MS = 20_000;
41
+ const DEFAULT_MAX_UPLOAD_BYTES = 10 * 1024 * 1024;
41
42
 
42
43
  export class XiasheError extends Error {
43
44
  constructor(message, options = {}) {
@@ -529,6 +530,16 @@ export class XiasheClient {
529
530
  return this.query(api.agentGateway.listForUser, this.authArgs({ limit }));
530
531
  }
531
532
 
533
+ async revokeAgent(agentConnectionId, options = {}) {
534
+ return this.mutation(
535
+ api.agentGateway.revokeConnection,
536
+ this.authArgs({
537
+ agentConnectionId,
538
+ idempotencyKey: options.idempotencyKey || createIdempotencyKey('cli-agent-revoke', [agentConnectionId])
539
+ })
540
+ );
541
+ }
542
+
532
543
  async createAgentChatTask(options = {}) {
533
544
  return this.mutation(
534
545
  api.agentGateway.createChatTask,
@@ -598,6 +609,12 @@ export class XiasheClient {
598
609
  if (!info.isFile()) {
599
610
  throw new XiasheError(`Not a file: ${absolutePath}`, { code: 'UPLOAD_NOT_FILE' });
600
611
  }
612
+ if (info.size > DEFAULT_MAX_UPLOAD_BYTES) {
613
+ throw new XiasheError(`File too large. Max ${DEFAULT_MAX_UPLOAD_BYTES} bytes.`, {
614
+ code: 'UPLOAD_FILE_TOO_LARGE',
615
+ details: { maxBytes: DEFAULT_MAX_UPLOAD_BYTES, size: info.size }
616
+ });
617
+ }
601
618
  const fileName = options.fileName || path.basename(absolutePath);
602
619
  const mime = options.mime || inferMime(absolutePath);
603
620
  const source = options.source || 'manual_upload';
@@ -663,6 +680,8 @@ export class XiasheClient {
663
680
  agentName: options.agentName || undefined,
664
681
  agentKind: options.agentKind || undefined,
665
682
  agentRef: options.agentRef || undefined,
683
+ webhookUrl: options.webhookUrl || undefined,
684
+ webhookAuthToken: options.webhookAuthToken || undefined,
666
685
  transport: options.transport || undefined
667
686
  },
668
687
  { timeoutMs: this.timeoutMs }
@@ -691,6 +710,11 @@ export class XiasheClient {
691
710
  async agentHeartbeat(options = {}) {
692
711
  return this.agentRest('/agent-gateway/heartbeat', {
693
712
  status: options.status || 'online',
713
+ agentName: options.agentName || undefined,
714
+ agentRef: options.agentRef || undefined,
715
+ webhookUrl: options.webhookUrl || undefined,
716
+ webhookAuthToken: options.webhookAuthToken || undefined,
717
+ webhookMode: options.webhookMode || undefined,
694
718
  capabilities: options.capabilities || undefined
695
719
  });
696
720
  }
@@ -701,6 +725,28 @@ export class XiasheClient {
701
725
  });
702
726
  }
703
727
 
728
+ async agentListTransfers(options = {}) {
729
+ return this.agentRest('/agent-gateway/transfers/list', {
730
+ limit: options.limit || 20
731
+ });
732
+ }
733
+
734
+ async agentAcceptTransfer(transferId, options = {}) {
735
+ return this.agentRest('/agent-gateway/transfers/accept', {
736
+ transferId,
737
+ idempotencyKey: options.idempotencyKey || undefined
738
+ });
739
+ }
740
+
741
+ async agentCompleteTransfer(transferId, options = {}) {
742
+ return this.agentRest('/agent-gateway/transfers/complete', {
743
+ transferId,
744
+ status: options.status || 'completed',
745
+ error: options.error || undefined,
746
+ idempotencyKey: options.idempotencyKey || undefined
747
+ });
748
+ }
749
+
704
750
  async agentAckTask(taskId, state = 'running') {
705
751
  return this.agentRest('/agent-gateway/tasks/ack', { taskId, state });
706
752
  }
@@ -716,6 +762,7 @@ export class XiasheClient {
716
762
  async agentCreateTask(options = {}) {
717
763
  return this.agentRest('/agent-gateway/tasks/create', {
718
764
  targetAgentConnectionId: options.targetAgentConnectionId,
765
+ targetAgentName: options.targetAgentName,
719
766
  chatId: options.chatId,
720
767
  content: options.content,
721
768
  attachments: options.attachments || undefined,
@@ -774,6 +821,9 @@ export async function saveAgentSession(profileName, claimResult) {
774
821
 
775
822
  export function printableAgentPrompt(issue) {
776
823
  const claimUrl = issue.claimUrl || issue.restBaseUrl?.replace(/\/+$/, '') + '/agent-gateway/claim';
824
+ const receiverCommand = DEFAULT_ENV === 'global'
825
+ ? 'npx -y @agentpie/cli agent run --ack'
826
+ : 'npx -y @xiashe/cli agent run --ack';
777
827
  if (DEFAULT_ENV === 'global') {
778
828
  return [
779
829
  'Connect this Agent to AgentPie. Please complete the setup automatically or call the HTTP endpoint directly. Do not expose the token to the end user.',
@@ -787,15 +837,21 @@ export function printableAgentPrompt(issue) {
787
837
  {
788
838
  token: issue.token,
789
839
  agentName: '<your agent name>',
790
- agentKind: '<codex|claude|coze|workbuddy|local|other>',
840
+ agentKind: '<mcp|http|npx|local|other>',
791
841
  transport: '<mcp|http|npx|manual>',
792
- agentRef: '<optional: device, workspace, or instance id>'
842
+ agentRef: '<optional: device, workspace, or instance id>',
843
+ webhookUrl: '<optional public HTTPS endpoint for immediate wake-up>',
844
+ webhookAuthToken: '<optional shared secret for webhook Authorization>'
793
845
  },
794
846
  null,
795
847
  2
796
848
  ),
797
849
  '',
798
- 'After claiming, save the returned runtimeToken and periodically POST heartbeat events to /agent-gateway/heartbeat on the REST Base URL.',
850
+ 'After claiming, save the returned runtimeToken. If you expose a public HTTPS webhook, AgentPie will POST task notifications there; return HTTP 202 and process with MCP/REST, or return JSON { "content": "..." } within 8 seconds to complete immediately. If webhook delivery fails, tasks remain queued for polling.',
851
+ '',
852
+ 'Persistent Agents may run a lightweight receiver loop with MCP or REST tool calls only; no long-lived socket is required. The loop should send heartbeat, inspect pendingTaskCount/pendingTransferCount, and only call a model when work is present. Default cadence is about 30s while idle, 10s while work is active, and up to 2 minutes after long idle periods. Use recommendedNextHeartbeatMs with jitter/backoff. Temporary sandbox Agents should not run a loop; reconnect when work is needed.',
853
+ '',
854
+ `Recommended receiver command for shell-capable runtimes: ${receiverCommand}`,
799
855
  '',
800
856
  'If you support MCP, add the MCP URL as a tool server and use the runtimeToken as a Bearer token.',
801
857
  '',
@@ -815,19 +871,25 @@ export function printableAgentPrompt(issue) {
815
871
  `POST ${claimUrl}`,
816
872
  'Content-Type: application/json',
817
873
  '',
818
- JSON.stringify(
819
- {
820
- token: issue.token,
821
- agentName: '<你的 Agent 名称>',
822
- agentKind: '<codex|claude|coze|workbuddy|local|other>',
823
- transport: '<mcp|http|npx|manual>',
824
- agentRef: '<可选:设备名、工作区或实例标识>'
825
- },
826
- null,
827
- 2
828
- ),
874
+ JSON.stringify(
875
+ {
876
+ token: issue.token,
877
+ agentName: '<你的 Agent 名称>',
878
+ agentKind: '<mcp|http|npx|local|other>',
879
+ transport: '<mcp|http|npx|manual>',
880
+ agentRef: '<可选:设备名、工作区或实例标识>',
881
+ webhookUrl: '<可选:用于即时唤醒的公网 HTTPS endpoint>',
882
+ webhookAuthToken: '<可选:webhook Authorization 共享密钥>'
883
+ },
884
+ null,
885
+ 2
886
+ ),
887
+ '',
888
+ '成功后保存返回的 runtimeToken。如果你能提供公网 HTTPS webhook,虾舍会在创建任务时直接 POST 通知;你可以快速返回 HTTP 202 后用 MCP/REST 处理,也可以在 8 秒内返回 JSON { "content": "..." } 让虾舍立即完成任务。webhook 失败时任务仍会保留在队列里,继续支持 polling。',
829
889
  '',
830
- '成功后保存返回的 runtimeToken,并定期 POST 心跳到 REST Base URL 的 /agent-gateway/heartbeat。',
890
+ '常驻 Agent 可以使用 MCP 或 REST 工具调用运行轻量任务接收循环,不需要长连接:发送心跳,查看 pendingTaskCount/pendingTransferCount;只有存在任务时才拉取任务、确认 running、执行并 complete 回虾舍。默认节奏是空闲约 30 秒一次、有任务约 10 秒一次、长时间空闲后最多约 2 分钟一次。',
891
+ '',
892
+ `如果运行环境可以执行 shell,推荐接收命令:${receiverCommand}`,
831
893
  '',
832
894
  '如果你支持 MCP,请把下面的 MCP URL 加为工具服务,并在调用时使用 runtimeToken 作为 Bearer Token。',
833
895
  '',
@@ -836,7 +898,10 @@ export function printableAgentPrompt(issue) {
836
898
  `MCP URL: ${issue.mcpUrl}`,
837
899
  `REST Base URL: ${issue.restBaseUrl}`,
838
900
  '',
839
- '连接完成后,你会出现在虾舍的 Agent 工作台里,可以接收 @提及、任务和文件。'
901
+ '连接完成后,你会出现在虾舍的 Agent 工作台里,可以接收 @提及、任务和文件。',
902
+ '',
903
+ '常驻 Agent:只发送轻量 heartbeat;没有任务时不要推理、不要调用模型。请使用 heartbeat 返回的 recommendedNextHeartbeatMs,并加入 jitter/backoff。',
904
+ '临时 sandbox:不要跑 receiver loop。需要工作时重新连接;完成一次性任务后即可退出。'
840
905
  ].join('\n');
841
906
  }
842
907
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiashe/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "main": "index.mjs",
6
6
  "exports": {