@sema-agent/client-core 0.98.0 → 0.100.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.
Files changed (236) hide show
  1. package/CHANGELOG.md +376 -0
  2. package/README.md +61 -35
  3. package/dist/adapt/arms.js +120 -55
  4. package/dist/adapt/panelTasks.d.ts +3 -2
  5. package/dist/adapt/panelTasks.js +34 -11
  6. package/dist/adapt/textStream.d.ts +1 -1
  7. package/dist/adapt/textStream.js +51 -28
  8. package/dist/adapter/activeRunSelfHeal.d.ts +11 -3
  9. package/dist/adapter/activeRunSelfHeal.js +210 -294
  10. package/dist/adapter/downstream/eventToSdkMessage.d.ts +25 -6
  11. package/dist/adapter/downstream/eventToSdkMessage.js +176 -12
  12. package/dist/adapter/downstream/terminalToSdkResult.js +10 -0
  13. package/dist/adapter/downstream/wiringManifestView.d.ts +3 -1
  14. package/dist/adapter/downstream/wiringManifestView.js +1 -0
  15. package/dist/adapter/runStream.js +82 -40
  16. package/dist/adapter/types.d.ts +2 -0
  17. package/dist/adapter/types.js +2 -1
  18. package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
  19. package/dist/agentsWireCaps.d.ts +7 -3
  20. package/dist/agentsWireCaps.js +133 -39
  21. package/dist/cloudConfigWireCaps.d.ts +10 -1
  22. package/dist/cloudConfigWireCaps.js +181 -65
  23. package/dist/compactionStatus.d.ts +34 -0
  24. package/dist/compactionStatus.js +196 -0
  25. package/dist/controlRouter.d.ts +4 -2
  26. package/dist/controlRouter.js +39 -51
  27. package/dist/coreValuePorts.d.ts +26 -1
  28. package/dist/coreValuePorts.js +10 -0
  29. package/dist/corruptSessionCopy.d.ts +2 -1
  30. package/dist/corruptSessionCopy.js +3 -3
  31. package/dist/decideFailureNote.js +3 -3
  32. package/dist/declared/supportFloorDeclared.js +1 -1
  33. package/dist/detachWire.js +3 -2
  34. package/dist/devicesFace.d.ts +34 -0
  35. package/dist/devicesFace.js +90 -0
  36. package/dist/displayUntrusted.d.ts +1 -0
  37. package/dist/displayUntrusted.js +153 -5
  38. package/dist/engineAgentPanelStore.d.ts +14 -4
  39. package/dist/engineAgentPanelStore.js +14 -0
  40. package/dist/engineCapReader.d.ts +2 -1
  41. package/dist/engineCapReader.js +7 -5
  42. package/dist/engineCapsCache.d.ts +8 -0
  43. package/dist/engineCapsCache.js +59 -6
  44. package/dist/engineCapsChange.d.ts +2 -0
  45. package/dist/engineCapsChange.js +9 -0
  46. package/dist/engineErrorCodes.d.ts +11 -2
  47. package/dist/engineErrorCodes.js +11 -12
  48. package/dist/engineRowRef.js +4 -0
  49. package/dist/engineSessionMessages.d.ts +1 -0
  50. package/dist/engineSessionMessages.js +7 -1
  51. package/dist/engineTargetSeat.d.ts +27 -0
  52. package/dist/engineTargetSeat.js +199 -0
  53. package/dist/engineToolDirectory.d.ts +3 -0
  54. package/dist/engineToolDirectory.js +4 -2
  55. package/dist/engineWireFor.js +3 -8
  56. package/dist/env/uiLanguage.d.ts +2 -1
  57. package/dist/env/uiLanguage.js +3 -2
  58. package/dist/eventLeg.d.ts +7 -5
  59. package/dist/eventLeg.js +68 -49
  60. package/dist/fileHistoryCaptureCapability.d.ts +2 -4
  61. package/dist/fileHistoryCaptureCapability.js +12 -22
  62. package/dist/fileHistoryLegNotice.d.ts +2 -1
  63. package/dist/fileHistoryLegNotice.js +3 -3
  64. package/dist/frameBinding.d.ts +3 -0
  65. package/dist/frameBinding.js +12 -0
  66. package/dist/gateOutcome.js +16 -2
  67. package/dist/gateVocabulary.d.ts +8 -7
  68. package/dist/gateVocabulary.js +71 -73
  69. package/dist/generated/engineFactTables.d.ts +18 -1
  70. package/dist/generated/engineFactTables.js +56 -0
  71. package/dist/generated/engineNoticeTables.js +12 -3
  72. package/dist/generated/settingsSchemaFns.d.ts +18 -0
  73. package/dist/generated/settingsSchemaFns.js +70 -0
  74. package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
  75. package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
  76. package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -0
  77. package/dist/generated/settingsSchemaMcpRequestEntry.js +162 -0
  78. package/dist/generated/settingsSchemaTables.d.ts +2 -0
  79. package/dist/generated/settingsSchemaTables.js +9 -0
  80. package/dist/generated/settingsSchemaTypes.d.ts +133 -0
  81. package/dist/generated/settingsSchemaTypes.js +1 -0
  82. package/dist/hitl/allowRuleShadow.d.ts +2 -1
  83. package/dist/hitl/allowRuleShadow.js +18 -15
  84. package/dist/hitl/approvalCardReasons.d.ts +3 -2
  85. package/dist/hitl/approvalCardReasons.js +29 -30
  86. package/dist/hitl/approvalHolds.d.ts +17 -0
  87. package/dist/hitl/approvalHolds.js +114 -29
  88. package/dist/hitl/askClassPair.d.ts +2 -2
  89. package/dist/hitl/askClassPair.js +16 -0
  90. package/dist/hitl/askGateWire.js +2 -1
  91. package/dist/hitl/askSettlementLine.d.ts +14 -4
  92. package/dist/hitl/askSettlementLine.js +67 -47
  93. package/dist/hitl/attributionLadder.d.ts +23 -0
  94. package/dist/hitl/attributionLadder.js +67 -0
  95. package/dist/hitl/automaticAnswerVerdict.d.ts +2 -1
  96. package/dist/hitl/automaticAnswerVerdict.js +8 -8
  97. package/dist/hitl/crashConvergedNotice.d.ts +5 -4
  98. package/dist/hitl/crashConvergedNotice.js +28 -41
  99. package/dist/hitl/decisionLedger.d.ts +55 -0
  100. package/dist/hitl/decisionLedger.js +156 -0
  101. package/dist/hitl/decisionRefusal.d.ts +1 -0
  102. package/dist/hitl/decisionRefusal.js +1 -1
  103. package/dist/hitl/decisionSend.d.ts +113 -0
  104. package/dist/hitl/decisionSend.js +579 -0
  105. package/dist/hitl/frameRouter.js +7 -8
  106. package/dist/hitl/hitlBridge.d.ts +1 -0
  107. package/dist/hitl/hitlBridge.js +21 -9
  108. package/dist/hitl/persistedRulesWire.d.ts +6 -5
  109. package/dist/hitl/persistedRulesWire.js +55 -73
  110. package/dist/hitl/planReviewWire.d.ts +5 -0
  111. package/dist/hitl/planReviewWire.js +53 -76
  112. package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
  113. package/dist/hitl/sessionPolicyDeliverable.js +49 -9
  114. package/dist/hitl/sessionPolicyWire.d.ts +2 -1
  115. package/dist/hitl/sessionPolicyWire.js +23 -24
  116. package/dist/hitl/suspendedReopen.d.ts +2 -1
  117. package/dist/hitl/suspendedReopen.js +7 -10
  118. package/dist/hitl/toolApprovalWire.d.ts +17 -5
  119. package/dist/hitl/toolApprovalWire.js +120 -147
  120. package/dist/hooksWireCaps.js +145 -56
  121. package/dist/host.d.ts +21 -0
  122. package/dist/hostTurnSettings.d.ts +110 -0
  123. package/dist/hostTurnSettings.js +692 -0
  124. package/dist/humanTurn.d.ts +15 -1
  125. package/dist/humanTurn.js +100 -12
  126. package/dist/humanTurnRead.d.ts +2 -0
  127. package/dist/humanTurnRead.js +22 -1
  128. package/dist/i18n/messages.en.d.ts +713 -0
  129. package/dist/i18n/messages.en.js +713 -0
  130. package/dist/i18n/messages.zh.js +854 -1
  131. package/dist/index.d.ts +45 -13
  132. package/dist/index.js +27 -9
  133. package/dist/inheritEnvCapability.d.ts +4 -2
  134. package/dist/inheritEnvCapability.js +12 -5
  135. package/dist/inheritEnvWire.d.ts +3 -2
  136. package/dist/inheritEnvWire.js +14 -16
  137. package/dist/injectionLaneNotice.d.ts +5 -0
  138. package/dist/injectionLaneNotice.js +46 -0
  139. package/dist/interactiveHalt.js +17 -6
  140. package/dist/liveModelCatalog.d.ts +2 -1
  141. package/dist/liveModelCatalog.js +14 -8
  142. package/dist/mcpPanel.d.ts +10 -1
  143. package/dist/mcpPanel.js +42 -13
  144. package/dist/mcpProbeCapability.d.ts +2 -1
  145. package/dist/mcpProbeCapability.js +7 -11
  146. package/dist/mcpProbeWire.d.ts +3 -1
  147. package/dist/mcpProbeWire.js +5 -0
  148. package/dist/mcpReconnect.js +2 -2
  149. package/dist/mcpToolToggles.d.ts +6 -0
  150. package/dist/mcpToolToggles.js +46 -0
  151. package/dist/mcpWireCaps.d.ts +43 -3
  152. package/dist/mcpWireCaps.js +194 -59
  153. package/dist/mcpWireTransport.d.ts +4 -0
  154. package/dist/mcpWireTransport.js +18 -0
  155. package/dist/memoryEntriesWire.js +5 -10
  156. package/dist/model/onboardJudgement.d.ts +93 -0
  157. package/dist/model/onboardJudgement.js +415 -0
  158. package/dist/model/tierVocabulary.d.ts +2 -0
  159. package/dist/model/tierVocabulary.js +17 -5
  160. package/dist/modelCapabilityProbe.d.ts +65 -0
  161. package/dist/modelCapabilityProbe.js +601 -0
  162. package/dist/modelIdentityResolvability.d.ts +5 -0
  163. package/dist/modelIdentityResolvability.js +49 -22
  164. package/dist/ownKey.d.ts +33 -0
  165. package/dist/ownKey.js +109 -0
  166. package/dist/panelReduce.d.ts +11 -1
  167. package/dist/panelReduce.js +95 -16
  168. package/dist/panelStateHolder.d.ts +1 -0
  169. package/dist/panelStateHolder.js +10 -1
  170. package/dist/permissionRuleIssue.d.ts +2 -1
  171. package/dist/permissionRuleIssue.js +23 -20
  172. package/dist/permissionRulesWriteCapability.d.ts +2 -1
  173. package/dist/permissionRulesWriteCapability.js +8 -6
  174. package/dist/pluginHooksWire.d.ts +46 -3
  175. package/dist/pluginHooksWire.js +220 -12
  176. package/dist/prepareRefusal.d.ts +8 -0
  177. package/dist/prepareRefusal.js +72 -0
  178. package/dist/printModelStatus.d.ts +63 -0
  179. package/dist/printModelStatus.js +155 -0
  180. package/dist/request/taskRequest.d.ts +16 -10
  181. package/dist/request/taskRequest.js +195 -58
  182. package/dist/resumeRefusalCopy.d.ts +14 -9
  183. package/dist/resumeRefusalCopy.js +89 -144
  184. package/dist/retryStatus.d.ts +55 -0
  185. package/dist/retryStatus.js +155 -19
  186. package/dist/ruleRefusalSentence.d.ts +4 -0
  187. package/dist/ruleRefusalSentence.js +58 -0
  188. package/dist/sandboxWire.d.ts +2 -1
  189. package/dist/sandboxWire.js +55 -21
  190. package/dist/scenarioRefusal.d.ts +10 -0
  191. package/dist/scenarioRefusal.js +111 -0
  192. package/dist/seam.d.ts +48 -9
  193. package/dist/seam.js +54 -5
  194. package/dist/seatContract.d.ts +272 -14
  195. package/dist/seatContract.js +711 -23
  196. package/dist/selfOrchestrationDenial.js +7 -19
  197. package/dist/sessionIdSegment.d.ts +6 -0
  198. package/dist/sessionIdSegment.js +24 -0
  199. package/dist/sessionMemoryStatus.js +6 -11
  200. package/dist/sessionPolicyCapability.d.ts +2 -1
  201. package/dist/sessionPolicyCapability.js +8 -6
  202. package/dist/settingsCredentialKeyPaths.d.ts +8 -0
  203. package/dist/settingsCredentialKeyPaths.js +219 -0
  204. package/dist/settingsHooksSalvage.d.ts +44 -0
  205. package/dist/settingsHooksSalvage.js +211 -0
  206. package/dist/skillToolListsCapability.d.ts +2 -1
  207. package/dist/skillToolListsCapability.js +8 -6
  208. package/dist/skillsWireCaps.d.ts +0 -3
  209. package/dist/skillsWireCaps.js +1 -2
  210. package/dist/sseIdleTriage.js +3 -2
  211. package/dist/subagent/engineSubagentResume.js +15 -9
  212. package/dist/subagentContentStore.d.ts +4 -0
  213. package/dist/subagentContentStore.js +157 -27
  214. package/dist/toolHistoryMismatch.js +3 -2
  215. package/dist/toolRoster.d.ts +3 -2
  216. package/dist/toolRoster.js +21 -20
  217. package/dist/toolsFlagNames.d.ts +8 -0
  218. package/dist/toolsFlagNames.js +110 -0
  219. package/dist/turnFailurePresentation.d.ts +12 -1
  220. package/dist/turnFailurePresentation.js +220 -15
  221. package/dist/usageAnalytics.js +6 -11
  222. package/dist/userAttachmentEnvelope.d.ts +1 -0
  223. package/dist/userAttachmentEnvelope.js +37 -7
  224. package/dist/userAttachmentSeat.d.ts +21 -0
  225. package/dist/userAttachmentSeat.js +75 -0
  226. package/dist/userInvokedSkillsCapability.d.ts +11 -1
  227. package/dist/userInvokedSkillsCapability.js +31 -7
  228. package/dist/wireErrorTriage.d.ts +7 -0
  229. package/dist/wireErrorTriage.js +23 -1
  230. package/dist/wireFailureShape.js +2 -1
  231. package/dist/wireRefusalCopy.d.ts +62 -16
  232. package/dist/wireRefusalCopy.js +307 -148
  233. package/dist/workflowsJournalCapability.d.ts +2 -1
  234. package/dist/workflowsJournalCapability.js +8 -6
  235. package/docs/INTEGRATION-CLIENTS.md +951 -42
  236. package/package.json +5 -5
