@epoch-agent/core 3.1.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { REASONING_EFFORTS, MODEL_ENTRY_PROTOCOLS, PROVIDER_TYPES, isModelEntryId, parseModelRef, OPERATION_TYPES as OPERATION_TYPES$1, COMPLIANCE_CATEGORIES, COMPLIANCE_ACTIONS, SEARCH_PROVIDER_TYPES, CURRENCIES, LANGS, isSettingsPaneId, SETTINGS_PANE_IDS, BRAND_WHEN_SIDEBAR_COLLAPSED, DEFAULT_PERMISSION_LEVEL, resolvePermissionLevel, PERMISSION_LEVELS, SHELL_KINDS, cronTimes, SCHEDULE_MAX_TIMES_PER_DAY, SCHEDULE_INTERVAL_MIN_MINUTES, SCHEDULE_INTERVAL_MAX_MINUTES, ToolExposure, MIN_OPTIONS, MAX_OPTIONS, MAX_HEADER_CHARS, MAX_QUESTIONS, SCHEDULE_DEFAULT_PERMISSION, approvalPolicyForLevel, SCHEDULE_DRAFT_TOOL, agentMessageLine, systemNote, LEAD_AGENT_ID, isValidAgentRoleName, DEFAULT_AGENT_ROLE, isValidCommandName, RESERVED_COMMAND_NAMES, isWirePluginArchiveName, contentToText, AGENT_MESSAGE_NOTE_TITLE, formatMoney, totalUsageTokens, OFFLOADED_IMAGE_NOTE, NOOP_TELEMETRY, METRIC, GEN_AI, isPromptOversize, promptTokens, entrySecretName, isEntrySecretName, entryRef, KEY_ACTIONS, tableOf, perAction, isKeyAction, parseSequence, RESERVED_CHORDS, chordId, sequenceId, ACTION_CONTEXTS, SEQUENCE_CONTEXTS, assertNeverPart, normalizeAppearanceTranslucent, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_REFS, utf8ByteLength, truncateToBudget, attachSessionSurface, isContextNearlyFull, isOperationType, normalizeApproval, SCHEDULE_DRAFT_SAVED_MARK, imagePartOmittedSummary, ENTRY_REF_PREFIX, placeholdersOf, SCHEDULE_CONFIRM_PLACEHOLDER, MAX_ATTACH_BYTES, SIMULTANEOUS_CONTEXTS, SESSION_REFERENCE_ERROR_CODES, filePartSummary, sessionPartSummary } from '@epoch-agent/protocol';
1
+ import { REASONING_EFFORTS, MODEL_ENTRY_PROTOCOLS, PROVIDER_TYPES, isModelEntryId, parseModelRef, OPERATION_TYPES as OPERATION_TYPES$1, COMPLIANCE_CATEGORIES, COMPLIANCE_ACTIONS, SEARCH_PROVIDER_TYPES, CURRENCIES, LANGS, isSettingsPaneId, SETTINGS_PANE_IDS, BRAND_WHEN_SIDEBAR_COLLAPSED, DEFAULT_PERMISSION_LEVEL, resolvePermissionLevel, PERMISSION_LEVELS, SHELL_KINDS, cronTimes, SCHEDULE_MAX_TIMES_PER_DAY, SCHEDULE_INTERVAL_MIN_MINUTES, SCHEDULE_INTERVAL_MAX_MINUTES, ToolExposure, MIN_OPTIONS, MAX_OPTIONS, MAX_HEADER_CHARS, MAX_QUESTIONS, SCHEDULE_DEFAULT_PERMISSION, approvalPolicyForLevel, SCHEDULE_DRAFT_TOOL, agentMessageLine, systemNote, LEAD_AGENT_ID, sessionSenderLabel, isValidAgentRoleName, DEFAULT_AGENT_ROLE, isValidCommandName, RESERVED_COMMAND_NAMES, isWirePluginArchiveName, contentToText, AGENT_MESSAGE_NOTE_TITLE, formatMoney, totalUsageTokens, OFFLOADED_IMAGE_NOTE, NOOP_TELEMETRY, METRIC, GEN_AI, isPromptOversize, promptTokens, entrySecretName, isEntrySecretName, entryRef, KEY_ACTIONS, tableOf, perAction, isKeyAction, parseSequence, RESERVED_CHORDS, chordId, sequenceId, ACTION_CONTEXTS, SEQUENCE_CONTEXTS, assertNeverPart, normalizeAppearanceTranslucent, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_REFS, utf8ByteLength, truncateToBudget, attachSessionSurface, isContextNearlyFull, isOperationType, normalizeApproval, SCHEDULE_DRAFT_SAVED_MARK, imagePartOmittedSummary, ENTRY_REF_PREFIX, placeholdersOf, SCHEDULE_CONFIRM_PLACEHOLDER, MAX_ATTACH_BYTES, SIMULTANEOUS_CONTEXTS, SESSION_REFERENCE_ERROR_CODES, filePartSummary, sessionPartSummary } from '@epoch-agent/protocol';
2
2
  export { API_KEY_ENV_VARS, COMPLIANCE_ACTIONS, COMPLIANCE_CATEGORIES, LEGACY_LEVEL_ALIASES, MAX_ATTACH_BYTES, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_ATTACH_BYTES, MAX_SESSION_REFS, OPERATION_TYPES, PERMISSION_LEVELS, PLAN_OUTCOMES, PROVIDER_INFOS, PROVIDER_TYPES, ToolExposure, apiKeyEnvVar, approvalPolicyForLevel, extractAllMentions, extractMentions, extractSessionMentions, getProviderInfo, isOperationType, isPermissionLevel, isPlanOutcome, isProviderType, normalizeApproval, resolvePermissionLevel } from '@epoch-agent/protocol';
3
3
  import { existsSync, mkdirSync, rmSync, writeFileSync, statSync, readdirSync, readFileSync, renameSync, realpathSync, symlinkSync, cpSync, lstatSync, unlinkSync, rmdirSync, mkdtempSync, copyFileSync, openSync, writeSync, closeSync, readSync } from 'fs';
4
4
  import { platform, tmpdir, homedir, hostname } from 'os';
@@ -2034,7 +2034,7 @@ var DelegateManager = class {
2034
2034
  async delegate(args, parentSessionId, signal) {
2035
2035
  const start = Date.now();
2036
2036
  const tasks = this.normalizeTasks(args);
2037
- const maxConcurrent = args.max_concurrent ?? this.config.max_concurrent_children;
2037
+ let maxConcurrent = args.max_concurrent ?? this.config.max_concurrent_children;
2038
2038
  if (this.currentDepth >= this.config.max_spawn_depth) {
2039
2039
  return {
2040
2040
  success: false,
@@ -2046,6 +2046,18 @@ var DelegateManager = class {
2046
2046
  return { success: true, output: this.buildSummary([], Date.now() - start), duration: 0 };
2047
2047
  }
2048
2048
  const background = args.background === true;
2049
+ const team = this.config.team;
2050
+ if (team) {
2051
+ const slots = team.availableMemberSlots(parentSessionId);
2052
+ if (slots <= 0) {
2053
+ return {
2054
+ success: false,
2055
+ output: `\u8FD9\u4E2A\u4F1A\u8BDD\u5DF2\u7ECF\u6709 ${team.memberLimit} \u4E2A\u6210\u5458\u5728\u8DD1\uFF08\u5E76\u53D1\u4E0A\u9650\uFF09\uFF0C\u8FD9\u4E00\u6279\u6CA1\u6D3E\u51FA\u53BB \u2014\u2014 \u7B49\u5176\u4E2D\u4E00\u4E2A\u6536\u5DE5\u518D\u6765\uFF0C\u6216\u8005\u5148 interrupt_agent \u6536\u6389\u4E00\u4E2A`,
2056
+ duration: 0
2057
+ };
2058
+ }
2059
+ maxConcurrent = Math.min(maxConcurrent, slots);
2060
+ }
2049
2061
  if (signal?.aborted) {
2050
2062
  return { success: false, output: ABORTED, duration: 0 };
2051
2063
  }
@@ -2151,6 +2163,21 @@ ${summary}`);
2151
2163
  const resuming = task.resumeSessionId !== void 0;
2152
2164
  const sessionId = task.resumeSessionId ?? `delegate-${randomUUID().slice(0, 8)}`;
2153
2165
  const memberId = task.agentId ?? sessionId;
2166
+ const failed = (error, summary = "") => ({
2167
+ goal: task.goal,
2168
+ success: false,
2169
+ summary,
2170
+ error,
2171
+ duration: Date.now() - start,
2172
+ ...task.role ? { role: task.role } : {}
2173
+ });
2174
+ const team = this.config.team;
2175
+ if (signal?.aborted) return failed(ABORTED);
2176
+ if (team && team.availableMemberSlots(parentSessionId) <= 0) {
2177
+ return failed(
2178
+ `\u8FD9\u4E2A\u4F1A\u8BDD\u5DF2\u7ECF\u6709 ${team.memberLimit} \u4E2A\u6210\u5458\u5728\u8DD1\uFF08\u5E76\u53D1\u4E0A\u9650\uFF09\uFF0C\u8FD9\u4E00\u4E2A\u6CA1\u6D3E\u51FA\u53BB\u3002\u7B49\u5176\u4E2D\u4E00\u4E2A\u6536\u5DE5\u518D\u6765\uFF0C\u6216\u8005\u5148 interrupt_agent \u6536\u6389\u4E00\u4E2A`
2179
+ );
2180
+ }
2154
2181
  if (resuming) {
2155
2182
  this.config.team?.markRunning(memberId);
2156
2183
  } else {
@@ -2161,15 +2188,6 @@ ${summary}`);
2161
2188
  ...task.role ? { role: task.role } : {}
2162
2189
  });
2163
2190
  }
2164
- const failed = (error, summary = "") => ({
2165
- goal: task.goal,
2166
- success: false,
2167
- summary,
2168
- error,
2169
- duration: Date.now() - start,
2170
- ...task.role ? { role: task.role } : {}
2171
- });
2172
- if (signal?.aborted) return failed(ABORTED);
2173
2191
  const controller = new AbortController();
2174
2192
  this.config.team?.setAbort(memberId, () => controller.abort());
2175
2193
  const unlink = linkAbort(isAbortSignal(signal) ? signal : void 0, controller);
