@fangyb/ahchat-bridge 0.1.32 → 0.1.33

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.js CHANGED
@@ -5515,6 +5515,21 @@ EXCEPTION \u2014 inner-voice envelope overrides no-reply:
5515
5515
  - In group chat, default to short. Long-form only when explicitly asked.
5516
5516
  - In 1:1 chat with the human, you may write longer answers when warranted.
5517
5517
 
5518
+ # Media generation replies
5519
+ - Official Seedream / Seedance MCP tools render visible AHChat media task cards.
5520
+ Let the card carry status, preview, download, copy, and regenerate actions.
5521
+ - Current media generation is one output per user request: one Seedream image or
5522
+ one Seedance video. Do not submit candidate batches, parallel tasks, or
5523
+ alternate versions in the same turn.
5524
+ - Do not print raw media URLs, request_id, task_id, polling logs, or repeated
5525
+ "let me check again" narration in the final reply unless the user explicitly
5526
+ asks for diagnostics.
5527
+ - For media submission or completion, write a short natural sentence only,
5528
+ such as "\u5DF2\u5F00\u59CB\u751F\u6210\uFF0C\u6211\u4F1A\u5728\u8FD9\u91CC\u66F4\u65B0\u7ED3\u679C\u3002" or "\u751F\u6210\u597D\u4E86\uFF0C\u53EF\u4EE5\u5728\u5361\u7247\u91CC\u67E5\u770B\u3002"
5529
+ - Do not use Bash, sleep loops, Monitor, curl polling, or background tasks just
5530
+ to wait for Seedream / Seedance. Seedream returns final images directly.
5531
+ Seedance is tracked by AHChat after one create_task call.
5532
+
5518
5533
  # Group chat \u2014 shared task board
5519
5534
  AHChat group conversations have a shared kanban board that is fed by structured
5520
5535
  task tools (TodoWrite when available; otherwise TaskCreate / TaskUpdate). Treat
@@ -5688,13 +5703,14 @@ list_available_skills \u67E5\u8BE2\u5F53\u524D Agent \u53EF\u76F4\u63A5\u4F7F\u7
5688
5703
  - \u5DF2\u51FA\u73B0\u5728 list_available_skills \u7684 assigned/local skill \u4E0D\u9700\u8981\u8BA9\u7528\u6237\u518D\u786E\u8BA4\u662F\u5426\u53EF\u7528\uFF1B\u4F46\u8BFB\u65E5\u5FD7\u3001\u8DD1\u547D\u4EE4\u3001\u5199\u6587\u4EF6\u3001\u53D1\u5E16\u3001\u8BFB\u5927\u91CF\u79C1\u5BC6\u4E0A\u4E0B\u6587\u7B49\u5177\u4F53\u9AD8\u98CE\u9669\u52A8\u4F5C\u6267\u884C\u524D\u5FC5\u987B\u8BF4\u660E\u539F\u56E0\u5E76\u9075\u5B88\u7528\u6237/\u7CFB\u7EDF\u6743\u9650\u8FB9\u754C\u3002
5689
5704
 
5690
5705
  # Cross-scope session isolation
5691
- \u6BCF\u4E2A scope\uFF08single / group\uFF09\u6709\u72EC\u7ACB\u7684 SDK Session / \u5DE5\u4F5C\u8BB0\u5FC6\uFF0C\u4F46\u540C\u4E00\u4E2A Agent \u7684\u6240\u6709 scope \u4F7F\u7528\u540C\u4E00\u4E2A\u5F53\u524D workdir\u3002
5692
- \u4F60\u5728 # Your scopes \u4E2D\u53EF\u4EE5\u770B\u5230\u6BCF\u4E2A scope \u5F53\u524D\u4F7F\u7528\u7684 workdir \u8DEF\u5F84\uFF1B\u6B63\u5E38\u60C5\u51B5\u4E0B\uFF0C\u540C\u4E00 Agent \u7684 single \u4E0E group scope \u8DEF\u5F84\u76F8\u540C\u3002
5706
+ \u6BCF\u4E2A scope\uFF08single / group\uFF09\u6709\u72EC\u7ACB\u7684 SDK Session / \u5DE5\u4F5C\u8BB0\u5FC6\uFF0Cworkdir \u4E5F\u6309 scope \u53D6\u4E0D\u540C\u6743\u5A01\u6765\u6E90\u3002
5707
+ \u4F60\u5728 # Your scopes \u4E2D\u53EF\u4EE5\u770B\u5230\u6BCF\u4E2A scope \u5F53\u524D\u4F7F\u7528\u7684 workdir \u8DEF\u5F84\u3002
5693
5708
 
5694
- - \u4F60\u53EF\u4EE5\u5728\u5F53\u524D workdir \u5185 Read/Glob/Grep/Write/Edit\uFF1B\u4E0D\u8981\u5047\u8BBE\u7FA4\u804A\u548C\u5355\u804A\u6709\u4E24\u4EFD\u4E92\u4E0D\u76F8\u901A\u7684\u6587\u4EF6\u533A\u3002
5695
- - \u5F53\u4F60\u5728\u7FA4 scope \u5B8C\u6210\u4E86\u6587\u4EF6\u4EA7\u51FA\uFF0C\u7528 neural_send \u628A\u6587\u4EF6\u8DEF\u5F84\u548C\u6458\u8981\u901A\u77E5\u4F60\u5728 single scope \u7684\u5206\u8EAB\uFF0C\u65B9\u4FBF\u7528\u6237\u5728\u5355\u804A\u4E2D\u67E5\u770B\u3002
5696
- - \u53CD\u8FC7\u6765\u4E5F\u4E00\u6837\uFF1A\u5355\u804A\u4EA7\u51FA\u540E\uFF0C\u7528 neural_send \u901A\u77E5\u76F8\u5173\u7FA4 scope\u3002
5697
- - neural_send \u7528\u6765\u540C\u6B65\u4E0A\u4E0B\u6587\u548C\u7ED3\u8BBA\uFF1B\u540C\u4E00 Agent \u8DE8 scope \u5171\u4EAB\u6587\u4EF6\u65F6\u901A\u5E38\u53EA\u9700\u8981\u4F20\u8DEF\u5F84\u548C\u6458\u8981\uFF0C\u4E0D\u9700\u8981\u590D\u5236\u6587\u4EF6\u3002
5709
+ - single workdir \u662F\u4F60\u7684\u79C1\u6709 Agent \u5DE5\u4F5C\u76EE\u5F55\uFF0C\u7528\u4E8E\u4F60\u548C\u7528\u6237\u7684 1:1 \u5355\u804A\u3002
5710
+ - group workdir \u662F\u8BE5\u7FA4\u7684\u5171\u4EAB\u5DE5\u4F5C\u76EE\u5F55\uFF1B\u5F53\u4F60\u5728\u8FD9\u4E2A\u7FA4 scope \u4E2D\u8FD0\u884C\u65F6\uFF0C\u5F53\u524D runtime cwd \u5C31\u662F\u8FD9\u4E2A\u7FA4\u76EE\u5F55\u3002
5711
+ - \u7528\u6237\u95EE\u201C\u4F60\u81EA\u5DF1\u7684\u5DE5\u4F5C\u76EE\u5F55\u201D\u548C\u201C\u8FD9\u4E2A\u7FA4\u804A\u5DE5\u4F5C\u76EE\u5F55\u201D\u65F6\uFF0C\u8981\u5206\u522B\u62A5\u544A single workdir \u548C\u5F53\u524D group workdir\uFF1B\u9664\u975E # Your scopes \u91CC\u4E24\u4E2A\u8DEF\u5F84\u5B57\u9762\u5B8C\u5168\u76F8\u540C\uFF0C\u4E0D\u8981\u8BF4\u5B83\u4EEC\u76F8\u540C\u3002
5712
+ - \u4F60\u53EA\u80FD\u5728\u5F53\u524D runtime cwd \u5185 Read/Glob/Grep/Write/Edit\uFF1B\u5728\u7FA4\u91CC\u4EA7\u51FA\u7684\u6587\u4EF6\u9ED8\u8BA4\u5C5E\u4E8E\u7FA4\u5171\u4EAB\u76EE\u5F55\u3002
5713
+ - \u8DE8 scope \u540C\u6B65\u4E0A\u4E0B\u6587\u548C\u7ED3\u8BBA\u7528 neural_send\uFF1B\u5982\u679C\u53E6\u4E00\u4E2A scope \u9700\u8981\u67E5\u770B\u6587\u4EF6\uFF0C\u4F20\u8DEF\u5F84\u548C\u6458\u8981\uFF0C\u4E0D\u8981\u5047\u88C5\u90A3\u4E2A scope \u7684 cwd \u81EA\u52A8\u76F8\u540C\u3002
5698
5714
 
5699
5715
  # Cross-scope awareness (Neural Send)
5700
5716
 