@@ -1,5 +1,6 @@
1
1
  import { engineWireTarget } from './engineWireTarget.js';
2
2
  import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
3
+ import { msg, renderMessage } from './i18n/translate.js';
3
4
  import { ownDataField } from './ownKey.js';
4
5
  export function projectSkillToolListsCapability(caps) {
5
6
  try {
@@ -30,17 +31,18 @@ export function skillToolListsAvailable(reading) {
30
31
  return 'no';
31
32
  return 'unknown';
32
33
  }
33
- export function skillToolListsDoctorDetail(reading) {
34
+ export function skillToolListsDoctorDetail(reading, lang) {
35
+ const subject = msg('notice.capability.subject.skillToolLists');
34
36
  switch (reading.kind) {
35
37
  case 'unreadable':
36
- return unreadableReadingDetail('skill tool lists');
38
+ return unreadableReadingDetail(renderMessage(subject, lang), lang);
37
39
  case 'unobserved':
38
- return 'skill tool lists not observed — the engine reports it on /v1/capabilities (skillToolLists); this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)';
40
+ return renderMessage(msg('notice.capability.unobserved', { subject, key: 'skillToolLists' }), lang);
39
41
  case 'not_reported':
40
- return 'skill tool lists not reported by this engine — the engine predates them: tool lists on request skills are not read, so they do not limit any tool';
42
+ return renderMessage(msg('notice.capability.skillToolLists.notReported'), lang);
41
43
  case 'absent':
42
- return 'skill tool lists off on this deployment — tool lists on request skills are not read';
44
+ return renderMessage(msg('notice.capability.skillToolLists.absent'), lang);
43
45
  case 'present':
44
- return 'skill tool lists on — a request skill’s allowed and disallowed tool lists are read as this run’s rules';
46
+ return renderMessage(msg('notice.capability.skillToolLists.present'), lang);
45
47
  }
46
48
  }
@@ -1,8 +1,5 @@
1
1
  import type { SkillSpec } from '@sema-agent/sdk';
2
2
  import { type SkillToolListsReading } from './skillToolListsCapability.js';
3
- export declare const SKILL_CAPS: {
4
- readonly content: 1048576;
5
- };
6
3
  export interface SkillCmdLike {
7
4
  type?: string;
8
5
  name?: string;
@@ -1,8 +1,7 @@
1
1
  import { skillToolListsAvailable } from './skillToolListsCapability.js';
2
- export const SKILL_CAPS = { content: 1_048_576 };
3
2
  export function toCappedSpec(name, description, whenToUse, body) {
4
3
  const n = name.trim();
5
- const c = body.trim().slice(0, SKILL_CAPS.content);
4
+ const c = body.trim();
6
5
  if (!n || !c)
7
6
  return null;
8
7
  const desc = [description.trim(), whenToUse.trim()]
@@ -1,5 +1,6 @@
1
1
  import { hostEnv } from './hostEnv.js';
2
2
  import { SseIdleError, probeHealth as sdkProbeHealth } from '@sema-agent/sdk';
3
+ import { readThrownSlot, thrownIsInstanceOf } from './wireFailureShape.js';
3
4
  export const SSE_HEARTBEAT_GRACE_ENV = 'SEMA_SSE_HEARTBEAT_GRACE_MS';
4
5
  export const SSE_GRACE_MIN_MS = 5_000;
5
6
  export const SSE_GRACE_MAX_MS = 600_000;
@@ -27,9 +28,9 @@ export function engineAliveIdleElapsedMs(err) {
27
28
  return typeof e.elapsedMs === 'number' && Number.isFinite(e.elapsedMs) ? e.elapsedMs : 0;
28
29
  }
29
30
  export function isSseIdleError(err) {
30
- if (err instanceof SseIdleError)
31
+ if (thrownIsInstanceOf(err, SseIdleError))
31
32
  return true;
32
- return err?.name === 'SseIdleError';
33
+ return readThrownSlot(err, 'name', 'data') === 'SseIdleError';
33
34
  }
34
35
  export async function probeEngineAlive(baseUrl, timeoutMs = 2_000) {
35
36
  return (await sdkProbeHealth(baseUrl, timeoutMs)).alive;
@@ -1,5 +1,6 @@
1
1
  import { hostLog } from '../host.js';
2
- import { resumeRetryLaterFromError } from '../wireErrorTriage.js';
2
+ import { isNotFoundFailure, resumeRetryLaterFromError } from '../wireErrorTriage.js';
3
+ import { readThrownSlot, THROWN_SLOT_UNREADABLE } from '../wireFailureShape.js';
3
4
  import { RESUME_SESSION_NOT_FOUND } from '../engineErrorCodes.js';
4
5
  import { displayUntrusted } from '../displayUntrusted.js';
5
6
  import { engineCapTrue } from '../engineCapsCache.js';
@@ -25,15 +26,22 @@ const RETENTION_LAPSED_CODES = new Set([
25
26
  RESUME_SESSION_NOT_FOUND,
26
27
  ]);
27
28
  function shapeOf(e) {
28
- const o = (e ?? {});
29
+ const status = readThrownSlot(e ?? {}, 'status', 'data');
30
+ const errorCode = readThrownSlot(e ?? {}, 'errorCode', 'data');
31
+ const message = readThrownSlot(e ?? {}, 'message');
32
+ if (status === THROWN_SLOT_UNREADABLE || errorCode === THROWN_SLOT_UNREADABLE) {
33
+ return { message: typeof message === 'string' && message !== '' ? message : String(e), unreadable: true };
34
+ }
29
35
  return {
30
- ...(typeof o.status === 'number' ? { status: o.status } : {}),
31
- ...(typeof o.errorCode === 'string' ? { errorCode: o.errorCode } : {}),
32
- message: typeof o.message === 'string' && o.message !== '' ? o.message : String(e),
36
+ ...(typeof status === 'number' ? { status } : {}),
37
+ ...(typeof errorCode === 'string' ? { errorCode } : {}),
38
+ message: typeof message === 'string' && message !== '' ? message : String(e),
33
39
  };
34
40
  }
35
41
  export function classifySubagentResumeFailure(e) {
36
- const { status, errorCode, message } = shapeOf(e);
42
+ const { status, errorCode, message, unreadable } = shapeOf(e);
43
+ if (unreadable === true)
44
+ return { reason: 'error', detail: message };
37
45
  if (status === undefined && errorCode === undefined) {
38
46
  const noAnswer = typeof e === 'object' ? noAnswerDetailFrom(e) : null;
39
47
  if (noAnswer !== null)
@@ -63,12 +71,10 @@ export function classifySubagentResumeFailure(e) {
63
71
  return { reason: 'row-contended', detail: message };
64
72
  if (errorCode === 'resume.row_gone')
65
73
  return { reason: 'row-gone', detail: message };
66
- if (errorCode === undefined && status === 404)
74
+ if (isNotFoundFailure(e) !== false)
67
75
  return { reason: 'not-found', detail: message };
68
76
  if (errorCode === undefined && status === 400)
69
77
  return { reason: 'bad-request', detail: message };
70
- if (errorCode?.startsWith('not_found.') === true)
71
- return { reason: 'not-found', detail: message };
72
78
  return { reason: 'error', detail: message };
73
79
  }
74
80
  export function resolveOwnerRunId(childTaskId, activeRunId) {
@@ -33,6 +33,9 @@ export interface SubagentContentEvent {
33
33
  isError?: boolean | undefined;
34
34
  }
35
35
  export declare function coerceOutput(v: unknown): string | undefined;
36
+ export declare function subagentContentEventOf(ev: {
37
+ readonly type: string;
38
+ }): SubagentContentEvent | undefined;
36
39
  export interface SubagentContentStoreConfig {
37
40
  maxBytesPerTask: number;
38
41
  maxBytesTotal: number;
@@ -41,6 +44,7 @@ export declare const SUBAGENT_CONTENT_STORE_DEFAULTS: Readonly<SubagentContentSt
41
44
  export declare function configureSubagentContentStore(next: Partial<SubagentContentStoreConfig>): void;
42
45
  export declare function subagentContentStoreConfig(): SubagentContentStoreConfig;
43
46
  export declare function __resetSubagentContentStoreConfigForTests(): void;
47
+ export declare function bindSubagentIdentityReader(fn: (id: string) => readonly string[] | undefined): void;
44
48
  export declare function registerSubagentContentAlias(parentToolCallId: string, taskId: string): void;
45
49
  export declare function registerSubagentAlias(parentToolCallId: string, taskId: string): void;
46
50
  export declare function publishSubagentContentEvent(ev: SubagentContentEvent): void;
@@ -3,6 +3,28 @@ import { toolEndOutputText } from './toolResultContent.js';
3
3
  export function coerceOutput(v) {
4
4
  return toolEndOutputText(v);
5
5
  }
6
+ export function subagentContentEventOf(ev) {
7
+ const t = ev.type;
8
+ if (t !== 'text_delta' && t !== 'reasoning_delta' && t !== 'text' && t !== 'reasoning' && t !== 'tool_start' && t !== 'tool_end')
9
+ return undefined;
10
+ const sub = ev;
11
+ const parent = sub.parentToolCallId;
12
+ if (typeof parent !== 'string')
13
+ return undefined;
14
+ return {
15
+ type: sub.type,
16
+ taskId: sub.taskId ?? parent,
17
+ parentToolCallId: parent,
18
+ delta: sub.delta,
19
+ text: sub.text,
20
+ eventId: sub.eventId,
21
+ toolCallId: sub.toolCallId,
22
+ toolName: sub.toolName,
23
+ args: sub.args,
24
+ output: coerceOutput(sub.output),
25
+ isError: sub.isError,
26
+ };
27
+ }
6
28
  const MAX_ITEMS_PER_TASK = 200;
7
29
  const MAX_TASKS = 32;
8
30
  const NOTIFY_COALESCE_MS = 250;
@@ -207,8 +229,40 @@ function dropTask(key) {
207
229
  totalBytes -= s.bytes;
208
230
  tasks.delete(key);
209
231
  }
232
+ let subagentIdsReader;
233
+ export function bindSubagentIdentityReader(fn) {
234
+ subagentIdsReader = fn;
235
+ }
236
+ function sameSubagentIds(id) {
237
+ let ids;
238
+ try {
239
+ ids = subagentIdsReader?.(id);
240
+ }
241
+ catch {
242
+ ids = undefined;
243
+ }
244
+ if (ids === undefined)
245
+ return [id];
246
+ return ids.includes(id) ? ids : [...ids, id];
247
+ }
248
+ function homeKeyOf(key) {
249
+ return sameSubagentIds(key).find((id) => tasks.has(id)) ?? key;
250
+ }
251
+ function contentKeyOf(taskId) {
252
+ const ids = sameSubagentIds(taskId);
253
+ const direct = ids.find((id) => tasks.has(id));
254
+ if (direct !== undefined)
255
+ return direct;
256
+ for (const id of ids) {
257
+ const parked = taskToParent.get(id)?.card;
258
+ if (parked !== undefined && tasks.has(parked))
259
+ return parked;
260
+ }
261
+ return '';
262
+ }
210
263
  const parentToTask = new Map();
211
264
  const taskToParent = new Map();
265
+ let parentStampSeq = 0;
212
266
  let notifyListener = null;
213
267
  const pendingNotify = new Set();
214
268
  let notifyTimer = null;
@@ -361,7 +415,8 @@ function aliasContentKey(parentToolCallId, taskId) {
361
415
  export function registerSubagentAlias(parentToolCallId, taskId) {
362
416
  if (!aliasContentKey(parentToolCallId, taskId))
363
417
  return;
364
- taskToParent.set(taskId, parentToolCallId);
418
+ if (taskToParent.get(taskId)?.card !== parentToolCallId)
419
+ taskToParent.set(taskId, { card: parentToolCallId, stamp: ++parentStampSeq });
365
420
  }
366
421
  function replaySeen(s, ev) {
367
422
  const id = ev.eventId;
@@ -437,7 +492,7 @@ function canonicalKey(ev) {
437
492
  return parentToTask.get(ev.parentToolCallId) ?? ev.parentToolCallId;
438
493
  }
439
494
  export function publishSubagentContentEvent(ev) {
440
- const key = canonicalKey(ev);
495
+ const key = homeKeyOf(canonicalKey(ev));
441
496
  const s = stateFor(key, ev.parentToolCallId);
442
497
  switch (ev.type) {
443
498
  case 'text_delta':
@@ -539,15 +594,17 @@ export function publishSubagentContentEvent(ev) {
539
594
  scheduleNotify(key);
540
595
  }
541
596
  export function pushSubagentLocalEcho(taskId, text) {
542
- const s = stateFor(taskId, tasks.get(taskId)?.parentToolCallId ?? '');
597
+ const known = contentKeyOf(taskId);
598
+ const key = known !== '' ? known : taskId;
599
+ const s = stateFor(key, tasks.get(key)?.parentToolCallId ?? '');
543
600
  flushBuffers(s);
544
601
  pushItem(s, { kind: 'echo', text });
545
602
  enforceTaskCap(s);
546
- enforceTotalCap(taskId);
547
- scheduleNotify(taskId);
603
+ enforceTotalCap(key);
604
+ scheduleNotify(key);
548
605
  }
549
606
  export function getSubagentContentSnapshot(taskId) {
550
- const key = tasks.has(taskId) ? taskId : (taskToParent.get(taskId) ?? '');
607
+ const key = contentKeyOf(taskId);
551
608
  const s = tasks.get(key);
552
609
  if (!s)
553
610
  return null;
@@ -593,17 +650,42 @@ export function planSubagentViewSlots(taskId) {
593
650
  return out;
594
651
  }
595
652
  export function parentToolCallIdOf(taskId) {
596
- return taskToParent.get(taskId) ?? tasks.get(taskId)?.parentToolCallId;
653
+ const ids = sameSubagentIds(taskId);
654
+ let stated;
655
+ let statedStamp = -1;
656
+ for (const id of ids) {
657
+ const hit = taskToParent.get(id);
658
+ if (hit === undefined)
659
+ continue;
660
+ if (stated === undefined || hit.stamp > statedStamp) {
661
+ stated = hit.card;
662
+ statedStamp = hit.stamp;
663
+ }
664
+ }
665
+ if (stated !== undefined)
666
+ return stated;
667
+ for (const id of ids) {
668
+ const fromContent = tasks.get(id)?.parentToolCallId;
669
+ if (fromContent !== undefined)
670
+ return fromContent;
671
+ }
672
+ return undefined;
597
673
  }
598
674
  export function settleSubagentContent(taskId) {
599
- const s = tasks.get(taskId);
675
+ const key = contentKeyOf(taskId);
676
+ const s = tasks.get(key);
600
677
  if (!s)
601
678
  return;
602
679
  flushBuffers(s);
603
- scheduleNotify(taskId);
680
+ scheduleNotify(key);
604
681
  }
605
682
  export function clearSubagentContent(taskId) {
606
- dropTask(taskId);
683
+ for (;;) {
684
+ const key = contentKeyOf(taskId);
685
+ if (key === '')
686
+ return;
687
+ dropTask(key);
688
+ }
607
689
  }
608
690
  const bgFacts = new Map();
609
691
  export function recordBgTerminalFacts(taskId, facts) {
@@ -619,10 +701,12 @@ export function recordBgTerminalFacts(taskId, facts) {
619
701
  scheduleNotify(taskId);
620
702
  }
621
703
  export function clearBgTerminalFacts(taskId) {
622
- bgFacts.delete(taskId);
704
+ for (const id of sameSubagentIds(taskId))
705
+ bgFacts.delete(id);
623
706
  }
624
707
  export function getBgTerminalFacts(taskId) {
625
- const key = bgFacts.has(taskId) ? taskId : (taskToParent.get(taskId) ?? '');
708
+ const ids = sameSubagentIds(taskId);
709
+ const key = ids.find((id) => bgFacts.has(id)) ?? ids.map((id) => taskToParent.get(id)?.card).find((c) => c !== undefined) ?? '';
626
710
  touchLru(bgFacts, key);
627
711
  return bgFacts.get(key);
628
712
  }
@@ -643,15 +727,35 @@ export function recordBgParentRun(taskId, runId, sessionId, sessionKey) {
643
727
  export function recordSubagentOwner(taskId, runId, sessionId, sessionKey) {
644
728
  if (!taskId || typeof runId !== 'string' || runId === '' || taskId === runId)
645
729
  return;
646
- if (bgParentRun.size >= MAX_BG_PARENT_RUNS && !bgParentRun.has(taskId)) {
730
+ const ids = sameSubagentIds(taskId);
731
+ const heldKeys = ids.filter((k) => bgParentRun.has(k));
732
+ const heldRecs = [];
733
+ for (const k of heldKeys) {
734
+ const rec = bgParentRun.get(k);
735
+ if (rec !== undefined)
736
+ heldRecs.push(rec);
737
+ }
738
+ if (bgParentRun.size >= MAX_BG_PARENT_RUNS && heldKeys.length === 0) {
647
739
  const oldest = bgParentRun.keys().next().value;
648
740
  if (oldest !== undefined)
649
741
  bgParentRun.delete(oldest);
650
742
  }
651
- const quarantinedRun = conflictQuarantine.get(taskId);
652
- if (quarantinedRun !== undefined && quarantinedRun === runId)
743
+ const quarantinedHere = ids.some((k) => conflictQuarantine.get(k) === runId);
744
+ if (quarantinedHere)
653
745
  return;
654
- const prior = bgParentRun.get(taskId);
746
+ const sameRunHeld = heldRecs.filter((r) => r.runId === runId);
747
+ const heldSlots = new Set(sameRunHeld.map((r) => r.sessionKey ?? DEFAULT_SESSION_KEY));
748
+ if (sameRunHeld.length > 1 && heldSlots.size > 1) {
749
+ ownerSessionConflictCount++;
750
+ const pairOf = (r) => ({
751
+ ...(r.sessionId !== undefined ? { sessionId: r.sessionId } : {}),
752
+ ...(r.sessionKey !== undefined ? { sessionKey: r.sessionKey } : {}),
753
+ });
754
+ lastOwnerSessionConflict = { taskId, runId, prior: pairOf(sameRunHeld[0]), next: pairOf(sameRunHeld[1]) };
755
+ quarantineRun(ids, runId);
756
+ return;
757
+ }
758
+ const prior = heldRecs.find((r) => r.runId === runId) ?? heldRecs[0];
655
759
  const sameRun = prior?.runId === runId;
656
760
  const incoming = typeof sessionId === 'string' && sessionId !== '' ? sessionId : undefined;
657
761
  const incomingKey = typeof sessionKey === 'string' && sessionKey !== '' ? sessionKey : undefined;
@@ -685,16 +789,13 @@ export function recordSubagentOwner(taskId, runId, sessionId, sessionKey) {
685
789
  const priorSlot = prior?.sessionKey ?? DEFAULT_SESSION_KEY;
686
790
  const nextSlot = nextPair.sessionKey ?? DEFAULT_SESSION_KEY;
687
791
  if (priorSlot !== nextSlot) {
688
- bgParentRun.delete(taskId);
689
- if (conflictQuarantine.size >= MAX_BG_PARENT_RUNS && !conflictQuarantine.has(taskId)) {
690
- const oldestQ = conflictQuarantine.keys().next().value;
691
- if (oldestQ !== undefined)
692
- conflictQuarantine.delete(oldestQ);
693
- }
694
- conflictQuarantine.set(taskId, runId);
792
+ quarantineRun(ids, runId);
695
793
  return;
696
794
  }
697
795
  }
796
+ for (const k of ids)
797
+ if (k !== taskId)
798
+ bgParentRun.delete(k);
698
799
  bgParentRun.delete(taskId);
699
800
  bgParentRun.set(taskId, { runId, ...nextPair });
700
801
  }
@@ -711,14 +812,43 @@ export function recordSubagentOwnerFromProgress(ev, ownerRunId, ownerSessionId,
711
812
  recordSubagentOwner(o.taskId, ownerRunId, ownerSessionId, ownerSessionKey);
712
813
  }
713
814
  export function getBgParentRun(taskId) {
714
- touchLru(bgParentRun, taskId);
715
- return bgParentRun.get(taskId)?.runId;
815
+ return getBgParentRunOwner(taskId)?.runId;
716
816
  }
717
817
  export function getBgParentRunOwner(taskId) {
718
818
  if (typeof taskId !== 'string' || taskId === '')
719
819
  return undefined;
720
- touchLru(bgParentRun, taskId);
721
- return bgParentRun.get(taskId);
820
+ const live = liveOwnerEntries(sameSubagentIds(taskId));
821
+ const first = live[0];
822
+ if (first === undefined)
823
+ return undefined;
824
+ if (!live.every(([, rec]) => sameOwnerRecord(rec, first[1])))
825
+ return undefined;
826
+ touchLru(bgParentRun, first[0]);
827
+ return first[1];
828
+ }
829
+ function liveOwnerEntries(ids) {
830
+ const out = [];
831
+ for (const k of ids) {
832
+ const rec = bgParentRun.get(k);
833
+ if (rec === undefined)
834
+ continue;
835
+ if (ids.some((q) => conflictQuarantine.get(q) === rec.runId))
836
+ continue;
837
+ out.push([k, rec]);
838
+ }
839
+ return out;
840
+ }
841
+ const sameOwnerRecord = (a, b) => a.runId === b.runId && a.sessionId === b.sessionId && a.sessionKey === b.sessionKey;
842
+ function quarantineRun(ids, runId) {
843
+ for (const k of ids) {
844
+ bgParentRun.delete(k);
845
+ if (conflictQuarantine.size >= MAX_BG_PARENT_RUNS && !conflictQuarantine.has(k)) {
846
+ const oldestQ = conflictQuarantine.keys().next().value;
847
+ if (oldestQ !== undefined)
848
+ conflictQuarantine.delete(oldestQ);
849
+ }
850
+ conflictQuarantine.set(k, runId);
851
+ }
722
852
  }
723
853
  export function __resetSubagentOwnerLedgerForTests() {
724
854
  bgParentRun.clear();
@@ -1,4 +1,5 @@
1
1
  import { rewindArchiveReadingAt, rewindConversationAvailability } from './rewindArchiveReading.js';
2
+ import { ownDataField } from './ownKey.js';
2
3
  export const TOOL_HISTORY_MISMATCH_KINDS = Object.freeze([
3
4
  'tool_use_without_result',
4
5
  'orphan_tool_result',
@@ -191,8 +192,8 @@ export function classifyToolHistoryMismatch(err) {
191
192
  let status;
192
193
  let rawMessage;
193
194
  try {
194
- code = err.code;
195
- status = err.status;
195
+ code = ownDataField(err, 'code');
196
+ status = ownDataField(err, 'status');
196
197
  rawMessage = err.message;
197
198
  }
198
199
  catch {
@@ -1,3 +1,4 @@
1
+ import type { UiLanguage } from './env/uiLanguage.js';
1
2
  export interface ToolRosterPathTargetView {
2
3
  param: string;
3
4
  access: string;
@@ -77,8 +78,8 @@ export type HandsSeamReading = {
77
78
  export declare function handsSeamReadingOf(view: {
78
79
  readonly hands?: WiringManifestHandsView;
79
80
  } | null | undefined): HandsSeamReading;
80
- export declare function handsSeamDetail(reading: HandsSeamReading): string;
81
- export declare function handsMountedDetail(reading: HandsMountedReading): string;
81
+ export declare function handsSeamDetail(reading: HandsSeamReading, lang?: UiLanguage): string;
82
+ export declare function handsMountedDetail(reading: HandsMountedReading, lang?: UiLanguage): string;
82
83
  export declare function toolRosterNames(roster: ToolRosterView | undefined): readonly string[];
83
84
  export interface ToolShim {
84
85
  name: string;
@@ -1,4 +1,5 @@
1
1
  import { displayUntrusted } from './displayUntrusted.js';
2
+ import { msg, renderMessage } from './i18n/translate.js';
2
3
  import { HANDS_REASON_NO_EXECUTION_ENV, projectHandsSection } from './handsSeam.js';
3
4
  const str = (v) => typeof v === 'string' && v.length > 0 ? v : undefined;
4
5
  const strArr = (v) => Array.isArray(v) ? v.filter((x) => typeof x === 'string') : undefined;
@@ -144,55 +145,55 @@ export function handsSeamReadingOf(view) {
144
145
  return { kind: 'mounted' };
145
146
  return seam.reason !== undefined ? { kind: 'not_mounted', reason: seam.reason } : { kind: 'not_mounted' };
146
147
  }
147
- const HANDS_NONE_STEM = 'this leg of the run was assembled with NO built-in file-and-shell tools';
148
- const HANDS_NONE_TAIL = "so on this leg the model had no tool of the engine's own for editing files or running commands (tools mounted by other conditions, such as external servers, and sub-runs delegated to other legs are not covered by this reading)";
149
148
  const HANDS_REASON_DISPLAY_MAX = 64;
150
- const HANDS_NOT_REPORTED_SENTENCE = 'whether this leg has built-in file-and-shell tools is not stated here — the engine did not report its hands seam (older engines and servers, and the static half of a manifest, never do); the tool roster may still answer it';
151
- export function handsSeamDetail(reading) {
149
+ function handsNotReported(lang) {
150
+ return renderMessage(msg('notice.capability.hands.notReported'), lang);
151
+ }
152
+ export function handsSeamDetail(reading, lang) {
152
153
  const kind = typeof reading === 'object' && reading !== null ? reading.kind : undefined;
153
154
  switch (kind) {
154
155
  case 'mounted':
155
- return 'this leg of the run was assembled with its built-in file tools mounted — the engine says so; whether a shell is reachable is answered by the tool roster, not by this statement';
156
+ return renderMessage(msg('notice.capability.hands.seamMounted'), lang);
156
157
  case 'not_mounted': {
157
158
  const raw = reading.reason;
158
159
  const reason = typeof raw === 'string' && raw.length > 0 ? raw : undefined;
159
160
  const why = reason === undefined
160
- ? 'the engine states it mounted no hands on this leg (it gave no reason)'
161
+ ? msg('notice.capability.hands.whyNoReason')
161
162
  : reason === HANDS_REASON_NO_EXECUTION_ENV
162
- ? 'the engine states it mounted no hands on this leg because no execution environment was supplied'
163
- : `the engine states it mounted no hands on this leg (reason: ${displayUntrusted(reason, { max: HANDS_REASON_DISPLAY_MAX })}, a word this build does not know)`;
164
- return `${HANDS_NONE_STEM} — ${why}, ${HANDS_NONE_TAIL}`;
163
+ ? msg('notice.capability.hands.whyNoExecutionEnv')
164
+ : msg('notice.capability.hands.whyUnknownReason', { reason: displayUntrusted(reason, { max: HANDS_REASON_DISPLAY_MAX }) });
165
+ return renderMessage(msg('notice.capability.hands.noneLine', { stem: msg('notice.capability.hands.noneStem'), why, tail: msg('notice.capability.hands.noneTail') }), lang);
165
166
  }
166
167
  default:
167
- return HANDS_NOT_REPORTED_SENTENCE;
168
+ return handsNotReported(lang);
168
169
  }
169
170
  }
170
- export function handsMountedDetail(reading) {
171
+ export function handsMountedDetail(reading, lang) {
171
172
  const r = reading;
172
173
  const kind = typeof r === 'object' && r !== null ? r.kind : undefined;
173
174
  switch (kind) {
174
175
  case 'mounted': {
175
176
  const rows = r.rows;
176
177
  if (typeof rows === 'number' && Number.isInteger(rows) && rows > 0)
177
- return `this run was assembled with file-and-shell tools mounted (${rows} of them)`;
178
- return HANDS_NOT_REPORTED_SENTENCE;
178
+ return renderMessage(msg('notice.capability.hands.rosterMounted', { rows }), lang);
179
+ return handsNotReported(lang);
179
180
  }
180
181
  case 'not-mounted':
181
- return `${HANDS_NONE_STEM} — the engine reports a roster and not one row was mounted by that condition, ${HANDS_NONE_TAIL}`;
182
+ return renderMessage(msg('notice.capability.hands.rosterNotMounted', { stem: msg('notice.capability.hands.noneStem'), tail: msg('notice.capability.hands.noneTail') }), lang);
182
183
  case 'unknown':
183
184
  switch (r.why) {
184
185
  case 'no-manifest':
185
- return 'whether this run has file-and-shell tools is unknown — no assembly manifest was observed for it';
186
+ return renderMessage(msg('notice.capability.hands.unknownNoManifest'), lang);
186
187
  case 'no-roster':
187
- return 'whether this run has file-and-shell tools is unknown — the manifest carries no tool roster (the static half never does; only an engine-minted effective manifest reports one)';
188
+ return renderMessage(msg('notice.capability.hands.unknownNoRoster'), lang);
188
189
  case 'roster-unreadable':
189
- return 'whether this run has file-and-shell tools is unknown — the tool roster could not be read in the shape this reader knows';
190
+ return renderMessage(msg('notice.capability.hands.unknownRosterUnreadable'), lang);
190
191
  case 'mount-condition-absent':
191
- return 'whether this run has file-and-shell tools is unknown — this engine does not report which condition mounted each tool, so an empty count here would be a fact about the reader, not about the run';
192
+ return renderMessage(msg('notice.capability.hands.unknownMountConditionAbsent'), lang);
192
193
  }
193
- return HANDS_NOT_REPORTED_SENTENCE;
194
+ return handsNotReported(lang);
194
195
  }
195
- return HANDS_NOT_REPORTED_SENTENCE;
196
+ return handsNotReported(lang);
196
197
  }
197
198
  export function toolRosterNames(roster) {
198
199
  return roster?.entries.map((e) => e.name) ?? [];
@@ -0,0 +1,8 @@
1
+ export interface ToolsFlagNames {
2
+ readonly kept: readonly string[];
3
+ readonly excluded: readonly string[];
4
+ readonly bare: boolean;
5
+ readonly detached: readonly string[];
6
+ readonly scoped: readonly string[];
7
+ }
8
+ export declare function parseToolsFlagNames(values: readonly string[]): ToolsFlagNames;
@@ -0,0 +1,110 @@
1
+ function readableStrings(values) {
2
+ const out = [];
3
+ try {
4
+ if (!Array.isArray(values))
5
+ return out;
6
+ const n = values.length;
7
+ for (let i = 0; i < n; i++) {
8
+ try {
9
+ const v = values[i];
10
+ if (typeof v === 'string')
11
+ out.push(v);
12
+ }
13
+ catch {
14
+ continue;
15
+ }
16
+ }
17
+ }
18
+ catch {
19
+ return out;
20
+ }
21
+ return out;
22
+ }
23
+ function splitToolsFlagTokens(values) {
24
+ const out = [];
25
+ for (const value of values) {
26
+ if (value === '')
27
+ continue;
28
+ let cur = '';
29
+ let inParen = false;
30
+ for (const ch of value) {
31
+ if (ch === '(') {
32
+ inParen = true;
33
+ cur += ch;
34
+ }
35
+ else if (ch === ')') {
36
+ inParen = false;
37
+ cur += ch;
38
+ }
39
+ else if (ch === ',') {
40
+ if (inParen)
41
+ cur += ch;
42
+ else {
43
+ if (cur.trim() !== '')
44
+ out.push(cur.trim());
45
+ cur = '';
46
+ }
47
+ }
48
+ else if (ch === ' ') {
49
+ if (inParen)
50
+ cur += ch;
51
+ else if (cur.trim() !== '') {
52
+ out.push(cur.trim());
53
+ cur = '';
54
+ }
55
+ }
56
+ else if (cur !== '' || ch.trim() !== '') {
57
+ cur += ch;
58
+ }
59
+ }
60
+ if (cur.trim() !== '')
61
+ out.push(cur.trim());
62
+ }
63
+ return out;
64
+ }
65
+ export function parseToolsFlagNames(values) {
66
+ const tokens = splitToolsFlagTokens(readableStrings(values));
67
+ const kept = [];
68
+ const excluded = new Set();
69
+ const detached = [];
70
+ const scoped = [];
71
+ let bare = false;
72
+ for (let i = 0; i < tokens.length; i++) {
73
+ let token = tokens[i];
74
+ if (token === undefined)
75
+ continue;
76
+ if (!token.startsWith('!')) {
77
+ kept.push(token);
78
+ continue;
79
+ }
80
+ let name = token.slice(1);
81
+ if (name === '') {
82
+ const next = tokens[i + 1];
83
+ if (next === undefined || next.startsWith('!') || next.startsWith('(')) {
84
+ bare = true;
85
+ continue;
86
+ }
87
+ i++;
88
+ detached.push(next);
89
+ token = `!${next}`;
90
+ name = next;
91
+ }
92
+ const paren = name.indexOf('(');
93
+ if (paren === 0) {
94
+ bare = true;
95
+ continue;
96
+ }
97
+ if (paren > 0) {
98
+ name = name.slice(0, paren);
99
+ scoped.push(token);
100
+ }
101
+ excluded.add(name);
102
+ }
103
+ return Object.freeze({
104
+ kept: Object.freeze(kept),
105
+ excluded: Object.freeze([...excluded]),
106
+ bare,
107
+ detached: Object.freeze(detached),
108
+ scoped: Object.freeze(scoped),
109
+ });
110
+ }