@sema-agent/client-core 0.98.0 → 0.99.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 (192) hide show
  1. package/CHANGELOG.md +199 -0
  2. package/README.md +35 -22
  3. package/dist/adapt/arms.js +61 -20
  4. package/dist/adapt/panelTasks.d.ts +1 -1
  5. package/dist/adapt/panelTasks.js +2 -2
  6. package/dist/adapter/activeRunSelfHeal.d.ts +4 -3
  7. package/dist/adapter/activeRunSelfHeal.js +162 -293
  8. package/dist/adapter/downstream/eventToSdkMessage.js +52 -4
  9. package/dist/adapter/runStream.js +52 -37
  10. package/dist/adapter/types.js +2 -1
  11. package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
  12. package/dist/agentsWireCaps.d.ts +0 -3
  13. package/dist/agentsWireCaps.js +33 -24
  14. package/dist/cloudConfigWireCaps.d.ts +1 -1
  15. package/dist/cloudConfigWireCaps.js +26 -4
  16. package/dist/controlRouter.d.ts +4 -2
  17. package/dist/controlRouter.js +39 -51
  18. package/dist/coreValuePorts.d.ts +26 -1
  19. package/dist/coreValuePorts.js +10 -0
  20. package/dist/corruptSessionCopy.d.ts +2 -1
  21. package/dist/corruptSessionCopy.js +3 -3
  22. package/dist/declared/supportFloorDeclared.js +1 -1
  23. package/dist/detachWire.js +3 -2
  24. package/dist/devicesFace.d.ts +34 -0
  25. package/dist/devicesFace.js +90 -0
  26. package/dist/displayUntrusted.d.ts +1 -0
  27. package/dist/displayUntrusted.js +3 -0
  28. package/dist/engineAgentPanelStore.d.ts +7 -0
  29. package/dist/engineAgentPanelStore.js +14 -0
  30. package/dist/engineCapReader.d.ts +2 -1
  31. package/dist/engineCapReader.js +7 -5
  32. package/dist/engineCapsCache.d.ts +8 -0
  33. package/dist/engineCapsCache.js +59 -6
  34. package/dist/engineCapsChange.d.ts +2 -0
  35. package/dist/engineCapsChange.js +9 -0
  36. package/dist/engineErrorCodes.d.ts +2 -1
  37. package/dist/engineErrorCodes.js +2 -7
  38. package/dist/engineRowRef.js +3 -0
  39. package/dist/engineSessionMessages.d.ts +1 -0
  40. package/dist/engineSessionMessages.js +7 -1
  41. package/dist/engineTargetSeat.d.ts +27 -0
  42. package/dist/engineTargetSeat.js +199 -0
  43. package/dist/engineWireFor.js +3 -8
  44. package/dist/env/uiLanguage.d.ts +2 -1
  45. package/dist/env/uiLanguage.js +3 -2
  46. package/dist/eventLeg.d.ts +8 -0
  47. package/dist/eventLeg.js +61 -41
  48. package/dist/fileHistoryCaptureCapability.d.ts +2 -1
  49. package/dist/fileHistoryCaptureCapability.js +12 -18
  50. package/dist/fileHistoryLegNotice.d.ts +2 -1
  51. package/dist/fileHistoryLegNotice.js +3 -3
  52. package/dist/frameBinding.d.ts +3 -0
  53. package/dist/frameBinding.js +12 -0
  54. package/dist/gateOutcome.js +16 -2
  55. package/dist/gateVocabulary.d.ts +8 -7
  56. package/dist/gateVocabulary.js +71 -73
  57. package/dist/generated/engineFactTables.d.ts +17 -1
  58. package/dist/generated/engineFactTables.js +29 -0
  59. package/dist/generated/engineNoticeTables.js +9 -3
  60. package/dist/generated/settingsSchemaFns.d.ts +6 -0
  61. package/dist/generated/settingsSchemaFns.js +57 -0
  62. package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
  63. package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
  64. package/dist/generated/settingsSchemaTables.d.ts +1 -0
  65. package/dist/generated/settingsSchemaTables.js +4 -0
  66. package/dist/generated/settingsSchemaTypes.d.ts +105 -0
  67. package/dist/generated/settingsSchemaTypes.js +1 -0
  68. package/dist/hitl/allowRuleShadow.d.ts +2 -1
  69. package/dist/hitl/allowRuleShadow.js +17 -14
  70. package/dist/hitl/approvalCardReasons.d.ts +3 -2
  71. package/dist/hitl/approvalCardReasons.js +27 -28
  72. package/dist/hitl/approvalHolds.d.ts +3 -0
  73. package/dist/hitl/approvalHolds.js +73 -29
  74. package/dist/hitl/askClassPair.d.ts +1 -1
  75. package/dist/hitl/askClassPair.js +16 -0
  76. package/dist/hitl/askGateWire.js +2 -1
  77. package/dist/hitl/askSettlementLine.d.ts +14 -4
  78. package/dist/hitl/askSettlementLine.js +67 -47
  79. package/dist/hitl/automaticAnswerVerdict.d.ts +2 -1
  80. package/dist/hitl/automaticAnswerVerdict.js +8 -8
  81. package/dist/hitl/crashConvergedNotice.d.ts +5 -4
  82. package/dist/hitl/crashConvergedNotice.js +28 -41
  83. package/dist/hitl/frameRouter.js +7 -8
  84. package/dist/hitl/hitlBridge.d.ts +1 -0
  85. package/dist/hitl/hitlBridge.js +3 -3
  86. package/dist/hitl/persistedRulesWire.d.ts +6 -5
  87. package/dist/hitl/persistedRulesWire.js +55 -73
  88. package/dist/hitl/planReviewWire.d.ts +5 -0
  89. package/dist/hitl/planReviewWire.js +8 -0
  90. package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
  91. package/dist/hitl/sessionPolicyDeliverable.js +46 -3
  92. package/dist/hitl/sessionPolicyWire.d.ts +2 -1
  93. package/dist/hitl/sessionPolicyWire.js +23 -24
  94. package/dist/hitl/suspendedReopen.d.ts +2 -1
  95. package/dist/hitl/suspendedReopen.js +7 -10
  96. package/dist/hitl/toolApprovalWire.d.ts +17 -5
  97. package/dist/hitl/toolApprovalWire.js +79 -40
  98. package/dist/hooksWireCaps.js +145 -56
  99. package/dist/host.d.ts +21 -0
  100. package/dist/hostTurnSettings.d.ts +71 -0
  101. package/dist/hostTurnSettings.js +291 -0
  102. package/dist/humanTurn.d.ts +14 -1
  103. package/dist/humanTurn.js +100 -12
  104. package/dist/humanTurnRead.d.ts +2 -0
  105. package/dist/humanTurnRead.js +22 -1
  106. package/dist/i18n/messages.en.d.ts +582 -0
  107. package/dist/i18n/messages.en.js +582 -0
  108. package/dist/i18n/messages.zh.js +718 -1
  109. package/dist/index.d.ts +29 -13
  110. package/dist/index.js +18 -9
  111. package/dist/inheritEnvCapability.d.ts +3 -2
  112. package/dist/inheritEnvCapability.js +3 -3
  113. package/dist/inheritEnvWire.d.ts +3 -2
  114. package/dist/inheritEnvWire.js +12 -14
  115. package/dist/interactiveHalt.js +17 -6
  116. package/dist/liveModelCatalog.d.ts +2 -1
  117. package/dist/liveModelCatalog.js +14 -8
  118. package/dist/mcpPanel.d.ts +10 -1
  119. package/dist/mcpPanel.js +40 -13
  120. package/dist/mcpProbeCapability.d.ts +2 -1
  121. package/dist/mcpProbeCapability.js +7 -11
  122. package/dist/mcpProbeWire.d.ts +3 -1
  123. package/dist/mcpProbeWire.js +5 -0
  124. package/dist/mcpWireCaps.d.ts +34 -0
  125. package/dist/mcpWireCaps.js +117 -17
  126. package/dist/memoryEntriesWire.js +5 -10
  127. package/dist/model/onboardJudgement.d.ts +93 -0
  128. package/dist/model/onboardJudgement.js +415 -0
  129. package/dist/model/tierVocabulary.d.ts +2 -0
  130. package/dist/model/tierVocabulary.js +17 -5
  131. package/dist/modelCapabilityProbe.d.ts +64 -0
  132. package/dist/modelCapabilityProbe.js +600 -0
  133. package/dist/modelIdentityResolvability.d.ts +3 -0
  134. package/dist/modelIdentityResolvability.js +26 -17
  135. package/dist/ownKey.d.ts +7 -0
  136. package/dist/ownKey.js +34 -0
  137. package/dist/panelReduce.d.ts +6 -1
  138. package/dist/panelReduce.js +50 -3
  139. package/dist/permissionRuleIssue.js +2 -0
  140. package/dist/permissionRulesWriteCapability.d.ts +2 -1
  141. package/dist/permissionRulesWriteCapability.js +8 -6
  142. package/dist/pluginHooksWire.d.ts +46 -3
  143. package/dist/pluginHooksWire.js +217 -11
  144. package/dist/printModelStatus.d.ts +63 -0
  145. package/dist/printModelStatus.js +155 -0
  146. package/dist/request/taskRequest.d.ts +11 -5
  147. package/dist/request/taskRequest.js +112 -16
  148. package/dist/resumeRefusalCopy.d.ts +12 -9
  149. package/dist/resumeRefusalCopy.js +70 -143
  150. package/dist/retryStatus.d.ts +37 -0
  151. package/dist/retryStatus.js +79 -0
  152. package/dist/scenarioRefusal.d.ts +9 -0
  153. package/dist/scenarioRefusal.js +111 -0
  154. package/dist/seam.d.ts +25 -1
  155. package/dist/seam.js +10 -1
  156. package/dist/seatContract.d.ts +260 -10
  157. package/dist/seatContract.js +692 -19
  158. package/dist/selfOrchestrationDenial.js +7 -19
  159. package/dist/sessionIdSegment.d.ts +6 -0
  160. package/dist/sessionIdSegment.js +24 -0
  161. package/dist/sessionMemoryStatus.js +6 -11
  162. package/dist/sessionPolicyCapability.d.ts +2 -1
  163. package/dist/sessionPolicyCapability.js +8 -6
  164. package/dist/settingsHooksSalvage.d.ts +44 -0
  165. package/dist/settingsHooksSalvage.js +211 -0
  166. package/dist/skillToolListsCapability.d.ts +2 -1
  167. package/dist/skillToolListsCapability.js +8 -6
  168. package/dist/sseIdleTriage.js +3 -2
  169. package/dist/subagent/engineSubagentResume.js +15 -9
  170. package/dist/subagentContentStore.d.ts +3 -0
  171. package/dist/subagentContentStore.js +22 -0
  172. package/dist/toolHistoryMismatch.js +3 -2
  173. package/dist/toolRoster.d.ts +3 -2
  174. package/dist/toolRoster.js +21 -20
  175. package/dist/turnFailurePresentation.d.ts +12 -1
  176. package/dist/turnFailurePresentation.js +212 -15
  177. package/dist/usageAnalytics.js +6 -11
  178. package/dist/userAttachmentEnvelope.d.ts +1 -0
  179. package/dist/userAttachmentEnvelope.js +37 -7
  180. package/dist/userAttachmentSeat.d.ts +21 -0
  181. package/dist/userAttachmentSeat.js +75 -0
  182. package/dist/userInvokedSkillsCapability.d.ts +11 -1
  183. package/dist/userInvokedSkillsCapability.js +31 -7
  184. package/dist/wireErrorTriage.d.ts +7 -0
  185. package/dist/wireErrorTriage.js +23 -1
  186. package/dist/wireFailureShape.js +2 -1
  187. package/dist/wireRefusalCopy.d.ts +13 -1
  188. package/dist/wireRefusalCopy.js +24 -28
  189. package/dist/workflowsJournalCapability.d.ts +2 -1
  190. package/dist/workflowsJournalCapability.js +8 -6
  191. package/docs/INTEGRATION-CLIENTS.md +542 -30
  192. package/package.json +5 -5