@@ -5921,11 +5937,121 @@ function createMcpToolInvocationId() {
5921
5937
  function isWSMessage(data) {
5922
5938
  return typeof data === "object" && data !== null && "type" in data && "payload" in data;
5923
5939
  }
5940
+ function isPlainRecord(value) {
5941
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
5942
+ const proto2 = Object.getPrototypeOf(value);
5943
+ return proto2 === Object.prototype || proto2 === null;
5944
+ }
5945
+ function invalidWsMessage(type, field) {
5946
+ return new Error(`Invalid WS message ${type} payload.${field}`);
5947
+ }
5948
+ function assertPayloadRecord(type, payload) {
5949
+ if (!isPlainRecord(payload)) {
5950
+ throw new Error(`Invalid WS message ${type} payload`);
5951
+ }
5952
+ }
5953
+ function assertStringPayloadField(type, payload, field) {
5954
+ if (typeof payload[field] !== "string") {
5955
+ throw invalidWsMessage(type, field);
5956
+ }
5957
+ }
5958
+ function assertNumberPayloadField(type, payload, field) {
5959
+ if (typeof payload[field] !== "number" || Number.isNaN(payload[field])) {
5960
+ throw invalidWsMessage(type, field);
5961
+ }
5962
+ }
5963
+ function assertArrayPayloadField(type, payload, field) {
5964
+ if (!Array.isArray(payload[field])) {
5965
+ throw invalidWsMessage(type, field);
5966
+ }
5967
+ }
5968
+ function assertRecordPayloadField(type, payload, field) {
5969
+ if (!isPlainRecord(payload[field])) {
5970
+ throw invalidWsMessage(type, field);
5971
+ }
5972
+ }
5973
+ function validateRequiredStrings(type, payload, fields) {
5974
+ for (const field of fields) assertStringPayloadField(type, payload, field);
5975
+ }
5976
+ function validateWSMessageShape(msg) {
5977
+ const type = msg.type;
5978
+ const payload = msg.payload;
5979
+ switch (type) {
5980
+ case "heartbeat": {
5981
+ assertPayloadRecord(type, payload);
5982
+ assertNumberPayloadField(type, payload, "ts");
5983
+ return;
5984
+ }
5985
+ case "client:hello": {
5986
+ assertPayloadRecord(type, payload);
5987
+ validateRequiredStrings(type, payload, ["sessionId", "platform", "version", "env", "traceId"]);
5988
+ return;
5989
+ }
5990
+ case "user:send_message": {
5991
+ assertPayloadRecord(type, payload);
5992
+ validateRequiredStrings(type, payload, ["id", "agentId", "conversationId", "content", "traceId"]);
5993
+ return;
5994
+ }
5995
+ case "user:group_message": {
5996
+ assertPayloadRecord(type, payload);
5997
+ validateRequiredStrings(type, payload, ["id", "groupId", "conversationId", "content", "traceId"]);
5998
+ assertArrayPayloadField(type, payload, "mentions");
5999
+ return;
6000
+ }
6001
+ case "agent:done": {
6002
+ assertPayloadRecord(type, payload);
6003
+ validateRequiredStrings(type, payload, [
6004
+ "ackId",
6005
+ "messageId",
6006
+ "agentId",
6007
+ "conversationId",
6008
+ "fullContent",
6009
+ "traceId"
6010
+ ]);
6011
+ assertArrayPayloadField(type, payload, "contentBlocks");
6012
+ assertRecordPayloadField(type, payload, "metadata");
6013
+ return;
6014
+ }
6015
+ case "agent:segment": {
6016
+ assertPayloadRecord(type, payload);
6017
+ validateRequiredStrings(type, payload, [
6018
+ "messageId",
6019
+ "ackId",
6020
+ "agentId",
6021
+ "conversationId",
6022
+ "groupId",
6023
+ "content",
6024
+ "traceId"
6025
+ ]);
6026
+ assertArrayPayloadField(type, payload, "contentBlocks");
6027
+ return;
6028
+ }
6029
+ case "agent:turn_complete": {
6030
+ assertPayloadRecord(type, payload);
6031
+ validateRequiredStrings(type, payload, ["ackId", "agentId", "conversationId", "groupId", "traceId"]);
6032
+ assertNumberPayloadField(type, payload, "segmentCount");
6033
+ return;
6034
+ }
6035
+ case "agent:no_reply": {
6036
+ assertPayloadRecord(type, payload);
6037
+ validateRequiredStrings(type, payload, ["ackId", "agentId", "conversationId", "traceId"]);
6038
+ return;
6039
+ }
6040
+ case "agent:error": {
6041
+ assertPayloadRecord(type, payload);
6042
+ validateRequiredStrings(type, payload, ["ackId", "agentId", "conversationId", "error", "traceId"]);
6043
+ return;
6044
+ }
6045
+ default:
6046
+ return;
6047
+ }
6048
+ }
5924
6049
  function parseWSMessage(raw) {
5925
6050
  const parsed = JSON.parse(raw);
5926
6051
  if (!isWSMessage(parsed)) {
5927
6052
  throw new Error("Invalid WS message: missing type/payload");
5928
6053
  }
6054
+ validateWSMessageShape(parsed);
5929
6055
  return parsed;
5930
6056
  }
5931
6057
  function isAskUserQuestionToolName(toolName) {
@@ -5939,7 +6065,7 @@ var SLUG_MAX_LEN = 32;
5939
6065
  function slugifyForFs(name) {
5940
6066
  const trimmed = name.trim();
5941
6067
  if (!trimmed) return "unnamed";
5942
- const slug = trimmed.replace(/[^\w\u4e00-\u9fa5 \-]/gu, "_").replace(/\s+/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
6068
+ const slug = trimmed.replace(/[^\w\u4e00-\u9fa5 -]/gu, "_").replace(/\s+/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
5943
6069
  const base = slug.length > 0 ? slug : "unnamed";
5944
6070
  return base.length > SLUG_MAX_LEN ? base.slice(0, SLUG_MAX_LEN) : base;
5945
6071
  }
@@ -6443,6 +6569,105 @@ var OFFICIAL_OFFICE_SKILL_MARKDOWN = Object.fromEntries(
6443
6569
  OFFICIAL_OFFICE_SKILLS.map((skill) => [skill.id, renderOfficialOfficeSkillMarkdown(skill)])
6444
6570
  );
6445
6571
 
6572
+ // ../shared/src/officialMediaSkills.ts
6573
+ var OFFICIAL_MEDIA_SKILL_IDS = [
6574
+ "media-video-generation"
6575
+ ];
6576
+ var OFFICIAL_MEDIA_SKILLS = [
6577
+ {
6578
+ id: "media-video-generation",
6579
+ name: "\u89C6\u9891\u751F\u6210",
6580
+ summary: "\u5B98\u65B9 Seedance \u89C6\u9891\u751F\u6210\u6D41\u7A0B\u6280\u80FD\uFF1A\u628A\u89C6\u9891\u9700\u6C42\u8F6C\u6210\u7A33\u5B9A\u4EFB\u52A1\uFF0C\u6BCF\u6B21\u53EA\u63D0\u4EA4\u4E00\u4E2A\u89C6\u9891\u4EFB\u52A1\uFF0C\u5E76\u4EA4\u7ED9 AHChat \u5A92\u4F53\u4EFB\u52A1\u5361\u8DDF\u8E2A\u7ED3\u679C\u3002",
6581
+ sourceType: "official",
6582
+ trustLevel: "official",
6583
+ status: "team_approved",
6584
+ taskTypes: [
6585
+ "\u89C6\u9891\u751F\u6210",
6586
+ "\u89C6\u9891",
6587
+ "\u751F\u89C6\u9891",
6588
+ "AI \u89C6\u9891",
6589
+ "Seedance",
6590
+ "\u6587\u751F\u89C6\u9891",
6591
+ "\u56FE\u751F\u89C6\u9891",
6592
+ "\u77ED\u89C6\u9891",
6593
+ "video_generation",
6594
+ "media_generation"
6595
+ ],
6596
+ applicableRoles: [
6597
+ "video",
6598
+ "media",
6599
+ "creative",
6600
+ "designer",
6601
+ "\u5BFC\u6F14",
6602
+ "\u89C6\u9891",
6603
+ "\u751F\u89C6\u9891",
6604
+ "\u521B\u610F",
6605
+ "\u8BBE\u8BA1",
6606
+ "\u591A\u5A92\u4F53",
6607
+ "\u5185\u5BB9"
6608
+ ],
6609
+ applicableScopes: ["single", "group", "smith"],
6610
+ problem: "\u89C6\u9891\u751F\u6210\u662F\u957F\u8017\u65F6\u5916\u90E8\u4EFB\u52A1\u3002\u6CA1\u6709\u4E13\u95E8\u6D41\u7A0B\u65F6\uFF0CAgent \u5BB9\u6613\u7528 Bash\u3001sleep \u6216\u53CD\u590D\u67E5\u8BE2\u5236\u9020\u566A\u97F3\uFF0C\u5E76\u628A task_id\u3001\u7B7E\u540D URL \u548C\u8F6E\u8BE2\u65E5\u5FD7\u66B4\u9732\u7ED9\u7528\u6237\u3002",
6611
+ inputs: [
6612
+ { name: "videoGoal", description: "\u89C6\u9891\u4E3B\u9898\u3001\u4E3B\u4F53\u3001\u52A8\u4F5C\u3001\u98CE\u683C\u548C\u7528\u6237\u671F\u671B\u7684\u6548\u679C\u3002", required: true },
6613
+ { name: "duration", description: "\u671F\u671B\u65F6\u957F\uFF1B\u7528\u6237\u672A\u6307\u5B9A\u65F6\u4F7F\u7528 Seedance \u9ED8\u8BA4\u77ED\u89C6\u9891\u65F6\u957F\u3002" },
6614
+ { name: "format", description: "\u6BD4\u4F8B\u3001\u5206\u8FA8\u7387\u3001\u662F\u5426\u5FEB\u901F\u7248\u3001\u662F\u5426\u9700\u8981\u58F0\u97F3\u6216\u53C2\u8003\u56FE\u3002" }
6615
+ ],
6616
+ outputs: [
6617
+ { name: "mediaTask", description: "\u4E00\u5F20 AHChat \u5A92\u4F53\u4EFB\u52A1\u5361\uFF0C\u5C55\u793A\u751F\u6210\u4E2D\u3001\u5B8C\u6210\u3001\u5931\u8D25\u3001\u9884\u89C8\u3001\u4E0B\u8F7D\u548C\u518D\u6B21\u751F\u6210\u3002", required: true },
6618
+ { name: "shortReply", description: "\u4E00\u53E5\u81EA\u7136\u77ED\u56DE\u590D\uFF0C\u907F\u514D\u91CD\u590D\u89E3\u91CA\u5DE5\u5177\u7EC6\u8282\u3002" }
6619
+ ],
6620
+ steps: [
6621
+ "\u5148\u5224\u65AD\u9700\u6C42\u662F\u5426\u8DB3\u591F\u63D0\u4EA4\uFF1A\u4E3B\u4F53\u3001\u52A8\u4F5C\u3001\u573A\u666F\u548C\u98CE\u683C\u6E05\u695A\u65F6\u76F4\u63A5\u5F00\u59CB\uFF1B\u7F3A\u5173\u952E\u8981\u7D20\u65F6\u6700\u591A\u95EE\u4E00\u4E2A\u805A\u7126\u95EE\u9898\u3002",
6622
+ "\u628A\u9700\u6C42\u6574\u7406\u6210 Seedance prompt\uFF1B\u7528\u6237\u8BF4\u201C\u5FEB\u901F\u7248\u3001\u8D28\u91CF\u4E00\u822C\u3001\u5148\u770B\u770B\u201D\u65F6\u4F18\u5148\u9009\u62E9\u5FEB\u901F / \u8F83\u4F4E\u5206\u8FA8\u7387\u53C2\u6570\uFF0C\u7528\u6237\u660E\u786E\u8981\u9AD8\u8D28\u91CF\u65F6\u518D\u63D0\u9AD8\u53C2\u6570\u3002",
6623
+ "\u6BCF\u6B21\u7528\u6237\u8BF7\u6C42\u53EA\u751F\u6210 1 \u4E2A\u89C6\u9891\u3002\u5982\u679C\u7528\u6237\u8981\u6C42\u591A\u4E2A\u89C6\u9891\u3001\u591A\u4E2A\u7248\u672C\u6216\u5019\u9009\uFF0C\u5148\u8BF4\u660E\u5F53\u524D ALL-CAN \u6D41\u7A0B\u4E00\u6B21\u53EA\u751F\u6210\u4E00\u4E2A\u89C6\u9891\uFF0C\u5E76\u8BA9\u7528\u6237\u5148\u9009\u4E00\u4E2A\u65B9\u5411\u3002",
6624
+ "\u8C03\u7528 mcp__seedance__seedance_create_task \u4E00\u6B21\u63D0\u4EA4 1 \u4E2A\u4EFB\u52A1\u3002\u63D0\u4EA4\u540E\u505C\u6B62\u672C\u8F6E\u624B\u52A8\u7B49\u5F85\uFF0C\u4E0D\u8981\u5E76\u53D1\u63D0\u4EA4\u591A\u4E2A\u4EFB\u52A1\uFF0C\u4E5F\u4E0D\u8981\u7528 Bash\u3001sleep\u3001curl\u3001Monitor\u3001\u540E\u53F0\u4EFB\u52A1\u6216\u5FAA\u73AF\u67E5\u8BE2\u6765\u7B49\u7ED3\u679C\u3002",
6625
+ "\u63D0\u4EA4\u6210\u529F\u540E\u53EA\u56DE\u590D\u4E00\u53E5\u81EA\u7136\u8BDD\u672F\uFF0C\u4F8B\u5982\u201C\u5DF2\u5F00\u59CB\u751F\u6210\uFF0C\u6211\u4F1A\u5728\u8FD9\u91CC\u66F4\u65B0\u7ED3\u679C\u3002\u201D\uFF1B\u8BA9 AHChat \u5A92\u4F53\u4EFB\u52A1\u5361\u5C55\u793A\u7B49\u5F85\u72B6\u6001\u3001\u8017\u65F6\u548C\u53C2\u6570\u3002",
6626
+ "\u7528\u6237\u4E3B\u52A8\u95EE\u201C\u597D\u4E86\u6CA1 / \u8FDB\u5EA6\u600E\u6837\u201D\u65F6\uFF0C\u6700\u591A\u8C03\u7528\u4E00\u6B21 mcp__seedance__seedance_check_task\uFF0C\u5E76\u6839\u636E\u7ED3\u679C\u7B80\u77ED\u56DE\u7B54\uFF1B\u4E0D\u8981\u5FAA\u73AF\u8F6E\u8BE2\u3002",
6627
+ "\u4EFB\u52A1\u5B8C\u6210\u540E\u53EA\u56DE\u590D\u4E00\u53E5\u81EA\u7136\u8BDD\u672F\uFF0C\u4F8B\u5982\u201C\u751F\u6210\u597D\u4E86\uFF0C\u53EF\u4EE5\u5728\u5361\u7247\u91CC\u67E5\u770B\u3002\u201D\uFF1B\u9884\u89C8\u3001\u4E0B\u8F7D\u3001\u590D\u5236\u94FE\u63A5\u548C\u518D\u6B21\u751F\u6210\u7531\u5A92\u4F53\u4EFB\u52A1\u5361\u627F\u8F7D\u3002"
6628
+ ],
6629
+ successCriteria: [
6630
+ "\u804A\u5929\u4E2D\u53EA\u51FA\u73B0\u4E00\u5F20\u6301\u7EED\u66F4\u65B0\u7684\u5A92\u4F53\u4EFB\u52A1\u5361\u548C\u4E00\u4E2A\u89C6\u9891\u7ED3\u679C\uFF0C\u4E0D\u51FA\u73B0\u591A\u4E2A\u5019\u9009\u4EFB\u52A1\u3001\u591A\u6BB5 Bash\u3001sleep\u3001curl \u6216\u91CD\u590D check_task \u65E5\u5FD7\u3002",
6631
+ "\u4E0D\u4F1A\u5411\u7528\u6237\u66B4\u9732 raw task_id\u3001request_id\u3001\u957F\u7B7E\u540D URL \u6216\u8F6E\u8BE2\u8FC7\u7A0B\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u8BCA\u65AD\u3002",
6632
+ "Agent \u7684\u6587\u672C\u56DE\u590D\u77ED\u800C\u81EA\u7136\uFF0C\u751F\u6210\u72B6\u6001\u3001\u53C2\u6570\u3001\u9884\u89C8\u548C\u64CD\u4F5C\u90FD\u7531\u5A92\u4F53\u5361\u5C55\u793A\u3002",
6633
+ "\u751F\u6210\u5931\u8D25\u3001\u989D\u5EA6\u4E0D\u8DB3\u6216\u914D\u7F6E\u7F3A\u5931\u65F6\u8BF4\u660E\u53EF\u7406\u89E3\u539F\u56E0\uFF0C\u5E76\u505C\u6B62\u91CD\u8BD5\u5FAA\u73AF\u3002"
6634
+ ],
6635
+ limitations: [
6636
+ "\u4F9D\u8D56\u5B98\u65B9 Seedance MCP \u5DF2\u542F\u7528\u3001\u516C\u53F8 Ark Key \u5DF2\u914D\u7F6E\u4E14\u6BCF\u65E5\u989D\u5EA6\u672A\u8017\u5C3D\u3002",
6637
+ "\u89C6\u9891\u751F\u6210\u4F1A\u6D88\u8017\u516C\u53F8\u5A92\u4F53\u989D\u5EA6\uFF1B\u5177\u4F53\u63D0\u4EA4\u8C03\u7528\u7531 MCP \u6743\u9650\u3001\u6BCF\u65E5\u9650\u989D\u548C\u5BA1\u8BA1\u7CFB\u7EDF\u63A7\u5236\u3002",
6638
+ "\u7B7E\u540D\u5A92\u4F53 URL \u53EF\u80FD\u8FC7\u671F\uFF0C\u5E94\u63D0\u793A\u7528\u6237\u53CA\u65F6\u5728\u5361\u7247\u91CC\u9884\u89C8\u6216\u4E0B\u8F7D\uFF0C\u4F46\u4E0D\u8981\u76F4\u63A5\u7C98\u8D34\u957F URL\u3002",
6639
+ "\u8BE5\u6280\u80FD\u53EA\u89C4\u8303\u89C6\u9891\u751F\u6210\u6D41\u7A0B\uFF0C\u4E0D\u8D1F\u8D23\u7F16\u8F91\u672C\u5730\u89C6\u9891\u6587\u4EF6\u6216\u957F\u671F\u540E\u53F0\u901A\u77E5\u3002"
6640
+ ],
6641
+ permissions: {
6642
+ readsProjectFiles: false,
6643
+ readsLogs: false,
6644
+ readsConversationContext: true,
6645
+ canRunBash: false,
6646
+ canWriteFiles: false,
6647
+ canPostToForum: false,
6648
+ permissionLevel: "medium"
6649
+ },
6650
+ sourceEvidence: {
6651
+ feedPostIds: [],
6652
+ feedCategories: [],
6653
+ groupIds: [],
6654
+ taskIds: [],
6655
+ contributingAgentIds: [],
6656
+ successExamples: [
6657
+ "ProductCore \u5A92\u4F53\u4EFB\u52A1\u72B6\u6001\u67B6\u6784\uFF1ASeedance \u957F\u4EFB\u52A1\u7531 AHChat \u5A92\u4F53\u4EFB\u52A1\u5361\u8DDF\u8E2A\uFF0C\u800C\u4E0D\u662F\u9760 Agent \u624B\u52A8\u8F6E\u8BE2\u3002",
6658
+ "\u5B98\u65B9 Seedance MCP\uFF1Amcp__seedance__seedance_create_task / mcp__seedance__seedance_check_task\u3002"
6659
+ ],
6660
+ failureExamples: [
6661
+ "Agent \u7528 Bash sleep \u6216\u5FAA\u73AF check_task \u7B49\u5F85\u89C6\u9891\uFF0C\u5BFC\u81F4\u804A\u5929\u91CC\u51FA\u73B0\u5927\u91CF\u65E0\u610F\u4E49\u5DE5\u5177\u8C03\u7528\u3002",
6662
+ "Agent \u628A task_id\u3001\u957F\u7B7E\u540D URL \u548C\u8F6E\u8BE2\u65E5\u5FD7\u4F5C\u4E3A\u6B63\u6587\u8F93\u51FA\uFF0C\u7834\u574F\u5FAE\u4FE1\u5F0F\u804A\u5929\u4F53\u9A8C\u3002"
6663
+ ]
6664
+ },
6665
+ installScope: "team",
6666
+ version: "1.0.0",
6667
+ createdBy: "system"
6668
+ }
6669
+ ];
6670
+
6446
6671
  // ../shared/src/officialWazaSkills.ts
6447
6672
  var WAZA_VERSION = "3.28.0";
6448
6673
  var WAZA_UPSTREAM = "Upstream: tw93/Waza (MIT) https://github.com/tw93/Waza";
@@ -6762,11 +6987,13 @@ var OFFICIAL_WAZA_SKILLS = [
6762
6987
  // ../shared/src/officialSkills.ts
6763
6988
  var OFFICIAL_SKILL_IDS = [
6764
6989
  ...OFFICIAL_OFFICE_SKILL_IDS,
6765
- ...OFFICIAL_WAZA_SKILL_IDS
6990
+ ...OFFICIAL_WAZA_SKILL_IDS,
6991
+ ...OFFICIAL_MEDIA_SKILL_IDS
6766
6992
  ];
6767
6993
  var OFFICIAL_SKILLS = [
6768
6994
  ...OFFICIAL_OFFICE_SKILLS,
6769
- ...OFFICIAL_WAZA_SKILLS
6995
+ ...OFFICIAL_WAZA_SKILLS,
6996
+ ...OFFICIAL_MEDIA_SKILLS
6770
6997
  ];
6771
6998
  function renderOfficialSkillMarkdown(skill) {
6772
6999
  return renderSkillManifestMarkdown(skill, { cacheSource: "shared-official" });
@@ -6900,7 +7127,42 @@ function searchTokens(value) {
6900
7127
  value.split(/[\s,,、/|]+/g).map((token) => token.trim()).filter((token) => token.length >= 2)
6901
7128
  )];
6902
7129
  }
6903
- var BROAD_TASK_TERMS = /* @__PURE__ */ new Set(["\u65B9\u6848", "\u5185\u5BB9", "\u6587\u6863", "\u5206\u6790", "\u4F18\u5316", "plan", "content", "document", "analysis"]);
7130
+ var BROAD_TASK_TERMS = /* @__PURE__ */ new Set([
7131
+ "\u65B9\u6848",
7132
+ "\u5185\u5BB9",
7133
+ "\u6587\u6863",
7134
+ "\u5206\u6790",
7135
+ "\u4F18\u5316",
7136
+ "\u7528\u6237",
7137
+ "\u5F53\u524D",
7138
+ "\u8FD9\u4E2A",
7139
+ "\u4E00\u4E2A",
7140
+ "\u4E00\u4E9B",
7141
+ "\u9700\u8981",
7142
+ "\u8D1F\u8D23",
7143
+ "\u53EF\u4EE5",
7144
+ "\u5DE5\u5177",
7145
+ "\u80FD\u529B",
7146
+ "\u8BA1\u5212",
7147
+ "plan",
7148
+ "content",
7149
+ "document",
7150
+ "analysis",
7151
+ "agent",
7152
+ "skill",
7153
+ "tool",
7154
+ "task",
7155
+ "user",
7156
+ "need",
7157
+ "needs",
7158
+ "use",
7159
+ "using",
7160
+ "create",
7161
+ "make",
7162
+ "help",
7163
+ "with"
7164
+ ]);
7165
+ var TASK_TOKEN_SCORE_CAP = 6;
6904
7166
  function entryCorpus(entry) {
6905
7167
  return [
6906
7168
  entry.id,
@@ -6911,6 +7173,27 @@ function entryCorpus(entry) {
6911
7173
  ...entry.applicableRoles
6912
7174
  ].join(" ").toLowerCase();
6913
7175
  }
7176
+ function meaningfulTokens(value) {
7177
+ return searchTokens(value).filter((token) => !BROAD_TASK_TERMS.has(token));
7178
+ }
7179
+ function tokensFuzzyMatch(left, right) {
7180
+ if (left === right) return true;
7181
+ if (left.length >= 2 && right.length >= 2 && (left.includes(right) || right.includes(left))) return true;
7182
+ return false;
7183
+ }
7184
+ function matchedTaskKeywords(corpus, taskText) {
7185
+ if (!taskText) return [];
7186
+ const taskTokens = meaningfulTokens(taskText);
7187
+ if (taskTokens.length === 0) return [];
7188
+ const corpusTokens = meaningfulTokens(corpus);
7189
+ const matches = [];
7190
+ for (const taskToken of taskTokens) {
7191
+ if (corpus.includes(taskToken) || corpusTokens.some((corpusToken) => tokensFuzzyMatch(taskToken, corpusToken))) {
7192
+ matches.push(taskToken);
7193
+ }
7194
+ }
7195
+ return [...new Set(matches)];
7196
+ }
6914
7197
  function scoreEntry(entry, query4) {
6915
7198
  const corpus = entryCorpus(entry);
6916
7199
  const queryText = normalizeText(query4.query);
@@ -6933,6 +7216,7 @@ function scoreEntry(entry, query4) {
6933
7216
  const normalizedTaskType = taskType.toLowerCase().replace(/_/g, " ");
6934
7217
  if (taskText.includes(normalizedTaskType) || taskText.includes(taskType.toLowerCase())) score += 4;
6935
7218
  }
7219
+ score += Math.min(TASK_TOKEN_SCORE_CAP, matchedTaskKeywords(corpus, taskText).length * 2);
6936
7220
  if (taskText && corpus.includes(taskText)) score += 2;
6937
7221
  }
6938
7222
  if (!queryText && !roleText && !taskText) score = 1;
@@ -6970,6 +7254,8 @@ function recommendationReasons(entry, input) {
6970
7254
  if (matchedRoles.length > 0) reasons.push(`\u5339\u914D\u89D2\u8272\uFF1A${matchedRoles.slice(0, 3).join("\u3001")}`);
6971
7255
  const matchedTasks = matchedTaskTypes(entry, taskText);
6972
7256
  if (matchedTasks.length > 0) reasons.push(`\u5339\u914D\u4EFB\u52A1\u7C7B\u578B\uFF1A${matchedTasks.slice(0, 3).join("\u3001")}`);
7257
+ const matchedKeywords = matchedTaskKeywords(entryCorpus(entry), taskText);
7258
+ if (matchedTasks.length === 0 && matchedKeywords.length > 0) reasons.push(`\u5339\u914D\u5173\u952E\u8BCD\uFF1A${matchedKeywords.slice(0, 3).join("\u3001")}`);
6973
7259
  if (entry.permissionLevel === "high") reasons.push("\u9AD8\u6743\u9650 skill\uFF1A\u9ED8\u8BA4\u6216\u5DF2\u5206\u914D\u65F6\u53EF\u6309\u4EFB\u52A1\u4F7F\u7528\uFF1B\u5199\u6587\u4EF6\u3001\u8DD1\u547D\u4EE4\u3001\u53D1\u5E03\u7B49\u5177\u4F53\u52A8\u4F5C\u524D\u518D\u786E\u8BA4");
6974
7260
  if (entry.runtimeAvailability === "smith_only") reasons.push("\u5F53\u524D\u53EA\u80FD\u7531 Smith \u8BFB\u53D6\u5B8C\u6574\u65B9\u6CD5\u5B66");
6975
7261
  if (entry.runtimeAvailability === "planned") reasons.push("\u5F53\u524D\u662F\u89C4\u5212\u4E2D\u7684 P0 skill \u5019\u9009\uFF0C\u4E0D\u80FD\u58F0\u79F0\u5DF2\u5B89\u88C5");
@@ -7200,6 +7486,7 @@ function normalizeMcpConnectionSnapshot(value) {
7200
7486
  customHeaders: normalizeMcpCustomHeaderSnapshot(raw.customHeaders),
7201
7487
  enabled: raw.enabled === true,
7202
7488
  alwaysLoad: raw.alwaysLoad === true,
7489
+ dailyCallLimit: normalizeMcpDailyCallLimitSnapshot(raw.dailyCallLimit),
7203
7490
  isBuiltin: false,
7204
7491
  ownerUserId: null,
7205
7492
  createdBy: null,
@@ -7209,6 +7496,11 @@ function normalizeMcpConnectionSnapshot(value) {
7209
7496
  bindings: bindings.length > 0 ? bindings : [{ connectionId: raw.id, targetKind: "global", targetId: MCP_GLOBAL_TARGET_ID, enabled: true }]
7210
7497
  };
7211
7498
  }
7499
+ function normalizeMcpDailyCallLimitSnapshot(value) {
7500
+ if (value === null || value === void 0 || value === "") return null;
7501
+ if (typeof value !== "number" || !Number.isFinite(value)) return null;
7502
+ return Math.max(0, Math.floor(value));
7503
+ }
7212
7504
  function normalizeMcpToolSnapshot(value) {
7213
7505
  if (!value || typeof value !== "object") return null;
7214
7506
  const raw = value;
@@ -7317,6 +7609,60 @@ var readpageScrapeTool = {
7317
7609
  enabled: true,
7318
7610
  permissionPolicy: "always_allow"
7319
7611
  };
7612
+ var seedreamGenerateImageTool = {
7613
+ name: "generate_image",
7614
+ displayName: "Seedream \u751F\u56FE",
7615
+ description: "\u4F7F\u7528\u706B\u5C71\u65B9\u821F Seedream \u751F\u6210\u5355\u5F20\u56FE\u7247\uFF0C\u652F\u6301\u6587\u672C\u751F\u56FE\u4E0E\u53C2\u8003\u56FE\u751F\u56FE\uFF0C\u4F1A\u4EA7\u751F\u516C\u53F8 Ark \u8D26\u53F7\u7528\u91CF\u3002",
7616
+ category: "media",
7617
+ riskLevel: "medium",
7618
+ enabled: true,
7619
+ permissionPolicy: "always_ask"
7620
+ };
7621
+ var seedreamEditImageTool = {
7622
+ name: "edit_image",
7623
+ displayName: "Seedream \u6539\u56FE",
7624
+ description: "\u4F7F\u7528\u706B\u5C71\u65B9\u821F Seedream \u6839\u636E\u53C2\u8003\u56FE\u548C\u63D0\u793A\u8BCD\u7F16\u8F91\u6216\u91CD\u7ED8\u5355\u5F20\u56FE\u7247\uFF0C\u4F1A\u4EA7\u751F\u516C\u53F8 Ark \u8D26\u53F7\u7528\u91CF\u3002",
7625
+ category: "media",
7626
+ riskLevel: "medium",
7627
+ enabled: true,
7628
+ permissionPolicy: "always_ask"
7629
+ };
7630
+ var seedreamGenerateImageGroupTool = {
7631
+ name: "generate_image_group",
7632
+ displayName: "Seedream \u5355\u56FE",
7633
+ description: "\u517C\u5BB9\u65E7\u540D\u79F0\u7684 Seedream \u5355\u56FE\u751F\u6210\u5DE5\u5177\uFF0C\u4F1A\u4EA7\u751F\u516C\u53F8 Ark \u8D26\u53F7\u7528\u91CF\u3002\u5F53\u524D\u6BCF\u6B21\u8BF7\u6C42\u53EA\u751F\u6210 1 \u5F20\u56FE\u7247\u3002",
7634
+ category: "media",
7635
+ riskLevel: "medium",
7636
+ enabled: true,
7637
+ permissionPolicy: "always_ask"
7638
+ };
7639
+ var seedanceUsageGuideTool = {
7640
+ name: "seedance_usage_guide",
7641
+ displayName: "Seedance \u4F7F\u7528\u8BF4\u660E",
7642
+ description: "\u67E5\u770B Seedance \u89C6\u9891\u751F\u6210\u6D41\u7A0B\u4E0E\u53C2\u6570\u8BF4\u660E\uFF0C\u4E0D\u521B\u5EFA\u65B0\u7684\u751F\u6210\u4EFB\u52A1\u3002",
7643
+ category: "media",
7644
+ riskLevel: "low",
7645
+ enabled: true,
7646
+ permissionPolicy: "always_allow"
7647
+ };
7648
+ var seedanceCreateTaskTool = {
7649
+ name: "seedance_create_task",
7650
+ displayName: "Seedance \u751F\u89C6\u9891",
7651
+ description: "\u4F7F\u7528\u706B\u5C71\u65B9\u821F Seedance \u521B\u5EFA\u5355\u4E2A\u89C6\u9891\u751F\u6210\u4EFB\u52A1\uFF0C\u4F1A\u4EA7\u751F\u516C\u53F8 Ark \u8D26\u53F7\u7528\u91CF\u3002\u5F53\u524D\u6BCF\u6B21\u8BF7\u6C42\u53EA\u751F\u6210 1 \u4E2A\u89C6\u9891\u3002",
7652
+ category: "media",
7653
+ riskLevel: "high",
7654
+ enabled: true,
7655
+ permissionPolicy: "always_ask"
7656
+ };
7657
+ var seedanceCheckTaskTool = {
7658
+ name: "seedance_check_task",
7659
+ displayName: "Seedance \u67E5\u7ED3\u679C",
7660
+ description: "\u67E5\u8BE2 Seedance \u89C6\u9891\u751F\u6210\u4EFB\u52A1\u72B6\u6001\u4E0E\u89C6\u9891 URL\uFF0C\u4E0D\u521B\u5EFA\u65B0\u7684\u751F\u6210\u4EFB\u52A1\u3002",
7661
+ category: "media",
7662
+ riskLevel: "low",
7663
+ enabled: true,
7664
+ permissionPolicy: "always_allow"
7665
+ };
7320
7666
  var context7ResolveLibraryTool = {
7321
7667
  name: "resolve-library-id",
7322
7668
  displayName: "\u89E3\u6790\u6587\u6863\u5E93",
@@ -7623,8 +7969,56 @@ var ALIYUN_IQS_MCP_PROVIDERS = [
7623
7969
  tools: [readpageBasicTool, readpageScrapeTool]
7624
7970
  }
7625
7971
  ];
7972
+ var VOLCENGINE_SEEDREAM_MCP_PROVIDER = {
7973
+ providerId: "volcengine_seedream",
7974
+ name: "Volcengine Seedream",
7975
+ summary: "\u706B\u5C71\u65B9\u821F Seedream \u56FE\u7247\u751F\u6210/\u7F16\u8F91 MCP\uFF0C\u4F7F\u7528\u516C\u53F8\u7EDF\u4E00 Ark Key\uFF0C\u5E76\u8FDB\u5165 AHChat \u8C03\u7528\u5BA1\u8BA1\u3002",
7976
+ serverName: "seedream",
7977
+ transport: "stdio",
7978
+ url: null,
7979
+ command: "ahchat-builtin",
7980
+ args: ["seedream-mcp"],
7981
+ env: {
7982
+ ARK_API_KEY: "",
7983
+ ARK_BASE_URL: "https://ark.cn-beijing.volces.com/api/v3"
7984
+ },
7985
+ authType: "x_api_key",
7986
+ customHeaders: [],
7987
+ enabled: true,
7988
+ alwaysLoad: true,
7989
+ tools: [
7990
+ seedreamGenerateImageTool,
7991
+ seedreamEditImageTool,
7992
+ seedreamGenerateImageGroupTool
7993
+ ]
7994
+ };
7995
+ var VOLCENGINE_SEEDANCE_MCP_PROVIDER = {
7996
+ providerId: "volcengine_seedance",
7997
+ name: "Volcengine Seedance",
7998
+ summary: "\u706B\u5C71\u65B9\u821F Seedance \u89C6\u9891\u751F\u6210 MCP\uFF0C\u4F7F\u7528\u516C\u53F8\u7EDF\u4E00 Ark Key\uFF0C\u5E76\u8FDB\u5165 AHChat \u8C03\u7528\u5BA1\u8BA1\u3002",
7999
+ serverName: "seedance",
8000
+ transport: "stdio",
8001
+ url: null,
8002
+ command: "ahchat-builtin",
8003
+ args: ["seedance-mcp"],
8004
+ env: {
8005
+ ARK_API_KEY: "",
8006
+ ARK_BASE_URL: "https://ark.cn-beijing.volces.com/api/v3"
8007
+ },
8008
+ authType: "x_api_key",
8009
+ customHeaders: [],
8010
+ enabled: true,
8011
+ alwaysLoad: true,
8012
+ tools: [
8013
+ seedanceUsageGuideTool,
8014
+ seedanceCreateTaskTool,
8015
+ seedanceCheckTaskTool
8016
+ ]
8017
+ };
7626
8018
  var OFFICIAL_MCP_PROVIDERS = [
7627
- ...ALIYUN_IQS_MCP_PROVIDERS
8019
+ ...ALIYUN_IQS_MCP_PROVIDERS,
8020
+ VOLCENGINE_SEEDANCE_MCP_PROVIDER,
8021
+ VOLCENGINE_SEEDREAM_MCP_PROVIDER
7628
8022
  ];
7629
8023
  var MCP_STORE_PROVIDERS = [
7630
8024
  {
@@ -8724,6 +9118,77 @@ function cronCreateDurableAllow(input) {
8724
9118
  priorDurable: input.durable
8725
9119
  };
8726
9120
  }
9121
+ var OFFICIAL_MEDIA_GENERATION_TOOL_NAMES = [
9122
+ "mcp__seedream__generate_image",
9123
+ "mcp__seedream__edit_image",
9124
+ "mcp__seedream__generate_image_group",
9125
+ "mcp__seedance__seedance_create_task"
9126
+ ];
9127
+ var OFFICIAL_MEDIA_GENERATION_TOOLS = new Set(OFFICIAL_MEDIA_GENERATION_TOOL_NAMES);
9128
+ var OFFICIAL_MEDIA_GENERATION_TOOL_PATTERNS = [
9129
+ /^mcp__seedream(?:_\d+)?__(?:generate_image|edit_image|generate_image_group)$/,
9130
+ /^mcp__seedance(?:_\d+)?__seedance_create_task$/
9131
+ ];
9132
+ function isOfficialMediaGenerationToolName(toolName) {
9133
+ return OFFICIAL_MEDIA_GENERATION_TOOLS.has(toolName) || OFFICIAL_MEDIA_GENERATION_TOOL_PATTERNS.some((pattern) => pattern.test(toolName));
9134
+ }
9135
+ function createOfficialMediaGenerationTurnGuard() {
9136
+ return {
9137
+ replyMessageId: null,
9138
+ toolName: null,
9139
+ duplicateDenied: false
9140
+ };
9141
+ }
9142
+ function resetOfficialMediaGenerationTurnGuard(guard, replyMessageId) {
9143
+ guard.replyMessageId = replyMessageId;
9144
+ guard.toolName = null;
9145
+ guard.duplicateDenied = false;
9146
+ }
9147
+ var OFFICIAL_MEDIA_DUPLICATE_DENY_REASON = "\u672C\u8F6E\u5DF2\u7ECF\u8C03\u7528\u8FC7\u5B98\u65B9\u5A92\u4F53\u751F\u6210\u5DE5\u5177";
9148
+ function isOfficialMediaGenerationDuplicateDenyMessage(message) {
9149
+ return message.includes(OFFICIAL_MEDIA_DUPLICATE_DENY_REASON);
9150
+ }
9151
+ function guardOfficialMediaGenerationTool(guard, toolName) {
9152
+ if (!isOfficialMediaGenerationToolName(toolName)) return null;
9153
+ if (!guard.toolName) {
9154
+ guard.toolName = toolName;
9155
+ return null;
9156
+ }
9157
+ guard.duplicateDenied = true;
9158
+ return {
9159
+ behavior: "deny",
9160
+ message: `\u672C\u8F6E\u5DF2\u7ECF\u8C03\u7528\u8FC7\u5B98\u65B9\u5A92\u4F53\u751F\u6210\u5DE5\u5177\uFF08${guard.toolName}\uFF09\u3002\u6BCF\u6761\u7528\u6237\u8BF7\u6C42\u53EA\u80FD\u751F\u6210\u4E00\u4E2A\u5A92\u4F53\u7ED3\u679C\uFF1B\u8BF7\u505C\u6B62\u91CD\u8BD5\uFF0C\u76F4\u63A5\u6839\u636E\u5DF2\u7ECF\u8FD4\u56DE\u7684\u5A92\u4F53\u5361\u7247\u56DE\u590D\u7528\u6237\u3002`
9161
+ };
9162
+ }
9163
+ function createOfficialMediaGenerationPreToolUseHooks(guard, toolNames, meta3) {
9164
+ const mediaToolNames = /* @__PURE__ */ new Set([
9165
+ ...OFFICIAL_MEDIA_GENERATION_TOOL_NAMES,
9166
+ ...Array.from(toolNames).filter(isOfficialMediaGenerationToolName)
9167
+ ]);
9168
+ return Array.from(mediaToolNames).map((toolName) => ({
9169
+ matcher: toolName,
9170
+ hooks: [
9171
+ async (_input) => {
9172
+ const decision = guardOfficialMediaGenerationTool(guard, toolName);
9173
+ if (!decision || decision.behavior !== "deny") return {};
9174
+ meta3.log("PreToolUse deny: duplicate official media generation tool in one turn", {
9175
+ agentId: meta3.agentId,
9176
+ scope: meta3.scope,
9177
+ toolName,
9178
+ firstToolName: guard.toolName,
9179
+ replyMessageId: guard.replyMessageId
9180
+ });
9181
+ return {
9182
+ hookSpecificOutput: {
9183
+ hookEventName: "PreToolUse",
9184
+ permissionDecision: "deny",
9185
+ permissionDecisionReason: decision.message
9186
+ }
9187
+ };
9188
+ }
9189
+ ]
9190
+ }));
9191
+ }
8727
9192
  function normalizedCommand(input) {
8728
9193
  const raw = input.command;
8729
9194
  return typeof raw === "string" ? raw.replace(/\s+/g, " ").trim() : "";
@@ -23377,8 +23842,10 @@ function date4(params) {
23377
23842
  config(en_default());
23378
23843
 
23379
23844
  // src/documentReader.ts
23380
- import fs3 from "fs/promises";
23381
- import path8 from "path";
23845
+ import fs4 from "fs/promises";
23846
+ import { execFile } from "child_process";
23847
+ import path9 from "path";
23848
+ import { promisify } from "util";
23382
23849
 
23383
23850
  // src/runtimeEnv.ts
23384
23851
  import { execFileSync } from "child_process";
@@ -23518,8 +23985,112 @@ function resolveUserPath(input) {
23518
23985
  return path7.isAbsolute(value) ? path7.normalize(value) : path7.resolve(value);
23519
23986
  }
23520
23987
 
23988
+ // src/officeRuntime.ts
23989
+ import fs3 from "fs";
23990
+ import os5 from "os";
23991
+ import path8 from "path";
23992
+ var OFFICECLI_EXECUTABLE_ENV = "AHCHAT_OFFICECLI_EXECUTABLE";
23993
+ var OFFICECLI_BIN_DIR_ENV = "AHCHAT_OFFICECLI_BIN_DIR";
23994
+ var logger6 = createModuleLogger("bridge.officeRuntime");
23995
+ function sanitizedOfficeCliProbeError(error51) {
23996
+ const rawCode = error51 && typeof error51 === "object" && "code" in error51 ? error51.code : void 0;
23997
+ const code = typeof rawCode === "string" ? rawCode : void 0;
23998
+ const sanitized = new Error(`OfficeCLI executable probe failed${code ? ` (${code})` : ""}`);
23999
+ if (error51 instanceof Error) sanitized.name = error51.name;
24000
+ return sanitized;
24001
+ }
24002
+ function defaultRuntimeRoot() {
24003
+ if (process.platform === "win32") {
24004
+ return path8.join(process.env.LOCALAPPDATA || path8.join(os5.homedir(), "AppData", "Local"), "AHChat", "runtime", "officecli");
24005
+ }
24006
+ if (process.platform === "darwin") {
24007
+ return path8.join(os5.homedir(), "Library", "Caches", "AHChat", "runtime", "officecli");
24008
+ }
24009
+ return path8.join(process.env.XDG_CACHE_HOME || path8.join(os5.homedir(), ".cache"), "ahchat", "runtime", "officecli");
24010
+ }
24011
+ function getManagedOfficeCliBinDir(env2 = process.env) {
24012
+ return env2[OFFICECLI_BIN_DIR_ENV] || path8.join(defaultRuntimeRoot(), "bin");
24013
+ }
24014
+ function getOfficeCliExecutableName() {
24015
+ return process.platform === "win32" ? "officecli.exe" : "officecli";
24016
+ }
24017
+ function getManagedOfficeCliExecutablePath(env2 = process.env) {
24018
+ return path8.join(getManagedOfficeCliBinDir(env2), getOfficeCliExecutableName());
24019
+ }
24020
+ function isExecutable(filePath, options = {}) {
24021
+ const logFailure = options.logFailure !== false;
24022
+ try {
24023
+ if (process.platform === "win32") return fs3.existsSync(filePath);
24024
+ fs3.accessSync(filePath, fs3.constants.X_OK);
24025
+ return true;
24026
+ } catch (error51) {
24027
+ if (logFailure) {
24028
+ logger6.error("OfficeCLI executable probe failed", {
24029
+ error: sanitizedOfficeCliProbeError(error51),
24030
+ fileName: path8.basename(filePath)
24031
+ });
24032
+ }
24033
+ return false;
24034
+ }
24035
+ }
24036
+ function withPrependedPath(env2, entries) {
24037
+ const pathEntries = entries.filter((entry) => entry && fs3.existsSync(entry));
24038
+ if (pathEntries.length === 0) return env2;
24039
+ const current = env2.PATH ?? "";
24040
+ return {
24041
+ ...env2,
24042
+ PATH: [...pathEntries, current].filter(Boolean).join(path8.delimiter)
24043
+ };
24044
+ }
24045
+ function statusForPath(filePath, source, env2, options = {}) {
24046
+ if (!isExecutable(filePath, { logFailure: options.logProbeFailure })) {
24047
+ return {
24048
+ ok: false,
24049
+ path: filePath,
24050
+ source,
24051
+ message: `officecli not executable at ${filePath}`
24052
+ };
24053
+ }
24054
+ const runtimeEnv = withPrependedPath(env2, [path8.dirname(filePath)]);
24055
+ const version2 = readCommandVersion(filePath, ["--version"], runtimeEnv);
24056
+ if (!version2) {
24057
+ return {
24058
+ ok: false,
24059
+ path: filePath,
24060
+ source,
24061
+ message: `officecli found at ${filePath} but --version failed`
24062
+ };
24063
+ }
24064
+ return { ok: true, path: filePath, source, version: version2 };
24065
+ }
24066
+ function detectOfficeCliRuntime(env2 = process.env) {
24067
+ const explicitPath = env2[OFFICECLI_EXECUTABLE_ENV]?.trim();
24068
+ if (explicitPath) return statusForPath(explicitPath, "env", env2);
24069
+ const managedPath = getManagedOfficeCliExecutablePath(env2);
24070
+ const managed = statusForPath(managedPath, "managed", env2, { logProbeFailure: false });
24071
+ if (managed.ok) return managed;
24072
+ const resolved = resolveCommand(["officecli"], withPrependedPath(env2, [path8.dirname(managedPath)]));
24073
+ if (!resolved) {
24074
+ return {
24075
+ ok: false,
24076
+ source: "managed",
24077
+ path: managedPath,
24078
+ message: `officecli not found. Run pnpm setup:office-runtime or set ${OFFICECLI_EXECUTABLE_ENV}.`
24079
+ };
24080
+ }
24081
+ return statusForPath(resolved.path, resolved.path === managedPath ? "managed" : "path", env2);
24082
+ }
24083
+ function withOfficeCliRuntimeEnv(status, env2 = process.env) {
24084
+ if (!status.ok || !status.path) return env2;
24085
+ return {
24086
+ ...withPrependedPath(env2, [path8.dirname(status.path)]),
24087
+ [OFFICECLI_EXECUTABLE_ENV]: status.path
24088
+ };
24089
+ }
24090
+
23521
24091
  // src/documentReader.ts
23522
- var logger6 = createModuleLogger("document.reader");
24092
+ var logger7 = createModuleLogger("document.reader");
24093
+ var execFileAsync = promisify(execFile);
23523
24094
  var SUPPORTED_DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set([
23524
24095
  ".docx",
23525
24096
  ".xls",
@@ -23556,31 +24127,31 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
23556
24127
  var DEFAULT_MAX_CHARS = 5e5;
23557
24128
  var DEFAULT_TIMEOUT_MS = 45e3;
23558
24129
  function isReadableDocumentPath(filePath) {
23559
- return SUPPORTED_DOCUMENT_EXTENSIONS.has(path8.extname(filePath).toLowerCase());
24130
+ return SUPPORTED_DOCUMENT_EXTENSIONS.has(path9.extname(filePath).toLowerCase());
23560
24131
  }
23561
24132
  function resolveDocumentPath(inputPath, cwd) {
23562
24133
  const trimmed = inputPath.trim();
23563
24134
  if (!trimmed) throw new Error("path is required");
23564
- const resolvedCwd = path8.resolve(resolveUserPath(cwd));
23565
- const candidate = path8.isAbsolute(trimmed) ? path8.resolve(resolveUserPath(trimmed)) : path8.resolve(resolvedCwd, trimmed);
23566
- const relative = path8.relative(resolvedCwd, candidate);
23567
- if (relative.startsWith("..") || path8.isAbsolute(relative)) {
24135
+ const resolvedCwd = path9.resolve(resolveUserPath(cwd));
24136
+ const candidate = path9.isAbsolute(trimmed) ? path9.resolve(resolveUserPath(trimmed)) : path9.resolve(resolvedCwd, trimmed);
24137
+ const relative = path9.relative(resolvedCwd, candidate);
24138
+ if (relative.startsWith("..") || path9.isAbsolute(relative)) {
23568
24139
  throw new Error("document path must be inside the current working directory");
23569
24140
  }
23570
24141
  return candidate;
23571
24142
  }
23572
24143
  async function readDocumentAsMarkdown(inputPath, opts = {}) {
23573
- const resolvedPath = opts.cwd ? resolveDocumentPath(inputPath, opts.cwd) : path8.resolve(resolveUserPath(inputPath));
23574
- const ext = path8.extname(resolvedPath).toLowerCase();
24144
+ const resolvedPath = opts.cwd ? resolveDocumentPath(inputPath, opts.cwd) : path9.resolve(resolveUserPath(inputPath));
24145
+ const ext = path9.extname(resolvedPath).toLowerCase();
23575
24146
  if (!isReadableDocumentPath(resolvedPath)) {
23576
24147
  throw new Error(`unsupported document type: ${ext || "(no extension)"}`);
23577
24148
  }
23578
- const stat3 = await fs3.stat(resolvedPath);
24149
+ const stat3 = await fs4.stat(resolvedPath);
23579
24150
  if (!stat3.isFile()) throw new Error("path is not a file");
23580
24151
  const warnings = [];
23581
24152
  let markdown;
23582
24153
  if (TEXT_EXTENSIONS.has(ext)) {
23583
- markdown = await fs3.readFile(resolvedPath, "utf-8");
24154
+ markdown = await fs4.readFile(resolvedPath, "utf-8");
23584
24155
  } else if (ext === ".xls") {
23585
24156
  markdown = await convertLegacyExcelDocument(resolvedPath);
23586
24157
  } else {
@@ -23598,7 +24169,7 @@ async function readDocumentAsMarkdown(inputPath, opts = {}) {
23598
24169
  if (!markdown.trim()) {
23599
24170
  warnings.push("No readable text was extracted from this document.");
23600
24171
  }
23601
- logger6.info("Document read as markdown", {
24172
+ logger7.info("Document read as markdown", {
23602
24173
  path: resolvedPath,
23603
24174
  ext,
23604
24175
  length: markdown.length,
@@ -23613,21 +24184,21 @@ async function readDocumentAsMarkdown(inputPath, opts = {}) {
23613
24184
  };
23614
24185
  }
23615
24186
  function documentSidecarPath(filePath, outputDir) {
23616
- const dir = outputDir ?? path8.dirname(filePath);
23617
- const base = path8.basename(filePath);
23618
- return path8.join(dir, `${base}.content.md`);
24187
+ const dir = outputDir ?? path9.dirname(filePath);
24188
+ const base = path9.basename(filePath);
24189
+ return path9.join(dir, `${base}.content.md`);
23619
24190
  }
23620
24191
  async function writeDocumentSidecar(filePath, opts = {}) {
23621
24192
  const result = await readDocumentAsMarkdown(filePath, opts);
23622
- const sidecarDir = opts.sidecarDir ? path8.resolve(resolveUserPath(opts.sidecarDir)) : path8.dirname(result.path);
24193
+ const sidecarDir = opts.sidecarDir ? path9.resolve(resolveUserPath(opts.sidecarDir)) : path9.dirname(result.path);
23623
24194
  if (opts.cwd) {
23624
- const resolvedCwd = path8.resolve(resolveUserPath(opts.cwd));
23625
- const relative = path8.relative(resolvedCwd, sidecarDir);
23626
- if (relative.startsWith("..") || path8.isAbsolute(relative)) {
24195
+ const resolvedCwd = path9.resolve(resolveUserPath(opts.cwd));
24196
+ const relative = path9.relative(resolvedCwd, sidecarDir);
24197
+ if (relative.startsWith("..") || path9.isAbsolute(relative)) {
23627
24198
  throw new Error("document sidecar path must be inside the current working directory");
23628
24199
  }
23629
24200
  }
23630
- await fs3.mkdir(sidecarDir, { recursive: true });
24201
+ await fs4.mkdir(sidecarDir, { recursive: true });
23631
24202
  const sidecarPath = documentSidecarPath(result.path, sidecarDir);
23632
24203
  const warningText = result.warnings.length > 0 ? `
23633
24204
 
@@ -23642,8 +24213,8 @@ ${result.warnings.map((w) => `- ${w}`).join("\n")}
23642
24213
  result.markdown,
23643
24214
  warningText
23644
24215
  ].join("\n");
23645
- await fs3.writeFile(sidecarPath, content, "utf-8");
23646
- logger6.info("Document sidecar written", {
24216
+ await fs4.writeFile(sidecarPath, content, "utf-8");
24217
+ logger7.info("Document sidecar written", {
23647
24218
  path: result.path,
23648
24219
  sidecarPath,
23649
24220
  length: content.length
@@ -23666,7 +24237,7 @@ async function convertOfficeDocument(filePath, timeoutMs) {
23666
24237
  abortSignal: controller.signal
23667
24238
  },
23668
24239
  onWarning: (issue2) => {
23669
- logger6.warn("Document conversion warning", {
24240
+ logger7.warn("Document conversion warning", {
23670
24241
  path: filePath,
23671
24242
  code: issue2.code,
23672
24243
  message: issue2.message
@@ -23676,10 +24247,53 @@ async function convertOfficeDocument(filePath, timeoutMs) {
23676
24247
  if (typeof result.value === "string") return result.value;
23677
24248
  if (result.value instanceof Uint8Array) return Buffer.from(result.value).toString("utf-8");
23678
24249
  return JSON.stringify(result.value, null, 2);
24250
+ } catch (e) {
24251
+ if (path9.extname(filePath).toLowerCase() !== ".docx") throw e;
24252
+ logger7.warn("Office parser failed; trying OfficeCLI text fallback", {
24253
+ path: filePath,
24254
+ error: e
24255
+ });
24256
+ try {
24257
+ return await convertDocxWithOfficeCli(filePath, timeoutMs);
24258
+ } catch (fallbackError) {
24259
+ logger7.warn("OfficeCLI text fallback failed", {
24260
+ path: filePath,
24261
+ error: fallbackError
24262
+ });
24263
+ throw e;
24264
+ }
23679
24265
  } finally {
23680
24266
  clearTimeout(timer);
23681
24267
  }
23682
24268
  }
24269
+ function parseOfficeCliParagraphText(value) {
24270
+ if (!value || typeof value !== "object") return "";
24271
+ const root = value;
24272
+ if (root.success !== true || !root.data || typeof root.data !== "object") return "";
24273
+ const data = root.data;
24274
+ if (!Array.isArray(data.results)) return "";
24275
+ return data.results.map((item) => {
24276
+ if (!item || typeof item !== "object") return "";
24277
+ const text = item.text;
24278
+ return typeof text === "string" ? text.trim() : "";
24279
+ }).filter((text) => text.length > 0).join("\n\n");
24280
+ }
24281
+ async function convertDocxWithOfficeCli(filePath, timeoutMs) {
24282
+ const executable = process.env[OFFICECLI_EXECUTABLE_ENV]?.trim() || "officecli";
24283
+ const { stdout } = await execFileAsync(executable, ["query", filePath, "paragraph", "--json"], {
24284
+ timeout: timeoutMs,
24285
+ maxBuffer: 20 * 1024 * 1024,
24286
+ windowsHide: true
24287
+ });
24288
+ const parsed = JSON.parse(stdout);
24289
+ const text = parseOfficeCliParagraphText(parsed);
24290
+ if (!text.trim()) throw new Error("OfficeCLI returned no paragraph text");
24291
+ logger7.info("Document read via OfficeCLI text fallback", {
24292
+ path: filePath,
24293
+ length: text.length
24294
+ });
24295
+ return text;
24296
+ }
23683
24297
  async function convertLegacyExcelDocument(filePath) {
23684
24298
  const XLSX = await import("./xlsx-E4ZR5JHK.js");
23685
24299
  const workbook = XLSX.readFile(filePath, { cellDates: true });
@@ -23728,7 +24342,9 @@ function normalizeDocumentText(value) {
23728
24342
  }
23729
24343
 
23730
24344
  // src/neuralMcpServer.ts
23731
- var logger7 = createModuleLogger("neural.mcpServer");
24345
+ var logger8 = createModuleLogger("neural.mcpServer");
24346
+ var VIDEO_GENERATION_SKILL_ID = OFFICIAL_MEDIA_SKILL_IDS[0];
24347
+ var AUTO_LOCAL_ENHANCER_LIMIT = 2;
23732
24348
  function formatSkillEntry(entry, index) {
23733
24349
  return [
23734
24350
  `${index + 1}. ${entry.displayName} (${entry.name})`,
@@ -23761,7 +24377,7 @@ function runtimeSkillIndexEntries(skillStore, agentId, smithDefaultAllSkills = f
23761
24377
  return entry.runtimeAvailability === "available";
23762
24378
  });
23763
24379
  } catch (e) {
23764
- logger7.warn("Runtime skill index unavailable", { error: e });
24380
+ logger8.warn("Runtime skill index unavailable", { error: e });
23765
24381
  return [];
23766
24382
  }
23767
24383
  }
@@ -23771,7 +24387,7 @@ function runtimeVisibleSkillIds(skillStore, runtimeEntries) {
23771
24387
  try {
23772
24388
  for (const name of skillStore.allowedNames()) ids.add(name);
23773
24389
  } catch (e) {
23774
- logger7.warn("Runtime skill names unavailable", { error: e });
24390
+ logger8.warn("Runtime skill names unavailable", { error: e });
23775
24391
  }
23776
24392
  for (const entry of runtimeEntries) {
23777
24393
  ids.add(entry.id);
@@ -23790,12 +24406,75 @@ function filterAgentAvailableSkillEntries(entries, availableIds) {
23790
24406
  if (!availableIds) return entries;
23791
24407
  return entries.filter((entry) => availableIds.has(entry.id) || availableIds.has(entry.name));
23792
24408
  }
23793
- function skillRuntimeContext(officeCliRuntime) {
23794
- return officeCliRuntime ? {
23795
- officeCliAvailable: officeCliRuntime.ok,
23796
- officeCliPath: officeCliRuntime.path,
23797
- officeCliVersion: officeCliRuntime.version,
23798
- officeCliMessage: officeCliRuntime.message
24409
+ function matchesVideoGenerationIntent(input) {
24410
+ const roleText = [input.name, input.role].join("\n").toLowerCase();
24411
+ if (/seedance|生视频|视频生成|生成视频|视频助手|ai\s*video|video\s*generation|creative\s*video/.test(roleText)) {
24412
+ return true;
24413
+ }
24414
+ if (roleText.includes("\u89C6\u9891") && /[生成创作制作导演剪辑]/.test(roleText)) {
24415
+ return true;
24416
+ }
24417
+ const promptText = [input.systemPrompt, input.initialInstruction].join("\n").toLowerCase();
24418
+ return /seedance|生视频|视频生成|生成视频|文生视频|图生视频|text-to-video|image-to-video|ai\s*video|video\s*generation/.test(promptText);
24419
+ }
24420
+ var AUTO_ASSIGN_SKILL_RULES = [
24421
+ {
24422
+ skillId: VIDEO_GENERATION_SKILL_ID,
24423
+ intent: "media_video_generation",
24424
+ matches: matchesVideoGenerationIntent
24425
+ }
24426
+ ];
24427
+ function autoAssignOfficialSkillIds(input) {
24428
+ return AUTO_ASSIGN_SKILL_RULES.filter((rule) => rule.matches(input)).map((rule) => rule.skillId);
24429
+ }
24430
+ function runtimeCachedSkillIds(skillStore) {
24431
+ if (!skillStore) return /* @__PURE__ */ new Set();
24432
+ try {
24433
+ return new Set(skillStore.allowedNames());
24434
+ } catch (e) {
24435
+ logger8.warn("Runtime skill names unavailable", { error: e });
24436
+ return /* @__PURE__ */ new Set();
24437
+ }
24438
+ }
24439
+ function isCurrentMachineLocalTarget(targetBridgeKey, currentBridgeKey) {
24440
+ const target = targetBridgeKey?.trim();
24441
+ if (!target) return true;
24442
+ const current = currentBridgeKey?.trim();
24443
+ return Boolean(current && target === current);
24444
+ }
24445
+ function selectLocalSkillEnhancersForCreateAgent(input, skillStore, alreadySelectedSkillIds) {
24446
+ if (!skillStore) return [];
24447
+ const cachedSkillIds = runtimeCachedSkillIds(skillStore);
24448
+ if (cachedSkillIds.size === 0) return [];
24449
+ const localCandidates2 = runtimeSkillIndexEntries(
24450
+ skillStore,
24451
+ null,
24452
+ true,
24453
+ true
24454
+ ).filter((entry) => {
24455
+ if (entry.runtimeAvailability !== "available") return false;
24456
+ if (entry.origin !== "local" && !isLocalSkillId(entry.id)) return false;
24457
+ if (alreadySelectedSkillIds.has(entry.id) || alreadySelectedSkillIds.has(entry.name)) return false;
24458
+ return cachedSkillIds.has(entry.id) || cachedSkillIds.has(entry.name);
24459
+ });
24460
+ if (localCandidates2.length === 0) return [];
24461
+ const localCandidateIds = new Set(localCandidates2.map((entry) => entry.id));
24462
+ const recommendations = recommendInitialSkillsForAgent({
24463
+ role: input.role,
24464
+ systemPrompt: input.systemPrompt,
24465
+ workingDirectory: input.workingDirectory,
24466
+ task: [input.name, input.role, input.initialInstruction].filter(Boolean).join("\n"),
24467
+ includePlanned: false,
24468
+ entries: localCandidates2
24469
+ });
24470
+ return recommendations.map((rec) => rec.skill.id).filter((skillId) => localCandidateIds.has(skillId)).filter((skillId, index, ids) => ids.indexOf(skillId) === index).slice(0, AUTO_LOCAL_ENHANCER_LIMIT);
24471
+ }
24472
+ function skillRuntimeContext(officeCliRuntime) {
24473
+ return officeCliRuntime ? {
24474
+ officeCliAvailable: officeCliRuntime.ok,
24475
+ officeCliPath: officeCliRuntime.path,
24476
+ officeCliVersion: officeCliRuntime.version,
24477
+ officeCliMessage: officeCliRuntime.message
23799
24478
  } : void 0;
23800
24479
  }
23801
24480
  var NEURAL_DEDUP_WINDOW_MS = 3e4;
@@ -23835,6 +24514,16 @@ function formatMachineOptionLine(machine) {
23835
24514
  const bridgeId = machine.bridgeId ? `\uFF0CbridgeId=${machine.bridgeId}` : "";
23836
24515
  return `- machine_bridge_key=${machine.bridgeKey} [${machineStatusText(machine)}] ${formatBridgeMachineLabel(machine)}${bridgeId}`;
23837
24516
  }
24517
+ function rejectRemoteCreateMachineBridgeKey(machineBridgeKey, deps) {
24518
+ if (!machineBridgeKey || machineBridgeKey === "auto") return null;
24519
+ const currentBridgeKey = deps.currentBridgeKey?.trim();
24520
+ if (!currentBridgeKey || machineBridgeKey === currentBridgeKey) return null;
24521
+ return [
24522
+ `[create_agent] \u4E3A\u907F\u514D\u628A\u65B0 Agent \u521B\u5EFA\u5230\u522B\u7684\u7535\u8111\uFF0C\u521B\u5EFA\u65F6\u4E0D\u8981\u4F20\u5176\u4ED6\u673A\u5668\u7684 machine_bridge_key\u3002`,
24523
+ `\u8BF7\u7701\u7565 machine_bridge_key\uFF0C\u8BA9\u5B83\u4F7F\u7528\u5F53\u524D\u673A\u5668\uFF08${currentBridgeKey}\uFF09\u3002`,
24524
+ `\u5982\u679C\u7528\u6237\u660E\u786E\u8981\u6C42\u5207\u5230\u5176\u4ED6\u7535\u8111\uFF0C\u8BF7\u5148\u521B\u5EFA Agent\uFF0C\u518D\u7528 update_agent_profile \u5207\u6362\u8FD0\u884C\u673A\u5668\u3002`
24525
+ ].join(" ");
24526
+ }
23838
24527
  async function fetchVisibleBridgeMachines(deps) {
23839
24528
  if (!deps.serverApiUrl || !deps.bridgeToken) return [];
23840
24529
  try {
@@ -23843,14 +24532,14 @@ async function fetchVisibleBridgeMachines(deps) {
23843
24532
  headers: bridgeAuthHeaders(deps.bridgeToken)
23844
24533
  });
23845
24534
  if (!res.ok) {
23846
- logger7.warn("Bridge machine listing failed", { status: res.status });
24535
+ logger8.warn("Bridge machine listing failed", { status: res.status });
23847
24536
  return [];
23848
24537
  }
23849
24538
  const body = await res.json();
23850
24539
  if (!Array.isArray(body)) return [];
23851
24540
  return body.filter(isBridgeMachineSummary);
23852
24541
  } catch (e) {
23853
- logger7.warn("Bridge machine listing failed", { error: e });
24542
+ logger8.warn("Bridge machine listing failed", { error: e });
23854
24543
  return [];
23855
24544
  }
23856
24545
  }
@@ -23895,7 +24584,7 @@ async function resolveTierSubscriptionPreference(preferredSubscriptionId, deps)
23895
24584
  (subscription) => subscription.billingMode === "company_billable" && subscription.isPrimaryCompany === true
23896
24585
  )?.id ?? preferredSubscriptionId;
23897
24586
  } catch (e) {
23898
- logger7.warn("Primary company tier preference resolution failed", { error: e });
24587
+ logger8.warn("Primary company tier preference resolution failed", { error: e });
23899
24588
  return preferredSubscriptionId;
23900
24589
  }
23901
24590
  }
@@ -24070,7 +24759,7 @@ async function createNeuralMcpServer(deps) {
24070
24759
  message: external_exports.string().min(1).describe('\u8981\u4F20\u7ED9\u76EE\u6807\u5206\u8EAB\u7684\u4E00\u6BB5\u81EA\u7136\u8BED\u8A00\u3002\u5B83\u4F1A\u4F5C\u4E3A\u4F60\u7684"\u5185\u5FC3\u72EC\u767D"\u51FA\u73B0\u5728\u90A3\u4E2A scope\u3002')
24071
24760
  },
24072
24761
  async (args) => {
24073
- logger7.info("neural_send tool called", {
24762
+ logger8.info("neural_send tool called", {
24074
24763
  agentId: deps.agentId,
24075
24764
  fromScope: currentScopeKey,
24076
24765
  rawTargetScope: args.target_scope,
@@ -24092,7 +24781,7 @@ async function createNeuralMcpServer(deps) {
24092
24781
  if (singleConvId) {
24093
24782
  conversationId = singleConvId;
24094
24783
  } else {
24095
- logger7.warn("neural_send: failed to resolve single conv", { agentId: deps.agentId });
24784
+ logger8.warn("neural_send: failed to resolve single conv", { agentId: deps.agentId });
24096
24785
  return {
24097
24786
  content: [{ type: "text", text: "[neural_send] \u65E0\u6CD5\u89E3\u6790\u5355\u804A conversationId\uFF0C\u6D88\u606F\u672A\u9001\u8FBE\u3002\u8BF7\u5237\u65B0\u4F1A\u8BDD\u540E\u91CD\u8BD5\u3002" }],
24098
24787
  isError: true
@@ -24101,7 +24790,7 @@ async function createNeuralMcpServer(deps) {
24101
24790
  } else if (args.target_scope.startsWith("group:")) {
24102
24791
  const r = await deps.groupRegistry.resolveScope(args.target_scope);
24103
24792
  if (!r) {
24104
- logger7.info("neural_send: target scope not found", { rawTargetScope: args.target_scope });
24793
+ logger8.info("neural_send: target scope not found", { rawTargetScope: args.target_scope });
24105
24794
  return {
24106
24795
  content: [{ type: "text", text: `[neural_send] \u627E\u4E0D\u5230\u7FA4\u300C${args.target_scope.slice(6)}\u300D\u3002\u8BF7\u786E\u8BA4\u7FA4\u540D\u662F\u5426\u6B63\u786E\u3002` }],
24107
24796
  isError: true
@@ -24118,7 +24807,7 @@ async function createNeuralMcpServer(deps) {
24118
24807
  cached2 = deps.groupRegistry.getById(r.groupId);
24119
24808
  }
24120
24809
  if (!cached2 || !cached2.members.includes(deps.agentId)) {
24121
- logger7.info("neural_send: not a member of target group", {
24810
+ logger8.info("neural_send: not a member of target group", {
24122
24811
  agentId: deps.agentId,
24123
24812
  groupId: r.groupId,
24124
24813
  groupName: r.groupName,
@@ -24133,7 +24822,7 @@ async function createNeuralMcpServer(deps) {
24133
24822
  isError: true
24134
24823
  };
24135
24824
  }
24136
- logger7.info("neural_send: member check passed", {
24825
+ logger8.info("neural_send: member check passed", {
24137
24826
  agentId: deps.agentId,
24138
24827
  groupId: r.groupId,
24139
24828
  groupName: r.groupName
@@ -24145,7 +24834,7 @@ async function createNeuralMcpServer(deps) {
24145
24834
  };
24146
24835
  }
24147
24836
  if (resolvedKey === currentScopeKey) {
24148
- logger7.warn("neural_send: self-send refused", { agentId: deps.agentId, scope: currentScopeKey });
24837
+ logger8.warn("neural_send: self-send refused", { agentId: deps.agentId, scope: currentScopeKey });
24149
24838
  return {
24150
24839
  content: [{ type: "text", text: "[neural_send] \u4E0D\u80FD\u628A\u6D88\u606F\u9001\u7ED9\u81EA\u5DF1\u5F53\u524D\u6240\u5728\u7684 scope\u3002" }],
24151
24840
  isError: true
@@ -24163,7 +24852,7 @@ async function createNeuralMcpServer(deps) {
24163
24852
  if (sendHistory.length >= NEURAL_DEDUP_MAX_REPEATS) {
24164
24853
  sendHistory.push(nowTs);
24165
24854
  recentNeuralSends.set(dedupKey, sendHistory);
24166
- logger7.warn("neural_send: identical message throttled (repetition guard)", {
24855
+ logger8.warn("neural_send: identical message throttled (repetition guard)", {
24167
24856
  agentId: deps.agentId,
24168
24857
  fromScope: currentScopeKey,
24169
24858
  toScope: resolvedKey,
@@ -24192,7 +24881,7 @@ async function createNeuralMcpServer(deps) {
24192
24881
  });
24193
24882
  sendHistory.push(nowTs);
24194
24883
  recentNeuralSends.set(dedupKey, sendHistory);
24195
- logger7.info("neural_send delivered", {
24884
+ logger8.info("neural_send delivered", {
24196
24885
  agentId: deps.agentId,
24197
24886
  fromScope: currentScopeKey,
24198
24887
  toScope: resolvedKey,
@@ -24203,7 +24892,7 @@ async function createNeuralMcpServer(deps) {
24203
24892
  content: [{ type: "text", text: `[neural_send] \u5DF2\u9001\u8FBE\u5230\u300C${toLabel}\u300D(scope: ${resolvedKey})\u3002` }]
24204
24893
  };
24205
24894
  } catch (err) {
24206
- logger7.error("neural_send dispatch failed", { agentId: deps.agentId, error: err });
24895
+ logger8.error("neural_send dispatch failed", { agentId: deps.agentId, error: err });
24207
24896
  return {
24208
24897
  content: [{ type: "text", text: `[neural_send] \u9001\u8FBE\u5931\u8D25\uFF1A${err.message}` }],
24209
24898
  isError: true
@@ -24229,7 +24918,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24229
24918
  async (args) => {
24230
24919
  const action = args.action;
24231
24920
  const content = args.content;
24232
- logger7.info("self_note tool called", {
24921
+ logger8.info("self_note tool called", {
24233
24922
  agentId: deps.agentId,
24234
24923
  scope: currentScopeKey,
24235
24924
  action,
@@ -24238,7 +24927,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24238
24927
  if (action === "read") {
24239
24928
  const current = deps.memoryStore.read(deps.agentId);
24240
24929
  if (current.length === 0) {
24241
- logger7.info("self_note read empty", {
24930
+ logger8.info("self_note read empty", {
24242
24931
  agentId: deps.agentId,
24243
24932
  scope: currentScopeKey
24244
24933
  });
@@ -24246,7 +24935,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24246
24935
  content: [{ type: "text", text: "[self_note] \u4F60\u7684\u7B14\u8BB0\u672C\u76EE\u524D\u662F\u7A7A\u7684\u3002" }]
24247
24936
  };
24248
24937
  }
24249
- logger7.info("self_note read ok", {
24938
+ logger8.info("self_note read ok", {
24250
24939
  agentId: deps.agentId,
24251
24940
  scope: currentScopeKey,
24252
24941
  notebookBytes: current.length
@@ -24257,7 +24946,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24257
24946
  }
24258
24947
  if (action === "append" || action === "write") {
24259
24948
  if (typeof content !== "string" || content.length === 0) {
24260
- logger7.warn("self_note missing content", {
24949
+ logger8.warn("self_note missing content", {
24261
24950
  agentId: deps.agentId,
24262
24951
  scope: currentScopeKey,
24263
24952
  action
@@ -24274,7 +24963,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24274
24963
  deps.memoryStore.write(deps.agentId, content);
24275
24964
  }
24276
24965
  const after = deps.memoryStore.read(deps.agentId);
24277
- logger7.info("self_note persisted", {
24966
+ logger8.info("self_note persisted", {
24278
24967
  agentId: deps.agentId,
24279
24968
  scope: currentScopeKey,
24280
24969
  action,
@@ -24285,14 +24974,14 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24285
24974
  content: [{ type: "text", text: `[self_note] \u5DF2${action === "append" ? "\u8FFD\u52A0" : "\u8986\u76D6"}\uFF0C\u5F53\u524D\u7B14\u8BB0\u672C\u5171 ${after.length} \u5B57\u7B26\u3002` }]
24286
24975
  };
24287
24976
  } catch (err) {
24288
- logger7.error("self_note write failed", { agentId: deps.agentId, action, error: err });
24977
+ logger8.error("self_note write failed", { agentId: deps.agentId, action, error: err });
24289
24978
  return {
24290
24979
  content: [{ type: "text", text: `[self_note] \u5199\u5165\u5931\u8D25\uFF1A${err.message}` }],
24291
24980
  isError: true
24292
24981
  };
24293
24982
  }
24294
24983
  }
24295
- logger7.warn("self_note invalid action", {
24984
+ logger8.warn("self_note invalid action", {
24296
24985
  agentId: deps.agentId,
24297
24986
  scope: currentScopeKey,
24298
24987
  action: String(action)
@@ -24311,7 +25000,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24311
25000
  \u901A\u5E38\u4F60\u4E0D\u9700\u8981\u4E3B\u52A8\u8C03\u2014\u2014\u8FD9\u4EFD\u5217\u8868\u5DF2\u7ECF\u5728\u4F60\u7684 system prompt \u9876\u90E8\u9759\u6001\u6CE8\u5165\u8FC7\u3002\u4EC5\u5728\u4F60\u6000\u7591\u5217\u8868\u8FC7\u65F6\uFF08\u6BD4\u5982\u7528\u6237\u521A\u8BF4\u81EA\u5DF1\u521A\u62C9\u4F60\u8FDB\u4E86\u4E00\u4E2A\u7FA4\uFF0C\u4F46\u4F60\u7684\u5FEB\u7167\u91CC\u6CA1\u6709\uFF09\u65F6\u5237\u65B0\u4E00\u6B21\u3002`,
24312
25001
  {},
24313
25002
  async () => {
24314
- logger7.info("neural_list_scopes tool called", {
25003
+ logger8.info("neural_list_scopes tool called", {
24315
25004
  agentId: deps.agentId,
24316
25005
  scope: currentScopeKey
24317
25006
  });
@@ -24319,7 +25008,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24319
25008
  let myGroups;
24320
25009
  if (cachedScopes && now - cachedScopes.at < SCOPES_CACHE_MS) {
24321
25010
  myGroups = cachedScopes.groups;
24322
- logger7.info("neural_list_scopes: cache hit", {
25011
+ logger8.info("neural_list_scopes: cache hit", {
24323
25012
  agentId: deps.agentId,
24324
25013
  cachedAt: cachedScopes.at,
24325
25014
  ageMs: now - cachedScopes.at
@@ -24331,7 +25020,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24331
25020
  name: g.name
24332
25021
  }));
24333
25022
  cachedScopes = { groups: myGroups, at: now };
24334
- logger7.info("neural_list_scopes: registry refreshed", {
25023
+ logger8.info("neural_list_scopes: registry refreshed", {
24335
25024
  agentId: deps.agentId,
24336
25025
  scope: currentScopeKey,
24337
25026
  myGroupCount: myGroups.length
@@ -24353,7 +25042,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24353
25042
  '\u8C03 neural_send(target_scope="...") \u65F6\u8BF7\u7528\u4E0A\u9762\u5217\u51FA\u7684 scope \u5B57\u7B26\u4E32\u3002',
24354
25043
  myGroups.length === 0 ? "\uFF08\u4F60\u4E0D\u662F\u4EFB\u4F55\u7FA4\u7684\u6210\u5458\uFF1B\u53EF\u4E0E\u7528\u6237\u5728 single \u901A\u8BDD\uFF0C\u4F46\u6682\u65F6\u6CA1\u6709\u8DE8\u7FA4\u5206\u8EAB\u53EF\u89E6\u8FBE\u3002\uFF09" : "\u82E5\u7528\u6237\u63D0\u5230\u7684\u7FA4\u540D\u4E0D\u5728\u5217\u8868\u91CC\uFF0C\u8BF4\u660E\u4F60\u4E0D\u662F\u8BE5\u7FA4\u6210\u5458\u2014\u2014\u522B\u5C1D\u8BD5 neural_send \u5230\u90A3\u4E2A\u7FA4\uFF08\u4F1A\u88AB\u62D2\uFF09\u3002"
24355
25044
  ].join("\n");
24356
- logger7.info("neural_list_scopes returned", {
25045
+ logger8.info("neural_list_scopes returned", {
24357
25046
  agentId: deps.agentId,
24358
25047
  scope: currentScopeKey,
24359
25048
  groupCount: myGroups.length
@@ -24384,7 +25073,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24384
25073
  async (args) => {
24385
25074
  const requestedScope = args.scope?.trim() || "current";
24386
25075
  const limit = Math.min(50, Math.max(1, Math.floor(args.limit ?? 20)));
24387
- logger7.info("read_chat_history tool called", {
25076
+ logger8.info("read_chat_history tool called", {
24388
25077
  agentId: deps.agentId,
24389
25078
  scope: currentScopeKey,
24390
25079
  requestedScope,
@@ -24414,7 +25103,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24414
25103
  cached2 = deps.groupRegistry.getById(r.groupId);
24415
25104
  }
24416
25105
  if (!cached2 || !cached2.members.includes(deps.agentId)) {
24417
- logger7.info("read_chat_history: membership denied", {
25106
+ logger8.info("read_chat_history: membership denied", {
24418
25107
  agentId: deps.agentId,
24419
25108
  groupId: r.groupId,
24420
25109
  requestedScope
@@ -24448,7 +25137,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24448
25137
  scopeLabel = `\u7FA4\u300C${r?.groupName ?? targetScope.groupId}\u300D`;
24449
25138
  }
24450
25139
  if (!conversationId) {
24451
- logger7.info("read_chat_history: no conversation for scope", {
25140
+ logger8.info("read_chat_history: no conversation for scope", {
24452
25141
  agentId: deps.agentId,
24453
25142
  requestedScope,
24454
25143
  scopeLabel
@@ -24462,7 +25151,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24462
25151
  };
24463
25152
  }
24464
25153
  resolvedScopeLabel = scopeLabel;
24465
- logger7.info("read_chat_history: resolved target", {
25154
+ logger8.info("read_chat_history: resolved target", {
24466
25155
  agentId: deps.agentId,
24467
25156
  requestedScope,
24468
25157
  conversationId,
@@ -24479,7 +25168,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24479
25168
  const url2 = `${base}/api/conversations/${encodeURIComponent(conversationId)}/messages?${params.toString()}`;
24480
25169
  const resp = await fetch(url2);
24481
25170
  if (!resp.ok) {
24482
- logger7.warn("read_chat_history: HTTP error", {
25171
+ logger8.warn("read_chat_history: HTTP error", {
24483
25172
  agentId: deps.agentId,
24484
25173
  status: resp.status,
24485
25174
  conversationId
@@ -24496,7 +25185,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24496
25185
  const messages = body.messages ?? [];
24497
25186
  const hasMore = body.hasMore === true;
24498
25187
  if (messages.length === 0) {
24499
- logger7.info("read_chat_history: empty result", {
25188
+ logger8.info("read_chat_history: empty result", {
24500
25189
  agentId: deps.agentId,
24501
25190
  conversationId,
24502
25191
  requestedScope
@@ -24526,7 +25215,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24526
25215
  `\u7EE7\u7EED\u7FFB\uFF1Aread_chat_history(before="${firstTs}", scope="${requestedScope}")`
24527
25216
  );
24528
25217
  }
24529
- logger7.info("read_chat_history returned", {
25218
+ logger8.info("read_chat_history returned", {
24530
25219
  agentId: deps.agentId,
24531
25220
  conversationId,
24532
25221
  scopeLabel: resolvedScopeLabel,
@@ -24537,7 +25226,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
24537
25226
  });
24538
25227
  return { content: [{ type: "text", text: lines.join("\n") }] };
24539
25228
  } catch (e) {
24540
- logger7.error("read_chat_history failed", { error: e, agentId: deps.agentId });
25229
+ logger8.error("read_chat_history failed", { error: e, agentId: deps.agentId });
24541
25230
  return {
24542
25231
  content: [{
24543
25232
  type: "text",
@@ -24564,7 +25253,7 @@ Pass either a relative path from the current working directory or an absolute pa
24564
25253
  async (args) => {
24565
25254
  const requestedPath = args.path.trim();
24566
25255
  const maxChars = args.max_chars ?? 12e4;
24567
- logger7.info("read_document tool called", {
25256
+ logger8.info("read_document tool called", {
24568
25257
  agentId: deps.agentId,
24569
25258
  scope: currentScopeKey,
24570
25259
  path: requestedPath,
@@ -24586,7 +25275,7 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
24586
25275
  warningText,
24587
25276
  result.markdown
24588
25277
  ].filter((line) => line.length > 0).join("\n");
24589
- logger7.info("read_document returned", {
25278
+ logger8.info("read_document returned", {
24590
25279
  agentId: deps.agentId,
24591
25280
  scope: currentScopeKey,
24592
25281
  path: result.path,
@@ -24597,7 +25286,7 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
24597
25286
  return { content: [{ type: "text", text }] };
24598
25287
  } catch (e) {
24599
25288
  const message = e instanceof Error ? e.message : String(e);
24600
- logger7.error("read_document failed", {
25289
+ logger8.error("read_document failed", {
24601
25290
  agentId: deps.agentId,
24602
25291
  scope: currentScopeKey,
24603
25292
  path: requestedPath,
@@ -24635,7 +25324,7 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
24635
25324
  if (!resolved.ok) {
24636
25325
  return { content: [{ type: "text", text: resolved.text }], isError: true };
24637
25326
  }
24638
- logger7.info("create_group_issue tool called", {
25327
+ logger8.info("create_group_issue tool called", {
24639
25328
  agentId: deps.agentId,
24640
25329
  scope: currentScopeKey,
24641
25330
  groupId: resolved.groupId,
@@ -24650,7 +25339,7 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
24650
25339
  (issue2) => issue2.status === "open" && issue2.title.trim() === title
24651
25340
  );
24652
25341
  if (duplicate) {
24653
- logger7.info("create_group_issue: duplicate open issue reused", {
25342
+ logger8.info("create_group_issue: duplicate open issue reused", {
24654
25343
  agentId: deps.agentId,
24655
25344
  groupId: resolved.groupId,
24656
25345
  issueId: duplicate.id,
@@ -24679,7 +25368,7 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
24679
25368
  });
24680
25369
  if (!res.ok) {
24681
25370
  const errText = await res.text().catch(() => "");
24682
- logger7.warn("create_group_issue: server rejected", {
25371
+ logger8.warn("create_group_issue: server rejected", {
24683
25372
  agentId: deps.agentId,
24684
25373
  groupId: resolved.groupId,
24685
25374
  status: res.status,
@@ -24691,7 +25380,7 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
24691
25380
  };
24692
25381
  }
24693
25382
  const payload = await res.json();
24694
- logger7.info("create_group_issue: created", {
25383
+ logger8.info("create_group_issue: created", {
24695
25384
  agentId: deps.agentId,
24696
25385
  groupId: resolved.groupId,
24697
25386
  issueId: payload.issue?.id,
@@ -24704,7 +25393,7 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
24704
25393
  }]
24705
25394
  };
24706
25395
  } catch (e) {
24707
- logger7.error("create_group_issue failed", { error: e, agentId: deps.agentId, groupId: resolved.groupId });
25396
+ logger8.error("create_group_issue failed", { error: e, agentId: deps.agentId, groupId: resolved.groupId });
24708
25397
  return {
24709
25398
  content: [{ type: "text", text: `[create_group_issue] \u521B\u5EFA\u5931\u8D25\uFF1A${e.message}` }],
24710
25399
  isError: true
@@ -24733,7 +25422,7 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
24733
25422
  if (!resolved.ok) {
24734
25423
  return { content: [{ type: "text", text: resolved.text }], isError: true };
24735
25424
  }
24736
- logger7.info("resolve_group_issue tool called", {
25425
+ logger8.info("resolve_group_issue tool called", {
24737
25426
  agentId: deps.agentId,
24738
25427
  scope: currentScopeKey,
24739
25428
  groupId: resolved.groupId,
@@ -24778,7 +25467,7 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
24778
25467
  );
24779
25468
  if (!res.ok) {
24780
25469
  const errText = await res.text().catch(() => "");
24781
- logger7.warn("resolve_group_issue: server rejected", {
25470
+ logger8.warn("resolve_group_issue: server rejected", {
24782
25471
  agentId: deps.agentId,
24783
25472
  groupId: resolved.groupId,
24784
25473
  issueId,
@@ -24791,7 +25480,7 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
24791
25480
  };
24792
25481
  }
24793
25482
  const payload = await res.json();
24794
- logger7.info("resolve_group_issue: resolved", {
25483
+ logger8.info("resolve_group_issue: resolved", {
24795
25484
  agentId: deps.agentId,
24796
25485
  groupId: resolved.groupId,
24797
25486
  issueId: payload.issue?.id ?? issueId
@@ -24803,7 +25492,7 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
24803
25492
  }]
24804
25493
  };
24805
25494
  } catch (e) {
24806
- logger7.error("resolve_group_issue failed", { error: e, agentId: deps.agentId, groupId: resolved.groupId, issueId });
25495
+ logger8.error("resolve_group_issue failed", { error: e, agentId: deps.agentId, groupId: resolved.groupId, issueId });
24807
25496
  return {
24808
25497
  content: [{ type: "text", text: `[resolve_group_issue] \u5173\u95ED\u5931\u8D25\uFF1A${e.message}` }],
24809
25498
  isError: true
@@ -24826,7 +25515,7 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
24826
25515
  if (!resolved.ok) {
24827
25516
  return { content: [{ type: "text", text: resolved.text }], isError: true };
24828
25517
  }
24829
- logger7.info("list_group_tasks tool called", {
25518
+ logger8.info("list_group_tasks tool called", {
24830
25519
  agentId: deps.agentId,
24831
25520
  scope: currentScopeKey,
24832
25521
  groupId: resolved.groupId,
@@ -24850,7 +25539,7 @@ ${body}`
24850
25539
  }]
24851
25540
  };
24852
25541
  } catch (e) {
24853
- logger7.error("list_group_tasks failed", { error: e, agentId: deps.agentId, groupId: resolved.groupId });
25542
+ logger8.error("list_group_tasks failed", { error: e, agentId: deps.agentId, groupId: resolved.groupId });
24854
25543
  return {
24855
25544
  content: [{ type: "text", text: `[list_group_tasks] \u67E5\u8BE2\u5931\u8D25\uFF1A${e.message}` }],
24856
25545
  isError: true
@@ -24879,7 +25568,7 @@ ${body}`
24879
25568
  if (!resolved.ok) {
24880
25569
  return { content: [{ type: "text", text: resolved.text }], isError: true };
24881
25570
  }
24882
- logger7.info("update_group_task tool called", {
25571
+ logger8.info("update_group_task tool called", {
24883
25572
  agentId: deps.agentId,
24884
25573
  scope: currentScopeKey,
24885
25574
  groupId: resolved.groupId,
@@ -24922,7 +25611,7 @@ ${body}`
24922
25611
  );
24923
25612
  if (!res.ok) {
24924
25613
  const errText = await res.text().catch(() => "");
24925
- logger7.warn("update_group_task: server rejected", {
25614
+ logger8.warn("update_group_task: server rejected", {
24926
25615
  agentId: deps.agentId,
24927
25616
  groupId: resolved.groupId,
24928
25617
  itemId,
@@ -24936,7 +25625,7 @@ ${body}`
24936
25625
  };
24937
25626
  }
24938
25627
  const payload = await res.json();
24939
- logger7.info("update_group_task: updated", {
25628
+ logger8.info("update_group_task: updated", {
24940
25629
  agentId: deps.agentId,
24941
25630
  groupId: resolved.groupId,
24942
25631
  itemId: payload.item?.id ?? itemId,
@@ -24949,7 +25638,7 @@ ${body}`
24949
25638
  }]
24950
25639
  };
24951
25640
  } catch (e) {
24952
- logger7.error("update_group_task failed", { error: e, agentId: deps.agentId, groupId: resolved.groupId, itemId, status });
25641
+ logger8.error("update_group_task failed", { error: e, agentId: deps.agentId, groupId: resolved.groupId, itemId, status });
24953
25642
  return {
24954
25643
  content: [{ type: "text", text: `[update_group_task] \u66F4\u65B0\u5931\u8D25\uFF1A${e.message}` }],
24955
25644
  isError: true
@@ -24964,18 +25653,18 @@ ${body}`
24964
25653
  \u8FD4\u56DE\u7ED3\u6784\u662F\u4E00\u6BB5 Markdown\uFF1A\u6BCF\u4E00\u6761\u542B id / \u540D\u5B57 / \u89D2\u8272 / \u673A\u5668\u5F52\u5C5E\u3002\u4F1A\u6807\u6CE8\u54EA\u4E00\u6761\u662F"\u4F60\u81EA\u5DF1"\uFF0C\u4EE5\u53CA\u4F60\u548C\u54EA\u4E9B Agent \u5DF2\u7ECF\u5171\u5728\u67D0\u4E2A\u7FA4\u91CC\u3002\u4EBA\u7C7B\u7528\u6237\u4F1A\u5E26 (\u4EBA\u7C7B) \u6807\u8BB0\u3002
24965
25654
  \u901A\u5E38\u4F60\u5728\u7528\u6237\u63D0\u5230\u5177\u4F53\u540C\u4E8B\u59D3\u540D\u3001\u6216\u601D\u8003"\u8BE5\u62C9\u8C01\u8FDB\u7FA4\u534F\u4F5C"\u65F6\u8C03\u4E00\u6B21\uFF1B\u4E0D\u8981\u6BCF\u8F6E\u90FD\u67E5\u3002
24966
25655
  \u652F\u6301 filter\uFF08\u6309\u540D\u5B57\u6216\u89D2\u8272\u6A21\u7CCA\u641C\u7D22\uFF09\u548C limit\uFF08\u9650\u5236\u8FD4\u56DE\u6761\u6570\uFF09\u53C2\u6570\u3002
24967
- Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\u53C2\u8003"\u53EF\u7528\u673A\u5668"\u91CC\u7684 bridgeKey\uFF0C\u7ED9 create_agent / update_agent_profile \u4F20 machine_bridge_key\uFF1B\u7701\u7565\u5219\u4F7F\u7528\u5F53\u524D Bridge \u6216\u4FDD\u7559\u539F\u504F\u597D\u3002
25656
+ Smith \u521B\u5EFA Agent \u65F6\u9ED8\u8BA4\u4E0D\u8981\u4F20 machine_bridge_key\uFF1B\u7701\u7565\u5373\u4F7F\u7528\u5F53\u524D Bridge\u3002\u53EA\u6709\u7528\u6237\u660E\u786E\u6307\u5B9A\u67D0\u53F0\u673A\u5668\u65F6\uFF0C\u624D\u53C2\u8003"\u53EF\u7528\u673A\u5668"\u91CC\u7684 bridgeKey\uFF0C\u5E76\u4F18\u5148\u901A\u8FC7 update_agent_profile \u5207\u6362\u3002
24968
25657
  \u8981\u628A\u4EBA\u7C7B\u62C9\u8FDB\u7FA4\uFF1A\u5728 create_group / add_to_group \u7684 member_ids / agent_ids \u91CC\u5E26\u4E0A**\u8BF7\u6C42\u8005\u7684\u4EBA\u7C7B id**\uFF08\u5373\u5217\u8868\u91CC\u5E26"(\u4EBA\u7C7B)"\u6807\u8BB0\u7684\u90A3\u4E00\u6761\uFF1B\u591A\u7528\u6237\u6A21\u5F0F\u4E0B\u6BCF\u4E2A\u7528\u6237\u90FD\u6709\u81EA\u5DF1\u72EC\u7ACB\u7684 id\uFF0C\u4F8B\u5982 agt_usr_XXX\uFF1B\u8001\u7684\u5355\u7528\u6237\u6A21\u5F0F\u4E0B\u662F agt_usr_self\uFF09\u3002\u4E0D\u8981\u786C\u7F16\u7801 agt_usr_self\u2014\u2014\u4EE5 list_contacts \u5B9E\u9645\u8FD4\u56DE\u7684 id \u4E3A\u51C6\u3002`,
24969
25658
  {
24970
25659
  filter: external_exports.string().optional().describe("\u53EF\u9009\u3002\u6309\u540D\u5B57\u6216\u89D2\u8272\u6A21\u7CCA\u8FC7\u6EE4\uFF08\u4E0D\u533A\u5206\u5927\u5C0F\u5199\uFF09\u3002"),
24971
25660
  limit: external_exports.number().int().min(1).max(200).optional().describe("\u6700\u591A\u8FD4\u56DE\u591A\u5C11\u6761\uFF0C\u9ED8\u8BA4\u4E0D\u9650\u3002")
24972
25661
  },
24973
25662
  async (args) => {
24974
- logger7.info("list_contacts tool called", { agentId: deps.agentId, scope: currentScopeKey });
25663
+ logger8.info("list_contacts tool called", { agentId: deps.agentId, scope: currentScopeKey });
24975
25664
  try {
24976
25665
  await deps.agentRegistry.refresh();
24977
25666
  } catch (e) {
24978
- logger7.warn("list_contacts: registry refresh failed, using cache", {
25667
+ logger8.warn("list_contacts: registry refresh failed, using cache", {
24979
25668
  agentId: deps.agentId,
24980
25669
  error: e
24981
25670
  });
@@ -25022,16 +25711,16 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25022
25711
  const onlineMachines = machines.filter((machine) => machine.status === "online");
25023
25712
  const offlineMachines = machines.filter((machine) => machine.status !== "online");
25024
25713
  const machineSection = machines.length > 0 ? [
25025
- "\u5728\u7EBF\u673A\u5668\uFF08\u63A8\u8350\uFF1Bcreate_agent / update_agent_profile \u53EA\u80FD\u4F20\u8FD9\u4E9B machine_bridge_key\uFF1B\u7701\u7565\u5219\u4F7F\u7528\u5F53\u524D Bridge \u6216\u4FDD\u7559\u539F\u504F\u597D\uFF09\uFF1A",
25714
+ "\u53EF\u7528\u673A\u5668\uFF08\u4EC5\u5728\u7528\u6237\u660E\u786E\u6307\u5B9A\u8FD0\u884C\u7535\u8111\u65F6\u4F7F\u7528\uFF1B\u666E\u901A create_agent \u4E0D\u8981\u4F20 machine_bridge_key\uFF0C\u7701\u7565\u5373\u5F53\u524D\u673A\u5668\uFF09\uFF1A",
25026
25715
  ...onlineMachines.length > 0 ? onlineMachines.map(formatMachineOptionLine) : ["- \u5F53\u524D\u6CA1\u6709\u5728\u7EBF\u673A\u5668\uFF1B\u53EF\u7701\u7565 machine_bridge_key\uFF0C\u8BA9\u5F53\u524D Bridge \u515C\u5E95\u3002"],
25027
25716
  ...offlineMachines.length > 0 ? [
25028
25717
  "",
25029
25718
  "\u79BB\u7EBF/\u4E0D\u53EF\u76F4\u63A5\u7528\u4E8E\u65B0\u5EFA\u7684\u673A\u5668\uFF08\u4E0D\u8981\u628A\u8FD9\u4E9B bridgeKey \u4F20\u7ED9 create_agent\uFF1B\u5426\u5219\u4EFB\u52A1\u4F1A Bridge offline\uFF09\uFF1A",
25030
25719
  ...offlineMachines.map(formatMachineOptionLine)
25031
25720
  ] : []
25032
- ].join("\n") : "\u53EF\u7528\u673A\u5668\uFF1A\u5F53\u524D Bridge\uFF08create_agent \u7701\u7565 machine_bridge_key \u5373\u4F7F\u7528\u5F53\u524D Bridge\uFF1Bupdate_agent_profile \u7701\u7565\u5373\u4FDD\u7559\u539F\u504F\u597D\uFF09\u3002";
25721
+ ].join("\n") : "\u53EF\u7528\u673A\u5668\uFF1A\u5F53\u524D Bridge\uFF08\u666E\u901A create_agent \u7701\u7565 machine_bridge_key \u5373\u4F7F\u7528\u5F53\u524D\u673A\u5668\uFF1Bupdate_agent_profile \u7701\u7565\u5373\u4FDD\u7559\u539F\u504F\u597D\uFF09\u3002";
25033
25722
  const text = shown === 0 ? q ? `\u672A\u627E\u5230\u4E0E "${args?.filter}" \u5339\u914D\u7684\u8054\u7CFB\u4EBA\u3002` : "\u5F53\u524D\u7CFB\u7EDF\u91CC\u8FD8\u6CA1\u6709\u4EFB\u4F55 Agent\u3002" : [header, "", machineSection, "", ...lines].join("\n");
25034
- logger7.info("list_contacts returned", {
25723
+ logger8.info("list_contacts returned", {
25035
25724
  agentId: deps.agentId,
25036
25725
  count: all.length,
25037
25726
  humanCount,
@@ -25094,7 +25783,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25094
25783
  }
25095
25784
  const initialMessage = typeof args.initial_message === "string" ? args.initial_message.trim().replaceAll(USR_SELF_ID, resolveMyHuman(deps.agentRegistry, deps.agentId)) : "";
25096
25785
  const hasInitial = initialMessage.length > 0;
25097
- logger7.info("create_group tool called", {
25786
+ logger8.info("create_group tool called", {
25098
25787
  agentId: deps.agentId,
25099
25788
  name: trimmedName,
25100
25789
  memberCount: dedup.length,
@@ -25125,7 +25814,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25125
25814
  });
25126
25815
  if (!res.ok) {
25127
25816
  const errText = await res.text().catch(() => "");
25128
- logger7.warn("create_group: server rejected", { status: res.status, errText });
25817
+ logger8.warn("create_group: server rejected", { status: res.status, errText });
25129
25818
  return {
25130
25819
  content: [{ type: "text", text: `[create_group] \u670D\u52A1\u7AEF\u62D2\u7EDD\uFF08${res.status}\uFF09\uFF1A${errText || "(no body)"}` }],
25131
25820
  isError: true
@@ -25133,7 +25822,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25133
25822
  }
25134
25823
  const group = await res.json();
25135
25824
  const groupScopeKey = `group:${group.id}`;
25136
- logger7.info("create_group: created", {
25825
+ logger8.info("create_group: created", {
25137
25826
  agentId: deps.agentId,
25138
25827
  groupId: group.id,
25139
25828
  name: group.name,
@@ -25161,7 +25850,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25161
25850
  }]
25162
25851
  };
25163
25852
  } catch (e) {
25164
- logger7.error("create_group failed", { error: e, name: trimmedName });
25853
+ logger8.error("create_group failed", { error: e, name: trimmedName });
25165
25854
  return {
25166
25855
  content: [{ type: "text", text: `[create_group] \u5EFA\u7FA4\u5931\u8D25\uFF1A${e.message}` }],
25167
25856
  isError: true
@@ -25218,7 +25907,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25218
25907
  const scopeInput = rawGroup.startsWith("group:") ? rawGroup : `group:${rawGroup}`;
25219
25908
  const resolved = await deps.groupRegistry.resolveScope(scopeInput);
25220
25909
  if (!resolved) {
25221
- logger7.info("add_to_group: group not found", { rawGroup, scopeInput });
25910
+ logger8.info("add_to_group: group not found", { rawGroup, scopeInput });
25222
25911
  return {
25223
25912
  content: [{ type: "text", text: `[add_to_group] \u627E\u4E0D\u5230\u7FA4\u300C${rawGroup}\u300D\u3002\u53EF\u8C03 neural_list_scopes() \u67E5\u770B\u4F60\u7684\u7FA4\u5217\u8868\u3002` }],
25224
25913
  isError: true
@@ -25230,7 +25919,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25230
25919
  cached2 = deps.groupRegistry.getById(resolved.groupId);
25231
25920
  }
25232
25921
  if (!cached2 || !cached2.members.includes(deps.agentId)) {
25233
- logger7.info("add_to_group: not a member of target group", {
25922
+ logger8.info("add_to_group: not a member of target group", {
25234
25923
  agentId: deps.agentId,
25235
25924
  groupId: resolved.groupId,
25236
25925
  groupName: resolved.groupName
@@ -25246,7 +25935,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25246
25935
  const alreadyIn = agentIds.filter((id) => cached2.members.includes(id));
25247
25936
  const toAdd = agentIds.filter((id) => !cached2.members.includes(id));
25248
25937
  if (toAdd.length === 0) {
25249
- logger7.info("add_to_group: all agents already in group", {
25938
+ logger8.info("add_to_group: all agents already in group", {
25250
25939
  agentId: deps.agentId,
25251
25940
  groupId: resolved.groupId,
25252
25941
  alreadyIn
@@ -25258,7 +25947,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25258
25947
  }]
25259
25948
  };
25260
25949
  }
25261
- logger7.info("add_to_group tool called", {
25950
+ logger8.info("add_to_group tool called", {
25262
25951
  agentId: deps.agentId,
25263
25952
  groupId: resolved.groupId,
25264
25953
  groupName: resolved.groupName,
@@ -25274,7 +25963,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25274
25963
  });
25275
25964
  if (!res.ok) {
25276
25965
  const errText = await res.text().catch(() => "");
25277
- logger7.warn("add_to_group: server rejected", {
25966
+ logger8.warn("add_to_group: server rejected", {
25278
25967
  status: res.status,
25279
25968
  errText,
25280
25969
  groupId: resolved.groupId,
@@ -25289,7 +25978,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25289
25978
  const a = deps.agentRegistry.getById(id);
25290
25979
  return a ? a.name : id;
25291
25980
  });
25292
- logger7.info("add_to_group: members added", {
25981
+ logger8.info("add_to_group: members added", {
25293
25982
  agentId: deps.agentId,
25294
25983
  groupId: resolved.groupId,
25295
25984
  groupName: resolved.groupName,
@@ -25308,7 +25997,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25308
25997
  }]
25309
25998
  };
25310
25999
  } catch (e) {
25311
- logger7.error("add_to_group failed", {
26000
+ logger8.error("add_to_group failed", {
25312
26001
  error: e,
25313
26002
  groupId: resolved.groupId,
25314
26003
  toAdd
@@ -25355,13 +26044,13 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25355
26044
  cached2 = deps.groupRegistry.getById(resolved.groupId);
25356
26045
  }
25357
26046
  if (!cached2 || !cached2.members.includes(deps.agentId)) {
25358
- logger7.info("leave_group: not a member", { agentId: deps.agentId, groupId: resolved.groupId });
26047
+ logger8.info("leave_group: not a member", { agentId: deps.agentId, groupId: resolved.groupId });
25359
26048
  return {
25360
26049
  content: [{ type: "text", text: `[leave_group] \u4F60\u4E0D\u5728\u7FA4\u300C${resolved.groupName}\u300D\u91CC\uFF0C\u65E0\u9700\u9000\u51FA\u3002` }],
25361
26050
  isError: true
25362
26051
  };
25363
26052
  }
25364
- logger7.info("leave_group tool called", {
26053
+ logger8.info("leave_group tool called", {
25365
26054
  agentId: deps.agentId,
25366
26055
  groupId: resolved.groupId,
25367
26056
  groupName: resolved.groupName
@@ -25374,13 +26063,13 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25374
26063
  });
25375
26064
  if (!res.ok) {
25376
26065
  const errText = await res.text().catch(() => "");
25377
- logger7.warn("leave_group: server rejected", { status: res.status, errText, groupId: resolved.groupId });
26066
+ logger8.warn("leave_group: server rejected", { status: res.status, errText, groupId: resolved.groupId });
25378
26067
  return {
25379
26068
  content: [{ type: "text", text: `[leave_group] \u670D\u52A1\u7AEF\u62D2\u7EDD\uFF08${res.status}\uFF09\uFF1A${errText || "(no body)"}` }],
25380
26069
  isError: true
25381
26070
  };
25382
26071
  }
25383
- logger7.info("leave_group: succeeded", {
26072
+ logger8.info("leave_group: succeeded", {
25384
26073
  agentId: deps.agentId,
25385
26074
  groupId: resolved.groupId,
25386
26075
  groupName: resolved.groupName
@@ -25395,7 +26084,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25395
26084
  }]
25396
26085
  };
25397
26086
  } catch (e) {
25398
- logger7.error("leave_group failed", { error: e, groupId: resolved.groupId });
26087
+ logger8.error("leave_group failed", { error: e, groupId: resolved.groupId });
25399
26088
  return {
25400
26089
  content: [{ type: "text", text: `[leave_group] \u9000\u7FA4\u5931\u8D25\uFF1A${e.message}` }],
25401
26090
  isError: true
@@ -25451,7 +26140,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25451
26140
  };
25452
26141
  }
25453
26142
  if (cached2.createdBy == null) {
25454
- logger7.info("remove_from_group: ownerless group rejected", { agentId: deps.agentId, groupId: resolved.groupId });
26143
+ logger8.info("remove_from_group: ownerless group rejected", { agentId: deps.agentId, groupId: resolved.groupId });
25455
26144
  return {
25456
26145
  content: [{ type: "text", text: `[remove_from_group] \u7FA4\u300C${resolved.groupName}\u300D\u6CA1\u6709\u7FA4\u4E3B\uFF08\u539F\u7FA4\u4E3B\u5DF2\u9000\u7FA4\uFF09\uFF0C\u6CA1\u4EBA\u80FD\u8E22\u6210\u5458\u3002` }],
25457
26146
  isError: true
@@ -25460,7 +26149,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25460
26149
  if (cached2.createdBy !== deps.agentId) {
25461
26150
  const ownerInfo = deps.agentRegistry.getById(cached2.createdBy);
25462
26151
  const ownerLabel = ownerInfo ? `${ownerInfo.name} (${cached2.createdBy})` : cached2.createdBy;
25463
- logger7.info("remove_from_group: not owner", {
26152
+ logger8.info("remove_from_group: not owner", {
25464
26153
  agentId: deps.agentId,
25465
26154
  groupId: resolved.groupId,
25466
26155
  ownerId: cached2.createdBy
@@ -25498,7 +26187,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25498
26187
  }]
25499
26188
  };
25500
26189
  }
25501
- logger7.info("remove_from_group tool called", {
26190
+ logger8.info("remove_from_group tool called", {
25502
26191
  agentId: deps.agentId,
25503
26192
  groupId: resolved.groupId,
25504
26193
  groupName: resolved.groupName,
@@ -25528,7 +26217,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25528
26217
  const a = deps.agentRegistry.getById(id);
25529
26218
  return a ? a.name : id;
25530
26219
  });
25531
- logger7.info("remove_from_group: completed", {
26220
+ logger8.info("remove_from_group: completed", {
25532
26221
  agentId: deps.agentId,
25533
26222
  groupId: resolved.groupId,
25534
26223
  removedCount: removed.length,
@@ -25569,7 +26258,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25569
26258
  }
25570
26259
  const latestReadableSkillNames = currentReadableSkillNames();
25571
26260
  if (!latestReadableSkillNames.includes(name)) {
25572
- logger7.warn("read_skill: not readable for agent", {
26261
+ logger8.warn("read_skill: not readable for agent", {
25573
26262
  agentId: deps.agentId,
25574
26263
  isSmith: deps.isSmith,
25575
26264
  name,
@@ -25583,7 +26272,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25583
26272
  isError: true
25584
26273
  };
25585
26274
  }
25586
- logger7.info("read_skill tool called", { agentId: deps.agentId, scope: currentScopeKey, name });
26275
+ logger8.info("read_skill tool called", { agentId: deps.agentId, scope: currentScopeKey, name });
25587
26276
  const content = deps.skillStore.read(name);
25588
26277
  if (!content) {
25589
26278
  return {
@@ -25594,7 +26283,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25594
26283
  isError: true
25595
26284
  };
25596
26285
  }
25597
- logger7.info("read_skill returned", { agentId: deps.agentId, name, bytes: content.length });
26286
+ logger8.info("read_skill returned", { agentId: deps.agentId, name, bytes: content.length });
25598
26287
  return { content: [{ type: "text", text: content }] };
25599
26288
  },
25600
26289
  {}
@@ -25603,7 +26292,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25603
26292
  "list_available_skills",
25604
26293
  `\u5217\u51FA\u5F53\u524D Agent \u6B64\u523B\u53EF\u76F4\u63A5\u6309\u4EFB\u52A1\u4F7F\u7528\u7684 skill\u3002
25605
26294
  \u666E\u901A Agent \u9009\u62E9 skill \u65F6\u5FC5\u987B\u5148\u8C03\u7528\u5B83\uFF1B\u4F18\u5148\u7528\u5B83\u56DE\u7B54"\u6211\u73B0\u5728\u80FD\u7528\u4EC0\u4E48 skill"\u548C\u4EFB\u52A1\u5F00\u59CB\u524D\u7684 skill \u9009\u62E9\u95EE\u9898\u3002
25606
- \u53EA\u8FD4\u56DE\u8F7B\u91CF\u6458\u8981\u3001\u6743\u9650\u3001\u6765\u6E90\u548C\u8FD0\u884C\u72B6\u6001\uFF1B\u4E0D\u8FD4\u56DE\u5B8C\u6574\u65B9\u6CD5\u5B66\u3002\u53EA\u5305\u542B\u5DF2\u7ECF\u843D\u5230\u5F53\u524D\u673A\u5668 runtime cache \u4E14\u5BF9\u5F53\u524D Agent \u53EF\u89C1\u7684 skill\u3002\u59CB\u7EC8\u53EA\u8FD4\u56DE runtimeAvailability=available\uFF1B\u4E0D\u4F1A\u8FD4\u56DE unavailable\u3001planned \u6216 smith_only\u3002include_unavailable \u662F\u65E7\u5BA2\u6237\u7AEF\u517C\u5BB9\u53C2\u6570\uFF0C\u5DF2\u5FFD\u7565\u3002
26295
+ \u53EA\u8FD4\u56DE\u8F7B\u91CF\u6458\u8981\u3001\u6743\u9650\u3001\u6765\u6E90\u548C\u8FD0\u884C\u72B6\u6001\uFF1B\u4E0D\u8FD4\u56DE\u5B8C\u6574\u65B9\u6CD5\u5B66\u3002Skill \u662F AHChat \u7684\u65B9\u6CD5\u5B66/\u6D41\u7A0B\u63D0\u793A\uFF0C\u4E0D\u662F\u53EF\u8C03\u7528 SDK \u5DE5\u5177\uFF1B\u4E0D\u8981\u8C03\u7528\u540D\u4E3A Skill \u7684\u901A\u7528\u5DE5\u5177\uFF0C\u4E5F\u4E0D\u8981\u628A\u8FD9\u91CC\u7684 skill \u540D\u79F0\u6216 ID \u586B\u8FDB tool \u53C2\u6570\u3002\u53EA\u5305\u542B\u5DF2\u7ECF\u843D\u5230\u5F53\u524D\u673A\u5668 runtime cache \u4E14\u5BF9\u5F53\u524D Agent \u53EF\u89C1\u7684 skill\u3002\u59CB\u7EC8\u53EA\u8FD4\u56DE runtimeAvailability=available\uFF1B\u4E0D\u4F1A\u8FD4\u56DE unavailable\u3001planned \u6216 smith_only\u3002include_unavailable \u662F\u65E7\u5BA2\u6237\u7AEF\u517C\u5BB9\u53C2\u6570\uFF0C\u5DF2\u5FFD\u7565\u3002
25607
26296
  \u5982\u679C\u8FD9\u91CC\u6CA1\u6709\u5339\u914D\u9879\uFF0C\u624D\u7528 list_skill_index \u67E5\u5019\u9009\u3002\u82E5 list_skill_index \u627E\u5230\u4E86\u5408\u9002\u4F46\u672A\u5206\u914D\u7684\u5019\u9009\uFF0C\u5FC5\u987B\u8C03\u7528 AskUserQuestion \u5DE5\u5177\u8BE2\u95EE\u7528\u6237\u662F\u5426\u8981\u4E3A\u5F53\u524D Agent \u542F\u7528/\u5206\u914D\uFF1B\u95EE\u9898 metadata \u5C3D\u91CF\u5E26\u4E0A skillId/skillName\uFF1B\u4E0D\u8981\u7528\u666E\u901A\u6587\u672C\u63D0\u95EE\uFF0C\u4E5F\u4E0D\u8981\u76F4\u63A5\u5047\u88C5\u8C03\u7528\u3002`,
25608
26297
  {
25609
26298
  query: external_exports.string().optional().describe("\u53EF\u9009\u3002\u6309 skill \u540D\u79F0\u3001\u6458\u8981\u6216\u5173\u952E\u8BCD\u641C\u7D22\u5F53\u524D\u53EF\u7528 skill\u3002"),
@@ -25623,14 +26312,14 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25623
26312
  entries: runtimeEntries,
25624
26313
  runtime: skillRuntimeContext(deps.officeCliRuntime)
25625
26314
  }), visibleSkillIds), availableSkillIds);
25626
- logger7.info("list_available_skills tool called", {
26315
+ logger8.info("list_available_skills tool called", {
25627
26316
  agentId: deps.agentId,
25628
26317
  scope: currentScopeKey,
25629
26318
  resultCount: entries.length,
25630
26319
  agentScoped: Boolean(availableSkillIds)
25631
26320
  });
25632
26321
  const text = entries.length > 0 ? entries.map((entry, index) => formatSkillEntry(entry, index)).join("\n") : "\u5F53\u524D\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u53EF\u7528 skill\u3002";
25633
- const scopeRule = deps.isSmith ? "\u89C4\u5219\uFF1ASmith \u662F\u7CFB\u7EDF\u7EC4\u7EC7\u8005\uFF0C\u7ED3\u679C\u5305\u542B\u5F53\u524D\u7528\u6237\u53EF\u89C1\u4E14\u5DF2\u5B89\u88C5/\u5DF2\u542F\u7528\u3001\u5DF2\u843D\u5F53\u524D\u673A\u5668 runtime cache \u4E14\u53EF\u8FD0\u884C\u7684\u8F7B\u91CF skill \u6458\u8981\uFF1B\u4E0D\u662F\u5B8C\u6574\u65B9\u6CD5\u5B66\u3002\u53EA\u6709 summary\u3001taskTypes\u3001outputs \u4E0E\u7528\u6237\u76EE\u6807\u5339\u914D\u65F6\u624D\u4F7F\u7528\u3002" : '\u89C4\u5219\uFF1A\u8FD9\u4E9B\u7ED3\u679C\u53EA\u5305\u542B\u5F53\u524D Agent \u5DF2\u5206\u914D/\u672C\u673A Local \u5DF2\u7ED1\u5B9A\u3001\u5DF2\u843D\u5F53\u524D\u673A\u5668 runtime cache \u4E14\u53EF\u8FD0\u884C\u7684\u8F7B\u91CF skill \u6458\u8981\uFF0C\u4E0D\u662F\u5B8C\u6574\u65B9\u6CD5\u5B66\u3002\u53EA\u6709 summary\u3001taskTypes\u3001outputs \u4E0E\u7528\u6237\u76EE\u6807\u5339\u914D\u65F6\u624D\u4F7F\u7528\uFF1B\u5982\u679C\u6CA1\u6709\u5339\u914D\u9879\uFF0C\u5C31\u76F4\u63A5\u5B8C\u6210\u4EFB\u52A1\uFF0C\u6216\u7528 list_skill_index \u641C\u7D22\u5019\u9009\uFF0C\u5E76\u8C03\u7528 AskUserQuestion \u5DE5\u5177\u8BE2\u95EE\u7528\u6237\u662F\u5426\u8981\u4E3A\u5F53\u524D Agent \u542F\u7528/\u5206\u914D\u8BE5 skill\u3002AskUserQuestion \u9009\u9879\u5FC5\u987B\u5305\u542B"\u542F\u7528/\u5206\u914D\u8FD9\u4E2A skill"\u548C"\u5148\u4E0D\u7528\uFF0C\u76F4\u63A5\u5904\u7406"\uFF0Cmetadata \u5C3D\u91CF\u5E26\u4E0A skillId/skillName\u3002\u7528\u6237\u786E\u8BA4\u524D\u4E0D\u8981\u58F0\u79F0\u5DF2\u4F7F\u7528\u672A\u5206\u914D skill\uFF1B\u786E\u8BA4\u540E\u5FC5\u987B\u91CD\u65B0\u67E5\u8BE2\u672C\u5DE5\u5177\uFF0C\u53EA\u6709\u51FA\u73B0\u5728\u8FD9\u91CC\u624D\u7B97\u53EF\u7528\u3002';
26322
+ const scopeRule = deps.isSmith ? "\u89C4\u5219\uFF1ASmith \u662F\u7CFB\u7EDF\u7EC4\u7EC7\u8005\uFF0C\u7ED3\u679C\u5305\u542B\u5F53\u524D\u7528\u6237\u53EF\u89C1\u4E14\u5DF2\u5B89\u88C5/\u5DF2\u542F\u7528\u3001\u5DF2\u843D\u5F53\u524D\u673A\u5668 runtime cache \u4E14\u53EF\u8FD0\u884C\u7684\u8F7B\u91CF skill \u6458\u8981\uFF1B\u4E0D\u662F\u5B8C\u6574\u65B9\u6CD5\u5B66\uFF0C\u4E5F\u4E0D\u662F\u53EF\u8C03\u7528 SDK \u5DE5\u5177\u3002\u53EA\u6709 summary\u3001taskTypes\u3001outputs \u4E0E\u7528\u6237\u76EE\u6807\u5339\u914D\u65F6\u624D\u4F7F\u7528\uFF1B\u4E0D\u8981\u8C03\u7528\u540D\u4E3A Skill \u7684\u901A\u7528\u5DE5\u5177\u3002" : '\u89C4\u5219\uFF1A\u8FD9\u4E9B\u7ED3\u679C\u53EA\u5305\u542B\u5F53\u524D Agent \u5DF2\u5206\u914D/\u672C\u673A Local \u5DF2\u7ED1\u5B9A\u3001\u5DF2\u843D\u5F53\u524D\u673A\u5668 runtime cache \u4E14\u53EF\u8FD0\u884C\u7684\u8F7B\u91CF skill \u6458\u8981\uFF0C\u4E0D\u662F\u5B8C\u6574\u65B9\u6CD5\u5B66\uFF0C\u4E5F\u4E0D\u662F\u53EF\u8C03\u7528 SDK \u5DE5\u5177\uFF1B\u4E0D\u8981\u8C03\u7528\u540D\u4E3A Skill \u7684\u901A\u7528\u5DE5\u5177\u3002\u53EA\u6709 summary\u3001taskTypes\u3001outputs \u4E0E\u7528\u6237\u76EE\u6807\u5339\u914D\u65F6\u624D\u4F7F\u7528\uFF1B\u5982\u679C\u6CA1\u6709\u5339\u914D\u9879\uFF0C\u5C31\u76F4\u63A5\u5B8C\u6210\u4EFB\u52A1\uFF0C\u6216\u7528 list_skill_index \u641C\u7D22\u5019\u9009\uFF0C\u5E76\u8C03\u7528 AskUserQuestion \u5DE5\u5177\u8BE2\u95EE\u7528\u6237\u662F\u5426\u8981\u4E3A\u5F53\u524D Agent \u542F\u7528/\u5206\u914D\u8BE5 skill\u3002AskUserQuestion \u9009\u9879\u5FC5\u987B\u5305\u542B"\u542F\u7528/\u5206\u914D\u8FD9\u4E2A skill"\u548C"\u5148\u4E0D\u7528\uFF0C\u76F4\u63A5\u5904\u7406"\uFF0Cmetadata \u5C3D\u91CF\u5E26\u4E0A skillId/skillName\u3002\u7528\u6237\u786E\u8BA4\u524D\u4E0D\u8981\u58F0\u79F0\u5DF2\u4F7F\u7528\u672A\u5206\u914D skill\uFF1B\u786E\u8BA4\u540E\u5FC5\u987B\u91CD\u65B0\u67E5\u8BE2\u672C\u5DE5\u5177\uFF0C\u53EA\u6709\u51FA\u73B0\u5728\u8FD9\u91CC\u624D\u7B97\u53EF\u7528\u3002';
25634
26323
  return {
25635
26324
  content: [{
25636
26325
  type: "text",
@@ -25659,7 +26348,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25659
26348
  },
25660
26349
  async (args) => {
25661
26350
  if (!deps.isSmith && deps.getAvailableSkillIds && !availableSkillsChecked) {
25662
- logger7.info("list_skill_index blocked before list_available_skills", {
26351
+ logger8.info("list_skill_index blocked before list_available_skills", {
25663
26352
  agentId: deps.agentId,
25664
26353
  scope: currentScopeKey
25665
26354
  });
@@ -25685,7 +26374,7 @@ Smith \u521B\u5EFA\u6216\u5207\u6362 Agent \u8FD0\u884C\u673A\u5668\u65F6\u53EF\
25685
26374
  entries: runtimeEntries,
25686
26375
  runtime: skillRuntimeContext(deps.officeCliRuntime)
25687
26376
  }), visibleSkillIds);
25688
- logger7.info("list_skill_index tool called", {
26377
+ logger8.info("list_skill_index tool called", {
25689
26378
  agentId: deps.agentId,
25690
26379
  scope: currentScopeKey,
25691
26380
  resultCount: entries.length
@@ -25738,7 +26427,7 @@ local_modelscope_* \u662F\u672C\u673A Local Skill\uFF0C\u4E0D\u5199\u5165 Server
25738
26427
  officeCliMessage: deps.officeCliRuntime.message
25739
26428
  } : void 0
25740
26429
  }).filter((rec) => filterRuntimeVisibleSkillEntries([rec.skill], visibleSkillIds).length > 0);
25741
- logger7.info("recommend_agent_skills tool called", {
26430
+ logger8.info("recommend_agent_skills tool called", {
25742
26431
  agentId: deps.agentId,
25743
26432
  scope: currentScopeKey,
25744
26433
  resultCount: recommendations.length
@@ -25750,7 +26439,8 @@ local_modelscope_* \u662F\u672C\u673A Local Skill\uFF0C\u4E0D\u5199\u5165 Server
25750
26439
  `[recommend_agent_skills] recommended initial skill set (${recommendations.length})`,
25751
26440
  formatSkillRecommendations(recommendations),
25752
26441
  "",
25753
- "\u8FB9\u754C\uFF1A\u63A8\u8350 != \u5B89\u88C5 != \u8C03\u7528\u3002\u9ED8\u8BA4/\u56E2\u961F\u5DF2\u542F\u7528 skill \u53EF\u6309\u4EFB\u52A1\u4F7F\u7528\uFF1B\u975E\u9ED8\u8BA4\u542F\u7528\u6216\u5199\u6587\u4EF6\u3001\u8DD1\u547D\u4EE4\u3001\u53D1\u5E03\u3001\u5927\u91CF\u8BFB\u53D6\u79C1\u5BC6\u4E0A\u4E0B\u6587\u7B49\u5177\u4F53\u9AD8\u98CE\u9669\u52A8\u4F5C\u524D\u624D\u9700\u8981\u786E\u8BA4\u3002"
26442
+ "\u8FB9\u754C\uFF1A\u63A8\u8350 != \u5B89\u88C5 != \u8C03\u7528\u3002\u9ED8\u8BA4/\u56E2\u961F\u5DF2\u542F\u7528 skill \u53EF\u6309\u4EFB\u52A1\u4F7F\u7528\uFF1B\u975E\u9ED8\u8BA4\u542F\u7528\u6216\u5199\u6587\u4EF6\u3001\u8DD1\u547D\u4EE4\u3001\u53D1\u5E03\u3001\u5927\u91CF\u8BFB\u53D6\u79C1\u5BC6\u4E0A\u4E0B\u6587\u7B49\u5177\u4F53\u9AD8\u98CE\u9669\u52A8\u4F5C\u524D\u624D\u9700\u8981\u786E\u8BA4\u3002",
26443
+ "local_modelscope_* \u662F\u672C\u673A Local Skill \u589E\u5F3A\u5019\u9009\uFF0C\u53EA\u80FD\u5728\u5F53\u524D\u673A\u5668\u7ED1\u5B9A\u5230 Agent\uFF0C\u4E0D\u5199\u5165 Server\uFF0C\u4E5F\u4E0D\u4F1A\u8DE8\u7528\u6237\u6216\u8DE8\u673A\u5668\u751F\u6548\u3002"
25754
26444
  ].join("\n")
25755
26445
  }]
25756
26446
  };
@@ -25776,7 +26466,7 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\uFF1B\u652F\u6301 offset \u5
25776
26466
  },
25777
26467
  async (args) => {
25778
26468
  if (!deps.isSmith) {
25779
- logger7.warn("fetch_logs: permission denied (non-Smith caller)", { agentId: deps.agentId });
26469
+ logger8.warn("fetch_logs: permission denied (non-Smith caller)", { agentId: deps.agentId });
25780
26470
  return {
25781
26471
  content: [{ type: "text", text: "[fetch_logs] \u6743\u9650\u62D2\u7EDD\uFF1A\u53EA\u6709 Smith \u80FD\u8C03\u7528\u3002" }],
25782
26472
  isError: true
@@ -25789,7 +26479,7 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\uFF1B\u652F\u6301 offset \u5
25789
26479
  isError: true
25790
26480
  };
25791
26481
  }
25792
- logger7.info("fetch_logs tool called", {
26482
+ logger8.info("fetch_logs tool called", {
25793
26483
  agentId: deps.agentId,
25794
26484
  source,
25795
26485
  startIso: args.start_iso,
@@ -25822,7 +26512,7 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\uFF1B\u652F\u6301 offset \u5
25822
26512
  });
25823
26513
  if (!res.ok) {
25824
26514
  const errText = await res.text().catch(() => "");
25825
- logger7.warn("fetch_logs: server rejected", { status: res.status, errText });
26515
+ logger8.warn("fetch_logs: server rejected", { status: res.status, errText });
25826
26516
  return {
25827
26517
  content: [{
25828
26518
  type: "text",
@@ -25832,7 +26522,7 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\uFF1B\u652F\u6301 offset \u5
25832
26522
  };
25833
26523
  }
25834
26524
  const json2 = await res.json();
25835
- logger7.info("fetch_logs returned", {
26525
+ logger8.info("fetch_logs returned", {
25836
26526
  source,
25837
26527
  count: json2.entries.length,
25838
26528
  truncated: json2.truncated,
@@ -25858,7 +26548,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
25858
26548
  const text = [header, "", ...lines].join("\n");
25859
26549
  return { content: [{ type: "text", text }] };
25860
26550
  } catch (e) {
25861
- logger7.error("fetch_logs failed", { error: e });
26551
+ logger8.error("fetch_logs failed", { error: e });
25862
26552
  return {
25863
26553
  content: [{ type: "text", text: `[fetch_logs] \u8C03\u7528\u5931\u8D25\uFF1A${e.message}` }],
25864
26554
  isError: true
@@ -25872,7 +26562,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
25872
26562
  `\u521B\u9020\u4E00\u4E2A\u65B0\u7684 Agent\u3002\u53EA\u6709\u4F60\uFF08Smith\uFF09\u80FD\u4F7F\u7528\u6B64\u5DE5\u5177\u3002
25873
26563
  \u65B0 Agent \u4F1A\u7ACB\u5373\u51FA\u73B0\u5728\u7CFB\u7EDF\u901A\u8BAF\u5F55\u4E2D\uFF0C\u62E5\u6709\u72EC\u7ACB\u7684 SDK runtime \u548C\u5DE5\u4F5C\u76EE\u5F55\u3002
25874
26564
  \u521B\u5EFA\u540E\u4F60\u53EF\u4EE5\u901A\u8FC7 create_group + add_to_group \u628A\u5B83\u62C9\u8FDB\u7FA4\u3002
25875
- \u521B\u5EFA\u65F6\u53EF\u4EE5\u9009\u62E9\u521D\u59CB\u8FD0\u884C\u673A\u5668\uFF1A\u5148\u7528 list_contacts \u67E5\u770B"\u53EF\u7528\u673A\u5668"\uFF0C\u518D\u4F20 machine_bridge_key\u3002\u540E\u7EED\u53EF\u7528 update_agent_profile \u5207\u6362\uFF1B\u4E0D\u4F20\u5219\u4F7F\u7528\u5F53\u524D Bridge\u3002
26565
+ \u521B\u5EFA\u65F6\u9ED8\u8BA4\u4F7F\u7528\u5F53\u524D Bridge\uFF1A\u666E\u901A\u521B\u5EFA\u4E0D\u8981\u4F20 machine_bridge_key\u3002\u53EA\u6709\u7528\u6237\u660E\u786E\u6307\u5B9A\u67D0\u53F0\u8FD0\u884C\u673A\u5668\u65F6\uFF0C\u624D\u5148\u521B\u5EFA Agent\uFF0C\u518D\u7528 update_agent_profile \u5207\u6362\u3002
25876
26566
 
25877
26567
  **\u80FD\u529B\u6863\u4F4D\u9009\u62E9\u6307\u5357\uFF1A**
25878
26568
  - **smart\uFF08\u65D7\u8230\uFF09**\uFF1A\u7F16\u6392\u8005\u3001\u590D\u6742\u63A8\u7406\u3001\u6700\u7EC8\u7EFC\u5408\u3001\u9AD8\u96BE\u5EA6\u89D2\u8272\u3002\u4F7F\u7528\u6700\u5F3A\u6A21\u578B\u3002
@@ -25906,15 +26596,15 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
25906
26596
  "\u53EF\u9009\u3002\u8BE5 Agent \u7684\u5DE5\u4F5C\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84\u3002\u4E0D\u4F20\u5219\u7531\u7CFB\u7EDF\u81EA\u52A8\u5206\u914D\u3002"
25907
26597
  ),
25908
26598
  machine_bridge_key: external_exports.string().optional().describe(
25909
- '\u53EF\u9009\u3002\u8FD0\u884C\u673A\u5668 bridgeKey\uFF0C\u6765\u81EA list_contacts \u7684"\u53EF\u7528\u673A\u5668"\u3002\u4E0D\u4F20\u5219\u4F7F\u7528\u5F53\u524D Bridge\uFF1B\u540E\u7EED\u53EF\u7528 update_agent_profile \u5207\u6362\u3002'
26599
+ "\u53EF\u9009\u3002\u53EA\u5141\u8BB8\u4F20\u5F53\u524D Bridge \u7684 bridgeKey\uFF1B\u666E\u901A\u521B\u5EFA\u8BF7\u7701\u7565\uFF0C\u7CFB\u7EDF\u4F1A\u4F7F\u7528\u5F53\u524D\u673A\u5668\u3002\u8DE8\u673A\u5668\u8FD0\u884C\u8BF7\u521B\u5EFA\u540E\u7528 update_agent_profile \u5207\u6362\u3002"
25910
26600
  ),
25911
26601
  skill_ids: external_exports.array(external_exports.string()).optional().describe(
25912
- "\u53EF\u9009\u3002\u521B\u5EFA\u540E\u7ACB\u5373\u5206\u914D\u7ED9\u65B0 Agent \u7684\u521D\u59CB skill \u5305\uFF08skill id \u5217\u8868\uFF09\u3002\u9ED8\u8BA4/\u56E2\u961F\u5DF2\u542F\u7528\u63A8\u8350\u53EF\u6309\u89D2\u8272\u76F4\u63A5\u4F20\u5165\uFF1B\u975E\u9ED8\u8BA4/\u672A\u542F\u7528 skill \u9700\u8981\u7528\u6237\u660E\u786E\u8981\u6C42\u6216\u786E\u8BA4\u540E\u518D\u4F20\u3002local_modelscope_* \u5C5E\u4E8E\u672C\u673A Local Skill\uFF0C\u4E0D\u5199\u5165 Server \u5206\u914D\uFF1B\u53EA\u6709\u65B0 Agent \u8FD0\u884C\u5728\u5F53\u524D\u673A\u5668\u65F6\u624D\u4F1A\u5199\u5165\u5F53\u524D\u673A\u5668 allowedAgentIds\u3002\u4E0D\u8981\u8BA9\u7528\u6237\u66FF\u7CFB\u7EDF\u5224\u65AD\u9ED8\u8BA4 skill \u662F\u5426\u53EF\u7528\u3002"
26602
+ "\u53EF\u9009\u3002\u521B\u5EFA\u540E\u7ACB\u5373\u5206\u914D\u7ED9\u65B0 Agent \u7684\u521D\u59CB skill \u5305\uFF08skill id \u5217\u8868\uFF09\u3002\u9ED8\u8BA4/\u56E2\u961F\u5DF2\u542F\u7528\u63A8\u8350\u53EF\u6309\u89D2\u8272\u76F4\u63A5\u4F20\u5165\uFF1B\u975E\u9ED8\u8BA4/\u672A\u542F\u7528 skill \u9700\u8981\u7528\u6237\u660E\u786E\u8981\u6C42\u6216\u786E\u8BA4\u540E\u518D\u4F20\u3002\u9700\u8981\u957F\u8017\u65F6\u5916\u90E8\u4EFB\u52A1\u7684\u5B98\u65B9\u6D41\u7A0B skill \u4F1A\u901A\u8FC7\u53EF\u6269\u5C55\u89C4\u5219\u505A\u4FDD\u5B88\u8865\u9F50\uFF1B\u672C\u673A Local Skill \u53EA\u4F5C\u4E3A\u5F53\u524D\u673A\u5668\u7684\u4EFB\u52A1\u589E\u5F3A\u5019\u9009\u3002local_modelscope_* \u5C5E\u4E8E\u672C\u673A Local Skill\uFF0C\u4E0D\u5199\u5165 Server \u5206\u914D\uFF1B\u53EA\u6709\u65B0 Agent \u8FD0\u884C\u5728\u5F53\u524D\u673A\u5668\u65F6\u624D\u4F1A\u5199\u5165\u5F53\u524D\u673A\u5668 allowedAgentIds\uFF0C\u4E0D\u80FD\u8DE8\u7528\u6237\u6216\u8DE8\u673A\u5668\u751F\u6548\u3002\u4E0D\u8981\u8BA9\u7528\u6237\u66FF\u7CFB\u7EDF\u5224\u65AD\u9ED8\u8BA4 skill \u662F\u5426\u53EF\u7528\u3002"
25913
26603
  )
25914
26604
  },
25915
26605
  async (args) => {
25916
26606
  if (!deps.isSmith) {
25917
- logger7.warn("create_agent: permission denied (non-Smith caller)", {
26607
+ logger8.warn("create_agent: permission denied (non-Smith caller)", {
25918
26608
  agentId: deps.agentId,
25919
26609
  scope: currentScopeKey
25920
26610
  });
@@ -25939,10 +26629,24 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
25939
26629
  const avatar = args.avatar && String(args.avatar).trim() || "";
25940
26630
  const initialInstruction = args.initial_instruction && String(args.initial_instruction).trim() || "";
25941
26631
  const workingDirectory = args.working_directory && String(args.working_directory).trim() || "";
25942
- const machineBridgeKey = args.machine_bridge_key && String(args.machine_bridge_key).trim() || "";
26632
+ const requestedMachineBridgeKey = args.machine_bridge_key && String(args.machine_bridge_key).trim() || "";
26633
+ const machineBridgeKey = requestedMachineBridgeKey === "auto" ? "" : requestedMachineBridgeKey;
26634
+ const remoteMachineError = rejectRemoteCreateMachineBridgeKey(machineBridgeKey, deps);
26635
+ if (remoteMachineError) {
26636
+ logger8.warn("create_agent: rejected remote machine_bridge_key on create", {
26637
+ agentId: deps.agentId,
26638
+ scope: currentScopeKey,
26639
+ requestedMachineBridgeKey: machineBridgeKey,
26640
+ currentBridgeKey: deps.currentBridgeKey ?? null
26641
+ });
26642
+ return {
26643
+ content: [{ type: "text", text: remoteMachineError }],
26644
+ isError: true
26645
+ };
26646
+ }
25943
26647
  const machineValidation = await validateOnlineMachineBridgeKey("create_agent", machineBridgeKey, deps);
25944
26648
  if (!machineValidation.ok) {
25945
- logger7.warn("create_agent: rejected offline or unknown machine_bridge_key", {
26649
+ logger8.warn("create_agent: rejected offline or unknown machine_bridge_key", {
25946
26650
  agentId: deps.agentId,
25947
26651
  scope: currentScopeKey,
25948
26652
  machineBridgeKey
@@ -25971,15 +26675,15 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
25971
26675
  capabilityTier: tier,
25972
26676
  subscriptionId: tierConfig.subscriptionId
25973
26677
  });
25974
- logger7.info("Tier resolved", { tier, subscriptionId: tierConfig.subscriptionId, model: tierConfig.modelName });
26678
+ logger8.info("Tier resolved", { tier, subscriptionId: tierConfig.subscriptionId, model: tierConfig.modelName });
25975
26679
  } else {
25976
- logger7.warn("Tier not found, using default", { tier, availableTiers: tiers.map((t) => t.tier) });
26680
+ logger8.warn("Tier not found, using default", { tier, availableTiers: tiers.map((t) => t.tier) });
25977
26681
  }
25978
26682
  } else {
25979
- logger7.warn("Failed to fetch tiers", { status: tierRes.status });
26683
+ logger8.warn("Failed to fetch tiers", { status: tierRes.status });
25980
26684
  }
25981
26685
  } catch (e) {
25982
- logger7.error("Tier resolution failed", { error: e });
26686
+ logger8.error("Tier resolution failed", { error: e });
25983
26687
  }
25984
26688
  }
25985
26689
  const body = { name, role, systemPrompt, avatar };
@@ -25992,7 +26696,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
25992
26696
  if (machineBridgeKey) {
25993
26697
  body.machineBridgeKey = machineBridgeKey;
25994
26698
  }
25995
- logger7.info("create_agent tool called", {
26699
+ logger8.info("create_agent tool called", {
25996
26700
  agentId: deps.agentId,
25997
26701
  requestedBy: deps.agentId,
25998
26702
  scope: currentScopeKey,
@@ -26013,7 +26717,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26013
26717
  });
26014
26718
  if (!res.ok) {
26015
26719
  const errText = await res.text().catch(() => "");
26016
- logger7.warn("create_agent: server rejected", { status: res.status, errText, name });
26720
+ logger8.warn("create_agent: server rejected", { status: res.status, errText, name });
26017
26721
  return {
26018
26722
  content: [{
26019
26723
  type: "text",
@@ -26024,7 +26728,44 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26024
26728
  }
26025
26729
  const agent = await res.json();
26026
26730
  const resolvedMachineBridgeKey = agent.machineBridgeKey ?? machineBridgeKey;
26731
+ const skillIntent = {
26732
+ name,
26733
+ role,
26734
+ systemPrompt,
26735
+ initialInstruction,
26736
+ workingDirectory
26737
+ };
26027
26738
  const requestedSkillIds = Array.isArray(args.skill_ids) ? args.skill_ids.map((id) => typeof id === "string" ? id.trim() : "").filter((id) => id.length > 0) : [];
26739
+ const autoAssignedOfficialSkillIds = autoAssignOfficialSkillIds(skillIntent);
26740
+ for (const skillId of autoAssignedOfficialSkillIds) {
26741
+ if (requestedSkillIds.includes(skillId)) continue;
26742
+ requestedSkillIds.push(skillId);
26743
+ logger8.info("create_agent: auto-added official workflow skill", {
26744
+ requestedBy: deps.agentId,
26745
+ newAgentId: agent.id,
26746
+ skillId
26747
+ });
26748
+ }
26749
+ const explicitlyRequestedLocalSkill = requestedSkillIds.some(isLocalSkillId);
26750
+ const localEnhancerTargetBridgeKey = resolvedMachineBridgeKey ?? machineBridgeKey;
26751
+ if (autoAssignedOfficialSkillIds.length > 0 && !explicitlyRequestedLocalSkill && deps.setLocalSkillAgentVisibility && isCurrentMachineLocalTarget(localEnhancerTargetBridgeKey, deps.currentBridgeKey)) {
26752
+ const localEnhancerSkillIds = selectLocalSkillEnhancersForCreateAgent(
26753
+ skillIntent,
26754
+ deps.skillStore,
26755
+ new Set(requestedSkillIds)
26756
+ );
26757
+ for (const skillId of localEnhancerSkillIds) {
26758
+ requestedSkillIds.push(skillId);
26759
+ }
26760
+ if (localEnhancerSkillIds.length > 0) {
26761
+ logger8.info("create_agent: auto-added local skill enhancers", {
26762
+ requestedBy: deps.agentId,
26763
+ newAgentId: agent.id,
26764
+ localEnhancerSkillIds,
26765
+ targetBridgeKey: localEnhancerTargetBridgeKey || "(current-bridge)"
26766
+ });
26767
+ }
26768
+ }
26028
26769
  const skillIds = Array.from(new Set(requestedSkillIds));
26029
26770
  const localSkillIds = skillIds.filter(isLocalSkillId);
26030
26771
  const serverSkillIds = skillIds.filter((id) => !isLocalSkillId(id));
@@ -26043,7 +26784,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26043
26784
  const assignBody = await assignRes.json();
26044
26785
  const assignedCount = assignBody.assigned?.length ?? 0;
26045
26786
  const skipped = assignBody.skipped ?? [];
26046
- logger7.info("create_agent: initial skills assigned", {
26787
+ logger8.info("create_agent: initial skills assigned", {
26047
26788
  requestedBy: deps.agentId,
26048
26789
  newAgentId: agent.id,
26049
26790
  assignedCount,
@@ -26052,7 +26793,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26052
26793
  skillAssignNote = skipped.length > 0 ? `\u5DF2\u5206\u914D ${assignedCount} \u4E2A\u521D\u59CB skill\uFF08${skipped.length} \u4E2A\u65E0\u6548\u5DF2\u8DF3\u8FC7\uFF09\u3002` : `\u5DF2\u5206\u914D ${assignedCount} \u4E2A\u521D\u59CB skill\u3002`;
26053
26794
  } else {
26054
26795
  const errText = await assignRes.text().catch(() => "");
26055
- logger7.warn("create_agent: initial skill assignment rejected", {
26796
+ logger8.warn("create_agent: initial skill assignment rejected", {
26056
26797
  newAgentId: agent.id,
26057
26798
  status: assignRes.status,
26058
26799
  errText
@@ -26060,18 +26801,18 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26060
26801
  skillAssignNote = `\u521D\u59CB skill \u5206\u914D\u5931\u8D25\uFF08${assignRes.status}\uFF09\uFF0C\u53EF\u7A0D\u540E\u7528 assign \u6D41\u7A0B\u8865\u914D\u3002`;
26061
26802
  }
26062
26803
  } catch (e) {
26063
- logger7.error("create_agent: initial skill assignment failed", { error: e, newAgentId: agent.id });
26804
+ logger8.error("create_agent: initial skill assignment failed", { error: e, newAgentId: agent.id });
26064
26805
  skillAssignNote = "\u521D\u59CB skill \u5206\u914D\u5931\u8D25\uFF0C\u53EF\u7A0D\u540E\u8865\u914D\u3002";
26065
26806
  }
26066
26807
  }
26067
26808
  if (localSkillIds.length > 0) {
26068
26809
  const targetBridgeKey = resolvedMachineBridgeKey ?? machineBridgeKey;
26069
- const localSkillTargetIsCurrentMachine = !targetBridgeKey || deps.currentBridgeKey != null && targetBridgeKey === deps.currentBridgeKey;
26810
+ const localSkillTargetIsCurrentMachine = isCurrentMachineLocalTarget(targetBridgeKey, deps.currentBridgeKey);
26070
26811
  let localAssignedCount = 0;
26071
26812
  const localSkipped = [];
26072
26813
  if (!localSkillTargetIsCurrentMachine) {
26073
26814
  localSkipped.push(...localSkillIds);
26074
- logger7.warn("create_agent: local skills skipped for remote machine target", {
26815
+ logger8.warn("create_agent: local skills skipped for remote machine target", {
26075
26816
  requestedBy: deps.agentId,
26076
26817
  newAgentId: agent.id,
26077
26818
  localSkillIds,
@@ -26080,7 +26821,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26080
26821
  });
26081
26822
  } else if (!deps.setLocalSkillAgentVisibility) {
26082
26823
  localSkipped.push(...localSkillIds);
26083
- logger7.warn("create_agent: local skill binder unavailable", {
26824
+ logger8.warn("create_agent: local skill binder unavailable", {
26084
26825
  requestedBy: deps.agentId,
26085
26826
  newAgentId: agent.id,
26086
26827
  localSkillIds
@@ -26096,7 +26837,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26096
26837
  }
26097
26838
  } catch (e) {
26098
26839
  localSkipped.push(skillId);
26099
- logger7.error("create_agent: local skill assignment failed", {
26840
+ logger8.error("create_agent: local skill assignment failed", {
26100
26841
  error: e,
26101
26842
  requestedBy: deps.agentId,
26102
26843
  newAgentId: agent.id,
@@ -26108,7 +26849,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26108
26849
  await deps.onLocalSkillVisibilityChanged?.([agent.id]);
26109
26850
  }
26110
26851
  }
26111
- logger7.info("create_agent: local skill assignment resolved", {
26852
+ logger8.info("create_agent: local skill assignment resolved", {
26112
26853
  requestedBy: deps.agentId,
26113
26854
  newAgentId: agent.id,
26114
26855
  localSkillIds,
@@ -26118,7 +26859,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26118
26859
  const localSkillNote = localAssignedCount > 0 ? `\u672C\u673A Local Skill \u5DF2\u7ED1\u5B9A ${localAssignedCount} \u4E2A\u5230\u5F53\u524D\u673A\u5668\uFF1B${localSkipped.length > 0 ? `${localSkipped.length} \u4E2A\u672A\u627E\u5230\u6216\u4E0D\u53EF\u7ED1\u5B9A\u3002` : "\u4E0D\u4F1A\u5199\u5165 Server\u3002"}` : `\u672C\u673A Local Skill ${localSkillIds.length} \u4E2A\u672A\u5199\u5165 Server${localSkipped.length > 0 ? "\uFF0C\u4E14\u672A\u7ED1\u5B9A\u5230\u5F53\u524D\u673A\u5668" : ""}\uFF1B\u5982\u679C\u65B0 Agent \u5728\u53E6\u4E00\u53F0\u673A\u5668\u8FD0\u884C\uFF0C\u9700\u8981\u5728\u90A3\u53F0\u673A\u5668\u5B89\u88C5\u5E76\u7ED1\u5B9A\u3002`;
26119
26860
  skillAssignNote = skillAssignNote ? `${skillAssignNote}${localSkillNote}` : localSkillNote;
26120
26861
  }
26121
- logger7.info("create_agent: created", {
26862
+ logger8.info("create_agent: created", {
26122
26863
  requestedBy: deps.agentId,
26123
26864
  scope: currentScopeKey,
26124
26865
  agentId: agent.id,
@@ -26137,7 +26878,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26137
26878
  });
26138
26879
  if (initialInstruction && deps.onAgentCreatedInitInstruction) {
26139
26880
  try {
26140
- logger7.info("create_agent: firing initial instruction dispatch", {
26881
+ logger8.info("create_agent: firing initial instruction dispatch", {
26141
26882
  requestedBy: deps.agentId,
26142
26883
  newAgentId: agent.id,
26143
26884
  newAgentName: agent.name,
@@ -26150,7 +26891,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26150
26891
  requestedBy: deps.agentId
26151
26892
  });
26152
26893
  } catch (e) {
26153
- logger7.error("create_agent: onAgentCreatedInitInstruction sync threw", {
26894
+ logger8.error("create_agent: onAgentCreatedInitInstruction sync threw", {
26154
26895
  error: e,
26155
26896
  newAgentId: agent.id
26156
26897
  });
@@ -26163,7 +26904,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26163
26904
  content: [{ type: "text", text: reply }]
26164
26905
  };
26165
26906
  } catch (e) {
26166
- logger7.error("create_agent failed", { error: e, name });
26907
+ logger8.error("create_agent failed", { error: e, name });
26167
26908
  return {
26168
26909
  content: [{ type: "text", text: `[create_agent] \u521B\u5EFA\u5931\u8D25\uFF1A${e.message}` }],
26169
26910
  isError: true
@@ -26235,7 +26976,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26235
26976
  deps
26236
26977
  );
26237
26978
  if (!machineValidation.ok) {
26238
- logger7.warn("update_agent_profile: rejected offline or unknown machine_bridge_key", {
26979
+ logger8.warn("update_agent_profile: rejected offline or unknown machine_bridge_key", {
26239
26980
  agentId: deps.agentId,
26240
26981
  targetAgentId: agentId,
26241
26982
  machineBridgeKey: requestedMachineBridgeKey
@@ -26266,11 +27007,11 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26266
27007
  subscriptionId: tierConfig.subscriptionId,
26267
27008
  model: tierConfig.modelName
26268
27009
  });
26269
- logger7.info("update_agent: tier resolved", { agentId, tier, subscriptionId: tierConfig.subscriptionId });
27010
+ logger8.info("update_agent: tier resolved", { agentId, tier, subscriptionId: tierConfig.subscriptionId });
26270
27011
  }
26271
27012
  }
26272
27013
  } catch (e) {
26273
- logger7.error("update_agent: tier resolution failed", { error: e });
27014
+ logger8.error("update_agent: tier resolution failed", { error: e });
26274
27015
  }
26275
27016
  }
26276
27017
  const patchBody = {};
@@ -26289,7 +27030,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26289
27030
  isError: true
26290
27031
  };
26291
27032
  }
26292
- logger7.info("update_agent_profile tool called", {
27033
+ logger8.info("update_agent_profile tool called", {
26293
27034
  agentId: deps.agentId,
26294
27035
  targetAgentId: agentId,
26295
27036
  targetName: existing.name,
@@ -26309,7 +27050,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26309
27050
  };
26310
27051
  }
26311
27052
  const updated = await res.json();
26312
- logger7.info("update_agent_profile: succeeded", {
27053
+ logger8.info("update_agent_profile: succeeded", {
26313
27054
  agentId: deps.agentId,
26314
27055
  targetAgentId: agentId,
26315
27056
  newName: updated.name
@@ -26321,7 +27062,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26321
27062
  }]
26322
27063
  };
26323
27064
  } catch (e) {
26324
- logger7.error("update_agent_profile failed", { error: e, agentId });
27065
+ logger8.error("update_agent_profile failed", { error: e, agentId });
26325
27066
  return {
26326
27067
  content: [{ type: "text", text: `[update_agent_profile] \u66F4\u65B0\u5931\u8D25\uFF1A${e.message}` }],
26327
27068
  isError: true
@@ -26358,7 +27099,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26358
27099
  };
26359
27100
  }
26360
27101
  const base = deps.serverApiUrl.replace(/\/$/, "");
26361
- logger7.info("archive_conversation tool called", {
27102
+ logger8.info("archive_conversation tool called", {
26362
27103
  agentId: deps.agentId,
26363
27104
  targetAgentId: agentId,
26364
27105
  conversationId
@@ -26379,7 +27120,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26379
27120
  isError: true
26380
27121
  };
26381
27122
  }
26382
- logger7.info("archive_conversation: succeeded", {
27123
+ logger8.info("archive_conversation: succeeded", {
26383
27124
  agentId: deps.agentId,
26384
27125
  conversationId
26385
27126
  });
@@ -26390,7 +27131,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26390
27131
  }]
26391
27132
  };
26392
27133
  } catch (e) {
26393
- logger7.error("archive_conversation failed", { error: e, conversationId });
27134
+ logger8.error("archive_conversation failed", { error: e, conversationId });
26394
27135
  return {
26395
27136
  content: [{ type: "text", text: `[archive_conversation] \u5F52\u6863\u5931\u8D25\uFF1A${e.message}` }],
26396
27137
  isError: true
@@ -26434,7 +27175,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26434
27175
  isError: true
26435
27176
  };
26436
27177
  }
26437
- logger7.info("transfer_group_owner tool called", {
27178
+ logger8.info("transfer_group_owner tool called", {
26438
27179
  agentId: deps.agentId,
26439
27180
  fromOwnerId: deps.agentId,
26440
27181
  scope: currentScopeKey,
@@ -26453,7 +27194,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26453
27194
  });
26454
27195
  if (!res.ok) {
26455
27196
  const errText = await res.text().catch(() => "");
26456
- logger7.warn("transfer_group_owner: server rejected", {
27197
+ logger8.warn("transfer_group_owner: server rejected", {
26457
27198
  status: res.status,
26458
27199
  errText,
26459
27200
  groupId: resolved.groupId
@@ -26466,7 +27207,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26466
27207
  isError: true
26467
27208
  };
26468
27209
  }
26469
- logger7.info("transfer_group_owner: succeeded", {
27210
+ logger8.info("transfer_group_owner: succeeded", {
26470
27211
  agentId: deps.agentId,
26471
27212
  fromOwnerId: deps.agentId,
26472
27213
  scope: currentScopeKey,
@@ -26480,7 +27221,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26480
27221
  }]
26481
27222
  };
26482
27223
  } catch (e) {
26483
- logger7.error("transfer_group_owner failed", { error: e, groupId: resolved.groupId });
27224
+ logger8.error("transfer_group_owner failed", { error: e, groupId: resolved.groupId });
26484
27225
  return {
26485
27226
  content: [{
26486
27227
  type: "text",
@@ -26549,7 +27290,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26549
27290
  }
26550
27291
  }
26551
27292
  }
26552
- logger7.info("list_friends called", {
27293
+ logger8.info("list_friends called", {
26553
27294
  agentId: deps.agentId,
26554
27295
  friendCount: friends.length
26555
27296
  });
@@ -26557,7 +27298,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26557
27298
  content: [{ type: "text", text: parts.join("\n") }]
26558
27299
  };
26559
27300
  } catch (e) {
26560
- logger7.error("list_friends failed", { error: e });
27301
+ logger8.error("list_friends failed", { error: e });
26561
27302
  return {
26562
27303
  content: [{ type: "text", text: `[list_friends] \u64CD\u4F5C\u5931\u8D25\uFF1A${e.message}` }],
26563
27304
  isError: true
@@ -26601,7 +27342,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26601
27342
  isError: true
26602
27343
  };
26603
27344
  }
26604
- logger7.info("accept_friend called", {
27345
+ logger8.info("accept_friend called", {
26605
27346
  agentId: deps.agentId,
26606
27347
  requestId,
26607
27348
  action
@@ -26617,7 +27358,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26617
27358
  content: [{ type: "text", text: `[accept_friend] \u5DF2\u62D2\u7EDD\u8BE5\u597D\u53CB\u7533\u8BF7\u3002` }]
26618
27359
  };
26619
27360
  } catch (e) {
26620
- logger7.error("accept_friend failed", { error: e });
27361
+ logger8.error("accept_friend failed", { error: e });
26621
27362
  return {
26622
27363
  content: [{ type: "text", text: `[accept_friend] \u64CD\u4F5C\u5931\u8D25\uFF1A${e.message}` }],
26623
27364
  isError: true
@@ -26695,7 +27436,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26695
27436
  isError: true
26696
27437
  };
26697
27438
  }
26698
- logger7.info("add_friend: request sent", {
27439
+ logger8.info("add_friend: request sent", {
26699
27440
  agentId: deps.agentId,
26700
27441
  targetUserId: lookup.user.id,
26701
27442
  targetName: lookup.user.name,
@@ -26708,7 +27449,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26708
27449
  }]
26709
27450
  };
26710
27451
  } catch (e) {
26711
- logger7.error("add_friend failed", { error: e });
27452
+ logger8.error("add_friend failed", { error: e });
26712
27453
  return {
26713
27454
  content: [{ type: "text", text: `[add_friend] \u64CD\u4F5C\u5931\u8D25\uFF1A${e.message}` }],
26714
27455
  isError: true
@@ -26728,7 +27469,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26728
27469
  }
26729
27470
  const category = normalizeFeedCategory(args.category);
26730
27471
  const groupId = (args.group_id ?? "").trim() || (deps.scope.kind === "group" ? deps.scope.groupId : void 0);
26731
- logger7.info(`${toolName} tool called`, {
27472
+ logger8.info(`${toolName} tool called`, {
26732
27473
  agentId: deps.agentId,
26733
27474
  scope: currentScopeKey,
26734
27475
  title,
@@ -26751,7 +27492,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26751
27492
  });
26752
27493
  if (!res.ok) {
26753
27494
  const errText = await res.text().catch(() => "");
26754
- logger7.warn(`${toolName}: server rejected`, { status: res.status, errText, title });
27495
+ logger8.warn(`${toolName}: server rejected`, { status: res.status, errText, title });
26755
27496
  return {
26756
27497
  content: [{
26757
27498
  type: "text",
@@ -26761,7 +27502,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26761
27502
  };
26762
27503
  }
26763
27504
  const payload = await res.json();
26764
- logger7.info(`${toolName}: created`, {
27505
+ logger8.info(`${toolName}: created`, {
26765
27506
  agentId: deps.agentId,
26766
27507
  scope: currentScopeKey,
26767
27508
  postId: payload.post?.id,
@@ -26774,7 +27515,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26774
27515
  }]
26775
27516
  };
26776
27517
  } catch (e) {
26777
- logger7.error(`${toolName} failed`, { error: e, title });
27518
+ logger8.error(`${toolName} failed`, { error: e, title });
26778
27519
  return {
26779
27520
  content: [{ type: "text", text: `[${toolName}] \u53D1\u5E03\u5931\u8D25\uFF1A${e.message}` }],
26780
27521
  isError: true
@@ -26829,7 +27570,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26829
27570
  const category = args.category ? normalizeFeedCategory(args.category) : void 0;
26830
27571
  const rawGroupId = (args.group_id ?? "").trim();
26831
27572
  const groupId = rawGroupId === "all" ? void 0 : rawGroupId || (deps.scope.kind === "group" ? deps.scope.groupId : void 0);
26832
- logger7.info("read_moments tool called", {
27573
+ logger8.info("read_moments tool called", {
26833
27574
  agentId: deps.agentId,
26834
27575
  scope: currentScopeKey,
26835
27576
  limit,
@@ -26846,7 +27587,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26846
27587
  });
26847
27588
  if (!res.ok) {
26848
27589
  const errText = await res.text().catch(() => "");
26849
- logger7.warn("read_moments: server rejected", { status: res.status, errText });
27590
+ logger8.warn("read_moments: server rejected", { status: res.status, errText });
26850
27591
  return {
26851
27592
  content: [{
26852
27593
  type: "text",
@@ -26857,7 +27598,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26857
27598
  }
26858
27599
  const payload = await res.json();
26859
27600
  const posts = Array.isArray(payload.posts) ? payload.posts : [];
26860
- logger7.info("read_moments returned", {
27601
+ logger8.info("read_moments returned", {
26861
27602
  agentId: deps.agentId,
26862
27603
  scope: currentScopeKey,
26863
27604
  count: posts.length,
@@ -26881,7 +27622,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26881
27622
  }]
26882
27623
  };
26883
27624
  } catch (e) {
26884
- logger7.error("read_moments failed", { error: e });
27625
+ logger8.error("read_moments failed", { error: e });
26885
27626
  return {
26886
27627
  content: [{ type: "text", text: `[read_moments] \u8BFB\u53D6\u5931\u8D25\uFF1A${e.message}` }],
26887
27628
  isError: true
@@ -26949,7 +27690,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26949
27690
  if (postToMomentsTool) toolNames.push("post_to_moments");
26950
27691
  if (postToForumTool) toolNames.push("post_to_forum");
26951
27692
  if (readMomentsTool) toolNames.push("read_moments");
26952
- logger7.info("Neural MCP server created", {
27693
+ logger8.info("Neural MCP server created", {
26953
27694
  agentId: deps.agentId,
26954
27695
  isSmith: deps.isSmith,
26955
27696
  scope: currentScopeKey,
@@ -26959,7 +27700,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
26959
27700
  }
26960
27701
 
26961
27702
  // src/groupDispatchMemory.ts
26962
- var logger8 = createModuleLogger("agent.dispatchMemory");
27703
+ var logger9 = createModuleLogger("agent.dispatchMemory");
26963
27704
  var GroupDispatchMemoryStore = class {
26964
27705
  memo = /* @__PURE__ */ new Map();
26965
27706
  getOrCreate(agentId, scope) {
@@ -26980,7 +27721,7 @@ var GroupDispatchMemoryStore = class {
26980
27721
  reset(agentId, scope, reason = "compact_completed") {
26981
27722
  const key = runtimeKey(agentId, scope);
26982
27723
  if (this.memo.delete(key)) {
26983
- logger8.info("Dispatch memory reset", {
27724
+ logger9.info("Dispatch memory reset", {
26984
27725
  agentId,
26985
27726
  scope: scope.kind === "single" ? "single" : scope.groupId,
26986
27727
  reason
@@ -27183,115 +27924,28 @@ function buildGroupInboxPrompt(entries, opts = {}) {
27183
27924
  return lines.join("\n");
27184
27925
  }
27185
27926
 
27186
- // src/officeRuntime.ts
27187
- import fs4 from "fs";
27188
- import os5 from "os";
27189
- import path9 from "path";
27190
- var OFFICECLI_EXECUTABLE_ENV = "AHCHAT_OFFICECLI_EXECUTABLE";
27191
- var OFFICECLI_BIN_DIR_ENV = "AHCHAT_OFFICECLI_BIN_DIR";
27192
- var logger9 = createModuleLogger("bridge.officeRuntime");
27193
- function sanitizedOfficeCliProbeError(error51) {
27194
- const rawCode = error51 && typeof error51 === "object" && "code" in error51 ? error51.code : void 0;
27195
- const code = typeof rawCode === "string" ? rawCode : void 0;
27196
- const sanitized = new Error(`OfficeCLI executable probe failed${code ? ` (${code})` : ""}`);
27197
- if (error51 instanceof Error) sanitized.name = error51.name;
27198
- return sanitized;
27199
- }
27200
- function defaultRuntimeRoot() {
27201
- if (process.platform === "win32") {
27202
- return path9.join(process.env.LOCALAPPDATA || path9.join(os5.homedir(), "AppData", "Local"), "AHChat", "runtime", "officecli");
27203
- }
27204
- if (process.platform === "darwin") {
27205
- return path9.join(os5.homedir(), "Library", "Caches", "AHChat", "runtime", "officecli");
27206
- }
27207
- return path9.join(process.env.XDG_CACHE_HOME || path9.join(os5.homedir(), ".cache"), "ahchat", "runtime", "officecli");
27208
- }
27209
- function getManagedOfficeCliBinDir(env2 = process.env) {
27210
- return env2[OFFICECLI_BIN_DIR_ENV] || path9.join(defaultRuntimeRoot(), "bin");
27211
- }
27212
- function getOfficeCliExecutableName() {
27213
- return process.platform === "win32" ? "officecli.exe" : "officecli";
27214
- }
27215
- function getManagedOfficeCliExecutablePath(env2 = process.env) {
27216
- return path9.join(getManagedOfficeCliBinDir(env2), getOfficeCliExecutableName());
27217
- }
27218
- function isExecutable(filePath, options = {}) {
27219
- const logFailure = options.logFailure !== false;
27220
- try {
27221
- if (process.platform === "win32") return fs4.existsSync(filePath);
27222
- fs4.accessSync(filePath, fs4.constants.X_OK);
27223
- return true;
27224
- } catch (error51) {
27225
- if (logFailure) {
27226
- logger9.error("OfficeCLI executable probe failed", {
27227
- error: sanitizedOfficeCliProbeError(error51),
27228
- fileName: path9.basename(filePath)
27229
- });
27230
- }
27231
- return false;
27232
- }
27233
- }
27234
- function withPrependedPath(env2, entries) {
27235
- const pathEntries = entries.filter((entry) => entry && fs4.existsSync(entry));
27236
- if (pathEntries.length === 0) return env2;
27237
- const current = env2.PATH ?? "";
27238
- return {
27239
- ...env2,
27240
- PATH: [...pathEntries, current].filter(Boolean).join(path9.delimiter)
27241
- };
27242
- }
27243
- function statusForPath(filePath, source, env2, options = {}) {
27244
- if (!isExecutable(filePath, { logFailure: options.logProbeFailure })) {
27245
- return {
27246
- ok: false,
27247
- path: filePath,
27248
- source,
27249
- message: `officecli not executable at ${filePath}`
27250
- };
27251
- }
27252
- const runtimeEnv = withPrependedPath(env2, [path9.dirname(filePath)]);
27253
- const version2 = readCommandVersion(filePath, ["--version"], runtimeEnv);
27254
- if (!version2) {
27255
- return {
27256
- ok: false,
27257
- path: filePath,
27258
- source,
27259
- message: `officecli found at ${filePath} but --version failed`
27260
- };
27261
- }
27262
- return { ok: true, path: filePath, source, version: version2 };
27263
- }
27264
- function detectOfficeCliRuntime(env2 = process.env) {
27265
- const explicitPath = env2[OFFICECLI_EXECUTABLE_ENV]?.trim();
27266
- if (explicitPath) return statusForPath(explicitPath, "env", env2);
27267
- const managedPath = getManagedOfficeCliExecutablePath(env2);
27268
- const managed = statusForPath(managedPath, "managed", env2, { logProbeFailure: false });
27269
- if (managed.ok) return managed;
27270
- const resolved = resolveCommand(["officecli"], withPrependedPath(env2, [path9.dirname(managedPath)]));
27271
- if (!resolved) {
27272
- return {
27273
- ok: false,
27274
- source: "managed",
27275
- path: managedPath,
27276
- message: `officecli not found. Run pnpm setup:office-runtime or set ${OFFICECLI_EXECUTABLE_ENV}.`
27277
- };
27278
- }
27279
- return statusForPath(resolved.path, resolved.path === managedPath ? "managed" : "path", env2);
27280
- }
27281
- function withOfficeCliRuntimeEnv(status, env2 = process.env) {
27282
- if (!status.ok || !status.path) return env2;
27283
- return {
27284
- ...withPrependedPath(env2, [path9.dirname(status.path)]),
27285
- [OFFICECLI_EXECUTABLE_ENV]: status.path
27286
- };
27287
- }
27288
-
27289
27927
  // src/sdkEventMapper.ts
27290
27928
  var logger10 = createModuleLogger("sdk.mapper");
27291
27929
  var HIGH_WATERMARK_INPUT_TOKENS = 12e4;
27292
27930
  var WARN_THRESHOLD_INPUT_TOKENS = 1e5;
27293
27931
  var LIVE_INPUT_PREVIEW_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit"]);
27294
27932
  var CONTEXT_OVERFLOW_LOCK_MS = 6e4;
27933
+ function parseJsonRecord(text) {
27934
+ try {
27935
+ const parsed = JSON.parse(text);
27936
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
27937
+ } catch {
27938
+ return null;
27939
+ }
27940
+ }
27941
+ function isSuccessfulOfficialMediaOutput(toolName, output) {
27942
+ if (!isOfficialMediaGenerationToolName(toolName)) return false;
27943
+ const parsed = parseJsonRecord(output);
27944
+ if (!parsed) return false;
27945
+ const state = typeof parsed.state === "string" ? parsed.state.toLowerCase() : typeof parsed.status === "string" ? parsed.status.toLowerCase() : "";
27946
+ if (!["succeeded", "success", "completed", "done"].includes(state)) return false;
27947
+ return Array.isArray(parsed.images) && parsed.images.length > 0 || typeof parsed.video_url === "string" || typeof parsed.videoUrl === "string";
27948
+ }
27295
27949
  function isContextOverflowText(text) {
27296
27950
  const trimmed = text.trim();
27297
27951
  return /^prompt is too long\b/i.test(trimmed) || /context length .* exceed/i.test(trimmed);
@@ -27302,6 +27956,10 @@ function isAuthFailureText(text, sdkError) {
27302
27956
  function isProviderApiErrorText(text) {
27303
27957
  return /^API Error:\s*\d+/i.test(text.trim());
27304
27958
  }
27959
+ function isNoReplyText(text) {
27960
+ const normalized = text.trim().replace(/^`+|`+$/g, "").trim().toLowerCase();
27961
+ return normalized === NO_REPLY_TOKEN || normalized === "<no-reply>" || normalized === "no-reply" || normalized === "no_reply" || normalized === "no reply";
27962
+ }
27305
27963
  function decodeJsonStringFragment(raw) {
27306
27964
  let out = "";
27307
27965
  for (let i = 0; i < raw.length; i++) {
@@ -27788,7 +28446,7 @@ function emitGroupSegment(proc, emit, base, content, contentBlocks, isSilent = f
27788
28446
  }
27789
28447
  function flushTextSegmentOnBlockStop(proc, emit, base) {
27790
28448
  const trimmed = proc.segmentBuffer.trim();
27791
- const isSilent = trimmed === NO_REPLY_TOKEN;
28449
+ const isSilent = isNoReplyText(trimmed);
27792
28450
  const isEmpty = trimmed.length === 0;
27793
28451
  if (!isEmpty) {
27794
28452
  const blocksForSegment = [...proc.contentBlocks, { type: "text", content: proc.segmentBuffer }];
@@ -27886,8 +28544,10 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
27886
28544
  if (block.type === "thinking") {
27887
28545
  proc.currentBlockType = "thinking";
27888
28546
  proc.accumulatedThinking = "";
28547
+ proc.suppressCurrentThinking = proc.officialMediaGenerationSatisfied === true;
27889
28548
  } else if (block.type === "text") {
27890
28549
  proc.currentBlockType = "text";
28550
+ proc.suppressCurrentThinking = false;
27891
28551
  if (isGroupTask(proc)) {
27892
28552
  proc.segmentBuffer = "";
27893
28553
  }
@@ -27896,10 +28556,11 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
27896
28556
  proc.currentToolName = block.name ?? "unknown";
27897
28557
  proc.accumulatedToolInput = "";
27898
28558
  const toolName = block.name ?? "unknown";
28559
+ proc.suppressCurrentToolUse = proc.officialMediaGenerationSatisfied === true && isOfficialMediaGenerationToolName(toolName);
27899
28560
  const isMcpTool = parseMcpRuntimeToolName(toolName) != null;
27900
28561
  proc.currentMcpInvocationId = isMcpTool ? createMcpToolInvocationId() : null;
27901
28562
  proc.currentMcpInvocationStartedAt = isMcpTool ? (/* @__PURE__ */ new Date()).toISOString() : null;
27902
- if (toolName !== "ExitPlanMode" && !isAskUserQuestionToolName(toolName)) {
28563
+ if (!isGroupTask(proc) && !proc.suppressCurrentToolUse && toolName !== "ExitPlanMode" && !isAskUserQuestionToolName(toolName)) {
27903
28564
  emit({
27904
28565
  type: "agent:tool_use",
27905
28566
  payload: {
@@ -27922,17 +28583,20 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
27922
28583
  const delta = ev.delta;
27923
28584
  if (!delta) break;
27924
28585
  if (delta.type === "thinking_delta" && typeof delta.thinking === "string") {
28586
+ if (proc.suppressCurrentThinking) break;
27925
28587
  proc.accumulatedThinking += delta.thinking;
27926
- emit({
27927
- type: "agent:thinking_chunk",
27928
- payload: { ...wireBase(base), chunk: delta.thinking }
27929
- });
28588
+ if (!isGroupTask(proc)) {
28589
+ emit({
28590
+ type: "agent:thinking_chunk",
28591
+ payload: { ...wireBase(base), chunk: delta.thinking }
28592
+ });
28593
+ }
27930
28594
  } else if (delta.type === "input_json_delta") {
27931
28595
  const partial2 = delta.partial_json;
27932
28596
  if (typeof partial2 === "string") {
27933
28597
  proc.accumulatedToolInput += partial2;
27934
28598
  const liveInput = extractLiveToolInput(proc.currentToolName, proc.accumulatedToolInput);
27935
- if (liveInput && proc.currentToolName != null) {
28599
+ if (!isGroupTask(proc) && liveInput && proc.currentToolName != null) {
27936
28600
  emit({
27937
28601
  type: "agent:tool_input_update",
27938
28602
  payload: {
@@ -27966,16 +28630,19 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
27966
28630
  }
27967
28631
  case "content_block_stop": {
27968
28632
  if (proc.currentBlockType === "thinking") {
27969
- emit({
27970
- type: "agent:thinking_done",
27971
- payload: wireBase(getTaskBase(proc))
27972
- });
27973
- proc.contentBlocks.push({
27974
- type: "thinking",
27975
- content: proc.accumulatedThinking,
27976
- isComplete: true
27977
- });
28633
+ if (!isGroupTask(proc) && !proc.suppressCurrentThinking) {
28634
+ emit({
28635
+ type: "agent:thinking_done",
28636
+ payload: wireBase(getTaskBase(proc))
28637
+ });
28638
+ proc.contentBlocks.push({
28639
+ type: "thinking",
28640
+ content: proc.accumulatedThinking,
28641
+ isComplete: true
28642
+ });
28643
+ }
27978
28644
  proc.accumulatedThinking = "";
28645
+ proc.suppressCurrentThinking = false;
27979
28646
  } else if (proc.currentBlockType === "text" && isGroupTask(proc)) {
27980
28647
  flushTextSegmentOnBlockStop(proc, emit, base);
27981
28648
  } else if (proc.currentBlockType === "tool_use") {
@@ -27992,19 +28659,21 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
27992
28659
  });
27993
28660
  }
27994
28661
  }
27995
- const lastToolUse = [...proc.contentBlocks].reverse().find((bl) => bl.type === "tool_use");
27996
- if (lastToolUse && lastToolUse.type === "tool_use") {
27997
- lastToolUse.input = parsedInput;
27998
- }
27999
- if (proc.currentToolName != null && LIVE_INPUT_PREVIEW_TOOLS.has(proc.currentToolName) && Object.keys(parsedInput).length > 0) {
28000
- emit({
28001
- type: "agent:tool_input_update",
28002
- payload: {
28003
- ...wireBase(base),
28004
- toolName: proc.currentToolName,
28005
- input: parsedInput
28006
- }
28007
- });
28662
+ if (!proc.suppressCurrentToolUse) {
28663
+ const lastToolUse = [...proc.contentBlocks].reverse().find((bl) => bl.type === "tool_use");
28664
+ if (lastToolUse && lastToolUse.type === "tool_use") {
28665
+ lastToolUse.input = parsedInput;
28666
+ }
28667
+ if (!isGroupTask(proc) && proc.currentToolName != null && LIVE_INPUT_PREVIEW_TOOLS.has(proc.currentToolName) && Object.keys(parsedInput).length > 0) {
28668
+ emit({
28669
+ type: "agent:tool_input_update",
28670
+ payload: {
28671
+ ...wireBase(base),
28672
+ toolName: proc.currentToolName,
28673
+ input: parsedInput
28674
+ }
28675
+ });
28676
+ }
28008
28677
  }
28009
28678
  if (proc.currentToolName === "TodoWrite") {
28010
28679
  const todos = extractTodosFromInput(parsedInput);
@@ -28069,7 +28738,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
28069
28738
  proc.contentBlocks.pop();
28070
28739
  }
28071
28740
  }
28072
- if (proc.currentToolName && proc.currentMcpInvocationId && proc.currentMcpInvocationStartedAt && parseMcpRuntimeToolName(proc.currentToolName)) {
28741
+ if (proc.currentToolName && !proc.suppressCurrentToolUse && proc.currentMcpInvocationId && proc.currentMcpInvocationStartedAt && parseMcpRuntimeToolName(proc.currentToolName)) {
28073
28742
  try {
28074
28743
  proc.mcpAuditRecorder?.recordStart({
28075
28744
  id: proc.currentMcpInvocationId,
@@ -28092,6 +28761,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
28092
28761
  }
28093
28762
  proc.accumulatedToolInput = "";
28094
28763
  }
28764
+ proc.suppressCurrentToolUse = false;
28095
28765
  proc.currentBlockType = null;
28096
28766
  break;
28097
28767
  }
@@ -28138,6 +28808,23 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
28138
28808
  const toolName = proc.currentToolName ?? "unknown";
28139
28809
  const isError = toolName === "ExitPlanMode" ? false : !!b.is_error;
28140
28810
  const output = typeof b.content === "string" ? b.content : JSON.stringify(b.content);
28811
+ const duplicateOfficialMediaDeny = isError && isOfficialMediaGenerationToolName(toolName) && isOfficialMediaGenerationDuplicateDenyMessage(output);
28812
+ if (duplicateOfficialMediaDeny) {
28813
+ logger10.info("Suppressing duplicate official media tool denial after success", {
28814
+ agentId: proc.agentId,
28815
+ replyMessageId: base.replyMessageId,
28816
+ traceId: base.traceId,
28817
+ toolName
28818
+ });
28819
+ proc.currentMcpInvocationId = null;
28820
+ proc.currentMcpInvocationStartedAt = null;
28821
+ proc.currentToolName = null;
28822
+ continue;
28823
+ }
28824
+ if (isSuccessfulOfficialMediaOutput(toolName, output)) {
28825
+ proc.officialMediaGenerationSatisfied = true;
28826
+ proc.officialMediaSessionRecycleRequested = true;
28827
+ }
28141
28828
  if (isAskUserQuestionToolName(toolName)) {
28142
28829
  proc.currentToolName = null;
28143
28830
  continue;
@@ -28166,26 +28853,28 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
28166
28853
  proc.currentMcpInvocationId = null;
28167
28854
  proc.currentMcpInvocationStartedAt = null;
28168
28855
  }
28169
- emit({
28170
- type: "agent:tool_result",
28171
- payload: {
28172
- ...wireBase(base),
28856
+ if (!isGroupTask(proc)) {
28857
+ emit({
28858
+ type: "agent:tool_result",
28859
+ payload: {
28860
+ ...wireBase(base),
28861
+ toolName,
28862
+ output,
28863
+ isError
28864
+ }
28865
+ });
28866
+ proc.contentBlocks.push({
28867
+ type: "tool_result",
28173
28868
  toolName,
28174
28869
  output,
28175
28870
  isError
28176
- }
28177
- });
28178
- proc.contentBlocks.push({
28179
- type: "tool_result",
28180
- toolName,
28181
- output,
28182
- isError
28183
- });
28184
- const lastToolUse = [...proc.contentBlocks].reverse().find((bl) => bl.type === "tool_use");
28185
- if (lastToolUse && lastToolUse.type === "tool_use") {
28186
- lastToolUse.status = isError ? "error" : "done";
28187
- if (lastToolUse.toolName === "ExitPlanMode") {
28188
- proc.planModeActive = false;
28871
+ });
28872
+ const lastToolUse = [...proc.contentBlocks].reverse().find((bl) => bl.type === "tool_use");
28873
+ if (lastToolUse && lastToolUse.type === "tool_use") {
28874
+ lastToolUse.status = isError ? "error" : "done";
28875
+ if (lastToolUse.toolName === "ExitPlanMode") {
28876
+ proc.planModeActive = false;
28877
+ }
28189
28878
  }
28190
28879
  }
28191
28880
  }
@@ -28244,7 +28933,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
28244
28933
  const groupMode = groupId != null;
28245
28934
  const usage = extractUsage(successMsg);
28246
28935
  const watermarkUsage = proc.peakContextUsage ?? usage;
28247
- if (trimmed === NO_REPLY_TOKEN) {
28936
+ if (isNoReplyText(trimmed)) {
28248
28937
  checkInputTokenWatermark(proc, watermarkUsage, base.traceId);
28249
28938
  emitUsageReported(proc, emit, base, usage);
28250
28939
  if (groupMode && proc.contentBlocks.length > 0) {
@@ -28585,6 +29274,9 @@ function resetAccumulators(proc) {
28585
29274
  proc.apiErrorEmitted = false;
28586
29275
  proc.peakContextUsage = void 0;
28587
29276
  proc.lastAssistantContentDescription = void 0;
29277
+ proc.officialMediaGenerationSatisfied = false;
29278
+ proc.suppressCurrentThinking = false;
29279
+ proc.suppressCurrentToolUse = false;
28588
29280
  }
28589
29281
 
28590
29282
  // src/forkHistoryReplay.ts
@@ -28772,11 +29464,24 @@ function missingSubscriptionMessage(subscriptionId) {
28772
29464
  }
28773
29465
  var NODE_USER_UID = 1e3;
28774
29466
  var POST_MERGE_CONTINUATION_ROUTE_MS = 15e3;
29467
+ var SCOPE_PROMPT_FINGERPRINT_REVISION = "workdir-scope-prompt-v2";
28775
29468
  var BINARY_ATTACHMENT_EXT_RE = /\.(?:7z|bmp|csv|doc|docx|gif|jpeg|jpg|m4a|mov|mp3|mp4|pdf|png|ppt|pptx|rar|rtf|wav|webm|webp|xls|xlsx|zip)$/i;
28776
29469
  var DOCUMENT_READING_RULES = `DOCUMENT READING:
28777
29470
  - The built-in Read tool cannot read binary office documents such as .docx, .xls, .xlsx, .pptx, .pdf, .odt, .ods, .odp, or .rtf.
28778
29471
  - When the user asks about document contents, use mcp__neural__read_document with the document path, or Read the provided .content.md extracted text path.
28779
29472
  - Do not report that a binary document is unreadable until you have tried read_document or the extracted text path.`;
29473
+ var MEDIA_GENERATION_RULES = `MEDIA GENERATION:
29474
+ - Official media MCP tools are first-class AHChat tasks. Do not use Bash, Monitor, sleep loops, background polling, curl polling, or TaskStop just to wait for image or video generation.
29475
+ - Seedream image tools return final images directly; no polling is needed. Generate exactly one image per user request for now. If the user asks for multiple candidates or a batch, say the current AHChat flow generates one image at a time and ask them to pick the first direction.
29476
+ - After a successful Seedream result, do not call another Seedream tool in the same turn to improve, regenerate, or create alternatives. If the user wants another version, ask them to send a new request after the current result is ready.
29477
+ - If a Seedream image tool returns an error, do not retry by switching between generate_image, edit_image, and generate_image_group in the same turn. Explain the issue briefly and ask for a usable public image URL/base64 image, or continue with text-only generation if the user confirms.
29478
+ - Seedance video flow: generate exactly one video per user request. Call mcp__seedance__seedance_create_task once; do not submit parallel tasks or alternate versions in the same turn. AHChat will track and refresh the visible media task card.
29479
+ - Keep media replies short. Do not print raw media URLs, request_id, task_id, polling logs, or "let me check again" narration unless the user explicitly asks for diagnostics.
29480
+ - When a media task is submitted or completed, write only a natural one-line note such as "\u5DF2\u5F00\u59CB\u751F\u6210\uFF0C\u6211\u4F1A\u5728\u8FD9\u91CC\u66F4\u65B0\u7ED3\u679C\u3002" or "\u751F\u6210\u597D\u4E86\uFF0C\u53EF\u4EE5\u5728\u5361\u7247\u91CC\u67E5\u770B\u3002"; let the media card show status, preview, download, copy, and regenerate actions.
29481
+ - If the user asks whether a Seedance task is ready, call mcp__seedance__seedance_check_task once and answer from that result. Do not loop, sleep, or invent external Seedance API endpoints.`;
29482
+ function isRecoveryDispatchTask(task) {
29483
+ return task.dispatchKind === "manual_continue" || task.dispatchKind === "regenerate";
29484
+ }
28780
29485
  function isSmithAgent2(agent) {
28781
29486
  return isSmithAgent(agent);
28782
29487
  }
@@ -28893,6 +29598,9 @@ var AGENT_SKILL_PROFILE_TTL_MS = 6e4;
28893
29598
  function isBoundarySkillIndexEntry(entry) {
28894
29599
  return entry.permissionLevel === "high";
28895
29600
  }
29601
+ var OFFICIAL_MEDIA_SKILL_STEPS_BY_ID = new Map(
29602
+ OFFICIAL_MEDIA_SKILLS.map((skill) => [skill.id, skill.steps])
29603
+ );
28896
29604
  function buildTaskSkillContext(task, officeCliRuntime = null, runtimeSkillIndexEntries2 = [], skillProfile = null) {
28897
29605
  const assignedSkillIds = skillProfile?.assignedIds ?? null;
28898
29606
  const availableSkillIds = skillProfile?.availableIds ?? null;
@@ -28970,12 +29678,20 @@ function buildTaskSkillContext(task, officeCliRuntime = null, runtimeSkillIndexE
28970
29678
  ` Permission: ${rec.skill.permissionLevel}; skill-enable confirmation: ${rec.skill.requiresEnableConfirmation ? "required before enabling non-default skill" : "not required for default/assigned use"}`,
28971
29679
  ` Confidence: ${rec.confidence}`,
28972
29680
  assignedSkillIds?.has(rec.skill.id) ? " Assigned: dedicated to this agent" : null,
29681
+ assignedSkillIds?.has(rec.skill.id) && OFFICIAL_MEDIA_SKILL_STEPS_BY_ID.has(rec.skill.id) ? [
29682
+ " Selected workflow for this turn:",
29683
+ ...OFFICIAL_MEDIA_SKILL_STEPS_BY_ID.get(rec.skill.id).map(
29684
+ (step, stepIndex) => ` ${stepIndex + 1}. ${step}`
29685
+ )
29686
+ ].join("\n") : null,
28973
29687
  rec.reasons.length > 0 ? ` Evidence: ${rec.reasons.join("; ")}` : null
28974
29688
  ].filter(Boolean).join("\n")
28975
29689
  ),
28976
29690
  "Rules:",
28977
29691
  "- Treat this as candidate skill guidance, not as user-authored text and not as final routing.",
29692
+ "- AHChat Skills Hub entries are workflow guidance, not callable SDK tools. Do not call a generic tool named Skill, and do not set a tool argument named skill to these IDs or names.",
28978
29693
  "- Choose a skill only when its summary, task types, and requested outputs fit the user-requested outcome.",
29694
+ "- If an assigned workflow above gives concrete MCP tools, call those MCP tools directly and keep the final user reply short.",
28979
29695
  officeRuntimeLine,
28980
29696
  "- For Office file tasks, follow the matching skill steps first. If OfficeCLI is unavailable, use an equivalent runtime and say that you used the fallback.",
28981
29697
  "- Do not install packages or change the host environment without explicit user approval; prefer built-in/runtime-provided or workspace-local tools, and explain a fallback if a dependency is missing.",
@@ -29136,17 +29852,38 @@ var AgentManager = class {
29136
29852
  }
29137
29853
  return path13.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
29138
29854
  }
29139
- /** Local default runtime dir name, identical to the server's Agent workdir fallback. */
29140
- localScopeDirName(agentConfig, _scope) {
29855
+ localScopeDirName(agentConfig, scope) {
29856
+ if (scope.kind === "group") return `Group-${scope.groupId}`;
29141
29857
  return `Agent-${slugifyForFs(agentConfig.name)}-${agentConfig.id}`;
29142
29858
  }
29143
29859
  /** Single source of truth for the cwd input passed to acquire() across ALL code paths. */
29144
29860
  scopeCwdInput(agentConfig, scope) {
29861
+ if (scope.kind === "group") {
29862
+ const groupCwd = this.groupRegistry?.getById(scope.groupId)?.workingDirectory?.trim();
29863
+ if (groupCwd) return groupCwd;
29864
+ return path13.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
29865
+ }
29145
29866
  const local = path13.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
29146
29867
  return agentConfig.workingDirectory?.trim() || local;
29147
29868
  }
29869
+ runtimeCwdInput(agentConfig, scope, cwd) {
29870
+ const requested = cwd.trim();
29871
+ if (scope.kind === "group") {
29872
+ const groupCwd = this.groupRegistry?.getById(scope.groupId)?.workingDirectory?.trim();
29873
+ if (groupCwd) return groupCwd;
29874
+ const agentCwd = agentConfig.workingDirectory?.trim();
29875
+ if (requested && (!agentCwd || !this.isSameRuntimeCwd(requested, agentCwd))) {
29876
+ return requested;
29877
+ }
29878
+ return path13.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
29879
+ }
29880
+ return agentConfig.workingDirectory?.trim() || requested || this.scopeCwdInput(agentConfig, scope);
29881
+ }
29882
+ workdirOverrideTarget(agentConfig, scope) {
29883
+ return scope.kind === "group" ? { targetKind: "group", targetId: scope.groupId } : { targetKind: "agent", targetId: agentConfig.id };
29884
+ }
29148
29885
  remapServerWorkspaceCwd(agentConfig, scope, requestedCwd) {
29149
- const overrideTarget = { targetKind: "agent", targetId: agentConfig.id };
29886
+ const overrideTarget = this.workdirOverrideTarget(agentConfig, scope);
29150
29887
  const overridden = this.workdirOverrideStore?.resolvePath(requestedCwd, overrideTarget);
29151
29888
  if (overridden?.overridden) {
29152
29889
  logger13.info("Local workdir override applied to runtime cwd", {
@@ -29346,7 +30083,7 @@ var AgentManager = class {
29346
30083
  modelInputModeForConfig(agentId, scope, cfg) {
29347
30084
  const key = runtimeKey(agentId, scope);
29348
30085
  if (this.visionBlockedScopes.has(key)) return "path-only";
29349
- return cfg.supportsVision === false ? "path-only" : "vision";
30086
+ return cfg.supportsVision === true ? "vision" : "path-only";
29350
30087
  }
29351
30088
  isSameRuntimeCwd(a, b) {
29352
30089
  const left = path13.normalize(a);
@@ -29425,6 +30162,40 @@ var AgentManager = class {
29425
30162
  });
29426
30163
  return null;
29427
30164
  }
30165
+ scopePromptFingerprint(agentConfig, scope, agentCwd, scopesSection) {
30166
+ return createHash("sha256").update(SCOPE_PROMPT_FINGERPRINT_REVISION).update("\0").update(agentConfig.id).update("\0").update(agentConfig.name).update("\0").update(scopeKey(scope)).update("\0").update(path13.normalize(agentCwd)).update("\0").update(scopesSection).digest("hex");
30167
+ }
30168
+ discardSessionIfScopePromptChanged(agentConfig, scope, sessionId, fingerprint) {
30169
+ const previous = this.sessionStore.getPromptFingerprint(agentConfig.id, scope);
30170
+ if (!sessionId) {
30171
+ this.sessionStore.setPromptFingerprint(agentConfig.id, scope, fingerprint);
30172
+ return null;
30173
+ }
30174
+ if (previous === fingerprint) return sessionId;
30175
+ if (!previous && scope.kind === "single") {
30176
+ this.sessionStore.setPromptFingerprint(agentConfig.id, scope, fingerprint);
30177
+ logger13.info("Retaining legacy single-scope session while recording prompt fingerprint", {
30178
+ agentId: agentConfig.id,
30179
+ scope: scopeKey(scope),
30180
+ sessionId,
30181
+ nextFingerprint: fingerprint,
30182
+ revision: SCOPE_PROMPT_FINGERPRINT_REVISION
30183
+ });
30184
+ return sessionId;
30185
+ }
30186
+ this.sessionStore.delete(agentConfig.id, scope);
30187
+ this.dispatchMemory.deleteScope(agentConfig.id, scope);
30188
+ this.sessionStore.setPromptFingerprint(agentConfig.id, scope, fingerprint);
30189
+ logger13.info("Cleared scoped session because scope prompt fingerprint changed", {
30190
+ agentId: agentConfig.id,
30191
+ scope: scopeKey(scope),
30192
+ sessionId,
30193
+ previousFingerprint: previous,
30194
+ nextFingerprint: fingerprint,
30195
+ revision: SCOPE_PROMPT_FINGERPRINT_REVISION
30196
+ });
30197
+ return null;
30198
+ }
29428
30199
  async awaitQueryReturn(query4, timeoutMs, agentId) {
29429
30200
  const ret = query4.return(void 0);
29430
30201
  try {
@@ -29480,6 +30251,47 @@ var AgentManager = class {
29480
30251
  this.agents.delete(key);
29481
30252
  this.lastUsedAt.delete(key);
29482
30253
  }
30254
+ /**
30255
+ * Runtime config reloads need a fresh SDK process, but the next turn should
30256
+ * resume the same Claude session so short follow-ups like "重新生成" keep context.
30257
+ */
30258
+ async closeRuntimeForRuntimeReload(proc, reason) {
30259
+ if (proc.status === "dead") return;
30260
+ const runtime = this.asRuntime(proc);
30261
+ const key = runtimeKey(proc.agentId, proc.scope);
30262
+ this.clearQuietFlushTimer(runtime);
30263
+ runtime.currentTask = null;
30264
+ runtime.injectedTasks = [];
30265
+ runtime.mergedTasks = [];
30266
+ runtime.planModeBuffer = [];
30267
+ runtime.groupInbox = [];
30268
+ try {
30269
+ runtime.inputController.close();
30270
+ await this.awaitQueryReturn(runtime.query, 5e3, proc.agentId);
30271
+ } catch (e) {
30272
+ logger13.error("runtime reload close failed", {
30273
+ agentId: proc.agentId,
30274
+ scope: scopeKey(proc.scope),
30275
+ reason,
30276
+ error: e
30277
+ });
30278
+ }
30279
+ proc.pendingTerminate = false;
30280
+ proc.pendingTerminatePreserveSession = false;
30281
+ proc.pendingTerminateReason = void 0;
30282
+ proc.status = "dead";
30283
+ this.agents.delete(key);
30284
+ this.lastUsedAt.delete(key);
30285
+ this.dormantScopes.delete(key);
30286
+ this.dormantGroupInboxes.delete(key);
30287
+ this.dispatchMemory.deleteScope(proc.agentId, proc.scope);
30288
+ logger13.info("runtime reload: scoped query removed, session preserved", {
30289
+ agentId: proc.agentId,
30290
+ scope: scopeKey(proc.scope),
30291
+ reason,
30292
+ sessionId: runtime.ccSessionId
30293
+ });
30294
+ }
29483
30295
  /** Evict LRU among idle (ready/starting + no injected tasks) agents past the idle timeout. */
29484
30296
  evictIdle() {
29485
30297
  const now = Date.now();
@@ -29556,13 +30368,15 @@ var AgentManager = class {
29556
30368
  throw new Error(`Refusing to spawn SDK runtime for human agent ${agentConfig.id}`);
29557
30369
  }
29558
30370
  const key = runtimeKey(agentConfig.id, scope);
29559
- const cwdInput = agentConfig.workingDirectory?.trim() || cwd || this.scopeCwdInput(agentConfig, scope);
30371
+ const cwdInput = this.runtimeCwdInput(agentConfig, scope, cwd);
29560
30372
  const agentCwd = await this.resolveRuntimeCwd(agentConfig, scope, cwdInput);
29561
30373
  const existing = this.agents.get(key);
29562
30374
  if (existing && existing.status !== "dead") {
29563
30375
  if (!this.isSameRuntimeCwd(existing.cwd, agentCwd) || existing.pendingTerminate) {
29564
30376
  if (existing.status === "working" && existing.currentTask) {
29565
30377
  existing.pendingTerminate = true;
30378
+ existing.pendingTerminatePreserveSession = false;
30379
+ existing.pendingTerminateReason = "cwd_changed";
29566
30380
  logger13.info("Runtime cwd changed while working; reload deferred until turn completes", {
29567
30381
  agentId: agentConfig.id,
29568
30382
  scope: scopeKey(scope),
@@ -29580,7 +30394,14 @@ var AgentManager = class {
29580
30394
  nextCwd: agentCwd,
29581
30395
  pendingTerminate: existing.pendingTerminate ?? false
29582
30396
  });
29583
- await this.terminateScope(agentConfig.id, scope);
30397
+ if (existing.pendingTerminatePreserveSession === true && this.isSameRuntimeCwd(existing.cwd, agentCwd)) {
30398
+ await this.closeRuntimeForRuntimeReload(
30399
+ existing,
30400
+ existing.pendingTerminateReason ?? "pending_runtime_reload"
30401
+ );
30402
+ } else {
30403
+ await this.terminateScope(agentConfig.id, scope);
30404
+ }
29584
30405
  } else {
29585
30406
  this.lastUsedAt.set(key, Date.now());
29586
30407
  return existing;
@@ -29597,7 +30418,7 @@ var AgentManager = class {
29597
30418
  throw new BridgeBusyError();
29598
30419
  }
29599
30420
  }
29600
- const proc = await this.getOrCreate(agentConfig, scope, agentCwd);
30421
+ const proc = await this.getOrCreate(agentConfig, scope, cwdInput);
29601
30422
  this.lastUsedAt.set(key, Date.now());
29602
30423
  return proc;
29603
30424
  }
@@ -29608,13 +30429,16 @@ var AgentManager = class {
29608
30429
  return existing;
29609
30430
  }
29610
30431
  const inputController = new InputController();
29611
- const cwdInput = agentConfig.workingDirectory?.trim() || cwd || this.scopeCwdInput(agentConfig, scope);
30432
+ const cwdInput = this.runtimeCwdInput(agentConfig, scope, cwd);
29612
30433
  const agentCwd = await this.resolveRuntimeCwd(agentConfig, scope, cwdInput);
29613
30434
  const cfg = await this.resolveAgentConfig(agentConfig);
29614
- if (cfg.instructions?.trim()) {
30435
+ const scopedInstructions = cfg.instructions?.trim() && scope.kind === "group" ? `# Agent project instructions
30436
+ ${cfg.instructions.trim()}` : "";
30437
+ if (cfg.instructions?.trim() && scope.kind === "single") {
29615
30438
  await fs6.writeFile(path13.join(agentCwd, "CLAUDE.md"), cfg.instructions.trim(), "utf-8");
29616
30439
  logger13.info("CLAUDE.md written", {
29617
30440
  agentId: agentConfig.id,
30441
+ scope: scopeKey(scope),
29618
30442
  bytes: cfg.instructions.trim().length
29619
30443
  });
29620
30444
  }
@@ -29625,7 +30449,10 @@ var AgentManager = class {
29625
30449
  try {
29626
30450
  await fs6.access(effectiveConfigDir);
29627
30451
  } catch (e) {
29628
- logger13.debug("Agent API key config dir missing; creating isolated dir", { error: e, agentId: agentConfig.id });
30452
+ logger13.debug("Agent API key config dir missing; creating isolated dir", {
30453
+ error: e,
30454
+ agentId: agentConfig.id
30455
+ });
29629
30456
  isNew = true;
29630
30457
  }
29631
30458
  await fs6.mkdir(effectiveConfigDir, { recursive: true });
@@ -29667,17 +30494,17 @@ var AgentManager = class {
29667
30494
  });
29668
30495
  }
29669
30496
  let savedSessionId = this.sessionStore.get(agentConfig.id, scope);
29670
- const agentOverride = agentConfig.workingDirectory ? this.workdirOverrideStore?.resolvePath(agentConfig.workingDirectory, {
29671
- targetKind: "agent",
29672
- targetId: agentConfig.id
29673
- }) : null;
30497
+ const runtimeOverride = cwdInput ? this.workdirOverrideStore?.resolvePath(
30498
+ cwdInput,
30499
+ this.workdirOverrideTarget(agentConfig, scope)
30500
+ ) : null;
29674
30501
  savedSessionId = this.discardSessionIfItBelongsToAnotherCwd(
29675
30502
  agentConfig,
29676
30503
  scope,
29677
30504
  agentCwd,
29678
30505
  effectiveConfigDir,
29679
30506
  savedSessionId,
29680
- agentOverride?.overridden === true
30507
+ runtimeOverride?.overridden === true
29681
30508
  );
29682
30509
  const queryFn = await this.getQueryFn();
29683
30510
  let procRef = null;
@@ -29743,11 +30570,28 @@ var AgentManager = class {
29743
30570
  },
29744
30571
  onLeaveGroup: (groupId) => this.deferLeaveGroup(agentConfig.id, groupId)
29745
30572
  });
30573
+ if (this.mcpRegistry) {
30574
+ try {
30575
+ await this.mcpRegistry.refresh();
30576
+ } catch (e) {
30577
+ logger13.warn("MCP registry refresh before runtime failed; using cached MCP config", {
30578
+ error: e,
30579
+ agentId: agentConfig.id,
30580
+ scope: scopeKey(scope)
30581
+ });
30582
+ }
30583
+ }
29746
30584
  const externalMcp = this.mcpRegistry?.buildForAgent({
29747
30585
  agentId: agentConfig.id,
29748
30586
  capabilityTier: cfg.capabilityTier,
29749
30587
  isSmith: smithAgent
29750
30588
  }) ?? { mcpServers: {}, allowedTools: [] };
30589
+ logger13.info("External MCP resolved for runtime", {
30590
+ agentId: agentConfig.id,
30591
+ scope: scopeKey(scope),
30592
+ serverNames: Object.keys(externalMcp.mcpServers),
30593
+ allowedToolCount: externalMcp.allowedTools.length
30594
+ });
29751
30595
  if (this.memoryStore) {
29752
30596
  logger13.info("Notebook pull on runtime start", {
29753
30597
  agentId: agentConfig.id,
@@ -29757,7 +30601,13 @@ var AgentManager = class {
29757
30601
  await this.memoryStore.pullFromServer(agentConfig.id);
29758
30602
  }
29759
30603
  const notebookSection = this.buildNotebookSection(agentConfig.id);
29760
- const scopesSection = this.buildScopesSection(agentConfig.id, scope, agentCwd);
30604
+ const scopesSection = this.buildScopesSection(agentConfig, scope, agentCwd);
30605
+ savedSessionId = this.discardSessionIfScopePromptChanged(
30606
+ agentConfig,
30607
+ scope,
30608
+ savedSessionId,
30609
+ this.scopePromptFingerprint(agentConfig, scope, agentCwd, scopesSection)
30610
+ );
29761
30611
  let forkHistorySection = "";
29762
30612
  if (!savedSessionId && scope.kind === "single") {
29763
30613
  const forkMeta = await consumeForkMeta(this.dataDir, agentConfig.id);
@@ -29795,6 +30645,7 @@ var AgentManager = class {
29795
30645
  cronLockOwnedByMe: cronLockSnapshot.sessionId != null && cronLockSnapshot.sessionId === savedSessionId
29796
30646
  });
29797
30647
  const planModeRef = { active: false, denyCount: 0 };
30648
+ const mediaGenerationTurnGuard = createOfficialMediaGenerationTurnGuard();
29798
30649
  const builtinWebSearchAllowed = this.queryConfig.allowBuiltinWebSearch;
29799
30650
  const options = {
29800
30651
  cwd: agentCwd,
@@ -29804,7 +30655,9 @@ var AgentManager = class {
29804
30655
  append: [
29805
30656
  PLATFORM_AGENT_RULES,
29806
30657
  DOCUMENT_READING_RULES,
30658
+ MEDIA_GENERATION_RULES,
29807
30659
  agentConfig.systemPrompt,
30660
+ scopedInstructions,
29808
30661
  notebookSection,
29809
30662
  forkHistorySection,
29810
30663
  scopesSection
@@ -29812,8 +30665,9 @@ var AgentManager = class {
29812
30665
  },
29813
30666
  permissionMode: "bypassPermissions",
29814
30667
  allowDangerouslySkipPermissions: true,
29815
- // allowedTools = auto-allow without prompting (irrelevant in bypassPermissions mode,
29816
- // but set to all available tools for consistency).
30668
+ // allowedTools is the visibility whitelist passed to Claude Code. MCP tools
30669
+ // with always_ask must still be included here so the model can request them;
30670
+ // the MCP server policy/permission layer decides whether execution asks.
29817
30671
  allowedTools: [
29818
30672
  "Read",
29819
30673
  "Edit",
@@ -30084,6 +30938,15 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
30084
30938
  },
30085
30939
  hooks: {
30086
30940
  PreToolUse: [
30941
+ ...createOfficialMediaGenerationPreToolUseHooks(
30942
+ mediaGenerationTurnGuard,
30943
+ externalMcp.allowedTools,
30944
+ {
30945
+ agentId: agentConfig.id,
30946
+ scope: scopeKey(scope),
30947
+ log: (msg, meta3) => logger13.warn(msg, meta3)
30948
+ }
30949
+ ),
30087
30950
  {
30088
30951
  matcher: "ExitPlanMode",
30089
30952
  hooks: [
@@ -30192,6 +31055,7 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
30192
31055
  segmentCount: 0,
30193
31056
  accumulatedToolInput: "",
30194
31057
  planModeRef,
31058
+ mediaGenerationTurnGuard,
30195
31059
  groupInbox: []
30196
31060
  };
30197
31061
  const runtime = Object.assign(proc, {
@@ -30309,7 +31173,15 @@ ${trimmed}`;
30309
31173
  });
30310
31174
  return section;
30311
31175
  }
30312
- buildScopesSection(agentId, scope, currentCwd) {
31176
+ promptWorkdir(agentConfig, scope, requestedCwd) {
31177
+ const remapped = this.remapServerWorkspaceCwd(agentConfig, scope, requestedCwd);
31178
+ if (!isFullyQualifiedAbsolutePath(remapped)) {
31179
+ return path13.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
31180
+ }
31181
+ return remapped;
31182
+ }
31183
+ buildScopesSection(agentConfig, scope, currentCwd) {
31184
+ const agentId = agentConfig.id;
30313
31185
  if (!this.groupRegistry) {
30314
31186
  logger13.info("Scopes injection skipped", { agentId, reason: "no_group_registry" });
30315
31187
  return "";
@@ -30318,15 +31190,32 @@ ${trimmed}`;
30318
31190
  const curKey = scopeKey(scope);
30319
31191
  const lines = [];
30320
31192
  const isCurSingle = curKey === "single";
31193
+ const singleScope = { kind: "single" };
31194
+ const singleWorkdir = isCurSingle ? currentCwd : this.promptWorkdir(agentConfig, singleScope, this.scopeCwdInput(agentConfig, singleScope));
31195
+ lines.push("Workdir semantics:");
31196
+ lines.push("- single workdir = your private Agent workspace for 1:1 chat.");
31197
+ lines.push(
31198
+ "- group workdir = that group's shared workspace; it is your runtime cwd while you are in that group."
31199
+ );
31200
+ lines.push(
31201
+ '- If asked for "your own workdir" vs "this group workdir", report the separate paths shown below.'
31202
+ );
31203
+ lines.push("");
30321
31204
  lines.push(`- single \u2014 1:1 chat with the user${isCurSingle ? " (you are here)" : ""}`);
30322
- lines.push(` workdir: ${currentCwd}`);
31205
+ lines.push(` workdir: ${singleWorkdir}`);
30323
31206
  let rosterCount = 0;
30324
31207
  for (const g of myGroups) {
30325
31208
  const key = `group:${g.groupId}`;
30326
31209
  const here = key === curKey ? " (you are here)" : "";
30327
31210
  const userMark = g.userJoined ? " [user joined]" : " [no user]";
30328
31211
  lines.push(`- ${key} \u2014 ${g.name}${here}${userMark}`);
30329
- lines.push(` workdir: ${currentCwd}`);
31212
+ const groupScope = { kind: "group", groupId: g.groupId };
31213
+ const groupWorkdir = key === curKey ? currentCwd : this.promptWorkdir(
31214
+ agentConfig,
31215
+ groupScope,
31216
+ g.workingDirectory?.trim() || this.scopeCwdInput(agentConfig, groupScope)
31217
+ );
31218
+ lines.push(` workdir: ${groupWorkdir}`);
30330
31219
  const others = g.members.filter((id) => id !== agentId).map((id) => {
30331
31220
  const a = this.agentRegistry?.getById(id);
30332
31221
  return a ? `${a.name} (${id}, role: ${a.role})` : `Agent(${id})`;
@@ -30409,6 +31298,28 @@ ${lines.join("\n")}`;
30409
31298
  await this.dispatchToSDK(runtime, task);
30410
31299
  return;
30411
31300
  }
31301
+ if (isRecoveryDispatchTask(task)) {
31302
+ logger13.warn("Recovery dispatch rejected while Agent is already working", {
31303
+ agentId: task.agentId,
31304
+ scope: scopeKey(task.scope),
31305
+ replyMessageId: task.replyMessageId,
31306
+ conversationId: task.conversationId,
31307
+ currentTaskReplyMessageId: runtime.currentTask?.replyMessageId,
31308
+ dispatchKind: task.dispatchKind,
31309
+ traceId: task.traceId
31310
+ });
31311
+ this.emit({
31312
+ type: "agent:error",
31313
+ payload: {
31314
+ agentId: task.agentId,
31315
+ conversationId: task.conversationId,
31316
+ ackId: task.replyMessageId,
31317
+ traceId: task.traceId,
31318
+ error: "Bridge is already working on another reply; recovery dispatch was rejected."
31319
+ }
31320
+ });
31321
+ return;
31322
+ }
30412
31323
  if (proc.planModeActive) {
30413
31324
  runtime.planModeBuffer.push(task);
30414
31325
  logger13.info("Message buffered during plan mode", {
@@ -30758,6 +31669,7 @@ ${lines.join("\n")}`;
30758
31669
  runtime.status = "working";
30759
31670
  runtime.currentTask = task;
30760
31671
  runtime.currentTaskStartedAt = Date.now();
31672
+ resetOfficialMediaGenerationTurnGuard(runtime.mediaGenerationTurnGuard, task.replyMessageId);
30761
31673
  runtime.cachedConversationId = task.conversationId;
30762
31674
  logger13.info("Agent run started", {
30763
31675
  agentId: runtime.agentId,
@@ -30905,9 +31817,9 @@ ${lines.join("\n")}`;
30905
31817
  throw new Error(`HTTP ${res.status}`);
30906
31818
  }
30907
31819
  const body = await res.json();
30908
- const runtimeCachedSkillIds = this.getRuntimeCachedSkillIds();
31820
+ const runtimeCachedSkillIds2 = this.getRuntimeCachedSkillIds();
30909
31821
  const serverAssignedIds = (body.assigned ?? []).map((s) => s.id);
30910
- const cachedServerAssignedIds = serverAssignedIds.filter((id) => runtimeCachedSkillIds.has(id));
31822
+ const cachedServerAssignedIds = serverAssignedIds.filter((id) => runtimeCachedSkillIds2.has(id));
30911
31823
  const localRuntimeSkillIds = this.getLocalRuntimeSkillIdsForAgent(agentId);
30912
31824
  const assignedIds = /* @__PURE__ */ new Set([...serverAssignedIds, ...localRuntimeSkillIds]);
30913
31825
  const availableIds = /* @__PURE__ */ new Set([...cachedServerAssignedIds, ...localRuntimeSkillIds]);
@@ -31252,7 +32164,7 @@ ${lines.join("\n")}`;
31252
32164
  }
31253
32165
  });
31254
32166
  }
31255
- const continuationTask = mergedBatch.at(-1);
32167
+ const continuationTask = mergedBatch.filter((task) => !isRecoveryDispatchTask(task)).at(-1);
31256
32168
  if (continuationTask) {
31257
32169
  proc.postMergeContinuationTask = continuationTask;
31258
32170
  proc.postMergeContinuationUntil = Date.now() + POST_MERGE_CONTINUATION_ROUTE_MS;
@@ -31264,6 +32176,16 @@ ${lines.join("\n")}`;
31264
32176
  routeUntil: new Date(proc.postMergeContinuationUntil).toISOString(),
31265
32177
  traceId: completedTask.traceId
31266
32178
  });
32179
+ } else {
32180
+ delete proc.postMergeContinuationTask;
32181
+ delete proc.postMergeContinuationUntil;
32182
+ logger13.info("Skipped post-merge continuation routing for recovery-only merged tasks", {
32183
+ agentId: proc.agentId,
32184
+ carrierReplyMessageId: completedTask.replyMessageId,
32185
+ mergedCount: mergedBatch.length,
32186
+ mergedReplyMessageIds: mergedBatch.map((task) => task.replyMessageId),
32187
+ traceId: completedTask.traceId
32188
+ });
31267
32189
  }
31268
32190
  runtime.mergedTasks = [];
31269
32191
  } else if (runtime.mergedTasks.length > 0) {
@@ -31273,6 +32195,37 @@ ${lines.join("\n")}`;
31273
32195
  });
31274
32196
  runtime.mergedTasks = [];
31275
32197
  }
32198
+ if (proc.officialMediaSessionRecycleRequested) {
32199
+ const hasPendingWork = runtime.injectedTasks.length > 0 || runtime.planModeBuffer.length > 0 || runtime.groupInbox.length > 0 || proc.postMergeContinuationTask != null || proc.pendingTerminate === true || proc.compactRequested === true || proc.pendingLeaveGroupId != null;
32200
+ if (!hasPendingWork) {
32201
+ proc.officialMediaSessionRecycleRequested = false;
32202
+ this.sessionStore.delete(proc.agentId, proc.scope);
32203
+ this.dispatchMemory.deleteScope(proc.agentId, proc.scope);
32204
+ logger13.info("Recycling SDK session after successful official media generation", {
32205
+ agentId: proc.agentId,
32206
+ scope: scopeKey(proc.scope),
32207
+ sessionId: proc.ccSessionId,
32208
+ completedAckId: completedTask?.replyMessageId,
32209
+ traceId: completedTask?.traceId
32210
+ });
32211
+ void this.closeRuntime(proc, "official_media_session_recycle");
32212
+ return;
32213
+ }
32214
+ logger13.info("Official media session recycle deferred because pending work remains", {
32215
+ agentId: proc.agentId,
32216
+ scope: scopeKey(proc.scope),
32217
+ sessionId: proc.ccSessionId,
32218
+ injectedTasks: runtime.injectedTasks.length,
32219
+ planModeBuffer: runtime.planModeBuffer.length,
32220
+ groupInbox: runtime.groupInbox.length,
32221
+ hasPostMergeContinuation: proc.postMergeContinuationTask != null,
32222
+ pendingTerminate: proc.pendingTerminate === true,
32223
+ compactRequested: proc.compactRequested === true,
32224
+ pendingLeaveGroup: proc.pendingLeaveGroupId != null,
32225
+ completedAckId: completedTask?.replyMessageId,
32226
+ traceId: completedTask?.traceId
32227
+ });
32228
+ }
31276
32229
  if (proc.pendingTerminate) {
31277
32230
  this.checkPendingTerminate(proc);
31278
32231
  return;
@@ -31357,6 +32310,7 @@ ${lines.join("\n")}`;
31357
32310
  proc.currentTask = next;
31358
32311
  proc.status = "working";
31359
32312
  proc.currentTaskStartedAt = Date.now();
32313
+ resetOfficialMediaGenerationTurnGuard(runtime.mediaGenerationTurnGuard, next.replyMessageId);
31360
32314
  logger13.info("Promoted next injected task after result", {
31361
32315
  agentId: proc.agentId,
31362
32316
  replyMessageId: next.replyMessageId,
@@ -31536,7 +32490,7 @@ ${lines.join("\n")}`;
31536
32490
  userInScope: group?.userJoined === true
31537
32491
  };
31538
32492
  }
31539
- deliverNeuralSend(agentConfig, payload) {
32493
+ async deliverNeuralSend(agentConfig, payload) {
31540
32494
  if (agentConfig.kind === "human") {
31541
32495
  logger13.warn("Neural send rejected: target is human principal", {
31542
32496
  agentId: agentConfig.id,
@@ -31575,8 +32529,31 @@ ${lines.join("\n")}`;
31575
32529
  traceId: createTraceId(),
31576
32530
  groupId: payload.groupId
31577
32531
  };
32532
+ const cwd = payload.targetCwd?.trim() || this.scopeCwdInput(agentConfig, targetScope);
32533
+ const resolvedCwd = await this.resolveRuntimeCwd(agentConfig, targetScope, cwd);
31578
32534
  const key = runtimeKey(agentConfig.id, targetScope);
31579
- const existingProc = this.agents.get(key);
32535
+ let existingProc = this.agents.get(key);
32536
+ if (existingProc && existingProc.status !== "dead" && !this.isSameRuntimeCwd(existingProc.cwd, resolvedCwd)) {
32537
+ if (existingProc.status === "working" && existingProc.currentTask) {
32538
+ existingProc.pendingTerminate = true;
32539
+ logger13.info("Neural send target runtime cwd changed while working; reload deferred", {
32540
+ agentId: agentConfig.id,
32541
+ toScope: payload.toScopeKey,
32542
+ currentCwd: existingProc.cwd,
32543
+ nextCwd: resolvedCwd,
32544
+ replyMessageId: existingProc.currentTask.replyMessageId
32545
+ });
32546
+ } else {
32547
+ logger13.info("Neural send target runtime cwd changed while idle; rebuilding", {
32548
+ agentId: agentConfig.id,
32549
+ toScope: payload.toScopeKey,
32550
+ currentCwd: existingProc.cwd,
32551
+ nextCwd: resolvedCwd
32552
+ });
32553
+ await this.terminateScope(agentConfig.id, targetScope);
32554
+ existingProc = void 0;
32555
+ }
32556
+ }
31580
32557
  logger13.info("Neural send dispatching", {
31581
32558
  agentId: agentConfig.id,
31582
32559
  fromScope: payload.fromScopeKey,
@@ -31587,6 +32564,7 @@ ${lines.join("\n")}`;
31587
32564
  messageLen: payload.message.length,
31588
32565
  conversationId: payload.conversationId ?? "(none)",
31589
32566
  groupId: payload.groupId ?? "(none)",
32567
+ cwd: resolvedCwd,
31590
32568
  replyMessageId: task.replyMessageId,
31591
32569
  peerCount: ctx.peers.length,
31592
32570
  peerNames: ctx.peers.map((p) => p.name),
@@ -31619,13 +32597,12 @@ ${lines.join("\n")}`;
31619
32597
  }
31620
32598
  return;
31621
32599
  }
31622
- const cwd = this.scopeCwdInput(agentConfig, targetScope);
31623
- void this.acquire(agentConfig, targetScope, cwd).then(() => {
32600
+ void this.acquire(agentConfig, targetScope, resolvedCwd).then(() => {
31624
32601
  logger13.info("Neural send new runtime acquired", {
31625
32602
  agentId: agentConfig.id,
31626
32603
  toScope: payload.toScopeKey,
31627
32604
  traceId: task.traceId,
31628
- cwd,
32605
+ cwd: resolvedCwd,
31629
32606
  replyMessageId: task.replyMessageId
31630
32607
  });
31631
32608
  return this.sendMessage({ ...task, agentId: agentConfig.id, scope: targetScope });
@@ -31634,7 +32611,7 @@ ${lines.join("\n")}`;
31634
32611
  agentId: agentConfig.id,
31635
32612
  toScope: payload.toScopeKey,
31636
32613
  traceId: task.traceId,
31637
- cwd,
32614
+ cwd: resolvedCwd,
31638
32615
  error: err
31639
32616
  });
31640
32617
  });
@@ -31821,16 +32798,19 @@ ${lines.join("\n")}`;
31821
32798
  for (const proc of [...this.agents.values()]) {
31822
32799
  if (proc.status === "working" || proc.status === "starting") {
31823
32800
  proc.pendingTerminate = true;
32801
+ proc.pendingTerminatePreserveSession = true;
32802
+ proc.pendingTerminateReason = reason;
31824
32803
  deferred++;
31825
32804
  logger13.info("Runtime reload deferred until turn completes", {
31826
32805
  agentId: proc.agentId,
31827
32806
  scope: scopeKey(proc.scope),
31828
32807
  status: proc.status,
31829
- reason
32808
+ reason,
32809
+ preserveSession: true
31830
32810
  });
31831
32811
  continue;
31832
32812
  }
31833
- await this.terminateScope(proc.agentId, proc.scope);
32813
+ await this.closeRuntimeForRuntimeReload(proc, reason);
31834
32814
  terminated++;
31835
32815
  }
31836
32816
  return { terminated, deferred };
@@ -31849,7 +32829,9 @@ ${lines.join("\n")}`;
31849
32829
  )) {
31850
32830
  this.dormantGroupInboxes.delete(key);
31851
32831
  }
31852
- const result = await this.terminateAgentForRuntimeReload(agentId, reason);
32832
+ const result = await this.terminateAgentForRuntimeReload(agentId, reason, {
32833
+ preserveSession: false
32834
+ });
31853
32835
  logger13.info("Agent scoped runtime reload requested", {
31854
32836
  agentId,
31855
32837
  reason,
@@ -31858,9 +32840,10 @@ ${lines.join("\n")}`;
31858
32840
  });
31859
32841
  return result;
31860
32842
  }
31861
- async terminateAgentForRuntimeReload(agentId, reason) {
32843
+ async terminateAgentForRuntimeReload(agentId, reason, options = {}) {
31862
32844
  let terminated = 0;
31863
32845
  let deferred = 0;
32846
+ const preserveSession = options.preserveSession ?? true;
31864
32847
  const procs = [...this.agents.values()].filter((proc) => proc.agentId === agentId);
31865
32848
  if (procs.length === 0) {
31866
32849
  logger13.info("runtime reload: no live runtime for agent", { agentId, reason });
@@ -31869,16 +32852,23 @@ ${lines.join("\n")}`;
31869
32852
  for (const proc of procs) {
31870
32853
  if (proc.status === "working" || proc.status === "starting") {
31871
32854
  proc.pendingTerminate = true;
32855
+ proc.pendingTerminatePreserveSession = preserveSession;
32856
+ proc.pendingTerminateReason = reason;
31872
32857
  deferred++;
31873
32858
  logger13.info("Runtime reload deferred until turn completes", {
31874
32859
  agentId: proc.agentId,
31875
32860
  scope: scopeKey(proc.scope),
31876
32861
  status: proc.status,
31877
- reason
32862
+ reason,
32863
+ preserveSession
31878
32864
  });
31879
32865
  continue;
31880
32866
  }
31881
- await this.terminateScope(proc.agentId, proc.scope);
32867
+ if (preserveSession) {
32868
+ await this.closeRuntimeForRuntimeReload(proc, reason);
32869
+ } else {
32870
+ await this.terminateScope(proc.agentId, proc.scope);
32871
+ }
31882
32872
  terminated++;
31883
32873
  }
31884
32874
  return { terminated, deferred };
@@ -31930,7 +32920,11 @@ ${lines.join("\n")}`;
31930
32920
  */
31931
32921
  checkPendingTerminate(proc) {
31932
32922
  if (!proc.pendingTerminate) return;
32923
+ const preserveSession = proc.pendingTerminatePreserveSession === true;
32924
+ const reason = proc.pendingTerminateReason ?? "deferred_terminate";
31933
32925
  proc.pendingTerminate = false;
32926
+ proc.pendingTerminatePreserveSession = false;
32927
+ proc.pendingTerminateReason = void 0;
31934
32928
  const runtime = this.asRuntime(proc);
31935
32929
  const pendingTasks = [...runtime.injectedTasks.splice(0), ...runtime.planModeBuffer.splice(0)];
31936
32930
  for (const task of pendingTasks) {
@@ -31965,10 +32959,16 @@ ${lines.join("\n")}`;
31965
32959
  logger13.info("checkPendingTerminate: executing deferred runtime-reload teardown", {
31966
32960
  agentId: proc.agentId,
31967
32961
  scope: scopeKey(proc.scope),
32962
+ reason,
32963
+ preserveSession,
31968
32964
  releasedPendingTaskCount: pendingTasks.length,
31969
32965
  releasedInboxCount: pendingInbox.length
31970
32966
  });
31971
- void this.terminateScope(proc.agentId, proc.scope);
32967
+ if (preserveSession) {
32968
+ void this.closeRuntimeForRuntimeReload(proc, reason);
32969
+ } else {
32970
+ void this.terminateScope(proc.agentId, proc.scope);
32971
+ }
31972
32972
  }
31973
32973
  /** Stop one scoped SDK runtime (workdir change). */
31974
32974
  async terminateScope(agentId, scope) {
@@ -31984,6 +32984,8 @@ ${lines.join("\n")}`;
31984
32984
  }
31985
32985
  if (proc.status === "working" && proc.currentTask) {
31986
32986
  proc.pendingTerminate = true;
32987
+ proc.pendingTerminatePreserveSession = false;
32988
+ proc.pendingTerminateReason = "terminate_scope";
31987
32989
  logger13.info("terminateScope: runtime working; teardown deferred until turn completes", {
31988
32990
  agentId,
31989
32991
  scope: scopeKey(scope),
@@ -32314,6 +33316,109 @@ ${lines.join("\n")}`;
32314
33316
  }
32315
33317
  return [...ids];
32316
33318
  }
33319
+ latestOpenToolUse(proc) {
33320
+ for (let i = proc.contentBlocks.length - 1; i >= 0; i -= 1) {
33321
+ const block = proc.contentBlocks[i];
33322
+ if (block?.type !== "tool_use") continue;
33323
+ if (block.status === "pending" || block.status === "running" || block.status === "paused" || block.status === "resumed") {
33324
+ return block;
33325
+ }
33326
+ return null;
33327
+ }
33328
+ return null;
33329
+ }
33330
+ emitLiveToolInputSnapshotForResume(proc, payload) {
33331
+ const task = proc.currentTask;
33332
+ const openTool = this.latestOpenToolUse(proc);
33333
+ if (!task || !openTool) return false;
33334
+ const toolName = proc.currentToolName ?? openTool.toolName;
33335
+ if (toolName !== openTool.toolName) return false;
33336
+ const liveInput = proc.accumulatedToolInput.length > 0 ? extractLiveToolInput(toolName, proc.accumulatedToolInput) : null;
33337
+ const input = liveInput && Object.keys(liveInput).length > 0 ? liveInput : Object.keys(openTool.input).length > 0 ? openTool.input : null;
33338
+ if (!input) return false;
33339
+ openTool.input = input;
33340
+ this.emit({
33341
+ type: "agent:tool_input_update",
33342
+ payload: {
33343
+ ackId: task.replyMessageId,
33344
+ agentId: proc.agentId,
33345
+ conversationId: task.conversationId,
33346
+ toolName,
33347
+ input,
33348
+ traceId: payload.traceId
33349
+ }
33350
+ });
33351
+ logger13.info("Reply session resume emitted live tool input snapshot", {
33352
+ requestId: payload.requestId,
33353
+ replySessionId: payload.replySessionId,
33354
+ replyMessageId: payload.replyMessageId,
33355
+ agentId: payload.agentId,
33356
+ scope: scopeKey(proc.scope),
33357
+ toolName,
33358
+ inputKeys: Object.keys(input),
33359
+ accumulatedToolInputLen: proc.accumulatedToolInput.length,
33360
+ traceId: payload.traceId
33361
+ });
33362
+ return true;
33363
+ }
33364
+ resumeReplySession(payload) {
33365
+ for (const [, proc] of this.agents) {
33366
+ if (proc.agentId !== payload.agentId) continue;
33367
+ const runtime = this.asRuntime(proc);
33368
+ if (runtime.currentTask?.replyMessageId !== payload.replyMessageId) continue;
33369
+ const lastTokenIndex = Math.max(0, payload.lastTokenIndex ?? 0);
33370
+ const missingDelta = runtime.accumulatedText.length > lastTokenIndex ? runtime.accumulatedText.slice(lastTokenIndex) : void 0;
33371
+ const canResume = proc.status === "working";
33372
+ const liveToolInputSnapshotEmitted = canResume ? this.emitLiveToolInputSnapshotForResume(runtime, payload) : false;
33373
+ logger13.info("Reply session resume resolved from active runtime", {
33374
+ requestId: payload.requestId,
33375
+ replySessionId: payload.replySessionId,
33376
+ replyMessageId: payload.replyMessageId,
33377
+ agentId: payload.agentId,
33378
+ scope: scopeKey(proc.scope),
33379
+ canResume,
33380
+ accumulatedTextLen: runtime.accumulatedText.length,
33381
+ missingDeltaLen: missingDelta?.length ?? 0,
33382
+ liveToolInputSnapshotEmitted,
33383
+ traceId: payload.traceId
33384
+ });
33385
+ return {
33386
+ requestId: payload.requestId,
33387
+ replySessionId: payload.replySessionId,
33388
+ replyMessageId: payload.replyMessageId,
33389
+ agentId: payload.agentId,
33390
+ conversationId: payload.conversationId,
33391
+ canResume,
33392
+ currentStatus: canResume ? "replying" : "paused",
33393
+ recoverability: canResume ? "resumable" : "retryable",
33394
+ ...missingDelta ? { missingDelta } : {},
33395
+ reason: canResume ? "active_runtime_resumed" : "runtime_not_working",
33396
+ traceId: payload.traceId,
33397
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
33398
+ };
33399
+ }
33400
+ logger13.warn("Reply session resume could not find active runtime", {
33401
+ requestId: payload.requestId,
33402
+ replySessionId: payload.replySessionId,
33403
+ replyMessageId: payload.replyMessageId,
33404
+ agentId: payload.agentId,
33405
+ conversationId: payload.conversationId,
33406
+ traceId: payload.traceId
33407
+ });
33408
+ return {
33409
+ requestId: payload.requestId,
33410
+ replySessionId: payload.replySessionId,
33411
+ replyMessageId: payload.replyMessageId,
33412
+ agentId: payload.agentId,
33413
+ conversationId: payload.conversationId,
33414
+ canResume: false,
33415
+ currentStatus: "paused",
33416
+ recoverability: "retryable",
33417
+ reason: "reply_session_not_found",
33418
+ traceId: payload.traceId,
33419
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
33420
+ };
33421
+ }
32317
33422
  /**
32318
33423
  * Resolve the conversationId that a scope-notice task should land on for the
32319
33424
  * given runtime scope. Returns null on resolve failure (server unreachable,
@@ -32426,7 +33531,8 @@ ${lines.join("\n")}`;
32426
33531
  }
32427
33532
  const runtime = this.asRuntime(proc);
32428
33533
  const key = runtimeKey(agentId, proc.scope);
32429
- const hadPendingRuntimeReload = proc.pendingTerminate === true;
33534
+ const hadPendingTerminate = proc.pendingTerminate === true;
33535
+ const preserveSessionForRuntimeReload = proc.pendingTerminatePreserveSession === true;
32430
33536
  if (!runtime.currentTask || runtime.currentTask.replyMessageId !== replyMessageId) {
32431
33537
  logger13.warn("cancelReply: replyMessageId mismatch", {
32432
33538
  agentId,
@@ -32513,7 +33619,7 @@ ${lines.join("\n")}`;
32513
33619
  traceId: t.traceId
32514
33620
  });
32515
33621
  }
32516
- if (hadPendingRuntimeReload) {
33622
+ if (hadPendingTerminate) {
32517
33623
  const pendingInbox = [...runtime.groupInbox];
32518
33624
  runtime.groupInbox = [];
32519
33625
  for (const entry of pendingInbox) {
@@ -32529,9 +33635,10 @@ ${lines.join("\n")}`;
32529
33635
  }
32530
33636
  });
32531
33637
  }
32532
- logger13.info("cancelReply: pending runtime reload will clear scoped session after stop", {
33638
+ logger13.info("cancelReply: pending deferred teardown handled after stop", {
32533
33639
  agentId,
32534
33640
  scope: scopeKey(proc.scope),
33641
+ preserveSession: preserveSessionForRuntimeReload,
32535
33642
  releasedInboxCount: pendingInbox.length,
32536
33643
  traceId
32537
33644
  });
@@ -32541,11 +33648,15 @@ ${lines.join("\n")}`;
32541
33648
  proc.status = "dead";
32542
33649
  this.agents.delete(key);
32543
33650
  this.lastUsedAt.delete(key);
32544
- if (hadPendingRuntimeReload) {
33651
+ if (hadPendingTerminate) {
32545
33652
  proc.pendingTerminate = false;
33653
+ proc.pendingTerminatePreserveSession = false;
33654
+ proc.pendingTerminateReason = void 0;
32546
33655
  this.dormantScopes.delete(key);
32547
33656
  this.dormantGroupInboxes.delete(key);
32548
- this.sessionStore.delete(agentId, proc.scope);
33657
+ if (!preserveSessionForRuntimeReload) {
33658
+ this.sessionStore.delete(agentId, proc.scope);
33659
+ }
32549
33660
  this.dispatchMemory.deleteScope(agentId, proc.scope);
32550
33661
  }
32551
33662
  logger13.info("cancelReply: process torn down", {
@@ -32553,7 +33664,7 @@ ${lines.join("\n")}`;
32553
33664
  scope: scopeKey(proc.scope),
32554
33665
  conversationId,
32555
33666
  traceId,
32556
- clearedScopedSession: hadPendingRuntimeReload
33667
+ sessionPreservedForRuntimeReload: preserveSessionForRuntimeReload
32557
33668
  });
32558
33669
  try {
32559
33670
  runtime.inputController.close();
@@ -33370,6 +34481,7 @@ import { fileURLToPath } from "url";
33370
34481
  var logger18 = createModuleLogger("mcp.registry");
33371
34482
  var AHCHAT_BUILTIN_MCP_COMMAND = "ahchat-builtin";
33372
34483
  var SEEDANCE_BUILTIN_MCP_ID = "seedance-mcp";
34484
+ var SEEDREAM_BUILTIN_MCP_ID = "seedream-mcp";
33373
34485
  var HttpMcpRegistry = class {
33374
34486
  constructor(serverApiUrl, bridgeToken = null, localStore = null) {
33375
34487
  this.serverApiUrl = serverApiUrl;
@@ -33443,7 +34555,7 @@ var HttpMcpRegistry = class {
33443
34555
  usedNames.add(serverName);
33444
34556
  mcpServers[serverName] = sdkConfig;
33445
34557
  for (const tool2 of connection.tools) {
33446
- if (!tool2.enabled || tool2.permissionPolicy !== "always_allow") continue;
34558
+ if (!tool2.enabled || tool2.permissionPolicy === "always_deny") continue;
33447
34559
  allowedTools.push(mcpRuntimeToolName(serverName, tool2.name));
33448
34560
  }
33449
34561
  }
@@ -33493,7 +34605,7 @@ var HttpMcpRegistry = class {
33493
34605
  return null;
33494
34606
  }
33495
34607
  if (connection.command === AHCHAT_BUILTIN_MCP_COMMAND) {
33496
- return resolveBuiltinMcpServerConfig(connection);
34608
+ return this.resolveBuiltinMcpServerConfig(connection);
33497
34609
  }
33498
34610
  return {
33499
34611
  type: "stdio",
@@ -33519,37 +34631,113 @@ var HttpMcpRegistry = class {
33519
34631
  };
33520
34632
  return connection.transport === "sse" ? { type: "sse", ...common } : { type: "http", ...common };
33521
34633
  }
33522
- };
33523
- function resolveBuiltinMcpServerConfig(connection) {
33524
- const [builtinId, ...extraArgs] = connection.args;
33525
- if (builtinId !== SEEDANCE_BUILTIN_MCP_ID) {
33526
- logger18.warn("Skipping unknown built-in MCP server", {
33527
- id: connection.id,
33528
- serverName: connection.serverName,
33529
- builtinId
33530
- });
33531
- return null;
34634
+ resolveBuiltinMcpServerConfig(connection) {
34635
+ const [builtinId, ...extraArgs] = connection.args;
34636
+ if (builtinId !== SEEDANCE_BUILTIN_MCP_ID && builtinId !== SEEDREAM_BUILTIN_MCP_ID) {
34637
+ logger18.warn("Skipping unknown built-in MCP server", {
34638
+ id: connection.id,
34639
+ serverName: connection.serverName,
34640
+ builtinId
34641
+ });
34642
+ return null;
34643
+ }
34644
+ const executable = builtinId === SEEDANCE_BUILTIN_MCP_ID ? resolveSeedanceMcpExecutable(extraArgs) : resolveSeedreamMcpExecutable(extraArgs);
34645
+ if (!executable) {
34646
+ logger18.warn("Skipping built-in MCP server because CLI bundle is missing", {
34647
+ id: connection.id,
34648
+ serverName: connection.serverName,
34649
+ builtinId
34650
+ });
34651
+ return null;
34652
+ }
34653
+ return {
34654
+ type: "stdio",
34655
+ command: executable.command,
34656
+ args: executable.args,
34657
+ env: {
34658
+ ...connection.env,
34659
+ ...executable.env,
34660
+ AHCHAT_SERVER_API_URL: this.serverApiUrl,
34661
+ ...this.bridgeToken ? { AHCHAT_BRIDGE_TOKEN: this.bridgeToken } : {},
34662
+ AHCHAT_MCP_SERVER_NAME: normalizeMcpServerName(connection.serverName)
34663
+ },
34664
+ alwaysLoad: connection.alwaysLoad
34665
+ };
33532
34666
  }
33533
- const executable = resolveSeedanceMcpExecutable(extraArgs);
33534
- return {
33535
- type: "stdio",
33536
- command: executable.command,
33537
- args: executable.args,
33538
- env: connection.env,
33539
- alwaysLoad: connection.alwaysLoad
33540
- };
33541
- }
33542
- function resolveSeedanceMcpExecutable(extraArgs) {
33543
- const currentDir = path14.dirname(fileURLToPath(import.meta.url));
33544
- const distCliPath = path14.join(currentDir, "seedanceMcpCli.cjs");
33545
- if (fs7.existsSync(distCliPath)) {
33546
- return { command: process.execPath, args: [distCliPath, ...extraArgs] };
34667
+ };
34668
+ function resolveSeedanceMcpExecutable(extraArgs, options = {}) {
34669
+ return resolveBundledMcpExecutable("seedanceMcpCli", extraArgs, options);
34670
+ }
34671
+ function resolveSeedreamMcpExecutable(extraArgs, options = {}) {
34672
+ return resolveBundledMcpExecutable("seedreamMcpCli", extraArgs, options);
34673
+ }
34674
+ function resolveBundledMcpExecutable(cliBaseName, extraArgs, options = {}) {
34675
+ const currentDir = options.currentDir ?? path14.dirname(fileURLToPath(import.meta.url));
34676
+ const cwd = options.cwd ?? process.cwd();
34677
+ const execPath = options.execPath ?? process.execPath;
34678
+ const existsSync3 = options.existsSync ?? fs7.existsSync;
34679
+ const distCliPath = firstExistingPath(
34680
+ [
34681
+ path14.join(currentDir, `${cliBaseName}.cjs`)
34682
+ ],
34683
+ existsSync3
34684
+ );
34685
+ if (distCliPath) {
34686
+ return {
34687
+ command: execPath,
34688
+ args: [distCliPath, ...extraArgs],
34689
+ env: shouldRunExecPathAsNode(execPath, options) ? { ELECTRON_RUN_AS_NODE: "1" } : void 0
34690
+ };
33547
34691
  }
33548
- const sourceCliPath = path14.join(currentDir, "seedanceMcpCli.ts");
33549
- if (fs7.existsSync(sourceCliPath)) {
34692
+ const sourceCliPath = firstExistingPath(
34693
+ [
34694
+ path14.join(currentDir, `${cliBaseName}.ts`)
34695
+ ],
34696
+ existsSync3
34697
+ );
34698
+ if (sourceCliPath) {
33550
34699
  return { command: "tsx", args: [sourceCliPath, ...extraArgs] };
33551
34700
  }
33552
- return { command: process.execPath, args: [distCliPath, ...extraArgs] };
34701
+ const workspaceDistCliPath = firstExistingPath(
34702
+ [
34703
+ path14.resolve(currentDir, `../../bridge/dist/${cliBaseName}.cjs`),
34704
+ path14.resolve(cwd, `packages/desktop/dist/${cliBaseName}.cjs`),
34705
+ path14.resolve(cwd, `packages/bridge/dist/${cliBaseName}.cjs`)
34706
+ ],
34707
+ existsSync3
34708
+ );
34709
+ if (workspaceDistCliPath) {
34710
+ return {
34711
+ command: execPath,
34712
+ args: [workspaceDistCliPath, ...extraArgs],
34713
+ env: shouldRunExecPathAsNode(execPath, options) ? { ELECTRON_RUN_AS_NODE: "1" } : void 0
34714
+ };
34715
+ }
34716
+ const workspaceSourceCliPath = firstExistingPath(
34717
+ [
34718
+ path14.resolve(currentDir, `../../bridge/src/${cliBaseName}.ts`),
34719
+ path14.resolve(cwd, `packages/bridge/src/${cliBaseName}.ts`)
34720
+ ],
34721
+ existsSync3
34722
+ );
34723
+ if (workspaceSourceCliPath) {
34724
+ return { command: "tsx", args: [workspaceSourceCliPath, ...extraArgs] };
34725
+ }
34726
+ return null;
34727
+ }
34728
+ function firstExistingPath(paths, existsSync3) {
34729
+ const seen = /* @__PURE__ */ new Set();
34730
+ for (const filePath of paths) {
34731
+ if (seen.has(filePath)) continue;
34732
+ seen.add(filePath);
34733
+ if (existsSync3(filePath)) return filePath;
34734
+ }
34735
+ return null;
34736
+ }
34737
+ function shouldRunExecPathAsNode(execPath, options) {
34738
+ if (typeof options.isElectron === "boolean") return options.isElectron;
34739
+ if (process.versions.electron) return true;
34740
+ return path14.basename(execPath).toLowerCase().includes("electron");
33553
34741
  }
33554
34742
  function uniqueServerName(serverName, usedNames) {
33555
34743
  if (!usedNames.has(serverName)) return serverName;
@@ -33919,6 +35107,18 @@ var wrapper_default = import_websocket.default;
33919
35107
  var logger22 = createModuleLogger("ws.connector");
33920
35108
  var WATCHDOG_INTERVAL_MS = 15e3;
33921
35109
  var STALE_THRESHOLD_MS = WS_HEARTBEAT_INTERVAL_MS * 2 + 15e3;
35110
+ function localNetworkAddresses() {
35111
+ const out = /* @__PURE__ */ new Set();
35112
+ for (const entries of Object.values(os8.networkInterfaces())) {
35113
+ for (const entry of entries ?? []) {
35114
+ if (entry.internal) continue;
35115
+ const address = entry.address.trim();
35116
+ if (!address) continue;
35117
+ out.add(address.toLowerCase());
35118
+ }
35119
+ }
35120
+ return [...out].sort();
35121
+ }
33922
35122
  var OUTBOX_CRITICAL_TYPES = /* @__PURE__ */ new Set([
33923
35123
  "agent:segment",
33924
35124
  "agent:turn_complete",
@@ -33931,7 +35131,8 @@ var OUTBOX_CRITICAL_TYPES = /* @__PURE__ */ new Set([
33931
35131
  "ask_question_updated",
33932
35132
  "artifact:created",
33933
35133
  "agent:todos_update",
33934
- "feedback:analysis_result"
35134
+ "feedback:analysis_result",
35135
+ "bridge:resume_reply_session_response"
33935
35136
  ]);
33936
35137
  var OUTBOX_MAX_ENTRIES = 300;
33937
35138
  function buildBridgeWebSocketUrl(serverUrl, bridgeToken) {
@@ -33941,6 +35142,24 @@ function buildBridgeWebSocketUrl(serverUrl, bridgeToken) {
33941
35142
  url2.searchParams.set("token", token);
33942
35143
  return url2.toString();
33943
35144
  }
35145
+ function bridgeResumeUnsupportedResponse(payload) {
35146
+ return {
35147
+ type: "bridge:resume_reply_session_response",
35148
+ payload: {
35149
+ requestId: payload.requestId,
35150
+ replySessionId: payload.replySessionId,
35151
+ replyMessageId: payload.replyMessageId,
35152
+ agentId: payload.agentId,
35153
+ conversationId: payload.conversationId,
35154
+ canResume: false,
35155
+ currentStatus: "paused",
35156
+ recoverability: "retryable",
35157
+ reason: "bridge_resume_not_supported",
35158
+ traceId: payload.traceId,
35159
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
35160
+ }
35161
+ };
35162
+ }
33944
35163
  var ServerConnector = class {
33945
35164
  ws = null;
33946
35165
  reconnectAttempts = 0;
@@ -33958,6 +35177,7 @@ var ServerConnector = class {
33958
35177
  onTaskDispatch;
33959
35178
  onGroupTaskDispatch;
33960
35179
  onStopGeneration;
35180
+ onResumeReplySession;
33961
35181
  onConnected;
33962
35182
  onRegistered;
33963
35183
  onServerPush;
@@ -33972,6 +35192,7 @@ var ServerConnector = class {
33972
35192
  this.onTaskDispatch = params.onTaskDispatch;
33973
35193
  this.onGroupTaskDispatch = params.onGroupTaskDispatch;
33974
35194
  this.onStopGeneration = params.onStopGeneration;
35195
+ this.onResumeReplySession = params.onResumeReplySession;
33975
35196
  this.onConnected = params.onConnected;
33976
35197
  this.onRegistered = params.onRegistered;
33977
35198
  this.onServerPush = params.onServerPush;
@@ -34048,6 +35269,7 @@ var ServerConnector = class {
34048
35269
  bridgeId: this.config.bridgeId,
34049
35270
  agents: ids,
34050
35271
  hostname: os8.hostname(),
35272
+ localAddresses: localNetworkAddresses(),
34051
35273
  runtimes: Object.keys(runtimes).length > 0 ? runtimes : void 0,
34052
35274
  queryConfig: {
34053
35275
  maxActive: qc.maxActive,
@@ -34085,6 +35307,7 @@ var ServerConnector = class {
34085
35307
  agentId: payload.agentId,
34086
35308
  conversationId: payload.conversationId,
34087
35309
  requestId,
35310
+ dispatchKind: payload.dispatchKind ?? "normal",
34088
35311
  traceId: payload.traceId
34089
35312
  });
34090
35313
  void this.onTaskDispatch(payload).catch((err) => {
@@ -34125,6 +35348,31 @@ var ServerConnector = class {
34125
35348
  });
34126
35349
  return;
34127
35350
  }
35351
+ case "bridge:resume_reply_session_request": {
35352
+ logger22.info("bridge:resume_reply_session_request received", {
35353
+ requestId: msg.payload.requestId,
35354
+ replySessionId: msg.payload.replySessionId,
35355
+ agentId: msg.payload.agentId,
35356
+ conversationId: msg.payload.conversationId,
35357
+ lastTokenIndex: msg.payload.lastTokenIndex ?? null,
35358
+ traceId: msg.payload.traceId
35359
+ });
35360
+ if (!this.onResumeReplySession) {
35361
+ this.send(bridgeResumeUnsupportedResponse(msg.payload));
35362
+ return;
35363
+ }
35364
+ void Promise.resolve(this.onResumeReplySession(msg.payload)).then((response) => this.send(response)).catch((err) => {
35365
+ logger22.error("Failed to handle bridge resume request", {
35366
+ error: err,
35367
+ requestId: msg.payload.requestId,
35368
+ replySessionId: msg.payload.replySessionId,
35369
+ agentId: msg.payload.agentId,
35370
+ traceId: msg.payload.traceId
35371
+ });
35372
+ this.send(bridgeResumeUnsupportedResponse(msg.payload));
35373
+ });
35374
+ return;
35375
+ }
34128
35376
  case "session:terminated": {
34129
35377
  logger22.warn("Session terminated by server, exiting bridge process", {
34130
35378
  reason: msg.payload.reason
@@ -35105,14 +36353,14 @@ async function dumpAgentContext(agentId, deps) {
35105
36353
  }
35106
36354
 
35107
36355
  // src/clipboardFiles.ts
35108
- import { execFile } from "child_process";
36356
+ import { execFile as execFile2 } from "child_process";
35109
36357
  import crypto3 from "crypto";
35110
36358
  import fs11 from "fs/promises";
35111
36359
  import os10 from "os";
35112
36360
  import path18 from "path";
35113
- import { promisify } from "util";
36361
+ import { promisify as promisify2 } from "util";
35114
36362
  var logger24 = createModuleLogger("bridge.clipboardFiles");
35115
- var execFileAsync = promisify(execFile);
36363
+ var execFileAsync2 = promisify2(execFile2);
35116
36364
  var MAX_CLIPBOARD_FILE_SIZE = 100 * 1024 * 1024;
35117
36365
  var WINDOWS_CLIPBOARD_TIMEOUT_MS = 3e3;
35118
36366
  function isRecord5(value) {
@@ -35207,7 +36455,7 @@ async function readWindowsClipboardPathCandidates() {
35207
36455
  "[pscustomobject]@{ files = $files; text = $text } | ConvertTo-Json -Compress;"
35208
36456
  ].join(" ");
35209
36457
  try {
35210
- const { stdout } = await execFileAsync("powershell.exe", [
36458
+ const { stdout } = await execFileAsync2("powershell.exe", [
35211
36459
  "-NoProfile",
35212
36460
  "-NonInteractive",
35213
36461
  "-STA",
@@ -35410,7 +36658,7 @@ async function readWorkdirFile(filePath, baseDir) {
35410
36658
  };
35411
36659
  }
35412
36660
  async function allocateTrashPath(trashDir, name) {
35413
- const safeName = name.replace(/[<>:"/\\|?*\x00-\x1F]/g, "_").replace(/[. ]+$/g, "") || "item";
36661
+ const safeName = name.split("").map((char) => isUnsafeFileNameChar(char) ? "_" : char).join("").replace(/[. ]+$/g, "") || "item";
35414
36662
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
35415
36663
  for (let index = 0; index < 1e3; index += 1) {
35416
36664
  const suffix = index === 0 ? "" : `-${index}`;
@@ -35424,6 +36672,10 @@ async function allocateTrashPath(trashDir, name) {
35424
36672
  }
35425
36673
  throw new Error("unable to allocate trash path");
35426
36674
  }
36675
+ function isUnsafeFileNameChar(char) {
36676
+ const code = char.charCodeAt(0);
36677
+ return code <= 31 || '<>:"/\\|?*'.includes(char);
36678
+ }
35427
36679
  async function trashWorkdirPath(opts) {
35428
36680
  const resolvedBaseDir = resolveUserPath(opts.baseDir);
35429
36681
  const resolvedTargetPath = resolveUserPath(opts.targetPath);
@@ -36218,7 +37470,8 @@ function groupInboxEntryFromDispatch(payload) {
36218
37470
  boardItems: payload.boardItems,
36219
37471
  boardSprints: payload.boardSprints,
36220
37472
  boardIssues: payload.boardIssues,
36221
- boardMeta: payload.boardMeta
37473
+ boardMeta: payload.boardMeta,
37474
+ dispatchKind: payload.dispatchKind
36222
37475
  };
36223
37476
  }
36224
37477
 
@@ -36315,7 +37568,8 @@ function createTaskDispatchHandler(agentManager, agentRegistry, emit) {
36315
37568
  replyMessageId: payload.ackId,
36316
37569
  traceId: payload.traceId,
36317
37570
  requestId,
36318
- planMode: payload.planMode ?? void 0
37571
+ planMode: payload.planMode ?? void 0,
37572
+ dispatchKind: payload.dispatchKind ?? "normal"
36319
37573
  });
36320
37574
  logger31.info("Agent run dispatched", {
36321
37575
  agentId: payload.agentId,
@@ -36355,6 +37609,7 @@ function createGroupTaskDispatchHandler(agentManager, agentRegistry, emit) {
36355
37609
  isMentioned: payload.isMentioned,
36356
37610
  senderKind: payload.sender.kind,
36357
37611
  chainDepth: payload.chainDepth,
37612
+ dispatchKind: payload.dispatchKind ?? "normal",
36358
37613
  traceId: payload.traceId
36359
37614
  });
36360
37615
  emitTaskAck(emit, payload.ackId, payload.agentId, payload.traceId);
@@ -36389,7 +37644,7 @@ function createGroupTaskDispatchHandler(agentManager, agentRegistry, emit) {
36389
37644
  }
36390
37645
  const groupScope = { kind: "group", groupId: payload.groupId };
36391
37646
  try {
36392
- const cwd = agentConfig.workingDirectory?.trim() || payload.cwd;
37647
+ const cwd = payload.cwd;
36393
37648
  await agentManager.acquire(
36394
37649
  agentConfig,
36395
37650
  groupScope,
@@ -36595,10 +37850,14 @@ import path25 from "path";
36595
37850
  var logger33 = createModuleLogger("session.store");
36596
37851
  var SessionStore = class {
36597
37852
  filePath;
37853
+ fingerprintPath;
36598
37854
  cache;
37855
+ fingerprints;
36599
37856
  constructor(dataDir) {
36600
37857
  this.filePath = path25.join(dataDir, "sessions.json");
37858
+ this.fingerprintPath = path25.join(dataDir, "session-fingerprints.json");
36601
37859
  this.cache = this.loadFromDisk();
37860
+ this.fingerprints = this.loadMapFromDisk(this.fingerprintPath, "session fingerprints");
36602
37861
  }
36603
37862
  cacheKey(agentId, scope) {
36604
37863
  return runtimeKey(agentId, scope);
@@ -36611,8 +37870,13 @@ var SessionStore = class {
36611
37870
  this.saveToDisk();
36612
37871
  }
36613
37872
  delete(agentId, scope) {
36614
- delete this.cache[this.cacheKey(agentId, scope)];
36615
- this.saveToDisk();
37873
+ const key = this.cacheKey(agentId, scope);
37874
+ const hadSession = Object.prototype.hasOwnProperty.call(this.cache, key);
37875
+ const hadFingerprint = Object.prototype.hasOwnProperty.call(this.fingerprints, key);
37876
+ delete this.cache[key];
37877
+ delete this.fingerprints[key];
37878
+ if (hadSession) this.saveToDisk();
37879
+ if (hadFingerprint) this.saveFingerprintsToDisk();
36616
37880
  }
36617
37881
  deleteAllForAgent(agentId) {
36618
37882
  const prefix = `${agentId}::`;
@@ -36626,10 +37890,27 @@ var SessionStore = class {
36626
37890
  if (changed) {
36627
37891
  this.saveToDisk();
36628
37892
  }
37893
+ let fingerprintsChanged = false;
37894
+ for (const key of Object.keys(this.fingerprints)) {
37895
+ if (key === agentId || key.startsWith(prefix)) {
37896
+ delete this.fingerprints[key];
37897
+ fingerprintsChanged = true;
37898
+ }
37899
+ }
37900
+ if (fingerprintsChanged) {
37901
+ this.saveFingerprintsToDisk();
37902
+ }
36629
37903
  }
36630
37904
  getAll() {
36631
37905
  return new Map(Object.entries(this.cache));
36632
37906
  }
37907
+ getPromptFingerprint(agentId, scope) {
37908
+ return this.fingerprints[this.cacheKey(agentId, scope)] ?? null;
37909
+ }
37910
+ setPromptFingerprint(agentId, scope, fingerprint) {
37911
+ this.fingerprints[this.cacheKey(agentId, scope)] = fingerprint;
37912
+ this.saveFingerprintsToDisk();
37913
+ }
36633
37914
  loadFromDisk() {
36634
37915
  try {
36635
37916
  if (!fs18.existsSync(this.filePath)) return {};
@@ -36655,6 +37936,22 @@ var SessionStore = class {
36655
37936
  return {};
36656
37937
  }
36657
37938
  }
37939
+ loadMapFromDisk(filePath, label) {
37940
+ try {
37941
+ if (!fs18.existsSync(filePath)) return {};
37942
+ const raw = fs18.readFileSync(filePath, "utf-8");
37943
+ const parsed = JSON.parse(raw);
37944
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
37945
+ const out = {};
37946
+ for (const [key, value] of Object.entries(parsed)) {
37947
+ if (typeof value === "string") out[key] = value;
37948
+ }
37949
+ return out;
37950
+ } catch (e) {
37951
+ logger33.warn(`Failed to load ${label} file, starting fresh`, { error: e, path: filePath });
37952
+ return {};
37953
+ }
37954
+ }
36658
37955
  saveToDisk() {
36659
37956
  try {
36660
37957
  const dir = path25.dirname(this.filePath);
@@ -36664,6 +37961,22 @@ var SessionStore = class {
36664
37961
  logger33.error("Failed to save sessions file", { error: e, path: this.filePath });
36665
37962
  }
36666
37963
  }
37964
+ saveFingerprintsToDisk() {
37965
+ try {
37966
+ const dir = path25.dirname(this.fingerprintPath);
37967
+ fs18.mkdirSync(dir, { recursive: true });
37968
+ fs18.writeFileSync(
37969
+ this.fingerprintPath,
37970
+ JSON.stringify(this.fingerprints, null, 2),
37971
+ "utf-8"
37972
+ );
37973
+ } catch (e) {
37974
+ logger33.error("Failed to save session fingerprints file", {
37975
+ error: e,
37976
+ path: this.fingerprintPath
37977
+ });
37978
+ }
37979
+ }
36667
37980
  };
36668
37981
 
36669
37982
  // src/workdirEnsure.ts
@@ -37138,6 +38451,10 @@ function localCodexRuntimeCapability(status) {
37138
38451
  message: status.message
37139
38452
  };
37140
38453
  }
38454
+ function normalizeAnalysisGuidance(guidance) {
38455
+ const trimmed = guidance?.trim();
38456
+ return trimmed ? trimmed : null;
38457
+ }
37141
38458
  function normalizeFeedbackText(text) {
37142
38459
  return text.trim().replace(/\s+/g, " ");
37143
38460
  }
@@ -37239,12 +38556,14 @@ function skippedResult(reason) {
37239
38556
  };
37240
38557
  }
37241
38558
  function buildFeedbackAnalysisPrompt(payload, options, attachments) {
38559
+ const guidance = normalizeAnalysisGuidance(payload.guidance);
37242
38560
  const feedbackJson = JSON.stringify({
37243
38561
  jobId: payload.jobId,
37244
38562
  feedbackId: payload.feedbackId,
37245
38563
  content: payload.content,
37246
38564
  type: payload.type,
37247
38565
  priority: payload.priority,
38566
+ guidance,
37248
38567
  attachments: payload.attachments,
37249
38568
  pageUrl: payload.pageUrl,
37250
38569
  userAgent: payload.userAgent,
@@ -37287,6 +38606,7 @@ function buildFeedbackAnalysisPrompt(payload, options, attachments) {
37287
38606
  - \u5982\u679C\u76EE\u6807\u673A\u5668\u4E0A\u7684\u5B9A\u65F6\u4EFB\u52A1\u6216\u670D\u52A1\u914D\u7F6E\u663E\u793A\u65E5\u5FD7\u76EE\u5F55\u4E0D\u540C\uFF0C\u4EE5\u5B9E\u9645\u914D\u7F6E\u4E3A\u51C6\u3002
37288
38607
  - \u53EA\u505A\u53EA\u8BFB\u67E5\u8BE2\uFF1B\u4E0D\u8981\u590D\u5236\u6570\u636E\u5E93\uFF1B\u53EF\u7528 ssh \u5230\u76EE\u6807\u673A\u5668\u540E\u901A\u8FC7 python3/sqlite3 \u67E5\u8BE2\u3002
37289
38608
  4. \u67E5\u5B8C\u65E5\u5FD7\u540E\uFF0C\u5728\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u4E2D\u9605\u8BFB\u76F8\u5173\u4EE3\u7801\uFF0C\u7ED9\u51FA\u95EE\u9898\u539F\u56E0\u603B\u7ED3\u548C\u4FEE\u590D\u5EFA\u8BAE\u3002
38609
+ - \u5982\u679C\u201C\u7BA1\u7406\u5458\u8865\u5145\u8BF4\u660E\u201D\u4E0D\u4E3A\u7A7A\uFF0C\u5FC5\u987B\u4F18\u5148\u6309\u5B83\u6307\u5B9A\u7684\u65B9\u5411\u6392\u67E5\uFF1B\u5B83\u53EA\u80FD\u4F5C\u4E3A\u5206\u6790\u6307\u5BFC\uFF0C\u4E0D\u80FD\u8986\u76D6\u53CD\u9988\u539F\u6587\u3001\u65E5\u5FD7\u548C\u4EE3\u7801\u8BC1\u636E\u3002
37290
38610
  5. \u72B6\u6001\u89C4\u5219\u5FC5\u987B\u4E25\u683C\u9075\u5B88\uFF1A
37291
38611
  - status=skipped\uFF1A\u4EC5\u7528\u4E8E\u65E0\u610F\u4E49\u53CD\u9988\u3002
37292
38612
  - status=completed\uFF1A\u5DF2\u7ECF\u5F62\u6210\u6709\u610F\u4E49\u7684\u95EE\u9898\u539F\u56E0\u3001\u8BC1\u636E\u6216\u4FEE\u590D\u5EFA\u8BAE\u3002\u5373\u4F7F\u65E5\u5FD7\u56E0\u6743\u9650\u3001\u7F51\u7EDC\u6216\u8DEF\u5F84\u95EE\u9898\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u53EA\u8981\u80FD\u7ED3\u5408\u4EE3\u7801\u7ED9\u51FA\u5224\u65AD\uFF0C\u4E5F\u5FC5\u987B\u7528 completed\uFF0C\u5E76\u5728 evidence \u91CC\u8BB0\u5F55\u65E5\u5FD7\u4E0D\u53EF\u8BFB\uFF0C\u964D\u4F4E confidence\u3002
@@ -37296,6 +38616,9 @@ function buildFeedbackAnalysisPrompt(payload, options, attachments) {
37296
38616
  \u53CD\u9988\uFF1A
37297
38617
  ${feedbackJson}
37298
38618
 
38619
+ \u7BA1\u7406\u5458\u8865\u5145\u8BF4\u660E\uFF1A
38620
+ ${guidance ?? "\uFF08\u65E0\uFF09"}
38621
+
37299
38622
  \u9644\u4EF6\u672C\u5730\u5316\u7ED3\u679C\uFF1A
37300
38623
  ${attachmentJson}
37301
38624
 
@@ -37523,14 +38846,14 @@ async function listModels(queryFn, opts = {}) {
37523
38846
  }
37524
38847
 
37525
38848
  // src/officeRuntimeSetup.ts
37526
- import { execFile as execFile2 } from "child_process";
38849
+ import { execFile as execFile3 } from "child_process";
37527
38850
  import crypto4 from "crypto";
37528
38851
  import fsSync2 from "fs";
37529
38852
  import fs22 from "fs/promises";
37530
38853
  import os13 from "os";
37531
38854
  import path31 from "path";
37532
- import { promisify as promisify2 } from "util";
37533
- var execFileAsync2 = promisify2(execFile2);
38855
+ import { promisify as promisify3 } from "util";
38856
+ var execFileAsync3 = promisify3(execFile3);
37534
38857
  var logger38 = createModuleLogger("bridge.officeRuntimeSetup");
37535
38858
  var REPO = "iOfficeAI/OfficeCLI";
37536
38859
  var DEFAULT_VERSION = "v1.0.110";
@@ -37614,7 +38937,7 @@ async function sha256(filePath) {
37614
38937
  }
37615
38938
  async function runBestEffort(command, args) {
37616
38939
  try {
37617
- await execFileAsync2(command, args);
38940
+ await execFileAsync3(command, args);
37618
38941
  return true;
37619
38942
  } catch (error51) {
37620
38943
  logger38.error("OfficeCLI best-effort command failed", {
@@ -38135,7 +39458,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
38135
39458
  }
38136
39459
  const skillStore = new SkillStore(config2.dataDir);
38137
39460
  const currentBridgeKey = bridgeKeyForBridgeToken(config2.bridgeToken);
38138
- const localSkillStore = new LocalSkillStore(config2.dataDir, { machineBridgeKey: currentBridgeKey });
39461
+ const localSkillStore = new LocalSkillStore(config2.dataDir);
38139
39462
  skillStore.seed("log-analysis", LOG_ANALYSIS_SKILL);
38140
39463
  const runtimeSkillSync = await syncRuntimeSkillsFromServer({
38141
39464
  skillStore,
@@ -38311,6 +39634,10 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
38311
39634
  traceId: payload.traceId
38312
39635
  });
38313
39636
  },
39637
+ onResumeReplySession: (payload) => ({
39638
+ type: "bridge:resume_reply_session_response",
39639
+ payload: agentManager.resumeReplySession(payload)
39640
+ }),
38314
39641
  onConnected: async () => {
38315
39642
  await agentRegistry.refresh();
38316
39643
  await groupRegistry.refresh();