@@ -2554,6 +2572,11 @@ function createMemoryTool(memory) {
2554
2572
  "action=add \u65B0\u589E\u6761\u76EE\uFF1Breplace \u66FF\u6362\u5DF2\u6709\u6761\u76EE\uFF1Bremove \u5220\u9664\uFF1Bsearch \u68C0\u7D22\uFF1Bread \u6309 id \u53D6\u5168\u6587\uFF1Bbudget \u67E5\u770B\u914D\u989D\u3002",
2555
2573
  'target=user \u5B58"\u7528\u6237\u662F\u8C01/\u504F\u597D\u4EC0\u4E48"\uFF1Btarget=memory \u5B58"\u6211\u9700\u8981\u8BB0\u4F4F\u7684\u9879\u76EE\u77E5\u8BC6"\u3002',
2556
2574
  "\u53EA\u8BB0\u5F55\u975E\u663E\u800C\u6613\u89C1\u3001\u4EE5\u540E\u8FD8\u4F1A\u7528\u5230\u7684\u4FE1\u606F\u2014\u2014\u4E0D\u8981\u8BB0\u5F55\u80FD\u4ECE\u4EE3\u7801\u6216 git \u5386\u53F2\u8BFB\u51FA\u6765\u7684\u5185\u5BB9\u3002",
2575
+ "\u5199\u4E4B\u524D\u5148\u5206\u6E05\u4E09\u4EF6\u4E8B\u3002\u8BB0\u504F\u4E86\u4E00\u6761\u4F1A\u4E00\u76F4\u7559\u5728\u540E\u9762\u6BCF\u4E00\u8F6E\u91CC\uFF0C\u6BD4\u5C11\u8BB0\u4E00\u6761\u574F\u5F97\u591A\uFF1A",
2576
+ "\u2460 \u8303\u56F4\uFF1A\u7528\u6237\u660E\u786E\u8BF4\u4E86\u300C\u4EE5\u540E\u90FD\u8FD9\u6837\u300D\u624D\u8BB0\u6210\u504F\u597D\uFF1B\u53EA\u662F\u4E00\u6B21\u6027\u8981\u6C42\uFF08\u300C\u8FD9\u6B21\u5148\u7ED9\u65B9\u6848\u300D\uFF09\u5C31\u7167\u4ED6\u8981\u8FC7\u8FD9\u4E00\u6B21\u5199\uFF0C\u522B\u5347\u683C\u3002\u62FF\u4E0D\u51C6\u5C31\u5F15\u539F\u8BDD\u3002",
2577
+ "\u2461 \u5F52\u5C5E\uFF1A\u7528\u6237\u7684\u539F\u8BDD\u662F\u4E8B\u5B9E\uFF1B\u4F60\u81EA\u5DF1\u6216\u5B50 agent \u7684\u63A8\u65AD\u3001\u5047\u8BBE\u3001\u6CA1\u9A8C\u8BC1\u7684\u7ED3\u8BBA\u4E0D\u662F\u2014\u2014\u522B\u8BB0\u6210\u7528\u6237\u7684\u610F\u601D\u3002",
2578
+ "\u2462 \u8BC1\u636E\uFF1A\u7F3A\u8BC1\u636E\u4E0D\u7B49\u4E8E\u6CA1\u53D1\u751F\u3002\u6CA1\u770B\u5230\u6388\u6743 / \u6CA1\u505A\u5B8C\uFF0C\u5C31\u5199\u300C\u672A\u89C1\u300D\uFF1B\u522B\u58F0\u79F0\u5B8C\u6210\u3001\u5DF2\u9A8C\u8BC1\u3001\u7528\u6237\u5DF2\u6279\u51C6\u3002",
2579
+ "\u9879\u76EE\u51B3\u7B56\u8FDB target=memory\uFF0C\u7528\u6237\u600E\u4E48\u5DE5\u4F5C\u8FDB target=user\uFF0C\u522B\u6DF7\uFF1B\u7528\u6237\u540E\u6765\u7EA0\u6B63\u8FC7\u7684\u7528 replace \u8986\u76D6\uFF0C\u522B\u65B0\u65E7\u5E76\u5B58\u3002",
2557
2580
  "system prompt \u91CC\u7684 MEMORY INDEX \u53EA\u6709\u6BCF\u6761\u7684\u9996\u884C\u6458\u8981\uFF1B\u8981\u5168\u6587\u7528 read\uFF0C\u627E\u4E0D\u5230\u7684\u7528 search\u3002"
2558
2581
  ].join("\n"),
2559
2582
  parameters: {
@@ -4427,9 +4450,16 @@ var TeamTaskBoard = class {
4427
4450
  }
4428
4451
  };
4429
4452
  // src/team/registry.ts