@@ -58,7 +58,6 @@ export declare const STOP_PARK_RESUME_WON = "stop.park_resume_won";
58
58
  export declare const STOP_NOT_LANDED = "stop.not_landed";
59
59
  export declare const STOP_NOT_LOCAL = "stop.not_local";
60
60
  export declare const STOP_PARKED = "stop.parked";
61
- export declare const STOP_CONFLICT_CODES: readonly ["stop.park_arbiter_unreachable", "stop.park_resume_won", "stop.not_landed", "stop.not_local", "stop.parked"];
62
61
  export declare const OUTPUT_INVALID = "output.invalid";
63
62
  export declare const RESUME_POLICY_FOLD_CODE = "resume_blocked_by_policy";
64
63
  export declare const STATUS_DERIVED_COARSE_CODES: readonly ["request.rejected", "auth.unauthorized", "auth.forbidden", "not_found.resource", "request.payload_too_large", "request.unprocessable", "limit.rate_exceeded", "capability.unavailable", "internal.error"];
@@ -128,6 +127,8 @@ export declare function isWorkflowParkRefusalCode(code: unknown): boolean;
128
127
  export declare const DRAINING_ERROR_CODE = "draining";
129
128
  export declare const SCENARIO_NOT_ALLOWED_ERROR_CODE = "scenario_not_allowed";
