@sema-agent/client-core 0.99.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 (128) hide show
  1. package/CHANGELOG.md +177 -0
  2. package/README.md +32 -19
  3. package/dist/adapt/arms.js +60 -36
  4. package/dist/adapt/panelTasks.d.ts +2 -1
  5. package/dist/adapt/panelTasks.js +32 -9
  6. package/dist/adapt/textStream.d.ts +1 -1
  7. package/dist/adapt/textStream.js +51 -28
  8. package/dist/adapter/activeRunSelfHeal.d.ts +7 -0
  9. package/dist/adapter/activeRunSelfHeal.js +58 -11
  10. package/dist/adapter/downstream/eventToSdkMessage.d.ts +25 -6
  11. package/dist/adapter/downstream/eventToSdkMessage.js +125 -9
  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 +32 -5
  16. package/dist/adapter/types.d.ts +2 -0
  17. package/dist/agentsWireCaps.d.ts +7 -0
  18. package/dist/agentsWireCaps.js +100 -15
  19. package/dist/cloudConfigWireCaps.d.ts +10 -1
  20. package/dist/cloudConfigWireCaps.js +156 -62
  21. package/dist/compactionStatus.d.ts +34 -0
  22. package/dist/compactionStatus.js +196 -0
  23. package/dist/decideFailureNote.js +3 -3
  24. package/dist/displayUntrusted.js +150 -5
  25. package/dist/engineAgentPanelStore.d.ts +7 -4
  26. package/dist/engineErrorCodes.d.ts +9 -1
  27. package/dist/engineErrorCodes.js +9 -5
  28. package/dist/engineRowRef.js +1 -0
  29. package/dist/engineToolDirectory.d.ts +3 -0
  30. package/dist/engineToolDirectory.js +4 -2
  31. package/dist/eventLeg.d.ts +1 -7
  32. package/dist/eventLeg.js +7 -8
  33. package/dist/fileHistoryCaptureCapability.d.ts +0 -3
  34. package/dist/fileHistoryCaptureCapability.js +0 -4
  35. package/dist/generated/engineFactTables.d.ts +1 -0
  36. package/dist/generated/engineFactTables.js +27 -0
  37. package/dist/generated/engineNoticeTables.js +3 -0
  38. package/dist/generated/settingsSchemaFns.d.ts +12 -0
  39. package/dist/generated/settingsSchemaFns.js +13 -0
  40. package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -0
  41. package/dist/generated/settingsSchemaMcpRequestEntry.js +162 -0
  42. package/dist/generated/settingsSchemaTables.d.ts +1 -0
  43. package/dist/generated/settingsSchemaTables.js +5 -0
  44. package/dist/generated/settingsSchemaTypes.d.ts +28 -0
  45. package/dist/hitl/allowRuleShadow.js +2 -2
  46. package/dist/hitl/approvalCardReasons.js +2 -2
  47. package/dist/hitl/approvalHolds.d.ts +14 -0
  48. package/dist/hitl/approvalHolds.js +41 -0
  49. package/dist/hitl/askClassPair.d.ts +2 -2
  50. package/dist/hitl/askClassPair.js +2 -2
  51. package/dist/hitl/attributionLadder.d.ts +23 -0
  52. package/dist/hitl/attributionLadder.js +67 -0
  53. package/dist/hitl/decisionLedger.d.ts +55 -0
  54. package/dist/hitl/decisionLedger.js +156 -0
  55. package/dist/hitl/decisionRefusal.d.ts +1 -0
  56. package/dist/hitl/decisionRefusal.js +1 -1
  57. package/dist/hitl/decisionSend.d.ts +113 -0
  58. package/dist/hitl/decisionSend.js +579 -0
  59. package/dist/hitl/hitlBridge.js +18 -6
  60. package/dist/hitl/planReviewWire.js +45 -76
  61. package/dist/hitl/sessionPolicyDeliverable.js +3 -6
  62. package/dist/hitl/toolApprovalWire.js +43 -109
  63. package/dist/hostTurnSettings.d.ts +46 -7
  64. package/dist/hostTurnSettings.js +408 -7
  65. package/dist/humanTurn.d.ts +2 -1
  66. package/dist/humanTurn.js +3 -3
  67. package/dist/i18n/messages.en.d.ts +131 -0
  68. package/dist/i18n/messages.en.js +143 -12
  69. package/dist/i18n/messages.zh.js +148 -12
  70. package/dist/index.d.ts +18 -2
  71. package/dist/index.js +10 -1
  72. package/dist/inheritEnvCapability.d.ts +1 -0
  73. package/dist/inheritEnvCapability.js +9 -2
  74. package/dist/inheritEnvWire.js +2 -2
  75. package/dist/injectionLaneNotice.d.ts +5 -0
  76. package/dist/injectionLaneNotice.js +46 -0
  77. package/dist/mcpPanel.js +2 -0
  78. package/dist/mcpReconnect.js +2 -2
  79. package/dist/mcpToolToggles.d.ts +6 -0
  80. package/dist/mcpToolToggles.js +46 -0
  81. package/dist/mcpWireCaps.d.ts +10 -4
  82. package/dist/mcpWireCaps.js +106 -71
  83. package/dist/mcpWireTransport.d.ts +4 -0
  84. package/dist/mcpWireTransport.js +18 -0
  85. package/dist/modelCapabilityProbe.d.ts +2 -1
  86. package/dist/modelCapabilityProbe.js +10 -9
  87. package/dist/modelIdentityResolvability.d.ts +2 -0
  88. package/dist/modelIdentityResolvability.js +23 -5
  89. package/dist/ownKey.d.ts +26 -0
  90. package/dist/ownKey.js +75 -0
  91. package/dist/panelReduce.d.ts +5 -0
  92. package/dist/panelReduce.js +45 -13
  93. package/dist/panelStateHolder.d.ts +1 -0
  94. package/dist/panelStateHolder.js +10 -1
  95. package/dist/permissionRuleIssue.d.ts +2 -1
  96. package/dist/permissionRuleIssue.js +22 -21
  97. package/dist/pluginHooksWire.js +12 -10
  98. package/dist/prepareRefusal.d.ts +8 -0
  99. package/dist/prepareRefusal.js +72 -0
  100. package/dist/request/taskRequest.d.ts +10 -10
  101. package/dist/request/taskRequest.js +106 -65
  102. package/dist/resumeRefusalCopy.d.ts +3 -1
  103. package/dist/resumeRefusalCopy.js +22 -4
  104. package/dist/retryStatus.d.ts +18 -0
  105. package/dist/retryStatus.js +76 -19
  106. package/dist/ruleRefusalSentence.d.ts +4 -0
  107. package/dist/ruleRefusalSentence.js +58 -0
  108. package/dist/sandboxWire.d.ts +2 -1
  109. package/dist/sandboxWire.js +55 -21
  110. package/dist/scenarioRefusal.d.ts +2 -1
  111. package/dist/scenarioRefusal.js +5 -5
  112. package/dist/seam.d.ts +24 -9
  113. package/dist/seam.js +44 -4
  114. package/dist/seatContract.d.ts +16 -8
  115. package/dist/seatContract.js +21 -6
  116. package/dist/settingsCredentialKeyPaths.d.ts +8 -0
  117. package/dist/settingsCredentialKeyPaths.js +219 -0
  118. package/dist/skillsWireCaps.d.ts +0 -3
  119. package/dist/skillsWireCaps.js +1 -2
  120. package/dist/subagentContentStore.d.ts +1 -0
  121. package/dist/subagentContentStore.js +135 -27
  122. package/dist/toolsFlagNames.d.ts +8 -0
  123. package/dist/toolsFlagNames.js +110 -0
  124. package/dist/turnFailurePresentation.js +15 -7
  125. package/dist/wireRefusalCopy.d.ts +51 -17
  126. package/dist/wireRefusalCopy.js +298 -135
  127. package/docs/INTEGRATION-CLIENTS.md +423 -26
  128. package/package.json +4 -4
