@sema-agent/client-core 0.110.0 → 0.111.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 (176) hide show
  1. package/CHANGELOG.md +169 -0
  2. package/README.md +50 -18
  3. package/dist/abortableSleep.d.ts +7 -0
  4. package/dist/abortableSleep.js +37 -0
  5. package/dist/adapt/arms.js +25 -4
  6. package/dist/adapt/toolCards.d.ts +3 -1
  7. package/dist/adapt/toolCards.js +4 -2
  8. package/dist/adapter/activeRunSelfHeal.d.ts +39 -0
  9. package/dist/adapter/activeRunSelfHeal.js +171 -3
  10. package/dist/adapter/downstream/eventToSdkMessage.js +10 -10
  11. package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -0
  12. package/dist/adapter/downstream/terminalToSdkResult.js +11 -0
  13. package/dist/adapter/runStream.d.ts +5 -0
  14. package/dist/adapter/runStream.js +15 -3
  15. package/dist/attachmentRoute.d.ts +20 -0
  16. package/dist/attachmentRoute.js +39 -0
  17. package/dist/attachmentsWireCaps.js +1 -1
  18. package/dist/builtinOutputStyles.d.ts +12 -0
  19. package/dist/builtinOutputStyles.js +147 -0
  20. package/dist/compactionStatus.d.ts +9 -0
  21. package/dist/compactionStatus.js +29 -5
  22. package/dist/controlRouter.js +2 -1
  23. package/dist/coreValuePorts.d.ts +39 -1
  24. package/dist/coreValuePorts.js +10 -0
  25. package/dist/displayUntrusted.d.ts +1 -0
  26. package/dist/displayUntrusted.js +6 -0
  27. package/dist/engineHealthFacts.d.ts +11 -0
  28. package/dist/engineHealthFacts.js +21 -0
  29. package/dist/engineHealthProbeVerdict.d.ts +23 -0
  30. package/dist/engineHealthProbeVerdict.js +115 -0
  31. package/dist/engineNoticeCodes.js +5 -7
  32. package/dist/engineRepoint.d.ts +12 -5
  33. package/dist/engineRepoint.js +44 -19
  34. package/dist/engineRowRef.d.ts +3 -0
  35. package/dist/engineRowRef.js +11 -1
  36. package/dist/engineSwapCrossing.d.ts +57 -0
  37. package/dist/engineSwapCrossing.js +297 -0
  38. package/dist/engineUnavailable.d.ts +44 -0
  39. package/dist/engineUnavailable.js +492 -0
  40. package/dist/eventLeg.js +3 -3
  41. package/dist/generated/sdkFactTables.d.ts +1 -1
  42. package/dist/generated/sdkFactTables.js +1 -0
  43. package/dist/generated/settingsSchemaTables.d.ts +4 -0
  44. package/dist/generated/settingsSchemaTables.js +1 -0
  45. package/dist/hitl/approvalDelivery.d.ts +1 -0
  46. package/dist/hitl/approvalDelivery.js +1 -1
  47. package/dist/hitl/approvalResolution.d.ts +1 -1
  48. package/dist/hitl/approvalResolution.js +2 -1
  49. package/dist/hitl/askGateWire.js +5 -6
  50. package/dist/hitl/decisionRefusal.d.ts +2 -0
  51. package/dist/hitl/decisionRefusal.js +7 -8
  52. package/dist/hitl/decisionRefusalCarrier.d.ts +3 -0
  53. package/dist/hitl/decisionRefusalCarrier.js +348 -0
  54. package/dist/hitl/decisionSend.d.ts +7 -0
  55. package/dist/hitl/decisionSend.js +34 -12
  56. package/dist/hitl/editedApprovalAcceptance.js +1 -1
  57. package/dist/hitl/elicitationRefusal.d.ts +4 -0
  58. package/dist/hitl/elicitationRefusal.js +23 -0
  59. package/dist/hitl/frameRouter.d.ts +2 -2
  60. package/dist/hitl/frameRouter.js +8 -15
  61. package/dist/hitl/gateIdentity.d.ts +5 -0
  62. package/dist/hitl/gateIdentity.js +23 -0
  63. package/dist/hitl/hitlBridge.d.ts +6 -0
  64. package/dist/hitl/hitlBridge.js +10 -4
  65. package/dist/hitl/hitlHostSurface.d.ts +2 -1
  66. package/dist/hitl/hitlHostSurface.js +7 -2
  67. package/dist/hitl/localAllowRedemption.d.ts +67 -0
  68. package/dist/hitl/localAllowRedemption.js +256 -0
  69. package/dist/hitl/parkResolver.js +7 -4
  70. package/dist/hitl/persistedRulesWire.d.ts +16 -0
  71. package/dist/hitl/persistedRulesWire.js +70 -0
  72. package/dist/hitl/planReviewWire.d.ts +3 -0
  73. package/dist/hitl/planReviewWire.js +23 -6
  74. package/dist/hitl/policyDenyCause.d.ts +1 -1
  75. package/dist/hitl/policyDenyCause.js +1 -1
  76. package/dist/hitl/resumeRunningCard.d.ts +1 -0
  77. package/dist/hitl/resumeRunningCard.js +1 -0
  78. package/dist/hitl/screenCardCarriers.d.ts +15 -0
  79. package/dist/hitl/screenCardCarriers.js +41 -0
  80. package/dist/hitl/screenDecisionCards.d.ts +98 -0
  81. package/dist/hitl/screenDecisionCards.js +362 -0
  82. package/dist/hitl/standingRows.d.ts +3 -1
  83. package/dist/hitl/standingRows.js +18 -0
  84. package/dist/hitl/toolApprovalWire.d.ts +30 -8
  85. package/dist/hitl/toolApprovalWire.js +264 -121
  86. package/dist/hooksWireCaps.js +3 -3
  87. package/dist/hostSettingNoticeArm.d.ts +3 -0
  88. package/dist/hostSettingNoticeArm.js +12 -0
  89. package/dist/hostTurnSettings.d.ts +3 -0
  90. package/dist/hostTurnSettings.js +38 -5
  91. package/dist/humanTurnRead.js +11 -1
  92. package/dist/i18n/messages.en.d.ts +129 -0
  93. package/dist/i18n/messages.en.js +135 -7
  94. package/dist/i18n/messages.zh.js +142 -6
  95. package/dist/i18n/translate.d.ts +3 -0
  96. package/dist/i18n/translate.js +78 -10
  97. package/dist/i18n/zh.d.ts +1 -0
  98. package/dist/i18n/zh.js +1 -0
  99. package/dist/index.d.ts +43 -17
  100. package/dist/index.js +30 -12
  101. package/dist/interactiveHalt.js +2 -1
  102. package/dist/interactiveInterrupt.js +20 -2
  103. package/dist/liveModelCatalog.js +2 -2
  104. package/dist/localEngineSeatReading.d.ts +2 -2
  105. package/dist/localEngineSeatReading.js +5 -3
  106. package/dist/localEngineSpawn.d.ts +0 -7
  107. package/dist/localEngineSpawn.js +0 -92
  108. package/dist/localEngineStep.d.ts +2 -2
  109. package/dist/localEngineStep.js +2 -0
  110. package/dist/mcpReconnect.js +3 -3
  111. package/dist/mcpWireCaps.js +1 -1
  112. package/dist/model/engineModelWords.d.ts +3 -0
  113. package/dist/model/engineModelWords.js +13 -0
  114. package/dist/model/subagentModelWord.d.ts +21 -2
  115. package/dist/model/subagentModelWord.js +100 -29
  116. package/dist/modelCapabilityProbe.js +3 -40
  117. package/dist/notifications.d.ts +19 -0
  118. package/dist/notifications.js +114 -12
  119. package/dist/ownKey.d.ts +6 -0
  120. package/dist/ownKey.js +31 -0
  121. package/dist/pendingUserRow.d.ts +4 -0
  122. package/dist/pendingUserRow.js +16 -0
  123. package/dist/permissionsDeclaration.d.ts +1 -0
  124. package/dist/permissionsDeclaration.js +11 -1
  125. package/dist/planReviewCardFacts.d.ts +3 -0
  126. package/dist/planReviewCardFacts.js +52 -2
  127. package/dist/pluginHooksWire.d.ts +9 -1
  128. package/dist/pluginHooksWire.js +40 -6
  129. package/dist/printToolResultFrame.js +4 -2
  130. package/dist/promptBlockedCopy.js +11 -6
  131. package/dist/promptSuggestionBatch.d.ts +7 -0
  132. package/dist/promptSuggestionBatch.js +9 -0
  133. package/dist/promptSuggestionsTail.d.ts +39 -0
  134. package/dist/promptSuggestionsTail.js +116 -0
  135. package/dist/request/taskRequest.js +10 -6
  136. package/dist/requestCoordinate.d.ts +1 -0
  137. package/dist/requestCoordinate.js +13 -0
  138. package/dist/rewindArchiveReading.js +4 -4
  139. package/dist/runCancelContext.d.ts +2 -1
  140. package/dist/runCancelContext.js +1 -0
  141. package/dist/runPermissionModeSwitch.js +2 -2
  142. package/dist/scenarioRefusal.js +11 -13
  143. package/dist/scenarioSkills.js +11 -6
  144. package/dist/seam.d.ts +16 -2
  145. package/dist/seam.js +10 -0
  146. package/dist/seatContract.d.ts +109 -9
  147. package/dist/seatContract.js +218 -15
  148. package/dist/sessionCostReading.d.ts +70 -0
  149. package/dist/sessionCostReading.js +150 -0
  150. package/dist/sessionHooksRoster.d.ts +4 -0
  151. package/dist/sessionHooksRoster.js +158 -0
  152. package/dist/sessionMemoryStatus.js +2 -2
  153. package/dist/sessionReadRedaction.d.ts +7 -0
  154. package/dist/sessionReadRedaction.js +26 -0
  155. package/dist/sessionSyncFileHistory.js +8 -9
  156. package/dist/settingsHooksSalvage.js +2 -1
  157. package/dist/sseIdleTriage.js +2 -1
  158. package/dist/storeDurabilityWord.d.ts +15 -0
  159. package/dist/storeDurabilityWord.js +18 -0
  160. package/dist/storePostureCapability.d.ts +7 -3
  161. package/dist/storePostureCapability.js +69 -39
  162. package/dist/subagent/engineSubagentResume.js +2 -2
  163. package/dist/subagent/engineSubagentTail.js +2 -1
  164. package/dist/subagentContentStore.d.ts +11 -0
  165. package/dist/subagentContentStore.js +28 -2
  166. package/dist/toolResult.d.ts +1 -0
  167. package/dist/toolResult.js +2 -0
  168. package/dist/userAttachmentEnvelope.d.ts +2 -1
  169. package/dist/userAttachmentEnvelope.js +10 -0
  170. package/dist/wireErrorTriage.js +2 -1
  171. package/dist/wireFailureShape.d.ts +4 -0
  172. package/dist/wireFailureShape.js +141 -19
  173. package/dist/wireRefusalCopy.d.ts +6 -5
  174. package/dist/wireRefusalCopy.js +49 -92
  175. package/docs/INTEGRATION-CLIENTS.md +2118 -17
  176. package/package.json +6 -2