4453
+ var DEFAULT_MAX_RUNNING_MEMBERS = 3;
4454
+ var DEFAULT_MAX_WOKEN_SESSIONS = 3;
4455
+ var WAKE_RAMP_MS = 6e4;
4430
4456
  var TeamRegistry = class {
4431
- constructor(inboxCapacity = DEFAULT_INBOX_CAPACITY) {
4457
+ constructor(inboxCapacity = DEFAULT_INBOX_CAPACITY, limits = {}) {
4432
4458
  this.inboxCapacity = inboxCapacity;
4459
+ this.limits = {
4460
+ maxRunningMembers: limits.maxRunningMembers ?? DEFAULT_MAX_RUNNING_MEMBERS,
4461
+ maxWokenSessions: limits.maxWokenSessions ?? DEFAULT_MAX_WOKEN_SESSIONS
4462
+ };
4433
4463
  this.tasks = new TeamTaskBoard();
4434
4464
  this.tasks.onChange(() => this.notify());
4435
4465
  }
@@ -4438,6 +4468,10 @@ var TeamRegistry = class {
4438
4468
  bySessionId = /* @__PURE__ */ new Map();
4439
4469
  mainInboxes = /* @__PURE__ */ new Map();
4440
4470
  sessions = /* @__PURE__ */ new Set();
4471
+ activeTurns = /* @__PURE__ */ new Map();
4472
+ wokenSessions = /* @__PURE__ */ new Map();
4473
+ limits;
4474
+ bridge;
4441
4475
  aborters = /* @__PURE__ */ new Map();
4442
4476
  listeners = /* @__PURE__ */ new Set();
4443
4477
  tasks;
@@ -4533,6 +4567,74 @@ var TeamRegistry = class {
4533
4567
  hasSession(sessionId) {
4534
4568
  return this.sessions.has(sessionId);
4535
4569
  }
4570
+ beginSessionTurn(sessionId) {
4571
+ this.activeTurns.set(sessionId, (this.activeTurns.get(sessionId) ?? 0) + 1);
4572
+ }
4573
+ endSessionTurn(sessionId) {
4574
+ const n = this.activeTurns.get(sessionId);
4575
+ if (n === void 0) return;
4576
+ if (n <= 1) {
4577
+ this.activeTurns.delete(sessionId);
4578
+ this.wokenSessions.delete(sessionId);
4579
+ return;
4580
+ }
4581
+ this.activeTurns.set(sessionId, n - 1);
4582
+ }
4583
+ isSessionActive(sessionId) {
4584
+ return this.activeTurns.has(sessionId);
4585
+ }
4586
+ setSessionBridge(bridge) {
4587
+ this.bridge = bridge;
4588
+ }
4589
+ async wakeSession(sessionId, text) {
4590
+ if (!this.bridge) {
4591
+ return {
4592
+ ok: false,
4593
+ reason: "\u8FD9\u4E2A\u5BBF\u4E3B\u4E0D\u652F\u6301\u5524\u9192\u522B\u7684\u4F1A\u8BDD\uFF08CLI \u5355\u4F1A\u8BDD\u6A21\u5F0F\uFF09\u3002\u8BA9\u5B83\u81EA\u5DF1\u53D1\u4E00\u53E5\u8BDD\u624D\u80FD\u63A5\u4E0A"
4594
+ };
4595
+ }
4596
+ const now = Date.now();
4597
+ this.reapWokenSessions(now);
4598
+ if (this.wokenSessions.has(sessionId)) {
4599
+ return {
4600
+ ok: false,
4601
+ reason: `${sessionId} \u521A\u88AB\u53EB\u8D77\u6765\uFF0C\u8FD8\u6CA1\u771F\u6B63\u5F00\u8DD1 \u2014\u2014 \u522B\u91CD\u590D\u53EB\u3002\u770B\u5B83\u7B54\u4E86\u4EC0\u4E48\uFF1Asession_messages_read ${sessionId}`
4602
+ };
4603
+ }
4604
+ if (this.wokenSessions.size >= this.limits.maxWokenSessions) {
4605
+ return {
4606
+ ok: false,
4607
+ reason: `\u73B0\u5728\u5DF2\u7ECF\u6709 ${this.wokenSessions.size} \u6BB5\u88AB\u53EB\u9192\u7684\u4F1A\u8BDD\u5728\u8DD1\uFF08\u4E0A\u9650 ${this.limits.maxWokenSessions} \u6BB5\uFF09\u2014\u2014 \u7B49\u5176\u4E2D\u4E00\u6BB5\u8DD1\u5B8C\u518D\u53EB\u4E0B\u4E00\u4E2A\uFF0C\u6216\u8005\u628A\u5B83\u4EEC\u8981\u5E72\u7684\u4E8B\u5199\u8FDB\u4F60\u81EA\u5DF1\u7684\u7ED3\u8BBA\u91CC`
4608
+ };
4609
+ }
4610
+ const r = await this.bridge.wake(sessionId, text);
4611
+ if (r.ok) this.wokenSessions.set(sessionId, now);
4612
+ return r;
4613
+ }
4614
+ reapWokenSessions(now) {
4615
+ for (const [id, at] of this.wokenSessions) {
4616
+ if (!this.activeTurns.has(id) && now - at > WAKE_RAMP_MS) this.wokenSessions.delete(id);
4617
+ }
4618
+ }
4619
+ get memberLimit() {
4620
+ return this.limits.maxRunningMembers;
4621
+ }
4622
+ availableMemberSlots(parentSessionId) {
4623
+ let running = 0;
4624
+ for (const entry of this.members.values()) {
4625
+ if (entry.info.parentSessionId === parentSessionId && entry.info.status === "running") {
4626
+ running += 1;
4627
+ }
4628
+ }
4629
+ return Math.max(0, this.limits.maxRunningMembers - running);
4630
+ }
4631
+ sessionExists(sessionId) {
4632
+ if (this.bridge) return this.bridge.exists(sessionId);
4633
+ return this.sessions.has(sessionId);
4634
+ }
4635
+ sessionTitle(sessionId) {
4636
+ return this.bridge?.title?.(sessionId);
4637
+ }
4536
4638
  sessionIds() {
4537
4639
  return [...this.sessions];
4538
4640
  }
@@ -4570,9 +4672,10 @@ var TeamRegistry = class {
4570
4672
  if (msg.to === LEAD_AGENT_ID) {
4571
4673
  const sender = this.members.get(msg.from);
4572
4674
  if (sender) {
4573
- this.mainInbox(sender.info.parentSessionId).push(msg);
4675
+ const parent = sender.info.parentSessionId;
4676
+ this.mainInbox(parent).push(msg);
4574
4677
  this.notify();
4575
- return { ok: true, to: msg.to, status: "running" };
4678
+ return { ok: true, to: msg.to, status: this.isSessionActive(parent) ? "running" : "idle" };
4576
4679
  }
4577
4680
  return { ok: false, to: msg.to, reason: `\u4E3B\u4F1A\u8BDD\u4E0D\u80FD\u53D1\u7ED9 ${LEAD_AGENT_ID}` };
4578
4681
  }
@@ -4589,11 +4692,19 @@ var TeamRegistry = class {
4589
4692
  this.notify();
4590
4693
  return { ok: true, to: msg.to, status: entry.info.status };
4591
4694
  }
4592
- if (this.sessions.has(msg.to)) {
4695
+ if (this.isSessionActive(msg.to)) {
4593
4696
  this.mainInbox(msg.to).push(msg);
4594
4697
  this.notify();
4595
4698
  return { ok: true, to: msg.to, status: "running" };
4596
4699
  }
4700
+ if (this.sessionExists(msg.to)) {
4701
+ const senderIsMember = this.members.has(msg.from);
4702
+ return {
4703
+ ok: false,
4704
+ to: msg.to,
4705
+ reason: senderIsMember ? `${msg.to} \u73B0\u5728\u6CA1\u5728\u8DD1\uFF0C\u4E0B\u4E00\u8F6E\u4E0D\u4F1A\u6765 \u2014\u2014 \u8FD9\u6761\u6D88\u606F\u6CA1\u9001\u51FA\u53BB\u3002\u4F60\u53EB\u4E0D\u9192\u522B\u7684\u4F1A\u8BDD\uFF08\u6210\u5458\u62FF\u4E0D\u5230 followup_task\uFF09\uFF1A\u8981\u7D27\u7684\u8BDD\u5199\u8FDB\u4F60\u8FD9\u4E00\u8F6E\u7684\u7ED3\u8BBA\u91CC\uFF0C\u6D3E\u4F60\u51FA\u6765\u7684\u4F1A\u8BDD\u4F1A\u770B\u5230` : `${msg.to} \u73B0\u5728\u6CA1\u5728\u8DD1\uFF0C\u4E0B\u4E00\u8F6E\u4E0D\u4F1A\u6765 \u2014\u2014 \u8FD9\u6761\u6D88\u606F\u6CA1\u9001\u51FA\u53BB\u3002\u8981\u7528 followup_task \u628A\u5B83\u53EB\u8D77\u6765\u8DD1\u4E00\u8F6E\uFF08agentId \u586B ${msg.to}\uFF0Cmessage \u586B\u4F60\u8981\u8BF4\u7684\u8BDD\uFF09`
4706
+ };
4707
+ }
4597
4708
  return {
4598
4709
  ok: false,
4599
4710
  to: msg.to,
@@ -4606,7 +4717,8 @@ var TeamRegistry = class {
4606
4717
  from: args.from,
4607
4718
  to: args.to,
4608
4719
  text: args.text,
4609
- sentAt: Date.now()
4720
+ sentAt: Date.now(),
4721
+ ...args.fromLabel ? { fromLabel: args.fromLabel } : {}
4610
4722
  };
4611
4723
  }
4612
4724
  };
@@ -4616,11 +4728,11 @@ function createSendMessageTool(team) {
4616
4728
  return {
4617
4729
  name: SEND_MESSAGE_TOOL,
4618
4730
  description: [
4619
- "\u7ED9\u53E6\u4E00\u4E2A agent \u6216**\u53E6\u4E00\u6BB5\u4F1A\u8BDD**\u53D1\u4E00\u6761\u6D88\u606F\u3002**\u4E0D\u662F\u6D3E\u6D3B** \u2014\u2014 \u4E0D\u4F1A\u65B0\u5F00\u6210\u5458\u3001\u4E0D\u4F1A\u7B49\u5B83\u4EA4\u7ED3\u8BBA\u3002",
4731
+ "\u7ED9\u53E6\u4E00\u4E2A agent \u6216**\u6B63\u6709\u4E00\u6BB5\u5728\u8DD1\u7684\u4E3B\u4F1A\u8BDD**\u53D1\u4E00\u6761\u6D88\u606F\u3002**\u4E0D\u662F\u6D3E\u6D3B** \u2014\u2014 \u4E0D\u4F1A\u65B0\u5F00\u6210\u5458\u3001\u4E0D\u4F1A\u7B49\u5B83\u4EA4\u7ED3\u8BBA\u3002",
4620
4732
  "\u53D1\u7ED9\u6B63\u5728\u8DD1\u7684\u6210\u5458\uFF08\u5B50 agent\uFF09\uFF1A\u5B83\u5728\u4E0B\u4E00\u6B65\u5C31\u6536\u5230\uFF0C\u5F53\u8F6E\u5C31\u80FD\u636E\u6B64\u6539\u53D8\u884C\u4E3A\u3002",
4621
- `\u53D1\u7ED9 \`${LEAD_AGENT_ID}\`\uFF08\u6D3E\u4F60\u51FA\u6765\u7684\u90A3\u4E2A\u4F1A\u8BDD\uFF09\uFF1A\u5B83\u4E0B\u4E00\u8F6E\u5F00\u5934\u4F1A\u770B\u5230\u3002`,
4622
- "\u53D1\u7ED9**\u53E6\u4E00\u6BB5\u4E3B\u4F1A\u8BDD**\uFF08\u7528 list_agents --all \u770B\u5230\u7684\u90A3\u4E2A sessionId\uFF09\uFF1A\u5B83\u4E0B\u4E00\u8F6E\u5F00\u5934\u4F1A\u770B\u5230\u3002",
4623
- "\u53D1\u7ED9\u5DF2\u7ECF\u6536\u5DE5\u7684\u6210\u5458\u4F1A\u5931\u8D25 \u2014\u2014 \u90A3\u4E9B\u8981\u9760 delegate_task \u91CD\u65B0\u6D3E\u3002",
4733
+ `\u53D1\u7ED9 \`${LEAD_AGENT_ID}\`\uFF08\u6D3E\u4F60\u51FA\u6765\u7684\u90A3\u4E2A\u4F1A\u8BDD\uFF09\uFF1A\u5B83\u5728\u8DD1\u65F6\u63A5\u4E0B\u6765\u7684\u6B65\u9AA4\u91CC\u4F1A\u770B\u5230\uFF1B\u5B83\u6CA1\u5728\u8DD1\u65F6\u8FD9\u6761\u53EA\u662F\u6392\u8FDB\u5B83\u7684\u6536\u4EF6\u7BB1\uFF0C\u7B49\u5B83\u4E0B\u6B21\u8DD1\u8D77\u6765\u624D\u8BFB\u5F97\u5230\uFF08\u4F60\u73B0\u5728\u7B49\u4E0D\u5230\u56DE\u97F3\uFF09\u3002`,
4734
+ "\u53D1\u7ED9**\u53E6\u4E00\u6BB5\u4E3B\u4F1A\u8BDD**\uFF08\u7528 list_agents --all \u770B\u5230\u7684\u90A3\u4E2A sessionId\uFF09\uFF1A\u53EA\u6709\u5B83**\u6B64\u523B\u6B63\u5728\u8DD1**\u624D\u9001\u5F97\u5230\u3002",
4735
+ "\u5BF9\u65B9\u6CA1\u5728\u8DD1\uFF08\u4F11\u7720 / \u5DF2\u7ECF\u6536\u5DE5\uFF09\u4F1A\u5F53\u573A\u5931\u8D25\uFF08\u53D1\u7ED9 lead \u90A3\u4E00\u6761\u9664\u5916\uFF0C\u5B83\u6392\u961F\uFF09\u2014\u2014 \u90A3\u79CD\u60C5\u51B5\u7528 followup_task \u628A\u5B83\u53EB\u8D77\u6765\u8DD1\u4E00\u8F6E\uFF0C\u522B\u5E72\u7B49\u3002",
4624
4736
  "\u7528 list_agents \u770B\u672C\u4F1A\u8BDD\u7684\u6210\u5458\uFF1B\u52A0 --all \u770B\u6240\u6709\u4F1A\u8BDD\u548C\u6210\u5458\u3002"
4625
4737
  ].join("\n"),
4626
4738
  parameters: {
@@ -4675,7 +4787,15 @@ function createSendMessageTool(team) {
4675
4787
  const target = team.get(to);
4676
4788
  const ownMember = target !== void 0 && target.parentSessionId === ctx.sessionId;
4677
4789
  const from = memberInfo ? memberInfo.agentId : ownMember ? LEAD_AGENT_ID : ctx.sessionId;
4678
- const result = team.deliver(TeamRegistry.message({ from, to, text }));
4790
+ const labelled = from === ctx.sessionId ? sessionSenderLabel(from, team.sessionTitle(from)) : "";
4791
+ const result = team.deliver(
4792
+ TeamRegistry.message({
4793
+ from,
4794
+ to,
4795
+ text,
4796
+ ...labelled && labelled !== from ? { fromLabel: labelled } : {}
4797
+ })
4798
+ );
4679
4799
  if (!result.ok) {
4680
4800
  return {
4681
4801
  success: false,
@@ -4684,9 +4804,17 @@ function createSendMessageTool(team) {
4684
4804
  duration: Date.now() - start
4685
4805
  };
4686
4806
  }
4807
+ if (result.status !== "running") {
4808
+ const who = result.to === LEAD_AGENT_ID ? "lead" : result.to;
4809
+ return {
4810
+ success: true,
4811
+ output: `\u5DF2\u6392\u8FDB ${who} \u7684\u6536\u4EF6\u7BB1\uFF0C\u4F46\u5B83\u73B0\u5728\u6CA1\u5728\u8DD1 \u2014\u2014 \u8FD9\u6761\u8981\u7B49\u5B83\u4E0B\u6B21\u8DD1\u8D77\u6765\u624D\u4F1A\u88AB\u8BFB\u5230\uFF0C\u4F60\u73B0\u5728\u7B49\u4E0D\u5230\u56DE\u97F3\u3002` + (result.to === LEAD_AGENT_ID ? "\u8981\u7D27\u7684\u8BDD\u4E5F\u5199\u8FDB\u4F60\u8FD9\u4E00\u8F6E\u7684\u7ED3\u8BBA\u91CC\u3002" : ""),
4812
+ duration: Date.now() - start
4813
+ };
4814
+ }
4687
4815
  return {
4688
4816
  success: true,
4689
- output: result.to === LEAD_AGENT_ID ? `\u5DF2\u9001\u5230 lead\uFF0C\u5B83\u4E0B\u4E00\u8F6E\u5F00\u5934\u4F1A\u770B\u5230\u3002` : `\u5DF2\u9001\u5230 ${result.to}\uFF08${result.status}\uFF09\uFF0C\u5B83\u4E0B\u4E00\u8F6E\u5F00\u5934\u4F1A\u770B\u5230\u3002`,
4817
+ output: result.to === LEAD_AGENT_ID ? `\u5DF2\u9001\u5230 lead\uFF0C\u5B83\u63A5\u4E0B\u6765\u7684\u6B65\u9AA4\u91CC\u4F1A\u770B\u5230\u3002` : `\u5DF2\u9001\u5230 ${result.to}\uFF0C\u5B83\u6B63\u5728\u8DD1\u7684\u90A3\u4E00\u8F6E\u4F1A\u770B\u5230\u3002`,
4690
4818
  duration: Date.now() - start
4691
4819
  };
4692
4820
  }
@@ -5107,7 +5235,8 @@ function spawnTeammate(team, manager) {
5107
5235
  "\u6D3E\u4E00\u4E2A**\u5177\u540D**\u7684\u6210\u5458\u5230\u540E\u53F0\u53BB\u5E72\u4E00\u4EF6\u6D3B\u3002\u5B83\u8DD1\u7740\u7684\u65F6\u5019\u4F60\u80FD\u7528 send_message \u8DDF\u5B83\u8BF4\u8BDD\u3002",
5108
5236
  "\u548C delegate_task \u7684\u533A\u522B\uFF1Adelegate_task \u662F\u4E00\u6B21\u6027\u7684\uFF08\u6D3E\u5B8C\u7B49\u7ED3\u8BBA\uFF0C\u4E2D\u9014\u8BF4\u4E0D\u4E0A\u8BDD\uFF09\uFF1B",
5109
5237
  "\u8FD9\u4E2A\u6D3E\u51FA\u53BB\u7684\u6210\u5458\u6709\u540D\u5B57\u3001\u5728\u540E\u53F0\u8DD1\u3001**\u4E2D\u9014\u6536\u5F97\u5230\u4F60\u7684\u6D88\u606F**\uFF0C\u4E5F\u80FD\u88AB interrupt_agent \u6253\u65AD\u3002",
5110
- "\u7528 list_agents \u770B\u73B0\u5728\u6709\u8C01\u3001\u5404\u81EA\u5728\u5E72\u4EC0\u4E48\uFF1Bteam_task_* \u90A3\u56DB\u4E2A\u5DE5\u5177\u7ED9\u5B83\u4EEC\u5206\u6D3B\u3002"
5238
+ "\u7528 list_agents \u770B\u73B0\u5728\u6709\u8C01\u3001\u5404\u81EA\u5728\u5E72\u4EC0\u4E48\uFF1Bteam_task_* \u90A3\u56DB\u4E2A\u5DE5\u5177\u7ED9\u5B83\u4EEC\u5206\u6D3B\u3002",
5239
+ "\u540C\u4E00\u4E2A\u4F1A\u8BDD\u6700\u591A\u540C\u65F6\u8DD1\u51E0\u4E2A\u6210\u5458\u662F\u6709\u4E0A\u9650\u7684\uFF08list_agents \u91CC\u6570 running \u90A3\u51E0\u6761\uFF09\uFF0C\u6EE1\u4E86\u4F1A\u6D3E\u4E0D\u51FA\u53BB \u2014\u2014 \u7B49\u4E00\u4E2A\u6536\u5DE5\uFF0C\u6216\u8005\u5148 interrupt_agent \u6536\u6389\u4E00\u4E2A\u3002"
5111
5240
  ].join("\n"),
5112
5241
  parameters: {
5113
5242
  type: "object",
@@ -5211,7 +5340,9 @@ function listAgents(team) {
5211
5340
  const self = team.bySession(ctx.sessionId);
5212
5341
  const scopeParent = self?.parentSessionId ?? ctx.sessionId;
5213
5342
  const members = showAll ? team.list() : team.list().filter((m) => m.parentSessionId === scopeParent);
5214
- const others = showAll ? team.sessionIds().filter((id) => id !== ctx.sessionId).map((id) => `- ${id} [\u4F1A\u8BDD] running \u2014 \u53E6\u4E00\u6BB5\u4E3B\u4F1A\u8BDD`) : [];
5343
+ const others = showAll ? team.sessionIds().filter((id) => id !== ctx.sessionId).map(
5344
+ (id) => `- ${id} [\u4F1A\u8BDD] ${team.isSessionActive(id) ? "running" : "idle"} \u2014 \u53E6\u4E00\u6BB5\u4E3B\u4F1A\u8BDD`
5345
+ ) : [];
5215
5346
  if (members.length === 0 && others.length === 0) {
5216
5347
  return ok3(
5217
5348
  showAll ? `\u8FD8\u6CA1\u6709\u4EFB\u4F55\u6210\u5458\u6216\u522B\u7684\u4F1A\u8BDD\u3002\u7528 spawn_teammate \u6216 delegate_task \u6D3E\u4E00\u4E2A\u3002` : `\u672C\u4F1A\u8BDD\u8FD8\u6CA1\u6D3E\u51FA\u4EFB\u4F55\u6210\u5458\u3002\u7528 spawn_teammate \u6216 delegate_task \u6D3E\u4E00\u4E2A\uFF0C\u6216\u52A0 --all \u770B\u6240\u6709\u4F1A\u8BDD\u3002`
@@ -5493,10 +5624,13 @@ function followupTask(team, manager) {
5493
5624
  return {
5494
5625
  name: "followup_task",
5495
5626
  description: [
5496
- "\u7ED9\u4E00\u4E2A**\u5DF2\u7ECF\u6536\u5DE5**\u7684\u6210\u5458\u518D\u6D3E\u4E00\u53E5\u8BDD\uFF0C\u8BA9\u5B83\u5E26\u7740\u4E0A\u4E00\u6B21\u7684\u5168\u90E8\u4E0A\u4E0B\u6587\u518D\u8DD1\u4E00\u8F6E\u3002",
5627
+ "\u53EB\u9192\u4E00\u4E2A**\u6CA1\u5728\u8DD1**\u7684\u5BF9\u65B9\uFF0C\u8BA9\u5B83\u5E26\u7740\u4E0A\u4E00\u6B21\u7684\u5168\u90E8\u4E0A\u4E0B\u6587\u518D\u8DD1\u4E00\u8F6E\u3002",
5628
+ "\u5BF9\u8C61\u53EF\u4EE5\u662F\uFF1A\u5DF2\u7ECF\u6536\u5DE5\u7684\u6210\u5458\uFF08list_agents \u91CC\u7684 agentId\uFF09\uFF0C\u6216\u8005**\u53E6\u4E00\u6BB5\u4E3B\u4F1A\u8BDD**\uFF08list_agents --all \u91CC\u7684 sessionId\uFF09\u3002",
5497
5629
  "\u548C send_message \u7684\u5206\u5DE5\uFF1Asend_message \u53EA\u5728\u5BF9\u65B9**\u6B63\u5728\u8DD1**\u7684\u65F6\u5019\u6709\u7528\uFF08\u5F53\u8F6E\u751F\u6548\uFF09\uFF1B",
5498
- "\u5BF9\u65B9\u5DF2\u7ECF\u6536\u5DE5\u4E86\u5C31\u7528\u8FD9\u4E2A \u2014\u2014 \u5B83\u63A5\u7740\u81EA\u5DF1\u90A3\u6BB5\u4F1A\u8BDD\u7EE7\u7EED\uFF0C\u4E0D\u662F\u4ECE\u96F6\u5F00\u59CB\u3002",
5499
- "\u4E00\u6B21\u5524\u9192 = \u4E00\u6B21\u5B8C\u6574\u7684\u6A21\u578B\u8C03\u7528\uFF08\u5168\u91CF\u5386\u53F2\u91CD\u53D1\uFF09\uFF0C\u80FD\u4E00\u6B21\u8BF4\u5B8C\u5C31\u522B\u62C6\u6210\u4E09\u6B21\u3002"
5630
+ "\u5BF9\u65B9\u6CA1\u5728\u8DD1\u5C31\u7528\u8FD9\u4E2A \u2014\u2014 \u5B83\u63A5\u7740\u81EA\u5DF1\u90A3\u6BB5\u4F1A\u8BDD\u7EE7\u7EED\uFF0C\u4E0D\u662F\u4ECE\u96F6\u5F00\u59CB\u3002",
5631
+ "\u53EB\u9192\u662F\u5F02\u6B65\u7684\uFF1A\u5DE5\u5177\u4E00\u8FD4\u56DE\u5C31\u7B97\u5B8C\u6210\uFF0C\u5B83\u81EA\u5DF1\u90A3\u4E00\u8F6E\u5728\u540E\u53F0\u8DD1\uFF0C\u4E0D\u7528\u7B49\u5B83\u7B54\u5B8C\u3002",
5632
+ "\u4E00\u6B21\u5524\u9192 = \u4E00\u6B21\u5B8C\u6574\u7684\u6A21\u578B\u8C03\u7528\uFF08\u5168\u91CF\u5386\u53F2\u91CD\u53D1\uFF09\uFF0C\u80FD\u4E00\u6B21\u8BF4\u5B8C\u5C31\u522B\u62C6\u6210\u4E09\u6B21\u3002",
5633
+ "\u540C\u65F6\u88AB\u53EB\u9192\u7684\u4F1A\u8BDD\u662F\u6709\u4E0A\u9650\u7684\uFF08\u9ED8\u8BA4 3 \u6BB5\uFF09\uFF0C\u8FDE\u7740\u53EB\u7B2C\u56DB\u6BB5\u4F1A\u88AB\u62D2 \u2014\u2014 \u7B49\u4E00\u6BB5\u8DD1\u5B8C\u518D\u53EB\u3002"
5500
5634
  ].join("\n"),
5501
5635
  parameters: {
5502
5636
  type: "object",
@@ -5523,40 +5657,64 @@ function followupTask(team, manager) {
5523
5657
  if (!agentId) return err2(7205, "\u7F3A\u5C11 agentId");
5524
5658
  if (!message) return err2(7206, "\u7F3A\u5C11 message");
5525
5659
  const member = team.get(agentId);
5526
- if (!member) {
5527
- return err2(7207, `\u6CA1\u6709\u8FD9\u4E2A\u6210\u5458\uFF1A${agentId}`, "\u7528 list_agents \u770B\u5F53\u524D\u6709\u8C01");
5660
+ if (member) {
5661
+ if (member.status === "running") {
5662
+ return err2(
5663
+ 7208,
5664
+ `${agentId} \u6B63\u5728\u8DD1\uFF0C\u4E0D\u9700\u8981\u5524\u9192`,
5665
+ "\u73B0\u5728\u7ED9\u5B83\u8BF4\u8BDD\u7528 send_message \u2014\u2014 \u90A3\u6761\u4F1A\u63D2\u5230\u5B83\u4E0B\u4E00\u4E2A\u6B65\u9AA4\u8FB9\u754C\uFF0C\u5F53\u8F6E\u5C31\u751F\u6548"
5666
+ );
5667
+ }
5668
+ const r = await manager.delegate(
5669
+ {
5670
+ tasks: [
5671
+ {
5672
+ goal: message,
5673
+ agentId,
5674
+ resumeSessionId: member.sessionId,
5675
+ ...member.role ? { role: member.role } : {}
5676
+ }
5677
+ ],
5678
+ background: true,
5679
+ max_concurrent: 1
5680
+ },
5681
+ ctx.sessionId,
5682
+ ctx.signal
5683
+ );
5684
+ if (!r.success) return { ...err2(7209, r.output), duration: Date.now() - start };
5685
+ return ok3(
5686
+ [
5687
+ `\u5DF2\u5524\u9192 ${agentId}\uFF08\u540E\u53F0\u4F5C\u4E1A ${r.jobId ?? "(\u65E0)"}\uFF09\uFF0C\u5B83\u5E26\u7740\u4E0A\u4E00\u6B21\u7684\u4E0A\u4E0B\u6587\u63A5\u7740\u5E72\u3002`,
5688
+ `\u770B\u5B83\u5E72\u5230\u54EA\u513F\u4E86\uFF1Atask_output ${r.jobId ?? ""} \u6216 list_agents`
5689
+ ].join("\n"),
5690
+ start
5691
+ );
5528
5692
  }
5529
- if (member.status === "running") {
5530
- return err2(
5531
- 7208,
5532
- `${agentId} \u6B63\u5728\u8DD1\uFF0C\u4E0D\u9700\u8981\u5524\u9192`,
5533
- "\u73B0\u5728\u7ED9\u5B83\u8BF4\u8BDD\u7528 send_message \u2014\u2014 \u90A3\u6761\u4F1A\u63D2\u5230\u5B83\u4E0B\u4E00\u4E2A\u6B65\u9AA4\u8FB9\u754C\uFF0C\u5F53\u8F6E\u5C31\u751F\u6548"
5693
+ if (team.sessionExists(agentId)) {
5694
+ if (team.isSessionActive(agentId)) {
5695
+ return err2(
5696
+ 7210,
5697
+ `${agentId} \u6B63\u5728\u8DD1\uFF0C\u4E0D\u9700\u8981\u5524\u9192`,
5698
+ "\u73B0\u5728\u7ED9\u5B83\u8BF4\u8BDD\u7528 send_message \u2014\u2014 \u90A3\u6761\u4F1A\u8FDB\u5B83\u6B63\u5728\u8DD1\u7684\u90A3\u4E00\u8F6E"
5699
+ );
5700
+ }
5701
+ const self = team.bySession(ctx.sessionId);
5702
+ const from = self ? self.agentId : ctx.sessionId;
5703
+ const fromLabel = self ? void 0 : sessionSenderLabel(from, team.sessionTitle(from));
5704
+ const r = await team.wakeSession(
5705
+ agentId,
5706
+ agentMessageLine({ from, text: message, ...fromLabel ? { fromLabel } : {} })
5707
+ );
5708
+ if (!r.ok) return { ...err2(7211, r.reason ?? "\u5524\u9192\u5931\u8D25"), duration: Date.now() - start };
5709
+ return ok3(
5710
+ [
5711
+ `\u5DF2\u628A\u4F1A\u8BDD ${agentId} \u53EB\u8D77\u6765\u8DD1\u4E00\u8F6E\uFF08\u4E0D\u7B49\u5B83\u7B54\u5B8C\uFF0C\u5B83\u81EA\u5DF1\u90A3\u4E00\u8F6E\u5728\u540E\u53F0\u8DD1\uFF09\u3002`,
5712
+ `\u770B\u5B83\u7B54\u4E86\u4EC0\u4E48\uFF1Asession_messages_read ${agentId}\uFF1B\u6216\u8005\u7B49\u5B83\u7ED9\u4F60\u56DE\u6D88\u606F\u3002`
5713
+ ].join("\n"),
5714
+ start
5534
5715
  );
5535
5716
  }
5536
- const r = await manager.delegate(
5537
- {
5538
- tasks: [
5539
- {
5540
- goal: message,
5541
- agentId,
5542
- resumeSessionId: member.sessionId,
5543
- ...member.role ? { role: member.role } : {}
5544
- }
5545
- ],
5546
- background: true,
5547
- max_concurrent: 1
5548
- },
5549
- ctx.sessionId,
5550
- ctx.signal
5551
- );
5552
- if (!r.success) return { ...err2(7209, r.output), duration: Date.now() - start };
5553
- return ok3(
5554
- [
5555
- `\u5DF2\u5524\u9192 ${agentId}\uFF08\u540E\u53F0\u4F5C\u4E1A ${r.jobId ?? "(\u65E0)"}\uFF09\uFF0C\u5B83\u5E26\u7740\u4E0A\u4E00\u6B21\u7684\u4E0A\u4E0B\u6587\u63A5\u7740\u5E72\u3002`,
5556
- `\u770B\u5B83\u5E72\u5230\u54EA\u513F\u4E86\uFF1Atask_output ${r.jobId ?? ""} \u6216 list_agents`
5557
- ].join("\n"),
5558
- start
5559
- );
5717
+ return err2(7207, `\u6CA1\u6709\u8FD9\u4E2A\u6210\u5458\u6216\u4F1A\u8BDD\uFF1A${agentId}`, "\u7528 list_agents --all \u770B\u5F53\u524D\u6709\u8C01");
5560
5718
  }
5561
5719
  };
5562
5720
  }
@@ -5839,6 +5997,14 @@ var SessionQueries = class {
5839
5997
  if (!meta) return { authorized: false, title: "", before: [], after: [], total: 0 };
5840
5998
  const total = this.db.prepare(`SELECT count(*) AS n FROM messages WHERE session_id = @sid`).get({ sid: input.sessionId }).n;
5841
5999
  const base2 = { authorized: true, title: meta.title, total };
6000
+ if (input.messageId === void 0) {
6001
+ return {
6002
+ ...base2,
6003
+ before: [],
6004
+ after: [],
6005
+ tail: this.tailRows(input.sessionId, input.tail ?? 0).reverse().map(toRecord)
6006
+ };
6007
+ }
5842
6008
  const anchor = this.recordRow(input.sessionId, input.messageId);
5843
6009
  if (!anchor) return { ...base2, before: [], after: [] };
5844
6010
  return {
@@ -5944,6 +6110,16 @@ var SessionQueries = class {
5944
6110
  LIMIT @n`
5945
6111
  ).all({ sid: sessionId, anchor: anchorId, n });
5946
6112
  }
6113
+ tailRows(sessionId, n) {
6114
+ if (n <= 0) return [];
6115
+ return this.db.prepare(
6116
+ `SELECT id, role, content, timestamp, active, tool_name
6117
+ FROM messages
6118
+ WHERE session_id = @sid
6119
+ ORDER BY id DESC
6120
+ LIMIT @n`
6121
+ ).all({ sid: sessionId, n });
6122
+ }
5947
6123
  messageRows(safe, sessionId, limit) {
5948
6124
  const sql = (table) => `
5949
6125
  SELECT m.id, m.session_id, m.role, m.content, m.timestamp, m.active,
@@ -6076,6 +6252,8 @@ function createSessionListTool(deps) {
6076
6252
  }
6077
6253
  var DEFAULT_WINDOW = 2;
6078
6254
  var MAX_WINDOW = 10;
6255
+ var DEFAULT_TAIL = 5;
6256
+ var MAX_TAIL = MAX_WINDOW;
6079
6257
  var DEFAULT_TRACE_LIMIT = 20;
6080
6258
  var MAX_TRACE_LIMIT = 50;
6081
6259
  var BODY_BUDGET = 1500;
@@ -6108,7 +6286,7 @@ function body(text, budget) {
6108
6286
  if (flat.length <= budget) return flat;
6109
6287
  const rest = flat.length - budget;
6110
6288
  return `${flat.slice(0, budget)}
6111
- \u2026[cut ${rest} more chars \u2014 lower before/after to spend the budget on fewer messages]`;
6289
+ \u2026[cut ${rest} more chars \u2014 narrow the window (before / after / tail) to spend the budget on fewer messages]`;
6112
6290
  }
6113
6291
  function surfaceOf(record, isCurrent) {
6114
6292
  if (!isCurrent) return record.surface === "active" ? "active there" : "compacted there";
@@ -6121,7 +6299,21 @@ function renderRecord(record, mark, budget, isCurrent) {
6121
6299
  ` ${body(record.content, budget).split("\n").join("\n ")}`
6122
6300
  ].join("\n");
6123
6301
  }
6302
+ function tailBudgetOf(count) {
6303
+ return Math.max(MIN_BODY, Math.floor(BODY_BUDGET / Math.max(1, count)));
6304
+ }
6305
+ function renderTail(out, sessionId, isCurrent) {
6306
+ const tail = out.tail ?? [];
6307
+ const head = [
6308
+ `Session ${sessionId}${isCurrent ? " (this session)" : ""} \u2014 ${out.title || "(untitled)"}`,
6309
+ tail.length === 0 ? "this session has no messages." : `latest ${tail.length} of ${out.total} message(s), oldest first:`
6310
+ ];
6311
+ if (tail.length === 0) return head.join("\n");
6312
+ const budget = tailBudgetOf(tail.length);
6313
+ return [...head, "", ...tail.map((r) => renderRecord(r, " ", budget, isCurrent))].join("\n");
6314
+ }
6124
6315
  function renderWindow(out, sessionId, isCurrent) {
6316
+ if (out.tail) return renderTail(out, sessionId, isCurrent);
6125
6317
  const anchor = out.anchor;
6126
6318
  if (!anchor) return "";
6127
6319
  const count = out.before.length + out.after.length + 1;
@@ -6140,6 +6332,7 @@ function createSessionMessagesReadTool(deps) {
6140
6332
  name: SESSION_MESSAGES_READ_TOOL,
6141
6333
  description: `\u628A\u67D0\u4E00\u6761\u5386\u53F2\u6D88\u606F\u8FDE\u540C\u5B83\u524D\u540E\u51E0\u6761\u4E00\u8D77\u8BFB\u51FA\u6765 \u2014\u2014 \u68C0\u7D22\u7ED9\u7684\u662F\u7247\u6BB5\uFF0C\u8FD9\u4E2A\u7ED9\u7684\u662F\u539F\u6587\u3002
6142
6334
  sessionId + messageId \u6765\u81EA session_search / session_messages_search \u7684\u547D\u4E2D\u3002
6335
+ **\u4E0D\u4F20 messageId \u5C31\u6539\u8BFB\u8FD9\u6BB5\u4F1A\u8BDD\u6700\u8FD1\u51E0\u6761** \u2014\u2014 \u6CA1\u547D\u4E2D\u3001\u4E0D\u77E5\u9053\u4ECE\u54EA\u8BFB\u8D77\u65F6\u7528\u8FD9\u4E2A\uFF0C\u522B\u53BB\u731C id\uFF08id \u662F\u5168\u5E93\u81EA\u589E\u7684\uFF0C\u731C\u4E0D\u4E2D\uFF09\u3002
6143
6336
  before / after \u5404\u9ED8\u8BA4 ${DEFAULT_WINDOW}\u3001\u4E0A\u9650 ${MAX_WINDOW}\uFF08\u4F20\u5927\u4E86\u81EA\u52A8\u5939\u7D27\uFF0C\u4E0D\u62A5\u9519\uFF09\u3002
6144
6337
  \u6B63\u6587\u6709\u5B57\u7B26\u9884\u7B97\uFF0C\u8D85\u4E86\u4F1A\u622A\u65AD\u5E76\u660E\u8BF4\u622A\u4E86\u591A\u5C11 \u2014\u2014 \u60F3\u770B\u5168\u5C31\u628A before / after \u8C03\u5C0F\u3002
6145
6338
  \u5DF2\u7ECF\u88AB\u538B\u7F29\u76D6\u6389\u7684\u539F\u6587\u7167\u6837\u8BFB\u5F97\u5230\uFF0C\u90A3\u6B63\u662F\u8FD9\u4E2A\u5DE5\u5177\u5B58\u5728\u7684\u7406\u7531\u3002`,
@@ -6150,7 +6343,11 @@ before / after \u5404\u9ED8\u8BA4 ${DEFAULT_WINDOW}\u3001\u4E0A\u9650 ${MAX_WIND
6150
6343
  sessionId: { type: "string", description: "\u8BFB\u54EA\u6BB5\u4F1A\u8BDD\u3002\u6765\u81EA\u68C0\u7D22\u7ED3\u679C" },
6151
6344
  messageId: {
6152
6345
  type: "number",
6153
- description: "\u951A\u70B9\u6D88\u606F\u7684 id\uFF08\u68C0\u7D22\u547D\u4E2D\u91CC # \u540E\u9762\u90A3\u4E2A\u6570\u5B57\uFF09"
6346
+ description: `\u951A\u70B9\u6D88\u606F\u7684 id\uFF08\u68C0\u7D22\u547D\u4E2D\u91CC # \u540E\u9762\u90A3\u4E2A\u6570\u5B57\uFF09\u3002\u7701\u7565\u65F6\u6539\u4E3A\u8BFB\u6700\u8FD1 ${DEFAULT_TAIL} \u6761`
6347
+ },
6348
+ tail: {
6349
+ type: "number",
6350
+ description: `\u7701\u7565 messageId \u65F6\u8BFB\u6700\u8FD1\u51E0\u6761\uFF0C\u9ED8\u8BA4 ${DEFAULT_TAIL}\uFF0C\u4E0A\u9650 ${MAX_TAIL}`
6154
6351
  },
6155
6352
  before: {
6156
6353
  type: "number",
@@ -6167,7 +6364,7 @@ before / after \u5404\u9ED8\u8BA4 ${DEFAULT_WINDOW}\u3001\u4E0A\u9650 ${MAX_WIND
6167
6364
  }
6168
6365
  } : {}
6169
6366
  },
6170
- required: ["sessionId", "messageId"]
6367
+ required: ["sessionId"]
6171
6368
  };
6172
6369
  },
6173
6370
  exposure: ToolExposure.Direct,
@@ -6184,14 +6381,15 @@ before / after \u5404\u9ED8\u8BA4 ${DEFAULT_WINDOW}\u3001\u4E0A\u9650 ${MAX_WIND
6184
6381
  const start = Date.now();
6185
6382
  const sessionId = String(args["sessionId"] ?? "").trim();
6186
6383
  if (!sessionId) return Promise.resolve(fail4("sessionId must not be empty", start, 8007));
6187
- const messageId = Number(args["messageId"]);
6188
- if (!Number.isInteger(messageId) || messageId <= 0) {
6384
+ const rawId = args["messageId"];
6385
+ const messageId = rawId === void 0 || rawId === null || rawId === "" ? void 0 : Number(rawId);
6386
+ if (messageId !== void 0 && (!Number.isInteger(messageId) || messageId <= 0)) {
6189
6387
  return Promise.resolve(
6190
6388
  fail4(
6191
6389
  "messageId must be a positive integer",
6192
6390
  start,
6193
6391
  8008,
6194
- "Use the number after # from a session_search / session_messages_search hit"
6392
+ "Use the number after # from a session_search / session_messages_search hit \u2014 or omit messageId entirely to read the latest messages in that session"
6195
6393
  )
6196
6394
  );
6197
6395
  }
@@ -6199,9 +6397,10 @@ before / after \u5404\u9ED8\u8BA4 ${DEFAULT_WINDOW}\u3001\u4E0A\u9650 ${MAX_WIND
6199
6397
  try {
6200
6398
  const out = deps.queries.readMessages({
6201
6399
  sessionId,
6202
- messageId,
6400
+ ...messageId === void 0 ? {} : { messageId },
6203
6401
  before: clampWindow(args["before"], DEFAULT_WINDOW, MAX_WINDOW),
6204
6402
  after: clampWindow(args["after"], DEFAULT_WINDOW, MAX_WINDOW),
6403
+ tail: clampWindow(args["tail"], DEFAULT_TAIL, MAX_TAIL),
6205
6404
  currentSessionId: ctx.sessionId,
6206
6405
  workspaceCwd: deps.workspaceCwd,
6207
6406
  allWorkspaces
@@ -6216,13 +6415,13 @@ before / after \u5404\u9ED8\u8BA4 ${DEFAULT_WINDOW}\u3001\u4E0A\u9650 ${MAX_WIND
6216
6415
  )
6217
6416
  );
6218
6417
  }
6219
- if (!out.anchor) {
6418
+ if (messageId !== void 0 && !out.anchor) {
6220
6419
  return Promise.resolve(
6221
6420
  fail4(
6222
6421
  `session ${sessionId} has no message #${messageId} (it has ${out.total})`,
6223
6422
  start,
6224
6423
  8010,
6225
- "messageId must come from a hit in that same session \u2014 ids are not positions"
6424
+ "messageId must come from a hit in that same session \u2014 ids are not positions. Omit messageId entirely to read the latest messages instead."
6226
6425
  )
6227
6426
  );
6228
6427
  }
@@ -6355,7 +6554,9 @@ function fail5(message, start, code, suggestion) {
6355
6554
  };
6356
6555
  }
6357
6556
  function emptyHint(query) {
6358
- return belowTrigramFloor(sanitizeFtsQuery(query)) ? ` Note: every word here is shorter than ${TRIGRAM_MIN_CHARS} characters, which the substring index cannot match at all \u2014 this is "cannot search", not "not found". Retry with a longer phrase.` : " Try fewer or different words.";
6557
+ return belowTrigramFloor(sanitizeFtsQuery(query)) ? ` Note: every word here is shorter than ${TRIGRAM_MIN_CHARS} characters, which the substring index cannot match at all \u2014 this is "cannot search", not "not found". Retry with a longer phrase.` : (
6558
+ " Try a shorter phrase copied verbatim from the text you expect \u2014 matching is on a continuous substring (at least 3 characters), not on separate keywords joined together."
6559
+ );
6359
6560
  }
6360
6561
  function clampLimit2(raw) {
6361
6562
  const n = Number(raw);
@@ -6397,7 +6598,7 @@ function createSessionSearchTool(deps) {
6397
6598
  properties: {
6398
6599
  query: {
6399
6600
  type: "string",
6400
- description: "\u68C0\u7D22\u8BCD\u3002\u5F53\u666E\u901A\u6587\u672C\u5199\uFF0C\u4E0D\u8981\u5199 FTS5 \u8BED\u6CD5\uFF08\u5F15\u53F7 / \u62EC\u53F7 / AND \u4F1A\u88AB\u6E05\u6389\uFF09"
6601
+ description: "\u68C0\u7D22\u8BCD\u3002\u5F53\u666E\u901A\u6587\u672C\u5199\uFF0C\u4E0D\u8981\u5199 FTS5 \u8BED\u6CD5\uFF08\u5F15\u53F7 / \u62EC\u53F7 / AND \u4F1A\u88AB\u6E05\u6389\uFF09\u3002\n\u5339\u914D\u7684\u662F**\u539F\u6587\u91CC\u8FDE\u7EED\u51FA\u73B0\u7684\u4E00\u6BB5**\uFF08\u81F3\u5C11 3 \u4E2A\u5B57\uFF09\uFF0C\u4E0D\u662F\u5206\u8BCD \u2014\u2014 \u6284\u539F\u6587\u91CC\u8FB9\u8FDE\u7740\u7684\u51E0\u4E2A\u5B57\u6BD4\u62FC\u5173\u952E\u8BCD\u51C6\u3002"
6401
6602
  },
6402
6603
  limit: {
6403
6604
  type: "number",
@@ -6489,7 +6690,7 @@ function createSessionMessagesSearchTool(deps) {
6489
6690
  },
6490
6691
  query: {
6491
6692
  type: "string",
6492
- description: "\u68C0\u7D22\u8BCD\u3002\u5F53\u666E\u901A\u6587\u672C\u5199\uFF0C\u4E0D\u8981\u5199 FTS5 \u8BED\u6CD5"
6693
+ description: "\u68C0\u7D22\u8BCD\u3002\u5F53\u666E\u901A\u6587\u672C\u5199\uFF0C\u4E0D\u8981\u5199 FTS5 \u8BED\u6CD5\u3002\n\u5339\u914D\u7684\u662F**\u539F\u6587\u91CC\u8FDE\u7EED\u51FA\u73B0\u7684\u4E00\u6BB5**\uFF08\u81F3\u5C11 3 \u4E2A\u5B57\uFF09\uFF0C\u4E0D\u662F\u5206\u8BCD \u2014\u2014 \u6284\u539F\u6587\u91CC\u8FB9\u8FDE\u7740\u7684\u51E0\u4E2A\u5B57\u6BD4\u62FC\u5173\u952E\u8BCD\u51C6\u3002"
6493
6694
  },
6494
6695
  limit: {
6495
6696
  type: "number",
@@ -6999,7 +7200,7 @@ function matches(tool, terms) {
6999
7200
  function createToolSearchTool(deps) {
7000
7201
  return {
7001
7202
  name: "tool_search",
7002
- description: '\u6309\u5173\u952E\u8BCD\u627E\u51FA**\u5F53\u524D\u5DE5\u5177\u5217\u8868\u91CC\u6CA1\u6709**\u7684\u5DE5\u5177\uFF0C\u627E\u5230\u4E4B\u540E\u5B83\u4EEC\u5C31\u4F1A\u51FA\u73B0\u5728\u4F60\u7684\u5DE5\u5177\u5217\u8868\u91CC\u3002\n\u8FD9\u53F0\u673A\u5668\u4E0A\u63A5\u7684\u5DE5\u5177\u53EF\u80FD\u5F88\u591A\uFF08\u6BD4\u5982\u5404\u79CD MCP server\uFF09\uFF0C\u5168\u90E8\u585E\u8FDB\u5217\u8868\u4F1A\u5360\u6389\u5927\u91CF\u4E0A\u4E0B\u6587\uFF0C\u6240\u4EE5\u4E0D\u5E38\u7528\u7684\u90A3\u4E9B\u9ED8\u8BA4\u4E0D\u5728\u91CC\u9762 \u2014\u2014 \u9700\u8981\u65F6\u7528\u8FD9\u4E2A\u5DE5\u5177\u628A\u5B83\u4EEC\u627E\u51FA\u6765\u3002\n\u67E5\u8BE2\u8BCD\u5199\u4F60\u60F3\u5E72\u7684\u4E8B\u6216\u76EE\u6807\u7CFB\u7EDF\uFF0C\u6BD4\u5982 "github issue"\u3001"\u6570\u636E\u5E93 \u67E5\u8BE2"\u3002\u591A\u4E2A\u8BCD\u662F\u300C\u90FD\u8981\u547D\u4E2D\u300D\uFF0C\u5148\u5199\u5BBD\u4E00\u70B9\u518D\u6536\u7A84\u3002\n\u26A0\uFE0F \u627E\u5230\u4E4B\u540E**\u4E0D\u8981\u5728\u8FD9\u4E00\u8F6E\u91CC\u8C03\u5B83** \u2014\u2014 \u5B83\u8981\u5230\u4F60\u7684\u4E0B\u4E00\u6B21\u53D1\u8A00\u624D\u771F\u6B63\u51FA\u73B0\u5728\u5DE5\u5177\u5217\u8868\u91CC\uFF0C\u76F4\u63A5\u8C03\u4F1A\u5931\u8D25\u3002',
7203
+ description: '\u6309\u5173\u952E\u8BCD\u627E\u51FA**\u5F53\u524D\u5DE5\u5177\u5217\u8868\u91CC\u6CA1\u6709**\u7684\u5DE5\u5177\uFF0C\u627E\u5230\u4E4B\u540E\u5B83\u4EEC\u5C31\u4F1A\u51FA\u73B0\u5728\u4F60\u7684\u5DE5\u5177\u5217\u8868\u91CC\u3002\n\u8FD9\u53F0\u673A\u5668\u4E0A\u63A5\u7684\u5DE5\u5177\u53EF\u80FD\u5F88\u591A\uFF08\u6BD4\u5982\u5404\u79CD MCP server\uFF09\uFF0C\u5168\u90E8\u585E\u8FDB\u5217\u8868\u4F1A\u5360\u6389\u5927\u91CF\u4E0A\u4E0B\u6587\uFF0C\u6240\u4EE5\u4E0D\u5E38\u7528\u7684\u90A3\u4E9B\u9ED8\u8BA4\u4E0D\u5728\u91CC\u9762 \u2014\u2014 \u9700\u8981\u65F6\u7528\u8FD9\u4E2A\u5DE5\u5177\u628A\u5B83\u4EEC\u627E\u51FA\u6765\u3002\n\u67E5\u8BE2\u8BCD\u5199\u4F60\u60F3\u5E72\u7684\u4E8B\u6216\u76EE\u6807\u7CFB\u7EDF\uFF0C\u6BD4\u5982 "github issue"\u3001"\u6570\u636E\u5E93 \u67E5\u8BE2"\u3002\u591A\u4E2A\u8BCD\u662F\u300C\u90FD\u8981\u547D\u4E2D\u300D\uFF0C\u5148\u5199\u5BBD\u4E00\u70B9\u518D\u6536\u7A84\u3002\n\u26A0\uFE0F \u627E\u5230\u4E4B\u540E**\u4E0D\u8981\u505C\u4E0B\u6765\u7B49\u7528\u6237** \u2014\u2014 \u7D27\u63A5\u7740\u518D\u53D1\u8D77\u4E00\u6B21\u8BF7\u6C42\uFF0C\u5B83\u4EEC\u5C31\u5DF2\u7ECF\u5728\u4F60\u7684\u5DE5\u5177\u5217\u8868\u91CC\u4E86\uFF1B\n\u552F\u4E00\u505A\u4E0D\u5230\u7684\u662F\u548C `tool_search` \u5728**\u540C\u4E00\u6B21\u54CD\u5E94\u91CC**\u5E76\u884C\u8C03\u5B83\u4EEC\uFF08\u53D1\u8FD9\u6B21\u8BF7\u6C42\u65F6\u5B83\u4EEC\u8FD8\u4E0D\u5728\u5217\u8868\u91CC\uFF09\u3002',
7003
7204
  parameters: {
7004
7205
  type: "object",
7005
7206
  properties: {
@@ -7040,7 +7241,7 @@ function createToolSearchTool(deps) {
7040
7241
  (${hits.length - picked.length} more matched but were not added \u2014 narrow the query if the tool you want is missing.)` : "";
7041
7242
  return Promise.resolve({
7042
7243
  success: true,
7043
- output: `Added ${picked.length} tool(s) to your tool list. They become callable on your next turn \u2014 do not call them in this one.
7244
+ output: `Added ${picked.length} tool(s) to your tool list. They are callable on your **next request** \u2014 the next step of this same turn. The only thing you cannot do is call them in the same response that ran this search. Do not stop and wait for the user.
7044
7245
 
7045
7246
  ${lines.join("\n")}${truncated}`,
7046
7247
  duration: Date.now() - start
@@ -14355,7 +14556,10 @@ function outputText(output) {
14355
14556
  function failureText(r) {
14356
14557
  const detail = r.error?.message?.trim() || outputText(r.output).trim();
14357
14558
  if (!detail) return "\u5DE5\u5177\u6267\u884C\u5931\u8D25\uFF08\u5DE5\u5177\u672A\u63D0\u4F9B\u539F\u56E0\uFF09";
14358
- return r.error?.code === void 0 ? `\u5DE5\u5177\u6267\u884C\u5931\u8D25\uFF1A${detail}` : `\u5DE5\u5177\u6267\u884C\u5931\u8D25 [${r.error.code}]: ${detail}`;
14559
+ const head = r.error?.code === void 0 ? `\u5DE5\u5177\u6267\u884C\u5931\u8D25\uFF1A${detail}` : `\u5DE5\u5177\u6267\u884C\u5931\u8D25 [${r.error.code}]: ${detail}`;
14560
+ const hint = r.error?.suggestion?.trim();
14561
+ return hint ? `${head}
14562
+ ${hint}` : head;
14359
14563
  }
14360
14564
  var ToolExecutor = class {
14361
14565
  constructor(deps) {
@@ -15007,6 +15211,7 @@ var AgentLoop = class {
15007
15211
  [GEN_AI.CONVERSATION_ID]: input.sessionId
15008
15212
  });
15009
15213
  try {
15214
+ this.config.team?.beginSessionTurn(input.sessionId);
15010
15215
  const rawHistory = (input.history ?? []).map((h) => ({
15011
15216
  role: h.role,
15012
15217
  content: h.content,
@@ -15604,6 +15809,7 @@ ${finalText}` };
15604
15809
  sessionId: input.sessionId,
15605
15810
  totalTokens: totalInput + totalOutput
15606
15811
  });
15812
+ this.config.team?.endSessionTurn(input.sessionId);
15607
15813
  runSpan.setAttribute("epoch.turns", turns.length);
15608
15814
  runSpan.setAttribute(GEN_AI.USAGE_INPUT_TOKENS, totalInput);
15609
15815
  runSpan.setAttribute(GEN_AI.USAGE_OUTPUT_TOKENS, totalOutput);
@@ -15674,7 +15880,8 @@ ${finalText}` };
15674
15880
  messages: compressed.messages.map((m) => unflattenMessage(m)),
15675
15881
  ...bill,
15676
15882
  ...compressed.carriedHead === void 0 ? {} : { carriedHead: compressed.carriedHead },
15677
- ...compressed.carriedTail === void 0 ? {} : { carriedTail: compressed.carriedTail }
15883
+ ...compressed.carriedTail === void 0 ? {} : { carriedTail: compressed.carriedTail },
15884
+ summarySkipped: compressed.summarySkipped === true
15678
15885
  };
15679
15886
  } catch {
15680
15887
  return { messages };
@@ -15943,6 +16150,11 @@ var SidebarMenuItemSchema = z.object({
15943
16150
  var SidebarNavItemSchema = SidebarMenuItemSchema.extend({
15944
16151
  primary: z.boolean().optional()
15945
16152
  });
16153
+ var TrayMenuItemSchema = SidebarMenuItemSchema.extend({
16154
+ activeLabel: z.string().min(1).optional(),
16155
+ activeIcon: z.string().min(1).optional(),
16156
+ closable: z.boolean().optional()
16157
+ });
15946
16158
  var BlankCardSchema = z.object({
15947
16159
  id: z.string().min(1),
15948
16160
  title: z.string().min(1),
@@ -16050,6 +16262,12 @@ var EpochConfigSchema = z.object({
16050
16262
  topbarMenu: z.array(SidebarMenuItemSchema).min(1).refine((items) => new Set(items.map((item) => item.id)).size === items.length, {
16051
16263
  message: "topbarMenu: id must be unique"
16052
16264
  }).optional(),
16265
+ trayMenuLeft: z.array(TrayMenuItemSchema).min(1).refine((items) => new Set(items.map((item) => item.id)).size === items.length, {
16266
+ message: "trayMenuLeft: id must be unique"
16267
+ }).optional(),
16268
+ trayMenuRight: z.array(TrayMenuItemSchema).min(1).refine((items) => new Set(items.map((item) => item.id)).size === items.length, {
16269
+ message: "trayMenuRight: id must be unique"
16270
+ }).optional(),
16053
16271
  blankCards: z.array(BlankCardSchema).min(1).refine((items) => new Set(items.map((item) => item.id)).size === items.length, {
16054
16272
  message: "blankCards: id must be unique"
16055
16273
  }).optional(),
@@ -18918,6 +19136,8 @@ var DESCRIPTIONS = {
18918
19136
  userMenuHost: "\u300C\u7528\u6237\u300D\u90A3\u4E00\u683C\u6574\u5F20\u83DC\u5355\u5F52\u5BBF\u4E3B\u81EA\u5DF1\u753B\u3002\u7F3A\u7701 false = \u7167\u65E7\u6211\u4EEC\u753B\u3002",
18919
19137
  sidebarHeadMenu: "\u5BBF\u4E3B\u81EA\u5B9A\u4E49\u7684\u4FA7\u680F\u5934\u90A3\u51E0\u679A\u56FE\u6807\u3002\u7F3A\u7701 = \u4E00\u679A\u90FD\u4E0D\u591A\uFF1B`id` \u4E0D\u8BB8\u91CD\u590D\uFF08\u90A3\u4E00\u6392\u4E0D\u5206\u91CC\u5916\uFF0C\u5199 `primary` \u4F1A\u88AB\u5265\u6389\uFF09\u3002",
18920
19138
  topbarMenu: "\u5BBF\u4E3B\u81EA\u5B9A\u4E49\u7684\u9876\u680F\u53F3\u4E0A\u56FE\u6807\u3002\u7F3A\u7701 = \u4E00\u679A\u90FD\u4E0D\u591A\uFF1B\u754C\u9762\u4E0A\u53EA\u628A\u7B2C\u4E00\u9879\u9732\u5728\u5916\u9762\uFF0C\u5176\u4F59\u6536\u8FDB\u300C\u22EF\u300D\u3002",
19139
+ trayMenuLeft: "\u5BBF\u4E3B\u81EA\u5B9A\u4E49\u7684\u6258\u76D8\u5DE6\u7AEF\u3002\u7F3A\u7701 = \u5DE6\u7AEF\u4E00\u679A\u90FD\u4E0D\u591A\uFF1B\u6BCF\u9879\u6709\u9ED8\u8BA4 / \u9009\u4E2D\u4E24\u5957\u6587\u6848\u548C\u56FE\u6807\uFF0C\u72B6\u6001\u7531\u5BBF\u4E3B\u4E0B\u53D1\u3001\u4E0D\u5728\u914D\u7F6E\u91CC\u3002",
19140
+ trayMenuRight: "\u5BBF\u4E3B\u81EA\u5B9A\u4E49\u7684\u6258\u76D8\u53F3\u7AEF\uFF08\u4E0A\u4E0B\u6587\u73AF\u4E4B\u524D\uFF09\u3002\u7F3A\u7701 = \u53F3\u7AEF\u4E00\u679A\u90FD\u4E0D\u591A\uFF1B\u5F62\u72B6\u548C\u5DE6\u7AEF\u90A3\u4E2A\u952E\u9010\u5B57\u76F8\u540C\uFF0C\u4E24\u8005\u4E92\u4E0D\u515C\u5E95\u3002",
18921
19141
  blankCards: "\u5BBF\u4E3B\u81EA\u5B9A\u4E49\u7684\u5F00\u573A\u5361\u7247\u3002\u7F3A\u7701 = \u65B0\u4F1A\u8BDD\u7A7A\u5C4F\u4E0A\u4E00\u5F20\u90FD\u6CA1\u6709\u3002",
18922
19142
  blankGreeting: "\u5BBF\u4E3B\u81EA\u5B9A\u4E49\u7684\u90A3\u53E5\u5F00\u573A\u62DB\u547C\u3002\u7F3A\u7701 = \u7528\u6211\u4EEC\u90A3\u53E5\uFF08\u548C\u4E0A\u9762\u51E0\u4E2A\u5BBF\u4E3B\u952E\u7684\u9ED8\u8BA4\u6863\u76F8\u53CD\uFF09\u3002",
18923
19143
  "blankGreeting.eyebrow": "\u62DB\u547C\u4E0A\u65B9\u90A3\u884C\u5C0F\u5B57\uFF0C\u6309\u8BED\u8A00\u7ED9\uFF08`zh` / `en`\uFF09\uFF0C\u81F3\u5C11\u7ED9\u4E00\u79CD\u3002",
@@ -22156,7 +22376,7 @@ var SessionManager = class {
22156
22376
  const lines = [
22157
22377
  `# ${meta.title || t("session_manage.export_untitled")}`,
22158
22378
  "",
22159
- t("session_manage.export_model", { model: meta.model }),
22379
+ meta.model ? t("session_manage.export_model", { model: meta.model }) : t("session_manage.export_model_unknown"),
22160
22380
  t("session_manage.export_time", { time: meta.startedAt.toISOString() }),
22161
22381
  t("session_manage.export_count", { count: messages.length }),
22162
22382
  "",
@@ -23667,6 +23887,14 @@ var MIGRATIONS4 = [
23667
23887
  up: (db) => {
23668
23888
  db.exec(`ALTER TABLE schedules DROP COLUMN max_budget_usd;`);
23669
23889
  }
23890
+ },
23891
+ {
23892
+ id: "schedule-cancel-request",
23893
+ version: 4,
23894
+ description: "\u9501\u8868\u591A\u4E00\u683C\uFF1A\u6709\u4EBA\u8BF7\u6C42\u7EC8\u6B62\u8FD9\u4E00\u6B21\u8FD0\u884C\u5417\uFF08\u534F\u4F5C\u5F0F\u53D6\u6D88\uFF0C2026-11-04\uFF09",
23895
+ up: (db) => {
23896
+ db.exec(`ALTER TABLE schedule_locks ADD COLUMN cancel_requested_at REAL;`);
23897
+ }
23670
23898
  }
23671
23899
  ];
23672
23900
  var ScheduleStore = class {
@@ -24073,7 +24301,8 @@ function acquireScheduleLock(db, scheduleId, clock2 = Date.now) {
24073
24301
  `INSERT INTO schedule_locks (schedule_id, pid, host, acquired_at, heartbeat_at)
24074
24302
  VALUES (@schedule_id, @pid, @host, @now, @now)
24075
24303
  ON CONFLICT(schedule_id) DO UPDATE SET
24076
- pid = @pid, host = @host, acquired_at = @now, heartbeat_at = @now
24304
+ pid = @pid, host = @host, acquired_at = @now, heartbeat_at = @now,
24305
+ cancel_requested_at = NULL
24077
24306
  WHERE schedule_locks.heartbeat_at < @stale`
24078
24307
  ).run({ schedule_id: scheduleId, pid, host, now, stale: now - LOCK_STALE_MS });
24079
24308
  if (info.changes === 0) {
@@ -24116,16 +24345,29 @@ function listRunningSchedules(db, clock2 = Date.now) {
24116
24345
  const now = clock2();
24117
24346
  const rows = db.prepare(
24118
24347
  `SELECT schedule_id AS scheduleId, pid, host,
24119
- acquired_at AS acquiredAt, heartbeat_at AS heartbeatAt
24348
+ acquired_at AS acquiredAt, heartbeat_at AS heartbeatAt,
24349
+ cancel_requested_at AS cancelRequestedAt
24120
24350
  FROM schedule_locks`
24121
24351
  ).all();
24122
24352
  return rows.filter((row) => isLive(row, now)).map((row) => ({
24123
24353
  scheduleId: row.scheduleId,
24124
24354
  startedAt: row.acquiredAt,
24125
24355
  pid: row.pid,
24126
- host: row.host
24356
+ host: row.host,
24357
+ ...row.cancelRequestedAt === null ? {} : { cancelRequestedAt: row.cancelRequestedAt }
24127
24358
  }));
24128
24359
  }
24360
+ function requestScheduleCancel(db, scheduleId, clock2 = Date.now) {
24361
+ const now = clock2();
24362
+ const holder = readHolder(db, scheduleId);
24363
+ if (!holder || !isLive(holder, now)) return false;
24364
+ const info = db.prepare("UPDATE schedule_locks SET cancel_requested_at = ? WHERE schedule_id = ?").run(now, scheduleId);
24365
+ return info.changes > 0;
24366
+ }
24367
+ function readCancelRequest(db, scheduleId) {
24368
+ const row = db.prepare("SELECT cancel_requested_at AS at FROM schedule_locks WHERE schedule_id = ?").get(scheduleId);
24369
+ return row?.at ?? void 0;
24370
+ }
24129
24371
  function readHolder(db, scheduleId) {
24130
24372
  const row = db.prepare(
24131
24373
  "SELECT pid, host, acquired_at AS acquiredAt, heartbeat_at AS heartbeatAt FROM schedule_locks WHERE schedule_id = ?"
@@ -28372,4 +28614,4 @@ function hasDedicatedExecContent(inv) {
28372
28614
  * `--tree` 的命令帮助里,让用户自己知道 `--tree` 意味着什么。
28373
28615
  */
28374
28616
 
28375
- export { ABOUT_DESC_MAX_CHARS, ABOUT_README_MAX_CHARS, AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, ATTACHMENT_MAX_TOTAL_BYTES, ATTACHMENT_RETENTION_DEFAULTS, AgentInbox, AgentLoop, AppearanceStore, ApprovalCache, BLOCKED_TOOLS, BOARD_TOOL_NAMES, BoardStore, BudgetGuard, BudgetStore, CHECKPOINT_MAX_TOTAL_BYTES, CLAUDE_EVENT_NAMES, CLAUDE_TOOL_NAMES, CODE_MODE_LIMITS, CODE_MODE_SDK_TAG, CONFIG_KEYS, CURRENT_CONFIG_VERSION, CheckpointManager, CheckpointStore, CodeSandbox, ComplianceEngine, ContextCompressor, DEFAULT_COMPLIANCE_ACTIONS, DEFAULT_COMPLIANCE_SETTINGS, DEFAULT_COMPRESSION_THRESHOLD, DEFAULT_GOAL_MAX_ROUNDS, DEFAULT_INBOX_CAPACITY, DEFAULT_MAX_HOLD_CHARS, DELEGATE_SESSION_SOURCE, DelegateManager, EMPTY_RULES, EPOCH_DISK_LEDGER, EpochConfigSchema, FTS_TABLES, FTS_TRIGGERS, GOAL_BLOCK_CODES, GoalService, GoalStore, HEADLESS_AUDIT_CODES, HookManager, INSTRUCTION_BUDGET_CHARS, INSTRUCTION_FILES, ImageLoadError, ImportTrustStore, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, LastOpenSessions, MARKETPLACE_DISPLAY_FIELDS, MARKETPLACE_FILE, MAX_AUDIT_ENTRIES, MAX_COMMAND_DEPTH, MAX_GOAL_MAX_ROUNDS, MAX_IMPORT_DEPTH, MAX_LAST_OPEN_SESSIONS, MAX_OBJECTIVE_CHARS, MAX_POST_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_ENTRIES_FILE, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, ManagedPolicyError, ManagedSettingsSchema, MemoryManager, ModelFailureTracker, NOMINAL_TOTAL_BYTES, NO_REVEALED_TOOLS, PACK_EXCLUDES, PERMISSION_AUDIT_CODES, PLUGIN_ICON_MAX_BYTES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_MANIFEST_KEYS, PLUGIN_NAME_PATTERN, PLUGIN_ROOT_ENV, PLUGIN_ROOT_TOKEN, PLUGIN_VISIBILITY, POLICY_DECISIONS, PROBE_VERSION, PROJECT_AGENTS_SUBDIR, PROVIDER_NO_CREDENTIAL, PermissionManager, PlanModeState, PluginAuthorSchema, PluginStore, PolicyRuleSchema, ProviderError, ProviderRouter, RECORDING_KEEP_RUNS, RECORDING_MAX_BYTES, ROLE_FRONTMATTER_SCHEMA, RUN_CODE_TOOL, RecentWorkspaces, SANDBOX_COVERS, SANDBOX_EXCLUDES, SCALAR_KEYS, SCHEDULE_DEFAULTS, SCHEDULE_DEFAULT_ALLOWLIST, SCHEDULE_ISSUE_CODES, SCHTASKS_FOLDER, SEND_MESSAGE_TOOL, SESSION_MESSAGES_READ_TOOL, SESSION_MESSAGES_SEARCH_TOOL, SESSION_QUERY_TOOLS, SESSION_SEARCH_TOOL, SESSION_TRACE_TOOL, SETTINGS_LAYER_ORDER, SETTING_WRITE_KEYS, SETTING_WRITE_LAYERS, SKILL_ASSET_DIRS, SKILL_CREATE_TOOL, SKILL_EDIT_TOOL, SKILL_FILE, SKILL_PATCH_TOOL, SKILL_VIEW_TOOL, SKILL_WRITE_FILE_TOOL, SLASH_COMMANDS_DIAG_MODULE, ScheduleRecorder, ScheduleRegistrar, ScheduleStore, SessionManager, SessionQueries, SessionReferences, SettingsFileError, SettingsFileSchema, SkillLearner, SkillSystem, TEAM_TOOL_NAMES, TOOL_SEARCH_TOOL, TaskNoticeTracker, TeamRegistry, ToolRegistry, TrackerDB, TrustManager, UNSETTABLE_USER_KEYS, Workspace, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, approvalEntryFor, approvalRootFor, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, capabilityOfRef, checkConfigValue, checkEpochVersion, checkFtsHealth, checkShadowing, classifyPersistFailure, classifyProviderError, clearModelCache, coalesceRecording, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, computeExecHash, configKeyByPath, configKeyTable, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createBoardTools, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createPluginScope, createRoleFile, createRoleScope, createRunCodeTool, createScheduleDraftTool, createSendMessageTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTeamTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, discoverySpec, displayAllows, displayCurrency, draftCommandLine, draftWidening, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, extractArchive, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, grantedPathsFor, hasDedicatedExecContent, hasExecTierContent, hasPromptCaching, hasProviderCredentials, hasReadTierContent, hasUsableModel, imageFromBase64, imageFromPath, imagePartTokens, importParts, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryProjectExtensions, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isTransientPersistFailure, isValidInterval, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listEntryModels, listRunningSchedules, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadModelEntries, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mentionsPluginRoot, mergeHeadlessPolicy, mergeRoles, mergeSchedulePatch, microsToUsd, modelEntriesPath, modelListCandidates, needsAllowlist, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, normalizeModelEntry, normalizeTrigger, offloadOldestImages, openArtifact, originOf, packFileName, packPlugin, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelEntry, parseModelList, parseRoleDefinition, parseScheduleDraft, parseSkillFrontmatter, parseTrigger, pendingImageTokens, persistFailureCode, persistParts, persistToolResults, persistedUsage, planPack, previewSkillImport, pricingFor, projectEntryForDisplay, pruneArtifacts, pruneAttachments, pruneRecordings, pruneSchedules, readEntryKey, readImageSize, readMarketplaces, readPluginAbout, readPluginIcon, readPluginManifest, readPluginRecords, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeRecordings, removeRoleFile, removeSessionArtifacts, removeSessionAttachments, renderImportTree, renderProjectContext, renderSdkDeclaration, renderSelfIndex, repairSchedules, requestImageBytes, resolveArtifactRetention, resolveCodeModeWorker, resolveComplianceDirs, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolvePricingAt, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveTar, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand2 as runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, saveModelEntries, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setDisplayCurrency, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteApply, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, substitutePluginRoot, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, testModelEntry, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, unsetUserSetting, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writableConfigKeys, writeSettingValue };
28617
+ export { ABOUT_DESC_MAX_CHARS, ABOUT_README_MAX_CHARS, AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, ATTACHMENT_MAX_TOTAL_BYTES, ATTACHMENT_RETENTION_DEFAULTS, AgentInbox, AgentLoop, AppearanceStore, ApprovalCache, BLOCKED_TOOLS, BOARD_TOOL_NAMES, BoardStore, BudgetGuard, BudgetStore, CHECKPOINT_MAX_TOTAL_BYTES, CLAUDE_EVENT_NAMES, CLAUDE_TOOL_NAMES, CODE_MODE_LIMITS, CODE_MODE_SDK_TAG, CONFIG_KEYS, CURRENT_CONFIG_VERSION, CheckpointManager, CheckpointStore, CodeSandbox, ComplianceEngine, ContextCompressor, DEFAULT_COMPLIANCE_ACTIONS, DEFAULT_COMPLIANCE_SETTINGS, DEFAULT_COMPRESSION_THRESHOLD, DEFAULT_GOAL_MAX_ROUNDS, DEFAULT_INBOX_CAPACITY, DEFAULT_MAX_HOLD_CHARS, DEFAULT_MAX_RUNNING_MEMBERS, DEFAULT_MAX_WOKEN_SESSIONS, DELEGATE_SESSION_SOURCE, DelegateManager, EMPTY_RULES, EPOCH_DISK_LEDGER, EpochConfigSchema, FTS_TABLES, FTS_TRIGGERS, GOAL_BLOCK_CODES, GoalService, GoalStore, HEADLESS_AUDIT_CODES, HookManager, INSTRUCTION_BUDGET_CHARS, INSTRUCTION_FILES, ImageLoadError, ImportTrustStore, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, LastOpenSessions, MARKETPLACE_DISPLAY_FIELDS, MARKETPLACE_FILE, MAX_AUDIT_ENTRIES, MAX_COMMAND_DEPTH, MAX_GOAL_MAX_ROUNDS, MAX_IMPORT_DEPTH, MAX_LAST_OPEN_SESSIONS, MAX_OBJECTIVE_CHARS, MAX_POST_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_ENTRIES_FILE, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, ManagedPolicyError, ManagedSettingsSchema, MemoryManager, ModelFailureTracker, NOMINAL_TOTAL_BYTES, NO_REVEALED_TOOLS, PACK_EXCLUDES, PERMISSION_AUDIT_CODES, PLUGIN_ICON_MAX_BYTES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_MANIFEST_KEYS, PLUGIN_NAME_PATTERN, PLUGIN_ROOT_ENV, PLUGIN_ROOT_TOKEN, PLUGIN_VISIBILITY, POLICY_DECISIONS, PROBE_VERSION, PROJECT_AGENTS_SUBDIR, PROVIDER_NO_CREDENTIAL, PermissionManager, PlanModeState, PluginAuthorSchema, PluginStore, PolicyRuleSchema, ProviderError, ProviderRouter, RECORDING_KEEP_RUNS, RECORDING_MAX_BYTES, ROLE_FRONTMATTER_SCHEMA, RUN_CODE_TOOL, RecentWorkspaces, SANDBOX_COVERS, SANDBOX_EXCLUDES, SCALAR_KEYS, SCHEDULE_DEFAULTS, SCHEDULE_DEFAULT_ALLOWLIST, SCHEDULE_ISSUE_CODES, SCHTASKS_FOLDER, SEND_MESSAGE_TOOL, SESSION_MESSAGES_READ_TOOL, SESSION_MESSAGES_SEARCH_TOOL, SESSION_QUERY_TOOLS, SESSION_SEARCH_TOOL, SESSION_TRACE_TOOL, SETTINGS_LAYER_ORDER, SETTING_WRITE_KEYS, SETTING_WRITE_LAYERS, SKILL_ASSET_DIRS, SKILL_CREATE_TOOL, SKILL_EDIT_TOOL, SKILL_FILE, SKILL_PATCH_TOOL, SKILL_VIEW_TOOL, SKILL_WRITE_FILE_TOOL, SLASH_COMMANDS_DIAG_MODULE, ScheduleRecorder, ScheduleRegistrar, ScheduleStore, SessionManager, SessionQueries, SessionReferences, SettingsFileError, SettingsFileSchema, SkillLearner, SkillSystem, TEAM_TOOL_NAMES, TOOL_SEARCH_TOOL, TaskNoticeTracker, TeamRegistry, ToolRegistry, TrackerDB, TrustManager, UNSETTABLE_USER_KEYS, Workspace, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, approvalEntryFor, approvalRootFor, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, capabilityOfRef, checkConfigValue, checkEpochVersion, checkFtsHealth, checkShadowing, classifyPersistFailure, classifyProviderError, clearModelCache, coalesceRecording, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, computeExecHash, configKeyByPath, configKeyTable, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createBoardTools, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createPluginScope, createRoleFile, createRoleScope, createRunCodeTool, createScheduleDraftTool, createSendMessageTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTeamTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, discoverySpec, displayAllows, displayCurrency, draftCommandLine, draftWidening, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, extractArchive, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, grantedPathsFor, hasDedicatedExecContent, hasExecTierContent, hasPromptCaching, hasProviderCredentials, hasReadTierContent, hasUsableModel, imageFromBase64, imageFromPath, imagePartTokens, importParts, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryProjectExtensions, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isTransientPersistFailure, isValidInterval, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listEntryModels, listRunningSchedules, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadModelEntries, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mentionsPluginRoot, mergeHeadlessPolicy, mergeRoles, mergeSchedulePatch, microsToUsd, modelEntriesPath, modelListCandidates, needsAllowlist, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, normalizeModelEntry, normalizeTrigger, offloadOldestImages, openArtifact, originOf, packFileName, packPlugin, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelEntry, parseModelList, parseRoleDefinition, parseScheduleDraft, parseSkillFrontmatter, parseTrigger, pendingImageTokens, persistFailureCode, persistParts, persistToolResults, persistedUsage, planPack, previewSkillImport, pricingFor, projectEntryForDisplay, pruneArtifacts, pruneAttachments, pruneRecordings, pruneSchedules, readCancelRequest, readEntryKey, readImageSize, readMarketplaces, readPluginAbout, readPluginIcon, readPluginManifest, readPluginRecords, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeRecordings, removeRoleFile, removeSessionArtifacts, removeSessionAttachments, renderImportTree, renderProjectContext, renderSdkDeclaration, renderSelfIndex, repairSchedules, requestImageBytes, requestScheduleCancel, resolveArtifactRetention, resolveCodeModeWorker, resolveComplianceDirs, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolvePricingAt, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveTar, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand2 as runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, saveModelEntries, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setDisplayCurrency, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteApply, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, substitutePluginRoot, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, testModelEntry, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, unsetUserSetting, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writableConfigKeys, writeSettingValue };