@@ -0,0 +1,219 @@
1
+ import { looksLikeKnownSecret, queryCarriesCredential } from './displayUntrusted.js';
2
+ const CREDENTIAL_WORDS = new Set([
3
+ 'key', 'keys', 'apikey', 'token', 'tokens', 'secret', 'secrets', 'password', 'passwd', 'pass', 'pwd', 'pin', 'otp',
4
+ 'auth', 'authorization', 'credential', 'credentials', 'cookie', 'cookies', 'session', 'private', 'cert', 'signature', 'salt',
5
+ ]);
6
+ const CREDENTIAL_STEMS = ['PASSWORD', 'PASSWD', 'SECRET', 'TOKEN', 'APIKEY', 'CREDENTIAL', 'COOKIE', 'PRIVATE'];
7
+ const CREDENTIAL_SUFFIXES = ['PASS', 'PWD', 'KEY', 'AUTH'];
8
+ const SECRET_CONFIG_NAME = /(?:^|[-_.])(?:token|key|secret|password|authorization|credential|cookie)s?$/i;
9
+ export function credentialNameWords(name) {
10
+ if (typeof name !== 'string')
11
+ return [];
12
+ return name
13
+ .replace(/([A-Z])(?=[A-Z][a-z])/g, '$1_')
14
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
15
+ .split(/[_\-.\s]+/)
16
+ .filter((w) => w.length > 0)
17
+ .map((w) => w.toLowerCase());
18
+ }
19
+ export function isCredentialEnvName(name) {
20
+ if (typeof name !== 'string')
21
+ return false;
22
+ if (credentialNameWords(name).some((w) => CREDENTIAL_WORDS.has(w)))
23
+ return true;
24
+ const upper = name.toUpperCase();
25
+ return CREDENTIAL_STEMS.some((stem) => upper.includes(stem)) || CREDENTIAL_SUFFIXES.some((suffix) => upper.endsWith(suffix));
26
+ }
27
+ export function isCredentialConfigKey(name) {
28
+ if (typeof name !== 'string')
29
+ return false;
30
+ const words = credentialNameWords(name);
31
+ const last = words[words.length - 1];
32
+ return SECRET_CONFIG_NAME.test(name) || (last !== undefined && CREDENTIAL_WORDS.has(last));
33
+ }
34
+ const DECIMAL_INTEGER_RE = /^\s*\d+\s*$/;
35
+ function stringCarriesCredential(value) {
36
+ if (looksLikeKnownSecret(value))
37
+ return true;
38
+ const text = value.trim();
39
+ if (!text.includes('://'))
40
+ return false;
41
+ let url;
42
+ try {
43
+ url = new URL(text);
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ if (url.username !== '' || url.password !== '')
49
+ return true;
50
+ return url.search.length > 1 && queryCarriesCredential(url.search.slice(1));
51
+ }
52
+ const ENV_ASSIGNMENT_RE = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/s;
53
+ const LONG_OPTION_RE = /^--?([A-Za-z][A-Za-z0-9_-]*)(?:=(.*))?$/s;
54
+ const HEADER_FORM_RE = /^\s*([A-Za-z][A-Za-z0-9_-]*)\s*:\s*\S/;
55
+ function argvFindings(args) {
56
+ const hits = new Map();
57
+ const add = (i, numericByNameOnly) => {
58
+ hits.set(i, (hits.get(i) ?? true) && numericByNameOnly);
59
+ };
60
+ const valueCarries = (value) => {
61
+ const header = HEADER_FORM_RE.exec(value);
62
+ return stringCarriesCredential(value) || (header !== null && isCredentialConfigKey(header[1] ?? ''));
63
+ };
64
+ args.forEach((arg, i) => {
65
+ if (valueCarries(arg))
66
+ add(i, false);
67
+ const assignment = ENV_ASSIGNMENT_RE.exec(arg);
68
+ if (assignment !== null && assignment[2] !== '') {
69
+ const assigned = assignment[2] ?? '';
70
+ if (valueCarries(assigned))
71
+ add(i, false);
72
+ if (isCredentialEnvName(assignment[1] ?? ''))
73
+ add(i, DECIMAL_INTEGER_RE.test(assigned));
74
+ }
75
+ const option = LONG_OPTION_RE.exec(arg);
76
+ if (option === null)
77
+ return;
78
+ const inline = option[2];
79
+ if (inline !== undefined && inline !== '' && valueCarries(inline))
80
+ add(i, false);
81
+ const optionName = option[1] ?? '';
82
+ if (optionName.length <= 1 || !isCredentialEnvName(optionName))
83
+ return;
84
+ if (inline !== undefined) {
85
+ if (inline !== '')
86
+ add(i, DECIMAL_INTEGER_RE.test(inline));
87
+ }
88
+ else {
89
+ const next = args[i + 1];
90
+ if (next !== undefined && next !== '')
91
+ add(i + 1, DECIMAL_INTEGER_RE.test(next));
92
+ }
93
+ });
94
+ return hits;
95
+ }
96
+ function isPresent(value) {
97
+ return value !== undefined && value !== null && value !== '' && value !== false;
98
+ }
99
+ function arrayKindOf(node) {
100
+ try {
101
+ return Array.isArray(node);
102
+ }
103
+ catch {
104
+ return undefined;
105
+ }
106
+ }
107
+ function ownKeysOf(node) {
108
+ try {
109
+ return Object.keys(node);
110
+ }
111
+ catch {
112
+ return undefined;
113
+ }
114
+ }
115
+ function readSlot(node, key) {
116
+ try {
117
+ return { ok: true, value: node[key] };
118
+ }
119
+ catch {
120
+ return { ok: false };
121
+ }
122
+ }
123
+ export function settingsCredentialKeyPaths(doc) {
124
+ const found = [];
125
+ if (doc === null || doc === undefined || typeof doc !== 'object')
126
+ return found;
127
+ const finding = (path, numericByNameOnly) => (numericByNameOnly ? { path, numericByNameOnly: true } : { path });
128
+ const ancestors = new WeakSet();
129
+ const stack = [{ node: doc, path: '', inEnv: false }];
130
+ while (stack.length > 0) {
131
+ const frame = stack.pop();
132
+ if (frame === undefined)
133
+ continue;
134
+ const { node, path, inEnv } = frame;
135
+ if (frame.exit === true) {
136
+ ancestors.delete(node);
137
+ continue;
138
+ }
139
+ if (ancestors.has(node))
140
+ continue;
141
+ ancestors.add(node);
142
+ stack.push({ node, path, inEnv, exit: true });
143
+ const isArray = arrayKindOf(node);
144
+ if (isArray === undefined) {
145
+ if (path !== '')
146
+ found.push(finding(path, false));
147
+ continue;
148
+ }
149
+ if (isArray) {
150
+ let items;
151
+ try {
152
+ items = Array.from(node);
153
+ }
154
+ catch {
155
+ if (path !== '')
156
+ found.push(finding(path, false));
157
+ continue;
158
+ }
159
+ if (items.length > 0 && items.every((item) => typeof item === 'string')) {
160
+ const hits = argvFindings(items);
161
+ for (const i of [...hits.keys()].sort((a, b) => a - b))
162
+ found.push(finding(`${path}[${i}]`, hits.get(i) === true));
163
+ continue;
164
+ }
165
+ items.forEach((item, i) => {
166
+ const itemPath = `${path}[${i}]`;
167
+ if (typeof item === 'string') {
168
+ if (stringCarriesCredential(item))
169
+ found.push(finding(itemPath, false));
170
+ }
171
+ else if (item !== null && typeof item === 'object') {
172
+ stack.push({ node: item, path: itemPath, inEnv: false });
173
+ }
174
+ });
175
+ continue;
176
+ }
177
+ const keys = ownKeysOf(node);
178
+ if (keys === undefined) {
179
+ if (path !== '')
180
+ found.push(finding(path, false));
181
+ continue;
182
+ }
183
+ for (const key of keys) {
184
+ const keyPath = path === '' ? key : `${path}.${key}`;
185
+ const nameIsCredential = inEnv ? isCredentialEnvName(key) : isCredentialConfigKey(key);
186
+ const slot = readSlot(node, key);
187
+ if (!slot.ok) {
188
+ if (nameIsCredential)
189
+ found.push(finding(keyPath, false));
190
+ continue;
191
+ }
192
+ const value = slot.value;
193
+ if (typeof value === 'string') {
194
+ const byValue = stringCarriesCredential(value);
195
+ if (byValue || (nameIsCredential && isPresent(value)))
196
+ found.push(finding(keyPath, !byValue && DECIMAL_INTEGER_RE.test(value)));
197
+ continue;
198
+ }
199
+ if (value !== null && typeof value === 'object') {
200
+ let nonEmpty;
201
+ try {
202
+ nonEmpty = Array.isArray(value) ? value.length > 0 : Object.keys(value).length > 0;
203
+ }
204
+ catch {
205
+ nonEmpty = true;
206
+ }
207
+ if (nameIsCredential && nonEmpty) {
208
+ found.push(finding(keyPath, false));
209
+ continue;
210
+ }
211
+ stack.push({ node: value, path: keyPath, inEnv: key === 'env' });
212
+ continue;
213
+ }
214
+ if (nameIsCredential && isPresent(value))
215
+ found.push(finding(keyPath, typeof value === 'number'));
216
+ }
217
+ }
218
+ return found;
219
+ }
@@ -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()]
@@ -44,6 +44,7 @@ export declare const SUBAGENT_CONTENT_STORE_DEFAULTS: Readonly<SubagentContentSt
44
44
  export declare function configureSubagentContentStore(next: Partial<SubagentContentStoreConfig>): void;