130
129
  export declare const SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE = "state.scenario_assignment_unknown";
130
+ export declare const USER_ATTACHMENT_INVALID_ERROR_CODE = "config.user_attachment_invalid";
131
+ export declare const USER_INVOKED_SKILL_UNKNOWN_ERROR_CODE = "config.user_invoked_skill_unknown";
131
132
  export declare const STREAM_MAX_DURATION = "STREAM_MAX_DURATION";
132
133
  export type ModelFallbackReason = 'inherit_no_tier_binding';
133
134
  export declare const MODEL_FALLBACK_INHERIT_NO_TIER_BINDING: ModelFallbackReason;
@@ -111,13 +111,6 @@ export const STOP_PARK_RESUME_WON = 'stop.park_resume_won';
111
111
  export const STOP_NOT_LANDED = 'stop.not_landed';
112
112
  export const STOP_NOT_LOCAL = 'stop.not_local';
113
113
  export const STOP_PARKED = 'stop.parked';
114
- export const STOP_CONFLICT_CODES = Object.freeze([
115
- STOP_PARK_ARBITER_UNREACHABLE,
116
- STOP_PARK_RESUME_WON,
117
- STOP_NOT_LANDED,
118
- STOP_NOT_LOCAL,
119
- STOP_PARKED,
120
- ]);
121
114
  export const OUTPUT_INVALID = 'output.invalid';
122
115
  export const RESUME_POLICY_FOLD_CODE = 'resume_blocked_by_policy';
123
116
  export const STATUS_DERIVED_COARSE_CODES = SDK_STATUS_DERIVED_COARSE_CODES;