@@ -3,6 +3,8 @@ import { engineWireTargetBaseUrl } from './engineWireTarget.js';
3
3
  import { storeSeatOf, createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
4
4
  import { projectSqlEngineCapability } from './sqlEngineCapability.js';
5
5
  import { ownDataField } from './ownKey.js';
6
+ import { readStoreDurability } from './storeDurabilityWord.js';
7
+ import { msg, renderMessage } from './i18n/translate.js';
6
8
  const nonEmpty = (v) => typeof v === 'string' && v !== '';
7
9
  export function projectStorePostureCapability(caps) {
8
10
  try {
@@ -21,8 +23,8 @@ function projectStorePostureOf(caps) {
21
23
  const store = seat.store;
22
24
  const declared = ownDataField(store, 'declared');
23
25
  const backend = ownDataField(store, 'backend');
24
- const durable = ownDataField(store, 'durable');
25
- if (!nonEmpty(declared) || !nonEmpty(backend) || typeof durable !== 'boolean')
26
+ const durability = durabilityOf(store, 'wire');
27
+ if (!nonEmpty(declared) || !nonEmpty(backend) || durability.kind === 'malformed')
26
28
  return undefined;
27
29
  const reason = ownDataField(store, 'degradedReason');
28
30
  if (reason !== undefined && !nonEmpty(reason))
@@ -35,12 +37,44 @@ function projectStorePostureOf(caps) {
35
37
  view: {
36
38
  declared,
37
39
  backend,
38
- durable,
40
+ ...(durability.kind === 'legacy' ? { durable: durability.durable } : {}),
41
+ ...(durability.kind === 'word' ? { durability: durability.durability } : {}),
42
+ ...(durability.kind === 'unrecognized' ? { unrecognizedDurability: durability.word } : {}),
39
43
  ...(nonEmpty(reason) ? { degradedReason: reason } : {}),
40
44
  ...(sqlReading.kind === 'present' ? { sql: sqlReading.view } : {}),
41
45
  },
42
46
  };
43
47
  }
48
+ const MALFORMED_DURABILITY = Object.freeze({ kind: 'malformed' });
49
+ function durabilityOf(section, side) {
50
+ try {
51
+ const word = readStoreDurability(section);
52
+ const durable = ownDataField(section, 'durable');
53
+ const unrecognized = side === 'view' ? ownDataField(section, 'unrecognizedDurability') : undefined;
54
+ const present = (word.kind === 'absent' ? 0 : 1) + (durable === undefined ? 0 : 1) + (unrecognized === undefined ? 0 : 1);
55
+ if (present !== 1)
56
+ return MALFORMED_DURABILITY;
57
+ if (word.kind === 'word')
58
+ return { kind: 'word', durability: word.durability };
59
+ if (word.kind === 'unrecognized')
60
+ return { kind: 'unrecognized', word: word.word };
61
+ if (typeof durable === 'boolean')
62
+ return { kind: 'legacy', durable };
63
+ if (nonEmpty(unrecognized))
64
+ return { kind: 'unrecognized', word: unrecognized };
65
+ return MALFORMED_DURABILITY;
66
+ }
67
+ catch {
68
+ return MALFORMED_DURABILITY;
69
+ }
70
+ }
71
+ function persistenceOf(d) {
72
+ if (d.kind === 'legacy')
73
+ return d.durable ? 'durable' : 'not_durable';
74
+ if (d.kind !== 'word')
75
+ return 'unknown';
76
+ return d.durability === 'durable' ? 'durable' : d.durability === 'ephemeral' ? 'not_durable' : 'unknown';
77
+ }
44
78
  const reader = createEngineCapReader({
45
79
  name: 'store',
46
80
  project: projectStorePostureCapability,
@@ -70,58 +104,54 @@ export function storePersistence(reading) {
70
104
  const r = presentView(reading);
71
105
  if (r?.kind !== 'present')
72
106
  return 'unknown';
73
- let durable;
74
- try {
75
- durable = r.view.durable;
76
- }
77
- catch {
78
- return 'unknown';
79
- }
80
- return durable === true ? 'durable' : durable === false ? 'not_durable' : 'unknown';
107
+ return persistenceOf(durabilityOf(r.view, 'view'));
81
108
  }
82
- const STORE_NOT_DURABLE_HEAD = 'NOT durable';
83
- export function storePostureHeadWord(reading) {
84
- return storePersistence(reading) === 'not_durable' ? STORE_NOT_DURABLE_HEAD : undefined;
109
+ const notDurableHead = () => msg('notice.capability.storePosture.notDurableHead');
110
+ export function storePostureHeadWord(reading, lang) {
111
+ return storePersistence(reading) === 'not_durable' ? renderMessage(notDurableHead(), lang) : undefined;
85
112
  }
86
113
  const WORD_DETAIL_MAX = 40;
87
114
  const word = (v) => capForDisplay(v, WORD_DETAIL_MAX);
88
- export function storePostureDoctorDetail(reading) {
89
- const unobserved = 'store posture not observed — the engine reports it on /v1/capabilities; this process has no usable capabilities reading cached for it, so whether this deployment persists its state is unknown';
115
+ export function storePostureDoctorDetail(reading, lang) {
116
+ const say = (ref) => renderMessage(ref, lang);
117
+ const unobserved = msg('notice.capability.storePosture.unobserved');
90
118
  const r = presentView(reading);
91
119
  if (r?.kind === 'unreadable')
92
- return unreadableReadingDetail('store posture');
93
- if (r?.kind === 'not_reported') {
94
- return 'store posture not reported by this engine; this does not say whether this deployment persists its state';
95
- }
120
+ return unreadableReadingDetail(say(msg('notice.capability.subject.storePosture')), lang);
121
+ if (r?.kind === 'not_reported')
122
+ return say(msg('notice.capability.storePosture.notReported'));
96
123
  if (r?.kind !== 'present')
97
- return unobserved;
124
+ return say(unobserved);
98
125
  let declared;
99
126
  let backend;
100
- let durable;
101
127
  let reason;
102
128
  try {
103
129
  declared = r.view.declared;
104
130
  backend = r.view.backend;
105
- durable = r.view.durable;
106
131
  reason = r.view.degradedReason;
107
132
  }
108
133
  catch {
109
- return unobserved;
110
- }
111
- if (!nonEmpty(declared) || !nonEmpty(backend) || typeof durable !== 'boolean')
112
- return unobserved;
113
- const assembled = declared === backend ? `store ${word(backend)}` : `store declared ${word(declared)}, running on ${word(backend)}`;
114
- if (durable) {
115
- return `${assembled} — durable: this replica persists its state, so it survives a restart`;
134
+ return say(unobserved);
116
135
  }
117
- const lost = `${STORE_NOT_DURABLE_HEAD}: this replica holds its state in memory and loses it on restart`;
136
+ const durability = durabilityOf(r.view, 'view');
137
+ if (!nonEmpty(declared) || !nonEmpty(backend) || durability.kind === 'malformed')
138
+ return say(unobserved);
139
+ const assembled = declared === backend
140
+ ? msg('notice.capability.storePosture.assembled', { backend: word(backend) })
141
+ : msg('notice.capability.storePosture.assembledDeclared', { declared: word(declared), backend: word(backend) });
142
+ if (durability.kind === 'unrecognized')
143
+ return say(msg('notice.capability.storePosture.unrecognized', { assembled, word: word(durability.word) }));
144
+ const persistence = persistenceOf(durability);
145
+ if (persistence === 'durable')
146
+ return say(msg('notice.capability.storePosture.durable', { assembled }));
147
+ if (persistence === 'unknown')
148
+ return say(msg('notice.capability.storePosture.unknown', { assembled }));
149
+ const line = msg(durability.kind === 'legacy' ? 'notice.capability.storePosture.memory' : 'notice.capability.storePosture.ephemeral', { assembled, head: notDurableHead() });
118
150
  if (!nonEmpty(reason))
119
- return `${assembled} — ${lost}`;
120
- if (reason === 'db_unreachable') {
121
- return `${assembled} — ${lost} (degraded: the declared database could not be opened at start-up, so the engine fell back rather than refusing to start)`;
122
- }
123
- if (reason === 'local_unwritable') {
124
- return `${assembled} — ${lost} (degraded: the default local file store could not be created — a read-only or full data directory is one possible cause, and this client cannot tell which applies)`;
125
- }
126
- return `${assembled} — ${lost} (degraded for a reason this client does not know yet: "${word(reason)}")`;
151
+ return say(line);
152
+ if (reason === 'db_unreachable')
153
+ return say(msg('notice.capability.storePosture.degraded.dbUnreachable', { line }));
154
+ if (reason === 'local_unwritable')
155
+ return say(msg('notice.capability.storePosture.degraded.localUnwritable', { line }));
156
+ return say(msg('notice.capability.storePosture.degraded.other', { line, reason: word(reason) }));
127
157
  }
@@ -1,7 +1,7 @@
1
1
  import { hostLog } from '../host.js';
2
2
  import { isNotFoundFailure, resumeRetryLaterFromError } from '../wireErrorTriage.js';
3
3
  import { readThrownSlot, THROWN_SLOT_UNREADABLE } from '../wireFailureShape.js';
4
- import { RESUME_SESSION_NOT_FOUND } from '../engineErrorCodes.js';
4
+ import { RESUME_SESSION_NOT_FOUND, STEERING_NOT_RUNNING } from '../engineErrorCodes.js';
5
5
  import { displayUntrusted } from '../displayUntrusted.js';
6
6
  import { engineCapTrue } from '../engineCapsCache.js';
7
7
  import { clientHasVerbs, engineWireFor, INJECTED_WIRE_SETTLE_MS, noAnswerDetailFrom, sendOnce, settleInjected } from '../engineWireFor.js';
@@ -63,7 +63,7 @@ export function classifySubagentResumeFailure(e) {
63
63
  }
64
64
  if (errorCode === 'steering.still_running')
65
65
  return { reason: 'still-running', detail: message };
66
- if (errorCode === 'steering.not_running')
66
+ if (errorCode === STEERING_NOT_RUNNING)
67
67
  return { reason: 'not-resumable', detail: message };
68
68
  if (errorCode === 'steering.ambiguous_target')
69
69
  return { reason: 'ambiguous-target', detail: message };
@@ -4,7 +4,7 @@ import { clientHasVerbs, engineWireFor, INJECTED_WIRE_SETTLE_MS, settleInjected
4
4
  import { engineCapStateVia } from '../engineCapsCache.js';
5
5
  import { engineSessionParamFor } from '../engineSessionParam.js';
6
6
  import { resolveOwnerContext } from './engineSubagentResume.js';
7
- import { coerceOutput, parentToolCallIdOf, publishSubagentContentEvent, settleSubagentContent, } from '../subagentContentStore.js';
7
+ import { coerceOutput, parentToolCallIdOf, publishSubagentContentEvent, settleSubagentContent, subagentToolEndDenialParts, } from '../subagentContentStore.js';
8
8
  import { noteBgOwnerAbsence } from './subagentOwnerAbsence.js';
9
9
  import { readFrameTrueMark } from '../ownKey.js';
10
10
  import { publishEngineInlineTaskModel } from '../engineInlineTaskStats.js';
@@ -143,6 +143,7 @@ export function tailEngineSubagent(taskId, opts) {
143
143
  ...(out !== undefined ? { output: out } : {}),
144
144
  ...(d.isError === true ? { isError: true } : {}),
145
145
  ...(readFrameTrueMark(d, 'notExecuted') ? { notExecuted: true } : {}),
146
+ ...subagentToolEndDenialParts(d),
146
147
  });
147
148
  }
148
149
  else if (t === 'task_settled') {
@@ -1,3 +1,4 @@
1
+ import { type CcToolDenialKind } from './gateVocabulary.js';
1
2
  export type SubagentContentItem = {
2
3
  kind: 'text';
3
4
  text: string;
@@ -12,6 +13,8 @@ export type SubagentContentItem = {
12
13
  output?: string;
13
14
  isError?: boolean;
14
15
  notExecuted?: true;
16
+ denialKind?: CcToolDenialKind;
17
+ refusalNoted?: true;
15
18
  } | {
16
19
  kind: 'echo';
17
20
  text: string;
@@ -33,7 +36,13 @@ export interface SubagentContentEvent {
33
36
  output?: string | undefined;
34
37
  isError?: boolean | undefined;
35
38
  notExecuted?: true | undefined;
39
+ denialKind?: CcToolDenialKind | undefined;
40
+ refusalNoted?: true | undefined;
36
41
  }
42
+ export declare function subagentToolEndDenialParts(frame: object): {
43
+ denialKind?: CcToolDenialKind;
44
+ refusalNoted?: true;
45
+ };
37
46
  export declare function coerceOutput(v: unknown): string | undefined;
38
47
  export declare function subagentContentEventOf(ev: {
39
48
  readonly type: string;
@@ -97,6 +106,8 @@ export type SubagentViewSlot = {
97
106
  output?: string;
98
107
  isError?: boolean;
99
108
  notExecuted?: true;
109
+ denialKind?: CcToolDenialKind;
110
+ refusalNoted?: true;
100
111
  };
101
112
  export declare function planSubagentViewSlots(taskId: string): SubagentViewSlot[];
102
113
  export declare function parentToolCallIdOf(taskId: string): string | undefined;
@@ -1,7 +1,18 @@
1
1
  import { DEFAULT_SESSION_KEY } from './sessionSlot.js';
2
- import { readFrameTrueMark, readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
2
+ import { guardedRead, readFrameTrueMark, readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
3
3
  import { cycleSeqValue } from './cycleOrder.js';
4
4
  import { toolEndOutputText } from './toolResultContent.js';
5
+ import { ccToolDenialKindForToolEnd, gateOutcomeOf } from './gateOutcome.js';
6
+ import { isCcToolDenialKind } from './gateVocabulary.js';
7
+ import { refusalNotedOf } from './engineRowRef.js';
8
+ export function subagentToolEndDenialParts(frame) {
9
+ const denialKind = guardedRead(() => ccToolDenialKindForToolEnd(frame));
10
+ const gate = guardedRead(() => gateOutcomeOf(frame));
11
+ return {
12
+ ...(denialKind !== undefined ? { denialKind } : {}),
13
+ ...(refusalNotedOf(denialKind, gate) ? { refusalNoted: true } : {}),
14
+ };
15
+ }
5
16
  export function coerceOutput(v) {
6
17
  return toolEndOutputText(v);
7
18
  }
@@ -26,6 +37,7 @@ export function subagentContentEventOf(ev) {
26
37
  output: coerceOutput(sub.output),
27
38
  isError: sub.isError,
28
39
  notExecuted: readFrameTrueMark(sub, 'notExecuted') ? true : undefined,
40
+ ...(t === 'tool_end' ? subagentToolEndDenialParts(ev) : {}),
29
41
  };
30
42
  }
31
43
  const MAX_ITEMS_PER_TASK = 200;
@@ -633,16 +645,26 @@ export function publishSubagentContentEvent(ev) {
633
645
  const outBefore = it.output;
634
646
  const errBefore = it.isError;
635
647
  const notExecBefore = it.notExecuted;
648
+ const denialBefore = it.denialKind;
649
+ const notedBefore = it.refusalNoted;
636
650
  it.output = ev.output ?? '';
637
651
  it.isError = ev.isError === true;
638
652
  if (ev.notExecuted === true)
639
653
  it.notExecuted = true;
640
654
  else
641
655
  delete it.notExecuted;
656
+ if (isCcToolDenialKind(ev.denialKind))
657
+ it.denialKind = ev.denialKind;
658
+ else
659
+ delete it.denialKind;
660
+ if (ev.refusalNoted === true)
661
+ it.refusalNoted = true;
662
+ else
663
+ delete it.refusalNoted;
642
664
  const delta = itemBytesOf(it) - before;
643
665
  s.itemBytes[at] = (s.itemBytes[at] ?? 0) + delta;
644
666
  addBytes(s, delta);
645
- stampPhase(s, it.id, 'end', ev.eventId, it.output !== outBefore || it.isError !== errBefore || it.notExecuted !== notExecBefore);
667
+ stampPhase(s, it.id, 'end', ev.eventId, it.output !== outBefore || it.isError !== errBefore || it.notExecuted !== notExecBefore || it.denialKind !== denialBefore || it.refusalNoted !== notedBefore);
646
668
  break;
647
669
  }
648
670
  const synthId = id ?? `${ev.taskId}-tool-${s.items.length}`;
@@ -654,6 +676,8 @@ export function publishSubagentContentEvent(ev) {
654
676
  output: ev.output ?? '',
655
677
  isError: ev.isError === true,
656
678
  ...(ev.notExecuted === true ? { notExecuted: true } : {}),
679
+ ...(isCcToolDenialKind(ev.denialKind) ? { denialKind: ev.denialKind } : {}),
680
+ ...(ev.refusalNoted === true ? { refusalNoted: true } : {}),
657
681
  });
658
682
  recordCut(s);
659
683
  stampPhase(s, synthId, 'end', ev.eventId, true);
@@ -698,6 +722,8 @@ export function planSubagentViewSlots(taskId) {
698
722
  ...(it.output !== undefined ? { output: it.output } : {}),
699
723
  ...(it.isError === true ? { isError: true } : {}),
700
724
  ...(it.notExecuted === true ? { notExecuted: true } : {}),
725
+ ...(it.denialKind !== undefined ? { denialKind: it.denialKind } : {}),
726
+ ...(it.refusalNoted === true ? { refusalNoted: true } : {}),
701
727
  });
702
728
  }
703
729
  else if (it.kind === 'text') {
@@ -109,6 +109,7 @@ export interface ToolResultRowFlags {
109
109
  readonly interruptedNeverStarted: boolean;
110
110
  readonly approvalWindowExpired: boolean;
111
111
  readonly denialLimitWindowExpired: boolean;
112
+ readonly refusalNoted: boolean;
112
113
  }
113
114
  export declare function toolResultRowFlagsOf(row: object | null | undefined): ToolResultRowFlags;
114
115
  export type ToolKillCause = NonNullable<ReturnType<typeof toolKillCauseAcrossEngineIdentity>> | 'memory_pressure';
@@ -8,6 +8,7 @@ import { guardedRead, ownDataField, ownSnapshotWhenTyped, readFrameTrueMark, rea
8
8
  import { displayUntrusted } from './displayUntrusted.js';
9
9
  import { isCoreSemaTaskTerminal } from './terminalStatuses.js';
10
10
  import { CORE_ENGINE_CARD_TYPES } from './generated/engineFactTables.js';
11
+ import { SEMA_REFUSAL_NOTED_KEY } from './engineRowRef.js';
11
12
  export const STRUCTURED_DETAIL_TYPES = frozenSet(CORE_ENGINE_CARD_TYPES);
12
13
  const LEGACY_STRUCTURED_DETAIL_TYPE = 'task-output';
13
14
  export function structuredDetailType(structured) {
@@ -318,6 +319,7 @@ export function toolResultRowFlagsOf(row) {
318
319
  interruptedNeverStarted: readFrameTrueMark(row, '_sema_interrupted_never_started'),
319
320
  approvalWindowExpired: readFrameTrueMark(row, '_sema_approval_window_expired'),
320
321
  denialLimitWindowExpired: readFrameTrueMark(row, '_sema_denial_limit_window_expired'),
322
+ refusalNoted: readFrameTrueMark(row, SEMA_REFUSAL_NOTED_KEY),
321
323
  });
322
324
  }
323
325
  const TOOL_KILL_TEXT = {
@@ -1,6 +1,6 @@
1
1
  import { type DescriptorView } from './humanTurnRead.js';
2
2
  export type UserAttachmentSource = 'at-mention' | 'compact-restore';
3
- export type UserAttachmentNotIncludedReason = 'too-large' | 'unreadable' | 'read-denied' | 'approval-required' | 'server-not-connected' | 'resource-not-listed' | 'read-failed';
3
+ export type UserAttachmentNotIncludedReason = 'too-large' | 'unreadable' | 'read-denied' | 'approval-required' | 'server-not-connected' | 'resource-not-listed' | 'read-failed' | 'tools-elsewhere' | 'tools-location-unconfirmed';
4
4
  export type UserAttachmentMcpResourcePart = {
5
5
  readonly kind: 'text';
6
6
  readonly text: string;
@@ -77,6 +77,7 @@ export type UserAttachmentDescriptor = {
77
77
  readonly truncated: boolean;
78
78
  };
79
79
  export declare function showAttachmentName(s: string): string;
80
+ export declare function showAttachmentNameCc(s: string): string;
80
81
  export declare function mintEnvelopeOf(d: DescriptorView, imageDelivery: 'attached' | 'not-attached'): string;
81
82
  export declare function seatTextOf(d: DescriptorView): string | undefined;
82
83
  export declare function mintReferenceOf(d: DescriptorView): string;
@@ -1,4 +1,5 @@
1
1
  import { readDescriptor } from './humanTurnRead.js';
2
+ import { msg, renderMessage } from './i18n/translate.js';
2
3
  const TILDE_CLASS_RUN = /[~\u02DC\u2053\u223C\u301C\uFF5E]+/g;
3
4
  function envelopeFence(text) {
4
5
  let longest = 0;
@@ -29,6 +30,13 @@ export function showAttachmentName(s) {
29
30
  return cp > 0xffff ? `\\u{${cp.toString(16)}}` : `\\u${hex4(cp)}`;
30
31
  });
31
32
  }
33
+ const CC_CONTROL_UNITS = /[\p{Cc}\u2028\u2029]/gu;
34
+ export function showAttachmentNameCc(s) {
35
+ return String(s ?? '')
36
+ .replaceAll('<', '&lt;')
37
+ .replaceAll('>', '&gt;')
38
+ .replace(CC_CONTROL_UNITS, (c) => `&#${c.charCodeAt(0)};`);
39
+ }
32
40
  const ESCAPE_NOTE = 'Some lines contain line-break control characters inside the line; they are shown as escape sequences (such as \\r or \\u2028), so those lines are not byte-for-byte the same as the file.';
33
41
  const plural = (n, one, many) => `${n} ${n === 1 ? one : many}`;
34
42
  function firstLine(source, what, name) {
@@ -169,6 +177,8 @@ const NOT_INCLUDED_REASON = Object.freeze({
169
177
  'server-not-connected': 'the MCP server it comes from is not connected',
170
178
  'resource-not-listed': 'the MCP server does not list that resource',
171
179
  'read-failed': 'reading it from the MCP server failed',
180
+ 'tools-elsewhere': renderMessage(msg('attachments.withheld.toolsElsewhere.model')),
181
+ 'tools-location-unconfirmed': renderMessage(msg('attachments.withheld.toolsLocationUnconfirmed.model')),
172
182
  });
173
183
  function targetWhat(target) {
174
184
  return target === 'directory' ? 'a directory' : target === 'file' ? 'a file' : 'a file or directory';
@@ -2,6 +2,7 @@ import { PROTOCOL_ERROR_NAME, effectiveWireCodeReading, isSlotCarrier, protocolE
2
2
  import { capForDisplay, escapeDisplayControlChars } from './fleetTaskDesc.js';
3
3
  import { readOwnDataValue } from './ownKey.js';
4
4
  import { fleetLeaseUnavailableFromError } from './wireRefusalCopy.js';
5
+ import { isStreamEndedWithoutTerminalError } from './sseIdleTriage.js';
5
6
  import { answerReadingOf, captureAnswer, captureUnanswered, causeSlotReadOf, effectiveCodeOf, noteTriageReading, ownReadingSlot } from './engineWireFor.js';
6
7
  import { CORRUPT_ROW_ERROR_CODE, DRAINING_ERROR_CODE, FLEET_LEASE_UNAVAILABLE, isCorruptSessionCode, RESUME_AT_ERROR_CODE_PREFIX, RESUME_RETRY_LATER_CODES, RESUME_USAGE_WINDOW_EXHAUSTED, SCENARIO_NOT_ALLOWED_ERROR_CODE, } from './engineErrorCodes.js';
7
8
  export const WIRE_NETWORK_ERROR_PATTERN = /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|EHOSTUNREACH|ENETUNREACH|EPIPE|socket hang up|UND_ERR|\bterminated\b|\bother side closed\b/i;
@@ -105,7 +106,7 @@ export function classifyTurnWireError(err) {
105
106
  if (captured !== undefined && captured.layer === err)
106
107
  return httpVerdictOf(captured, () => renderedText(err), undefined, topCauseRecordOf(err, topCauseRead));
107
108
  const slots = readTurnErrorSlots(err, topStatusOf(err, ans), topCauseRead);
108
- if (slots.status !== THROWN_SLOT_UNREADABLE && slots.name === 'StreamEndedWithoutTerminalError') {
109
+ if (slots.status !== THROWN_SLOT_UNREADABLE && isStreamEndedWithoutTerminalError(err)) {
109
110
  return noted({ kind: 'stream-ended-without-terminal' }, ans, captured, transportShapeOf(slots, err, ans), err, slots.errorCode, topCauseRead);
110
111
  }
111
112
  if (captured !== undefined) {
@@ -13,6 +13,8 @@ interface WireFailureShape {
13
13
  export declare const THROWN_SLOT_UNREADABLE: unique symbol;
14
14
  export declare function isSlotCarrier(x: {} | null | undefined): x is object;
15
15
  export declare function readThrownSlot(o: unknown, key: string, own?: boolean | 'data'): unknown;
16
+ export declare function errnoCode(e: {} | null | undefined): string | undefined;
17
+ export declare function thrownSlotOf(err: {} | null | undefined, name: string, kind?: boolean | 'data'): {} | null | undefined;
16
18
  export declare function thrownIsInstanceOf<C extends abstract new (...args: never[]) => unknown>(e: unknown, cls: C): e is InstanceType<C>;
17
19
  export type ThrownExtraReading = {
18
20
  readonly state: 'object';
@@ -27,6 +29,8 @@ export interface ThrownExtraSnapshot {
27
29
  readonly bag: ThrownExtraReading;
28
30
  }
29
31
  export declare function readThrownExtraSnapshot(o: {} | null | undefined): ThrownExtraSnapshot;
32
+ export declare function liftLegacyRefusalFacts(code: {} | null | undefined, bag: object): object;
33
+ export declare function placeThrownExtraOnCopy<V>(thrown: object, copy: object, copyBag: (bag: object) => V | undefined): 'placed' | 'not_placed' | 'place_failed';
30
34
  export declare const PROTOCOL_ERROR_NAME: Readonly<{
31
35
  readonly ApprovalBindingMismatchError: "ApprovalBindingMismatchError";
32
36
  readonly ApprovalStaleError: "ApprovalStaleError";
@@ -1,6 +1,7 @@
1
1
  import { msg, renderMessage } from './i18n/translate.js';
2
- import { guardedRead, ownDataField, readOwnDataValue } from './ownKey.js';
3
- import { RESUME_POLICY_FOLD_CODE } from './engineErrorCodes.js';
2
+ import { guardedRead, ownDataField, readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
3
+ import { CONFIG_AGENT_UNKNOWN_TOOL, CONFIG_TOOL_FACE_CONTROL, REQUEST_FIELD_CONFLICT, RESUME_POLICY_FOLD_CODE, SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE, USER_ATTACHMENT_INVALID_ERROR_CODE } from './engineErrorCodes.js';
4
+ import { requestCoordinateText } from './requestCoordinate.js';
4
5
  export const THROWN_SLOT_UNREADABLE = Symbol('thrown-slot-unreadable');
5
6
  export function isSlotCarrier(x) {
6
7
  return (typeof x === 'object' && x !== null) || typeof x === 'function';
@@ -20,6 +21,13 @@ export function readThrownSlot(o, key, own = false) {
20
21
  return THROWN_SLOT_UNREADABLE;
21
22
  }
22
23
  }
24
+ export function errnoCode(e) {
25
+ return guardedRead(() => readOwnDataNonEmptyString(e, 'code'));
26
+ }
27
+ export function thrownSlotOf(err, name, kind = false) {
28
+ const v = readThrownSlot(err, name, kind);
29
+ return v === THROWN_SLOT_UNREADABLE ? undefined : v;
30
+ }
23
31
  function readGuarded(o, key) {
24
32
  const v = readThrownSlot(o, key);
25
33
  return v === THROWN_SLOT_UNREADABLE ? undefined : v;
@@ -117,7 +125,125 @@ export function readThrownExtraSnapshot(o) {
117
125
  catch {
118
126
  return { bag: { state: 'unreadable' } };
119
127
  }
120
- return { bag: { state: 'object', value: slot } };
128
+ return { bag: { state: 'object', value: liftLegacyRefusalFacts(readThrownSlot(o, 'errorCode', 'data'), slot) } };
129
+ }
130
+ export function liftLegacyRefusalFacts(code, bag) {
131
+ try {
132
+ if (typeof code !== 'string')
133
+ return bag;
134
+ const dd = Object.getOwnPropertyDescriptor(bag, 'detail');
135
+ if (dd === undefined || !Object.hasOwn(dd, 'value'))
136
+ return bag;
137
+ const detail = dd.value;
138
+ if (typeof detail !== 'object' || detail === null || Array.isArray(detail))
139
+ return bag;
140
+ const moves = legacyRefusalMovesOf(code, bag, detail);
141
+ if (moves === undefined)
142
+ return bag;
143
+ const out = Object.create(null);
144
+ for (const key of Reflect.ownKeys(bag)) {
145
+ if (key === 'detail')
146
+ continue;
147
+ const d = Object.getOwnPropertyDescriptor(bag, key);
148
+ if (d !== undefined)
149
+ Object.defineProperty(out, key, { ...d, configurable: true });
150
+ }
151
+ for (const [key, value, override] of moves) {
152
+ if (!override && Object.getOwnPropertyDescriptor(out, key) !== undefined)
153
+ continue;
154
+ Object.defineProperty(out, key, { value, enumerable: true, writable: false, configurable: true });
155
+ }
156
+ return Object.freeze(out);
157
+ }
158
+ catch {
159
+ return bag;
160
+ }
161
+ }
162
+ const LEGACY_PROBLEMS_CODES = Object.freeze(['request.field_invalid', CONFIG_AGENT_UNKNOWN_TOOL, CONFIG_TOOL_FACE_CONTROL, 'request.unprocessable', RESUME_POLICY_FOLD_CODE]);
163
+ const LEGACY_HOOKS_KEYS = Object.freeze(['reason', 'event', 'alias', 'canonical', 'groupIndex', 'budgetMs', 'totalMs', 'type', 'key', 'count', 'cap']);
164
+ function legacyRefusalMovesOf(code, bag, detail) {
165
+ const moves = [];
166
+ const take = (from, to = from, override = false) => {
167
+ const v = guardedRead(() => readOwnDataValue(detail, from));
168
+ if (v !== undefined)
169
+ moves.push([to, v, override]);
170
+ };
171
+ const rootField = guardedRead(() => readOwnDataValue(bag, 'field'));
172
+ if (code === 'request.field_invalid' && rootField === 'settings.hooks') {
173
+ for (const k of LEGACY_HOOKS_KEYS)
174
+ take(k);
175
+ const path = legacyHooksPathOf(detail);
176
+ if (path !== undefined)
177
+ moves.push(['field', requestCoordinateText(path[0] === 'hooks' ? 'settings' : 'settings.hooks', path), true]);
178
+ for (const k of ['problems', 'total', 'callerTrust'])
179
+ take(k);
180
+ return moves;
181
+ }
182
+ if (code === REQUEST_FIELD_CONFLICT) {
183
+ take('kind', 'reason');
184
+ for (const k of ['fields', 'count', 'cap'])
185
+ take(k);
186
+ return moves;
187
+ }
188
+ if (LEGACY_PROBLEMS_CODES.includes(code)) {
189
+ for (const k of ['problems', 'total', 'callerTrust'])
190
+ take(k);
191
+ return moves;
192
+ }
193
+ if (code === 'conflict.session_placed')
194
+ take('placement_kind');
195
+ else if (code === SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE)
196
+ for (const k of ['scenario', 'source'])
197
+ take(k);
198
+ else if (code === 'steering.duplicate_input_id')
199
+ take('differs');
200
+ else if (code === USER_ATTACHMENT_INVALID_ERROR_CODE) {
201
+ const path = guardedRead(() => readOwnDataValue(detail, 'path'));
202
+ if (typeof path === 'string' && path.length > 0)
203
+ moves.push(['field', path, false]);
204
+ const index = guardedRead(() => readOwnDataValue(detail, 'index'));
205
+ if (typeof index === 'number' && Number.isSafeInteger(index) && index >= 0)
206
+ moves.push(['index', index, false]);
207
+ }
208
+ else
209
+ return undefined;
210
+ return moves;
211
+ }
212
+ function legacyHooksPathOf(detail) {
213
+ try {
214
+ const raw = readOwnDataValue(detail, 'path');
215
+ if (!Array.isArray(raw) || raw.length === 0)
216
+ return undefined;
217
+ const out = [];
218
+ for (let i = 0; i < raw.length; i++) {
219
+ if (!Object.hasOwn(raw, i))
220
+ return undefined;
221
+ const v = raw[i];
222
+ if (typeof v === 'string' || (typeof v === 'number' && Number.isSafeInteger(v) && v >= 0))
223
+ out.push(v);
224
+ else
225
+ return undefined;
226
+ }
227
+ return out;
228
+ }
229
+ catch {
230
+ return undefined;
231
+ }
232
+ }
233
+ export function placeThrownExtraOnCopy(thrown, copy, copyBag) {
234
+ try {
235
+ const bag = readThrownExtraSnapshot(thrown).bag;
236
+ if (bag.state !== 'object')
237
+ return 'not_placed';
238
+ const value = copyBag(bag.value);
239
+ if (value === undefined)
240
+ return 'not_placed';
241
+ Object.defineProperty(copy, EXTRA_KEY, { value, writable: true, enumerable: true, configurable: true });
242
+ return 'placed';
243
+ }
244
+ catch {
245
+ return 'place_failed';
246
+ }
121
247
  }
122
248
  export const PROTOCOL_ERROR_NAME = Object.freeze({
123
249
  ApprovalBindingMismatchError: 'ApprovalBindingMismatchError',
@@ -472,24 +598,20 @@ export function readRefusalNamedFields(o) {
472
598
  out.push(v);
473
599
  };
474
600
  add(guardedRead(() => readRefusalField(o)));
475
- const detail = guardedRead(() => readErrorRecord(o, 'detail'));
476
- if (detail !== undefined) {
477
- add(guardedRead(() => readOwnDataValue(detail, 'field')));
478
- try {
479
- const list = readOwnDataValue(detail, 'problems');
480
- if (Array.isArray(list)) {
481
- const n = list.length;
482
- const len = typeof n === 'number' && Number.isSafeInteger(n) && n > 0 ? Math.min(n, REFUSAL_PROBLEMS_READ_MAX) : 0;
483
- for (let i = 0; i < len; i += 1) {
484
- const item = guardedRead(() => readOwnDataValue(list, String(i)));
485
- if (typeof item !== 'object' || item === null)
486
- continue;
487
- add(guardedRead(() => readOwnDataValue(item, 'field')));
488
- }
601
+ try {
602
+ const list = readErrorPresent(o, 'problems');
603
+ if (Array.isArray(list)) {
604
+ const n = list.length;
605
+ const len = typeof n === 'number' && Number.isSafeInteger(n) && n > 0 ? Math.min(n, REFUSAL_PROBLEMS_READ_MAX) : 0;
606
+ for (let i = 0; i < len; i += 1) {
607
+ const item = guardedRead(() => readOwnDataValue(list, String(i)));
608
+ if (typeof item !== 'object' || item === null)
609
+ continue;
610
+ add(guardedRead(() => readOwnDataValue(item, 'field')));
489
611
  }
490
612
  }
491
- catch {
492
- }
613
+ }
614
+ catch {
493
615
  }
494
616
  return Object.freeze(out);
495
617
  }
@@ -108,28 +108,29 @@ export type HookMatcherRefusal = {
108
108
  readonly event: string;
109
109
  readonly alias: string;
110
110
  readonly canonical: string;
111
- readonly path?: readonly (string | number)[];
111
+ readonly groupIndex?: number;
112
+ readonly field?: string;
112
113
  } | {
113
114
  readonly reason: 'invalid_regex';
114
115
  readonly event: string;
115
116
  readonly groupIndex: number;
116
- readonly path?: readonly (string | number)[];
117
+ readonly field?: string;
117
118
  } | {
118
119
  readonly reason: 'over_budget';
119
120
  readonly event: string;
120
121
  readonly groupIndex: number;
121
122
  readonly budgetMs?: number;
122
- readonly path?: readonly (string | number)[];
123
+ readonly field?: string;
123
124
  } | {
124
125
  readonly reason: 'budget_exceeded';
125
126
  readonly event: string;
126
127
  readonly groupIndex: number;
127
128
  readonly totalMs?: number;
128
- readonly path?: readonly (string | number)[];
129
+ readonly field?: string;
129
130
  };
130
131
  export interface SettingsHooksRefusal {
131
132
  readonly reason: string;
132
- readonly path?: readonly (string | number)[];
133
+ readonly field: string;
133
134
  readonly matcher?: HookMatcherRefusal;
134
135
  readonly count?: number;
135
136
  readonly cap?: number;