45
45
  export declare function subagentContentStoreConfig(): SubagentContentStoreConfig;
46
46
  export declare function __resetSubagentContentStoreConfigForTests(): void;
47
+ export declare function bindSubagentIdentityReader(fn: (id: string) => readonly string[] | undefined): void;
47
48
  export declare function registerSubagentContentAlias(parentToolCallId: string, taskId: string): void;
48
49
  export declare function registerSubagentAlias(parentToolCallId: string, taskId: string): void;
49
50
  export declare function publishSubagentContentEvent(ev: SubagentContentEvent): void;
@@ -229,8 +229,40 @@ function dropTask(key) {
229
229
  totalBytes -= s.bytes;
230
230
  tasks.delete(key);
231
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
+ }
232
263
  const parentToTask = new Map();
233
264
  const taskToParent = new Map();
265
+ let parentStampSeq = 0;
234
266
  let notifyListener = null;
235
267
  const pendingNotify = new Set();
236
268
  let notifyTimer = null;
@@ -383,7 +415,8 @@ function aliasContentKey(parentToolCallId, taskId) {
383
415
  export function registerSubagentAlias(parentToolCallId, taskId) {
384
416
  if (!aliasContentKey(parentToolCallId, taskId))
385
417
  return;
386
- taskToParent.set(taskId, parentToolCallId);
418
+ if (taskToParent.get(taskId)?.card !== parentToolCallId)
419
+ taskToParent.set(taskId, { card: parentToolCallId, stamp: ++parentStampSeq });
387
420
  }
388
421
  function replaySeen(s, ev) {
389
422
  const id = ev.eventId;
@@ -459,7 +492,7 @@ function canonicalKey(ev) {
459
492
  return parentToTask.get(ev.parentToolCallId) ?? ev.parentToolCallId;
460
493
  }
461
494
  export function publishSubagentContentEvent(ev) {
462
- const key = canonicalKey(ev);
495
+ const key = homeKeyOf(canonicalKey(ev));
463
496
  const s = stateFor(key, ev.parentToolCallId);
464
497
  switch (ev.type) {
465
498
  case 'text_delta':
@@ -561,15 +594,17 @@ export function publishSubagentContentEvent(ev) {
561
594
  scheduleNotify(key);
562
595
  }
563
596
  export function pushSubagentLocalEcho(taskId, text) {
564
- 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 ?? '');
565
600
  flushBuffers(s);
566
601
  pushItem(s, { kind: 'echo', text });
567
602
  enforceTaskCap(s);
568
- enforceTotalCap(taskId);
569
- scheduleNotify(taskId);
603
+ enforceTotalCap(key);
604
+ scheduleNotify(key);
570
605
  }
571
606
  export function getSubagentContentSnapshot(taskId) {
572
- const key = tasks.has(taskId) ? taskId : (taskToParent.get(taskId) ?? '');
607
+ const key = contentKeyOf(taskId);
573
608
  const s = tasks.get(key);
574
609
  if (!s)
575
610
  return null;
@@ -615,17 +650,42 @@ export function planSubagentViewSlots(taskId) {
615
650
  return out;
616
651
  }
617
652
  export function parentToolCallIdOf(taskId) {
618
- 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;
619
673
  }
620
674
  export function settleSubagentContent(taskId) {
621
- const s = tasks.get(taskId);
675
+ const key = contentKeyOf(taskId);
676
+ const s = tasks.get(key);
622
677
  if (!s)
623
678
  return;
624
679
  flushBuffers(s);
625
- scheduleNotify(taskId);
680
+ scheduleNotify(key);
626
681
  }
627
682
  export function clearSubagentContent(taskId) {
628
- dropTask(taskId);
683
+ for (;;) {
684
+ const key = contentKeyOf(taskId);
685
+ if (key === '')
686
+ return;
687
+ dropTask(key);
688
+ }
629
689
  }
630
690
  const bgFacts = new Map();
631
691
  export function recordBgTerminalFacts(taskId, facts) {
@@ -641,10 +701,12 @@ export function recordBgTerminalFacts(taskId, facts) {
641
701
  scheduleNotify(taskId);
642
702
  }
643
703
  export function clearBgTerminalFacts(taskId) {
644
- bgFacts.delete(taskId);
704
+ for (const id of sameSubagentIds(taskId))
705
+ bgFacts.delete(id);
645
706
  }
646
707
  export function getBgTerminalFacts(taskId) {
647
- 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) ?? '';
648
710
  touchLru(bgFacts, key);
649
711
  return bgFacts.get(key);
650
712
  }
@@ -665,15 +727,35 @@ export function recordBgParentRun(taskId, runId, sessionId, sessionKey) {
665
727
  export function recordSubagentOwner(taskId, runId, sessionId, sessionKey) {
666
728
  if (!taskId || typeof runId !== 'string' || runId === '' || taskId === runId)
667
729
  return;
668
- 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) {
669
739
  const oldest = bgParentRun.keys().next().value;
670
740
  if (oldest !== undefined)
671
741
  bgParentRun.delete(oldest);
672
742
  }
673
- const quarantinedRun = conflictQuarantine.get(taskId);
674
- if (quarantinedRun !== undefined && quarantinedRun === runId)
743
+ const quarantinedHere = ids.some((k) => conflictQuarantine.get(k) === runId);
744
+ if (quarantinedHere)
745
+ return;
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);
675
756
  return;
676
- const prior = bgParentRun.get(taskId);
757
+ }
758
+ const prior = heldRecs.find((r) => r.runId === runId) ?? heldRecs[0];
677
759
  const sameRun = prior?.runId === runId;
678
760
  const incoming = typeof sessionId === 'string' && sessionId !== '' ? sessionId : undefined;
679
761
  const incomingKey = typeof sessionKey === 'string' && sessionKey !== '' ? sessionKey : undefined;
@@ -707,16 +789,13 @@ export function recordSubagentOwner(taskId, runId, sessionId, sessionKey) {
707
789
  const priorSlot = prior?.sessionKey ?? DEFAULT_SESSION_KEY;
708
790
  const nextSlot = nextPair.sessionKey ?? DEFAULT_SESSION_KEY;
709
791
  if (priorSlot !== nextSlot) {
710
- bgParentRun.delete(taskId);
711
- if (conflictQuarantine.size >= MAX_BG_PARENT_RUNS && !conflictQuarantine.has(taskId)) {
712
- const oldestQ = conflictQuarantine.keys().next().value;
713
- if (oldestQ !== undefined)
714
- conflictQuarantine.delete(oldestQ);
715
- }
716
- conflictQuarantine.set(taskId, runId);
792
+ quarantineRun(ids, runId);
717
793
  return;
718
794
  }
719
795
  }
796
+ for (const k of ids)
797
+ if (k !== taskId)
798
+ bgParentRun.delete(k);
720
799
  bgParentRun.delete(taskId);
721
800
  bgParentRun.set(taskId, { runId, ...nextPair });
722
801
  }
@@ -733,14 +812,43 @@ export function recordSubagentOwnerFromProgress(ev, ownerRunId, ownerSessionId,
733
812
  recordSubagentOwner(o.taskId, ownerRunId, ownerSessionId, ownerSessionKey);
734
813
  }
735
814
  export function getBgParentRun(taskId) {
736
- touchLru(bgParentRun, taskId);
737
- return bgParentRun.get(taskId)?.runId;
815
+ return getBgParentRunOwner(taskId)?.runId;
738
816
  }
739
817
  export function getBgParentRunOwner(taskId) {
740
818
  if (typeof taskId !== 'string' || taskId === '')
741
819
  return undefined;
742
- touchLru(bgParentRun, taskId);
743
- 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
+ }
744
852
  }
745
853
  export function __resetSubagentOwnerLedgerForTests() {
746
854
  bgParentRun.clear();
@@ -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
+ }
@@ -3,12 +3,13 @@ import { classifyTurnWireError, effectiveWireErrorCode, isPreStreamDrainingRejec
3
3
  import { isSseIdleError } from './sseIdleTriage.js';
4
4
  import { isCodeClassifiedGateFailure } from './gateFailureCodes.js';
5
5
  import { CORRUPT_ROW_ERROR_CODE, CORRUPT_SESSION_ERROR_CODE, MEMORY_CONTROL_PLANE_CORRUPT, SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE } from './engineErrorCodes.js';
6
- import { bodyShapeRefusalFromError, bodyShapeRefusalTouchesSettings, fleetLeaseUnavailableContent, fleetLeaseUnavailableFromError, hostPostureRefusalContent, hostPostureRefusalFromError, settingsPermissionBucketRefusalContent, settingsPermissionBucketRefusalFromError, toolDeclarationRefusalContent, toolDeclarationRefusalFromError, usageWindowExhaustedContent, usageWindowExhaustedFromError, } from './wireRefusalCopy.js';
6
+ import { admissionWallRefusalContent, admissionWallRefusalFromError, bodyShapeRefusalFromError, bodyShapeRefusalTouchesSettings, fleetLeaseUnavailableContent, fleetLeaseUnavailableFromError, hostPostureRefusalContent, hostPostureRefusalFromError, fieldLimitRefusalContent, fieldLimitRefusalFromError, toolDeclarationRefusalContent, toolDeclarationRefusalFromError, usageWindowExhaustedContent, usageWindowExhaustedFromError, userAttachmentRefusalFromError, } from './wireRefusalCopy.js';
7
7
  import { THROWN_SLOT_UNREADABLE, readErrorNumber, readThrownSlot, wireFailureTextsOf } from './wireFailureShape.js';
8
8
  import { provablyNotSent } from './engineWireFor.js';
9
9
  import { corruptStoredRowContent, scenarioDenyFromError, scenarioNotAllowedContent } from './wireErrorTriage.js';
10
10
  import { checkpointUnsupportedVersionContent, checkpointUnsupportedVersionFromError, requireExistingSessionRefusalContent, requireExistingSessionRefusalFromError, resumeContextUnavailableContent, resumeContextUnavailableFromError, resumePolicyBlockContent, resumePolicyBlockFromError, resumeRefusalContent, resumeRefusalFromError, } from './resumeRefusalCopy.js';
11
11
  import { resumeReopenContent, resumeReopenFromError } from './hitl/suspendedReopen.js';
12
+ import { prepareRefusalCodeOf, prepareRefusalNoteOf } from './prepareRefusal.js';
12
13
  import { isCorruptSessionError } from './corruptSession.js';
13
14
  import { corruptSessionContent } from './corruptSessionCopy.js';
14
15
  import { inheritEnvRefusalContent, inheritEnvRefusalFromError } from './inheritEnvWire.js';
@@ -309,25 +310,32 @@ function turnFailureNotesOf(err, verdict, ctx, waitSec, lang) {
309
310
  lines.push(corruptSessionContent(lang));
310
311
  const usageWindow = quota || scenarioDeny || resumeRefusal || resumeReopen || resumeGone ? null : usageWindowExhaustedFromError(err);
311
312
  if (usageWindow)
312
- lines.push(usageWindowExhaustedContent(usageWindow));
313
+ lines.push(usageWindowExhaustedContent(usageWindow, lang));
313
314
  const hostPosture = quota || scenarioDeny || resumeRefusal || resumeReopen || resumeGone || storedRowWhere !== undefined ? null : hostPostureRefusalFromError(err, sentRequest);
314
315
  if (hostPosture)
315
- lines.push(hostPostureRefusalContent(hostPosture));
316
+ lines.push(hostPostureRefusalContent(hostPosture, lang));
316
317
  const inheritEnv = hostPosture ? null : inheritEnvRefusalFromError(err, sentRequest);
317
318
  if (inheritEnv)
318
319
  lines.push(inheritEnvRefusalContent(inheritEnv, lang));
319
- const bucket = inheritEnv ? null : settingsPermissionBucketRefusalFromError(err);
320
+ const bucket = inheritEnv ? null : fieldLimitRefusalFromError(err);
320
321
  const toolDecl = toolDeclarationRefusalFromError(err);
321
322
  if (toolDecl)
322
- lines.push(toolDeclarationRefusalContent(toolDecl));
323
+ lines.push(toolDeclarationRefusalContent(toolDecl, lang));
324
+ const prepareCode = toolDecl ? undefined : prepareRefusalCodeOf(err);
325
+ const prepareNote = prepareCode === undefined ? undefined : prepareRefusalNoteOf(prepareCode, userAttachmentRefusalFromError(err) ?? undefined);
326
+ if (prepareNote !== undefined)
327
+ lines.push(prepareNote);
328
+ const wall = admissionWallRefusalFromError(err);
329
+ if (wall)
330
+ lines.push(admissionWallRefusalContent(wall));
323
331
  const lease = fleetLeaseUnavailableFromError(err);
324
332
  if (lease)
325
- lines.push(fleetLeaseUnavailableContent(lease));
333
+ lines.push(fleetLeaseUnavailableContent(lease, lang));
326
334
  const policyBlock = quota || scenarioDeny || resumeRefusal || resumeReopen || resumeGone || usageWindow || hostPosture ? null : resumePolicyBlockFromError(err);
327
335
  if (policyBlock)
328
336
  lines.push(resumePolicyBlockContent(policyBlock, lang));
329
337
  if (bucket)
330
- lines.push(settingsPermissionBucketRefusalContent(bucket));
338
+ lines.push(fieldLimitRefusalContent(bucket, lang));
331
339
  const settingsRefusal = settingsBodyShapeNote(err, sentRequest, lang);
332
340
  if (settingsRefusal !== undefined)
333
341
  lines.push(settingsRefusal);