@@ -266,6 +259,8 @@ export function isWorkflowParkRefusalCode(code) {
266
259
  export const DRAINING_ERROR_CODE = 'draining';
267
260
  export const SCENARIO_NOT_ALLOWED_ERROR_CODE = 'scenario_not_allowed';
268
261
  export const SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE = 'state.scenario_assignment_unknown';
262
+ export const USER_ATTACHMENT_INVALID_ERROR_CODE = 'config.user_attachment_invalid';
263
+ export const USER_INVOKED_SKILL_UNKNOWN_ERROR_CODE = 'config.user_invoked_skill_unknown';
269
264
  export const STREAM_MAX_DURATION = 'STREAM_MAX_DURATION';
270
265
  export const MODEL_FALLBACK_INHERIT_NO_TIER_BINDING = 'inherit_no_tier_binding';
271
266
  export function asModelFallbackReason(v) {
@@ -93,6 +93,9 @@ export const TRANSCRIPT_ROW_SIDECAR_KEYS = Object.freeze([
93
93
  '_sema_interrupted_never_started',
94
94
  '_sema_approval_window_expired',
95
95
  '_sema_denial_limit_window_expired',
96
+ '_sema_api_error_status',
97
+ '_sema_api_error_code',
98
+ '_sema_provider_condition',
96
99
  ]);
97
100
  export function parkHeldCallIdOf(carrier) {
98
101
  return readFrameStringKey(carrier, 'toolCallId');
@@ -32,6 +32,7 @@ export interface EngineHistoryToolResultBlock {
32
32
  readonly tool_use_id: string;
33
33
  readonly content: readonly EngineHistoryBlock[];
34
34
  readonly is_error: boolean;
35
+ readonly _sema_gate_parked?: true;
35
36
  }
36
37
  export interface EngineHistoryOpaqueBlock {
37
38
  readonly type: string;
@@ -1,3 +1,4 @@
1
+ import { isGateParkedToolEnd } from './gateOutcome.js';
1
2
  import { ownDataField, ownSendableField } from './ownKey.js';
2
3
  const isObjectLike = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
3
4
  function optionalOwn(o, key) {
@@ -286,7 +287,12 @@ function toolResultBody(row, tally) {
286
287
  blocks = mapBlocks(items, tally);
287
288
  }
288
289
  const isError = ownDataField(row, 'isError') === true;
289
- return { kind: 'message', role: 'user', body: { role: 'user', content: [{ type: 'tool_result', tool_use_id: id, content: blocks, is_error: isError }] } };
290
+ const parked = isGateParkedToolEnd(row);
291
+ return {
292
+ kind: 'message',
293
+ role: 'user',
294
+ body: { role: 'user', content: [{ type: 'tool_result', tool_use_id: id, content: blocks, is_error: isError, ...(parked ? { _sema_gate_parked: true } : {}) }] },
295
+ };
290
296
  }
291
297
  function projectRow(row, tally) {
292
298
  if (!isObjectLike(row))
@@ -0,0 +1,27 @@
1
+ import type { CloudLoginFailure, CloudLoginFailureReading, EipcStoreClient, EngineTargetRefusal, EngineTargetRefused, EngineTargetState, SeatLocalMcpReading } from './seatContract.js';
2
+ import type { McpProbeOutcome } from './mcpProbeWire.js';
3
+ import type { UiLanguage } from './env/uiLanguage.js';
4
+ export interface CloudLoginFailureContext {
5
+ readonly deadlineReached?: boolean;
6
+ readonly cancelled?: boolean;
7
+ }
8
+ export declare function cloudLoginFailureOf(err: {} | null | undefined, ctx?: CloudLoginFailureContext): CloudLoginFailureReading;
9
+ export declare function cloudLoginFailureText(failure: CloudLoginFailure | CloudLoginFailureReading, lang?: UiLanguage): string;
10
+ export declare function engineTargetRefusalText(refused: EngineTargetRefusal | EngineTargetRefused, lang?: UiLanguage): string;
11
+ export type EngineTargetReading = {
12
+ readonly kind: 'state';
13
+ readonly state: EngineTargetState;
14
+ } | {
15
+ readonly kind: 'not_reported';
16
+ } | {
17
+ readonly kind: 'malformed';
18
+ };
19
+ export interface EngineTargetWatch {
20
+ stop(): void;
21
+ isCurrent(generation: number): boolean;
22
+ }
23
+ export declare function watchEngineTarget(store: EipcStoreClient<EngineTargetState> | undefined, onState: (reading: EngineTargetReading, switched: boolean) => void): EngineTargetWatch;
24
+ export declare function seatMcpReadingOf(outcome: McpProbeOutcome, readAt: string, extra?: {
25
+ readonly restartRequired?: true;
26
+ readonly forcedAsk?: Readonly<Record<string, readonly string[]>>;
27
+ }): SeatLocalMcpReading;
@@ -0,0 +1,199 @@
1
+ import { CLOUD_LOGIN_FAILURES, ENGINE_TARGET_REFUSALS, LOCAL_SESSIONS_SPEC } from './seatContract.js';
2
+ import { ownDataField } from './ownKey.js';
3
+ import { readThrownSlot, readThrownStatusSlot } from './wireFailureShape.js';
4
+ import { displayUntrusted } from './displayUntrusted.js';
5
+ import { msg, renderMessage } from './i18n/translate.js';
6
+ const field = (v, key) => {
7
+ if (v === null || typeof v !== 'object')
8
+ return undefined;
9
+ try {
10
+ return ownDataField(v, key);
11
+ }
12
+ catch {
13
+ return undefined;
14
+ }
15
+ };
16
+ const OAUTH_WORDS = ['access_denied', 'expired_token', 'invalid_grant'];
17
+ export function cloudLoginFailureOf(err, ctx) {
18
+ if (field(ctx, 'cancelled') === true)
19
+ return Object.freeze({ failure: 'cancelled' });
20
+ if (field(ctx, 'deadlineReached') === true)
21
+ return Object.freeze({ failure: 'expired_token' });
22
+ if (err !== null && typeof err === 'object') {
23
+ const code = readThrownSlot(err, 'code', 'data');
24
+ if (typeof code === 'string' && code.length > 0) {
25
+ const word = OAUTH_WORDS.find((w) => w === code);
26
+ return Object.freeze({ failure: word ?? 'other' });
27
+ }
28
+ const status = readThrownStatusSlot(err);
29
+ if (typeof status === 'number' && Number.isInteger(status) && status >= 100 && status <= 599)
30
+ return Object.freeze({ failure: 'refused', status });
31
+ }
32
+ return Object.freeze({ failure: 'transport' });
33
+ }
34
+ const LOGIN_KEYS = {
35
+ access_denied: 'config.cloudLogin.accessDenied',
36
+ expired_token: 'config.cloudLogin.expiredToken',
37
+ invalid_grant: 'config.cloudLogin.invalidGrant',
38
+ cancelled: 'config.cloudLogin.cancelled',
39
+ transport: 'config.cloudLogin.transport',
40
+ refused: 'config.cloudLogin.refused',
41
+ no_tokens: 'config.cloudLogin.noTokens',
42
+ other: 'config.cloudLogin.other',
43
+ };
44
+ export function cloudLoginFailureText(failure, lang) {
45
+ const word = typeof failure === 'string' ? failure : field(failure, 'failure');
46
+ const known = CLOUD_LOGIN_FAILURES.find((w) => w === word) ?? 'other';
47
+ if (known === 'refused') {
48
+ const status = typeof failure === 'string' ? undefined : field(failure, 'status');
49
+ if (typeof status === 'number' && Number.isInteger(status) && status >= 100 && status <= 599) {
50
+ return renderMessage(msg('config.cloudLogin.refusedStatus', { status }), lang);
51
+ }
52
+ }
53
+ return renderMessage(msg(LOGIN_KEYS[known]), lang);
54
+ }
55
+ const REFUSAL_KEYS = {
56
+ busy: 'config.engineTarget.busy',
57
+ switching: 'config.engineTarget.switching',
58
+ not_configured: 'config.engineTarget.notConfigured',
59
+ not_signed_in: 'config.engineTarget.notSignedIn',
60
+ probe_failed: 'config.engineTarget.probeFailed',
61
+ org_policy: 'config.engineTarget.orgPolicy',
62
+ url_refused: 'config.engineTarget.urlRefused',
63
+ login_failed: 'config.engineTarget.loginFailed',
64
+ storage_unavailable: 'config.engineTarget.storageUnavailable',
65
+ no_local_runtime: 'config.engineTarget.noLocalRuntime',
66
+ input: 'config.engineTarget.input',
67
+ };
68
+ export function engineTargetRefusalText(refused, lang) {
69
+ const word = typeof refused === 'string' ? refused : field(refused, 'refusal');
70
+ const known = ENGINE_TARGET_REFUSALS.find((w) => w === word);
71
+ if (known === undefined)
72
+ return renderMessage(msg('config.engineTarget.unknown'), lang);
73
+ if (known === 'login_failed' && typeof refused !== 'string') {
74
+ const failure = field(refused, 'failure');
75
+ if (CLOUD_LOGIN_FAILURES.some((w) => w === failure)) {
76
+ const status = field(refused, 'status');
77
+ return cloudLoginFailureText({ failure: failure, ...(typeof status === 'number' ? { status } : {}) }, lang);
78
+ }
79
+ }
80
+ return renderMessage(msg(REFUSAL_KEYS[known]), lang);
81
+ }
82
+ const checkState = (v) => {
83
+ const check = LOCAL_SESSIONS_SPEC.stores?.['engineTargetState']?.check;
84
+ return typeof check === 'function' && check(v) === true;
85
+ };
86
+ export function watchEngineTarget(store, onState) {
87
+ let current;
88
+ let trusted = false;
89
+ let active = true;
90
+ let off;
91
+ const deliver = (state) => {
92
+ if (!active)
93
+ return;
94
+ let ok = false;
95
+ try {
96
+ ok = checkState(state);
97
+ }
98
+ catch {
99
+ ok = false;
100
+ }
101
+ if (!ok) {
102
+ trusted = false;
103
+ onState(Object.freeze({ kind: 'malformed' }), false);
104
+ return;
105
+ }
106
+ const s = state;
107
+ const switched = current !== undefined && s.generation !== current;
108
+ current = s.generation;
109
+ trusted = true;
110
+ onState(Object.freeze({ kind: 'state', state: s }), switched);
111
+ };
112
+ const handle = {
113
+ stop: () => {
114
+ if (!active)
115
+ return;
116
+ active = false;
117
+ try {
118
+ if (typeof off === 'function')
119
+ off();
120
+ }
121
+ catch {
122
+ off = undefined;
123
+ }
124
+ },
125
+ isCurrent: (generation) => active && trusted && current !== undefined && generation === current,
126
+ };
127
+ if (store === undefined || store === null) {
128
+ onState(Object.freeze({ kind: 'not_reported' }), false);
129
+ active = false;
130
+ return handle;
131
+ }
132
+ try {
133
+ if (typeof store !== 'object' || typeof store.onStateChange !== 'function' || typeof store.getStateSync !== 'function') {
134
+ onState(Object.freeze({ kind: 'malformed' }), false);
135
+ active = false;
136
+ return handle;
137
+ }
138
+ off = store.onStateChange((state) => deliver(state));
139
+ }
140
+ catch {
141
+ onState(Object.freeze({ kind: 'malformed' }), false);
142
+ active = false;
143
+ return handle;
144
+ }
145
+ let now;
146
+ try {
147
+ now = store.getStateSync();
148
+ }
149
+ catch {
150
+ trusted = false;
151
+ if (active)
152
+ onState(Object.freeze({ kind: 'malformed' }), false);
153
+ return handle;
154
+ }
155
+ deliver(now);
156
+ return handle;
157
+ }
158
+ const MCP_DETAIL_MAX = 200;
159
+ export function seatMcpReadingOf(outcome, readAt, extra) {
160
+ const restart = field(extra, 'restartRequired') === true ? { restartRequired: true } : {};
161
+ const status = field(outcome, 'status');
162
+ if (status === 'face') {
163
+ const face = field(outcome, 'face');
164
+ const servers = field(face, 'servers');
165
+ if (Array.isArray(servers)) {
166
+ const forced = field(extra, 'forcedAsk');
167
+ const rows = [];
168
+ for (const row of servers) {
169
+ const name = field(row, 'name');
170
+ const st = field(row, 'status');
171
+ if (typeof name !== 'string' || name.length === 0 || typeof st !== 'string')
172
+ continue;
173
+ const tc = field(row, 'toolCount');
174
+ const liveness = field(field(row, 'liveness'), 'state');
175
+ const ec = field(row, 'errorCode');
176
+ const fa = field(forced, name);
177
+ const forcedAsk = Array.isArray(fa) ? fa.filter((n) => typeof n === 'string' && n.length > 0) : [];
178
+ rows.push(Object.freeze({
179
+ name,
180
+ status: st,
181
+ ...(typeof tc === 'number' && Number.isSafeInteger(tc) && tc >= 0 ? { toolCount: tc } : {}),
182
+ ...(typeof liveness === 'string' && liveness.length > 0 ? { liveness } : {}),
183
+ ...(typeof ec === 'string' && ec.length > 0 ? { errorCode: ec } : {}),
184
+ ...(forcedAsk.length > 0 ? { forcedAsk: [...forcedAsk] } : {}),
185
+ }));
186
+ }
187
+ return Object.freeze({ status: 'listed', servers: rows, readAt, ...restart });
188
+ }
189
+ }
190
+ const cause = status === 'refused' ? field(outcome, 'cause') : status === 'unknown' ? field(outcome, 'why') : undefined;
191
+ const message = field(outcome, 'message');
192
+ return Object.freeze({
193
+ status: 'unreadable',
194
+ cause: typeof cause === 'string' && cause.length > 0 ? cause : 'no_verdict',
195
+ ...(typeof message === 'string' && message.length > 0 ? { detail: displayUntrusted(message, { max: MCP_DETAIL_MAX }) } : {}),
196
+ readAt,
197
+ ...restart,
198
+ });
199
+ }
@@ -1,6 +1,7 @@
1
1
  import { settleWithinDeadline } from './abortableSleep.js';
2
2
  import { makeEngineWireClient } from './engineWireSdk.js';
3
3
  import { engineWireTargetFor } from './engineWireTarget.js';
4
+ import { readThrownSlot } from './wireFailureShape.js';
4
5
  export const INJECTED_WIRE_SETTLE_MS = 60_000;
5
6
  export function engineWireFor(wire, sessionKey, usable) {
6
7
  if (wire !== undefined) {
@@ -285,15 +286,9 @@ function abortedBeforeSendError() {
285
286
  return e;
286
287
  }
287
288
  function answeredByEngine(e) {
288
- try {
289
- if (e === null || typeof e !== 'object')
290
- return false;
291
- const o = e;
292
- return typeof o.status === 'number' || typeof o.errorCode === 'string';
293
- }
294
- catch {
289
+ if (e === null || typeof e !== 'object')
295
290
  return false;
296
- }
291
+ return typeof readThrownSlot(e, 'status', 'data') === 'number' || typeof readThrownSlot(e, 'errorCode', 'data') === 'string';
297
292
  }
298
293
  const SETTLED_BY_PACKAGE_BRAND = Symbol.for('@sema-agent/client-core:engine-wire-settled');
299
294
  function settledByPackage(value) {
@@ -1,4 +1,5 @@
1
- export type UiLanguage = 'en' | 'zh';
1
+ import { SETTINGS_UI_LANGUAGE_VALUES } from '../generated/settingsSchemaTables.js';
2
+ export type UiLanguage = (typeof SETTINGS_UI_LANGUAGE_VALUES)[number];
2
3
  export declare const UI_LANGUAGES: readonly UiLanguage[];
3
4
  export declare const UI_LANGUAGE_ENDONYMS: Record<UiLanguage, string>;
4
5
  export declare function isUiLanguage(v: unknown): v is UiLanguage;
@@ -1,11 +1,12 @@
1
1
  import { parseLocaleTag } from './localeTag.js';
2
- export const UI_LANGUAGES = ['en', 'zh'];
2
+ import { SETTINGS_UI_LANGUAGE_VALUES } from '../generated/settingsSchemaTables.js';
3
+ export const UI_LANGUAGES = SETTINGS_UI_LANGUAGE_VALUES;
3
4
  export const UI_LANGUAGE_ENDONYMS = {
4
5
  en: 'English',
5
6
  zh: '中文',
6
7
  };
7
8
  export function isUiLanguage(v) {
8
- return v === 'en' || v === 'zh';
9
+ return typeof v === 'string' && UI_LANGUAGES.includes(v);
9
10
  }
10
11
  export function pickUiLanguage(localeTag) {
11
12
  return parseLocaleTag(localeTag).language === 'zh' ? 'zh' : 'en';
@@ -2,6 +2,7 @@ import type { AgentEvent } from '@sema-agent/sdk';
2
2
  import type { EngineBoundRun } from './engineRowRef.js';
3
3
  import { type AskGateWireDeps } from './hitl/askGateWire.js';
4
4
  import { type ActiveRunBusySignal } from './adapter/runStream.js';
5
+ import type { ApprovalRequestChromeEvent, ApprovalRevokeChromeEvent } from './seam.js';
5
6
  export declare const EVENT_LEG_KINDS: readonly ["live", "durable", "continuation"];
6
7
  export type EventLegKind = (typeof EVENT_LEG_KINDS)[number];
7
8
  export type EventLegStage = 'bindRun' | 'stampOwner' | 'hitlFrames' | 'askBridge' | 'idleTriage';
@@ -69,6 +70,13 @@ export interface EventLegStreamContext {
69
70
  readonly leg: EventLegKind;
70
71
  readonly runId: string | undefined;
71
72
  }
73
+ export interface ApprovalFrameContext {
74
+ readonly leg: EventLegKind;
75
+ readonly windowIsCurrent: boolean;
76
+ readonly receivedAtMs: number;
77
+ readonly streamEnded: AbortSignal;
78
+ }
79
+ export declare function approvalFrameContextOf(arm: ApprovalRequestChromeEvent | ApprovalRevokeChromeEvent): ApprovalFrameContext | undefined;
72
80
  export interface EventLegPorts {
73
81
  readonly run?: EventLegRunPorts;
74
82
  readonly owner?: EventLegOwnerPorts;
package/dist/eventLeg.js CHANGED
@@ -1,4 +1,4 @@
1
- import { frameBindingOf, registerFrameBinding } from './frameBinding.js';
1
+ import { approvalFrameContextOfFrame, frameBindingOf, registerApprovalFrameContext, registerFrameBinding } from './frameBinding.js';
2
2
  import { bridgeAskUserQuestionGates } from './hitl/askGateWire.js';
3
3
  import { diagnoseSseIdleTear } from './sseIdleTriage.js';
4
4
  import { recordSubagentOwnerFromProgress } from './subagentContentStore.js';
@@ -6,6 +6,8 @@ import { activeRunBusySignal } from './adapter/runStream.js';
6
6
  import { invokeHostCallbackIsolated } from './hostCallbackGuard.js';
7
7
  import { hostLog } from './host.js';
8
8
  import { guardedRead, readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
9
+ import { settleEngineClosedApproval } from './hitl/approvalHolds.js';
10
+ import { approvalCompleteParked } from './hitl/approvalCompleteParked.js';
9
11
  export const EVENT_LEG_KINDS = Object.freeze(['live', 'durable', 'continuation']);
10
12
  export const EVENT_LEG_TABLE = Object.freeze({
11
13
  live: Object.freeze({ stages: Object.freeze(['bindRun', 'stampOwner', 'hitlFrames', 'askBridge', 'idleTriage']), windowIsCurrent: true }),
@@ -18,7 +20,7 @@ function makeFrameStageDomains(domains) {
18
20
  const FRAME_STAGE_DOMAINS = makeFrameStageDomains({
19
21
  bindRun: Object.freeze(['meta', 'done', 'failed']),
20
22
  stampOwner: Object.freeze(['task_progress']),
21
- hitlFrames: Object.freeze(['question', 'question_complete', 'elicitation', 'elicitation_complete', 'tool_approval', 'tool_approval_complete']),
23
+ hitlFrames: Object.freeze(['question', 'question_complete', 'elicitation', 'elicitation_complete', 'tool_approval', 'tool_approval_complete', 'approval_request', 'approval_revoke']),
22
24
  });
23
25
  const HITL_PORT_OF = Object.freeze({
24
26
  question: 'question',
@@ -27,8 +29,14 @@ const HITL_PORT_OF = Object.freeze({
27
29
  elicitation_complete: 'elicitation',
28
30
  tool_approval: 'toolApproval',
29
31
  tool_approval_complete: 'toolApproval',
32
+ approval_request: 'register',
33
+ approval_revoke: 'register',
30
34
  });
31
35
  const inDomain = (stage, frameType) => FRAME_STAGE_DOMAINS[stage].includes(frameType);
36
+ export function approvalFrameContextOf(arm) {
37
+ const frame = guardedRead(() => readOwnDataValue(arm, 'frame'));
38
+ return typeof frame === 'object' && frame !== null ? approvalFrameContextOfFrame(frame) : undefined;
39
+ }
32
40
  const HOST_PORT_MISSING = 'host_port_missing';
33
41
  export function composeEventLeg(source, leg, ports) {
34
42
  const kind = leg.kind;
@@ -136,12 +144,18 @@ export function composeEventLeg(source, leg, ports) {
136
144
  const boundInfo = Object.freeze({ cause, leg: kind });
137
145
  callPort('run.onBound', () => runPorts.onBound?.(binding, boundInfo));
138
146
  };
139
- const deliverHitl = (ev, env) => {
147
+ const deliverHitl = (ev, env, streamEnded) => {
140
148
  if (!inDomain('hitlFrames', ev.type))
141
149
  return false;
142
150
  const port = HITL_PORT_OF[ev.type];
151
+ if (port === 'register') {
152
+ registerApprovalFrameContext(ev, Object.freeze({ leg: env.leg, windowIsCurrent: env.windowIsCurrent, receivedAtMs: Date.now(), streamEnded }));
153
+ return false;
154
+ }
143
155
  if (port === 'toolApproval' && hostBridge !== undefined)
144
156
  return false;
157
+ if (ev.type === 'tool_approval_complete')
158
+ settleEngineClosedApproval(ev, approvalCompleteParked(ev));
145
159
  const threw = callPort(`hitl.${port}`, () => hitl?.[port]?.call(hitl, ev, env));
146
160
  if (threw)
147
161
  hitlUndelivered++;
@@ -153,49 +167,55 @@ export function composeEventLeg(source, leg, ports) {
153
167
  let binding;
154
168
  let runEvidence = false;
155
169
  const env = Object.freeze({ windowIsCurrent: EVENT_LEG_TABLE[streamKind].windowIsCurrent, leg: streamKind });
156
- for await (const ev of stream) {
157
- if (taskId === undefined && streamKind === 'live')
158
- taskId = readHeaderRunId();
159
- const refusal = streamKind === 'live' && !runEvidence && inDomain('bindRun', ev.type) ? refusalOf(ev, taskId) : undefined;
160
- if (!inDomain('bindRun', ev.type))
161
- runEvidence = true;
162
- if (refusal !== undefined) {
163
- if (runPorts !== undefined && typeof runPorts.onRefused === 'function' && isCurrentNow())
164
- callPort('run.onRefused', () => runPorts.onRefused?.(refusal, info));
165
- }
166
- else {
167
- if (ev.type === 'meta' || ev.type === 'done') {
168
- const carrier = ev.type === 'meta' ? ev : ev.result;
169
- const tid = typeof carrier === 'object' && carrier !== null ? guardedRead(() => readOwnDataNonEmptyString(carrier, 'taskId')) : undefined;
170
- const sid = typeof carrier === 'object' && carrier !== null ? guardedRead(() => readOwnDataNonEmptyString(carrier, 'sessionId')) : undefined;
171
- const runId = ev.type === 'done' && tid !== undefined && tid === sid ? undefined : tid;
172
- if (streamKind === 'live' && runId !== undefined && runId !== taskId) {
173
- taskId = runId;
174
- sessionId = sid;
170
+ const ended = new AbortController();
171
+ try {
172
+ for await (const ev of stream) {
173
+ if (taskId === undefined && streamKind === 'live')
174
+ taskId = readHeaderRunId();
175
+ const refusal = streamKind === 'live' && !runEvidence && inDomain('bindRun', ev.type) ? refusalOf(ev, taskId) : undefined;
176
+ if (!inDomain('bindRun', ev.type))
177
+ runEvidence = true;
178
+ if (refusal !== undefined) {
179
+ if (runPorts !== undefined && typeof runPorts.onRefused === 'function' && isCurrentNow())
180
+ callPort('run.onRefused', () => runPorts.onRefused?.(refusal, info));
181
+ }
182
+ else {
183
+ if (ev.type === 'meta' || ev.type === 'done') {
184
+ const carrier = ev.type === 'meta' ? ev : ev.result;
185
+ const tid = typeof carrier === 'object' && carrier !== null ? guardedRead(() => readOwnDataNonEmptyString(carrier, 'taskId')) : undefined;
186
+ const sid = typeof carrier === 'object' && carrier !== null ? guardedRead(() => readOwnDataNonEmptyString(carrier, 'sessionId')) : undefined;
187
+ const runId = ev.type === 'done' && tid !== undefined && tid === sid ? undefined : tid;
188
+ if (streamKind === 'live' && runId !== undefined && runId !== taskId) {
189
+ taskId = runId;
190
+ sessionId = sid;
191
+ }
192
+ else if (sid !== undefined && taskId !== undefined && (runId === undefined || runId === taskId)) {
193
+ sessionId = sid;
194
+ }
175
195
  }
176
- else if (sid !== undefined && taskId !== undefined && (runId === undefined || runId === taskId)) {
177
- sessionId = sid;
196
+ if (taskId !== undefined) {
197
+ if (binding === undefined || binding.taskId !== taskId || binding.sessionId !== sessionId) {
198
+ binding = Object.freeze({ taskId, ...(sessionId !== undefined ? { sessionId } : {}) });
199
+ }
200
+ if (sessionId !== undefined)
201
+ runSessions.set(taskId, sessionId);
202
+ registerFrameBinding(ev, binding);
203
+ noteBound(binding);
178
204
  }
179
205
  }
180
- if (taskId !== undefined) {
181
- if (binding === undefined || binding.taskId !== taskId || binding.sessionId !== sessionId) {
182
- binding = Object.freeze({ taskId, ...(sessionId !== undefined ? { sessionId } : {}) });
183
- }
184
- if (sessionId !== undefined)
185
- runSessions.set(taskId, sessionId);
186
- registerFrameBinding(ev, binding);
187
- noteBound(binding);
206
+ if (inDomain('stampOwner', ev.type)) {
207
+ const b = frameBindingOf(ev);
208
+ recordSubagentOwnerFromProgress(ev, b?.taskId, b?.sessionId, sessionKey);
188
209
  }
210
+ if (deliverHitl(ev, env, ended.signal))
211
+ continue;
212
+ for (const tap of taps)
213
+ callPort('taps', () => tap(ev));
214
+ yield ev;
189
215
  }
190
- if (inDomain('stampOwner', ev.type)) {
191
- const b = frameBindingOf(ev);
192
- recordSubagentOwnerFromProgress(ev, b?.taskId, b?.sessionId, sessionKey);
193
- }
194
- if (deliverHitl(ev, env))
195
- continue;
196
- for (const tap of taps)
197
- callPort('taps', () => tap(ev));
198
- yield ev;
216
+ }
217
+ finally {
218
+ ended.abort();
199
219
  }
200
220
  }
201
221
  const streamOf = (raw, streamKind, streamRunId) => {
@@ -1,3 +1,4 @@
1
+ import type { UiLanguage } from './env/uiLanguage.js';
1
2
  export type FileHistoryCaptureReading = {
2
3
  kind: 'unobserved';
3
4
  } | {
@@ -18,7 +19,7 @@ export declare function fileHistoryDeclarationField(reading: FileHistoryCaptureR
18
19
  export declare const FILE_HISTORY_TIGHTEN_VERDICTS: readonly ["not_requested", "declare", "already_off", "unjudged"];
19
20
  export type FileHistoryTightenVerdict = (typeof FILE_HISTORY_TIGHTEN_VERDICTS)[number];
20
21
  export declare function fileHistoryTightenVerdict(reading: FileHistoryCaptureReading, captureOffByUser: boolean): FileHistoryTightenVerdict;
21
- export declare function fileHistoryUnjudgedRefusal(reading: FileHistoryCaptureReading, captureOffByUser: boolean): string | undefined;
22
+ export declare function fileHistoryUnjudgedRefusal(reading: FileHistoryCaptureReading, captureOffByUser: boolean, lang?: UiLanguage): string | undefined;
22
23
  export interface FileHistoryTightenJudgement {
23
24
  readonly verdict: FileHistoryTightenVerdict;
24
25
  readonly reading: FileHistoryCaptureReading;
@@ -1,3 +1,4 @@
1
+ import { msg, renderMessage } from './i18n/translate.js';
1
2
  import { capForDisplay } from './fleetTaskDesc.js';
2
3
  import { engineWireTarget } from './engineWireTarget.js';
3
4
  import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
@@ -60,21 +61,11 @@ export function fileHistoryTightenVerdict(reading, captureOffByUser) {
60
61
  return 'already_off';
61
62
  return 'unjudged';
62
63
  }
63
- const FILE_HISTORY_REFUSAL_NOT_YET = "Nothing was sent: file checkpointing is turned off in your settings, but this engine's capabilities have not been read " +
64
- 'yet, so whether it can stop recording file history for a session is unknown and sending now could record it anyway. ' +
65
- 'Try again in a moment; to send regardless and let file history be recorded this time, turn file checkpointing back on in your settings.';
66
- const FILE_HISTORY_REFUSAL_NOT_SAID = 'Nothing was sent: file checkpointing is turned off in your settings, but this engine did not report whether it can ' +
67
- 'stop recording file history for a session, so sending now could record it anyway. Trying again will not change that ' +
68
- 'while this engine reports the same; to send and let file history be recorded this time, turn file checkpointing back on in your settings.';
69
- const FILE_HISTORY_REFUSAL_UNRECOGNIZED = 'Nothing was sent: file checkpointing is turned off in your settings, but this engine reported a file-history capture mode ' +
70
- 'this client does not recognize, so whether it can stop recording file history for a session is unknown and sending now could ' +
71
- 'record it anyway. Trying again will not change that while this engine reports the same; to send and let file history be ' +
72
- 'recorded this time, turn file checkpointing back on in your settings.';
73
- const FILE_HISTORY_REFUSAL_UNREADABLE = "Nothing was sent: file checkpointing is turned off in your settings, but this engine's report on whether it can stop " +
74
- 'recording file history for a session could not be read by this client, so sending now could record it anyway. Trying ' +
75
- 'again will not change that while this engine reports the same; to send and let file history be recorded this time, ' +
76
- 'turn file checkpointing back on in your settings.';
77
- function unjudgedRefusalOf(reading) {
64
+ const FILE_HISTORY_REFUSAL_NOT_YET = 'session.fileHistoryRefusal.notYet';
65
+ const FILE_HISTORY_REFUSAL_NOT_SAID = 'session.fileHistoryRefusal.notSaid';
66
+ const FILE_HISTORY_REFUSAL_UNRECOGNIZED = 'session.fileHistoryRefusal.unrecognized';
67
+ const FILE_HISTORY_REFUSAL_UNREADABLE = 'session.fileHistoryRefusal.unreadable';
68
+ function unjudgedRefusalKeyOf(reading) {
78
69
  let kind;
79
70
  let word;
80
71
  try {
@@ -92,8 +83,11 @@ function unjudgedRefusalOf(reading) {
92
83
  return FILE_HISTORY_REFUSAL_UNRECOGNIZED;
93
84
  return FILE_HISTORY_REFUSAL_NOT_YET;
94
85
  }
95
- export function fileHistoryUnjudgedRefusal(reading, captureOffByUser) {
96
- return fileHistoryTightenVerdict(reading, captureOffByUser) === 'unjudged' ? unjudgedRefusalOf(reading) : undefined;
86
+ function unjudgedRefusalOf(reading, lang) {
87
+ return renderMessage(msg(unjudgedRefusalKeyOf(reading)), lang);
88
+ }
89
+ export function fileHistoryUnjudgedRefusal(reading, captureOffByUser, lang) {
90
+ return fileHistoryTightenVerdict(reading, captureOffByUser) === 'unjudged' ? unjudgedRefusalOf(reading, lang) : undefined;
97
91
  }
98
92
  const FILE_HISTORY_REFRESH_WITHIN_MS = 3000;
99
93
  export async function judgeFileHistoryTighten(captureOffByUser, opts) {
@@ -101,7 +95,7 @@ export async function judgeFileHistoryTighten(captureOffByUser, opts) {
101
95
  const failClosed = () => {
102
96
  const reading = { kind: 'unobserved' };
103
97
  return closed
104
- ? { verdict: 'unjudged', reading, refreshed: false, refusal: FILE_HISTORY_REFUSAL_NOT_YET }
98
+ ? { verdict: 'unjudged', reading, refreshed: false, refusal: renderMessage(msg(FILE_HISTORY_REFUSAL_NOT_YET)) }
105
99
  : { verdict: 'not_requested', reading, refreshed: false, refusal: undefined };
106
100
  };
107
101
  try {
@@ -1,4 +1,5 @@
1
1
  import type { AgentEvent } from '@sema-agent/sdk';
2
+ import type { UiLanguage } from './env/uiLanguage.js';
2
3
  import { type FileHistoryCaptureReading } from './fileHistoryCaptureCapability.js';
3
4
  export type FileHistoryDeclarationFact = 'sent' | 'not_sent' | 'unknown';
4
5
  export declare const FILE_HISTORY_LEG_VERDICTS: readonly ["not_honored", "honored", "not_declared", "unknown"];
@@ -10,7 +11,7 @@ export interface FileHistoryLegNoticeInput {
10
11
  readonly legWord: string | undefined;
11
12
  }
12
13
  export declare function fileHistoryLegNoticeVerdict(input: FileHistoryLegNoticeInput): FileHistoryLegNoticeVerdict;
13
- export declare function fileHistoryLegNoticeSentence(verdict: FileHistoryLegNoticeVerdict): string | null;
14
+ export declare function fileHistoryLegNoticeSentence(verdict: FileHistoryLegNoticeVerdict, lang?: UiLanguage): string | null;
14
15
  export declare function fileHistoryDeclarationOfBody(body: object | null | undefined): FileHistoryDeclarationFact;
15
16
  export type OutboundBodyField = {
16
17
  kind: 'absent';
@@ -1,4 +1,5 @@
1
1
  import { fileHistoryCaptureMode } from './fileHistoryCaptureCapability.js';
2
+ import { msg, renderMessage } from './i18n/translate.js';
2
3
  import { frameProvesDelivery } from './promptDelivery.js';
3
4
  import { FILE_HISTORY_DISABLED } from './request/taskRequest.js';
4
5
  export const FILE_HISTORY_LEG_VERDICTS = Object.freeze(['not_honored', 'honored', 'not_declared', 'unknown']);
@@ -35,10 +36,9 @@ export function fileHistoryLegNoticeVerdict(input) {
35
36
  return 'not_declared';
36
37
  return 'unknown';
37
38
  }
38
- const NOT_HONORED_SENTENCE = 'The engine is still capturing file history for this session, though your settings asked it not to.';
39
- export function fileHistoryLegNoticeSentence(verdict) {
39
+ export function fileHistoryLegNoticeSentence(verdict, lang) {
40
40
  if (verdict === 'not_honored')
41
- return NOT_HONORED_SENTENCE;
41
+ return renderMessage(msg('session.fileHistoryLeg.notHonored'), lang);
42
42
  return null;
43
43
  }
44
44
  export function fileHistoryDeclarationOfBody(body) {