@sema-agent/client-core 0.84.1 → 0.85.1

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 (91) hide show
  1. package/CHANGELOG.md +206 -0
  2. package/README.md +20 -13
  3. package/dist/adapt/arms.js +1 -1
  4. package/dist/adapt.d.ts +1 -1
  5. package/dist/adapt.js +1 -1
  6. package/dist/adapter/activeRunSelfHeal.d.ts +3 -0
  7. package/dist/adapter/activeRunSelfHeal.js +149 -17
  8. package/dist/adapter/downstream/terminalToSdkResult.js +9 -5
  9. package/dist/adapter/runStream.js +6 -2
  10. package/dist/agentSession/engineSessionBackgroundStop.d.ts +50 -0
  11. package/dist/agentSession/engineSessionBackgroundStop.js +291 -0
  12. package/dist/agentsWireCaps.d.ts +2 -1
  13. package/dist/cloudConfigWireCaps.js +2 -1
  14. package/dist/corruptSession.d.ts +3 -0
  15. package/dist/corruptSession.js +29 -0
  16. package/dist/corruptSessionCopy.d.ts +1 -0
  17. package/dist/corruptSessionCopy.js +4 -0
  18. package/dist/decideFailureNote.js +4 -1
  19. package/dist/decideReceipt.d.ts +6 -0
  20. package/dist/decideReceipt.js +30 -1
  21. package/dist/effortWire.d.ts +2 -1
  22. package/dist/effortWire.js +2 -4
  23. package/dist/engineErrorCodes.d.ts +9 -0
  24. package/dist/engineErrorCodes.js +29 -0
  25. package/dist/engineNoticeCodes.d.ts +9 -0
  26. package/dist/engineNoticeCodes.js +44 -156
  27. package/dist/engineWireFor.d.ts +43 -0
  28. package/dist/engineWireFor.js +399 -0
  29. package/dist/engineWireSdk.d.ts +4 -0
  30. package/dist/fileHistoryCaptureCapability.d.ts +4 -1
  31. package/dist/fileHistoryCaptureCapability.js +43 -9
  32. package/dist/gateVocabulary.d.ts +1 -2
  33. package/dist/gateVocabulary.js +1 -22
  34. package/dist/generated/engineNoticeTables.d.ts +3 -0
  35. package/dist/generated/engineNoticeTables.js +156 -0
  36. package/dist/generated/toolNameTables.d.ts +2 -0
  37. package/dist/generated/toolNameTables.js +43 -0
  38. package/dist/headlessPermissionModeWire.js +2 -4
  39. package/dist/hitl/armedGateRegistry.d.ts +1 -0
  40. package/dist/hitl/armedGateRegistry.js +1 -1
  41. package/dist/hitl/frameRouter.js +4 -2
  42. package/dist/hitl/parkResolver.js +3 -1
  43. package/dist/hitl/planReviewWire.d.ts +11 -0
  44. package/dist/hitl/planReviewWire.js +191 -72
  45. package/dist/hitl/rosterMountedNames.d.ts +2 -0
  46. package/dist/hitl/rosterMountedNames.js +38 -0
  47. package/dist/hitl/sessionPolicyDeliverable.d.ts +6 -2
  48. package/dist/hitl/sessionPolicyDeliverable.js +25 -45
  49. package/dist/hitl/sessionPolicyWire.js +1 -38
  50. package/dist/hitl/toolApprovalWire.d.ts +4 -2
  51. package/dist/hitl/toolApprovalWire.js +4 -2
  52. package/dist/host.d.ts +1 -1
  53. package/dist/host.js +11 -2
  54. package/dist/index.d.ts +10 -4
  55. package/dist/index.js +7 -3
  56. package/dist/permissionWireCaps.d.ts +2 -1
  57. package/dist/permissionWireCaps.js +2 -7
  58. package/dist/request/taskRequest.d.ts +4 -0
  59. package/dist/request/taskRequest.js +30 -1
  60. package/dist/resumeRefusalCopy.js +4 -2
  61. package/dist/runTerminal.js +4 -0
  62. package/dist/sandboxWire.js +1 -1
  63. package/dist/sealedKeyCapability.d.ts +17 -0
  64. package/dist/sealedKeyCapability.js +42 -0
  65. package/dist/seatContract.d.ts +2 -1
  66. package/dist/seatContract.js +5 -21
  67. package/dist/subagent/engineCompactWire.d.ts +13 -2
  68. package/dist/subagent/engineCompactWire.js +48 -37
  69. package/dist/subagent/engineDelegatedPrompt.d.ts +9 -1
  70. package/dist/subagent/engineDelegatedPrompt.js +16 -16
  71. package/dist/subagent/engineRowStopGate.d.ts +2 -2
  72. package/dist/subagent/engineRowStopGate.js +4 -4
  73. package/dist/subagent/engineSubagentOutput.d.ts +8 -0
  74. package/dist/subagent/engineSubagentOutput.js +37 -18
  75. package/dist/subagent/engineSubagentResume.d.ts +11 -2
  76. package/dist/subagent/engineSubagentResume.js +28 -14
  77. package/dist/subagent/engineSubagentSteer.d.ts +10 -1
  78. package/dist/subagent/engineSubagentSteer.js +16 -11
  79. package/dist/subagent/engineSubagentTail.d.ts +10 -1
  80. package/dist/subagent/engineSubagentTail.js +35 -17
  81. package/dist/subagent/engineTaskHandleWire.d.ts +13 -0
  82. package/dist/subagent/engineTaskHandleWire.js +41 -20
  83. package/dist/subagent/subagentOwnerAbsence.js +2 -5
  84. package/dist/taskRequestWords.d.ts +5 -0
  85. package/dist/taskRequestWords.js +4 -0
  86. package/dist/wireErrorTriage.d.ts +1 -0
  87. package/dist/wireErrorTriage.js +3 -1
  88. package/dist/wireRefusalCopy.d.ts +10 -0
  89. package/dist/wireRefusalCopy.js +62 -2
  90. package/docs/INTEGRATION-CLIENTS.md +867 -22
  91. package/package.json +1 -1
@@ -1,82 +1,10 @@
1
- export const ENGINE_NOTICE_CODES = Object.freeze([
2
- 'config.autocompact_window_clamped',
3
- 'config.env_timeout_discarded',
4
- 'config.materialize_env_discarded',
5
- 'config.models_swapped',
6
- 'config.context_settings_swapped',
7
- 'config.read_face_swapped',
8
- 'config.read_face_deployment_clamped',
9
- 'config.write_face_swapped',
10
- 'config.write_face_deployment_clamped',
11
- 'config.tool_model_gate_removed',
12
- 'config.tool_model_gate_unknown_class',
13
- 'config.tool_model_gate_env_invalid',
14
- 'config.artifact_host_invalid',
15
- 'config.task_root_not_canonical',
16
- 'config.write_protection_target_view_absent',
17
- 'config.write_protection_unresolved',
18
- 'config.execution_env_capability_invalid',
19
- 'config.tool_card_undeclared',
20
- 'config.tool_face_undeclared',
21
- 'config.tool_face_invalid',
22
- 'config.forward_sink_failed',
23
- 'config.durable_gate_unavailable',
24
- 'config.peer_admission_out_of_range',
25
- 'config.peer_lane_unmounted',
26
- 'config.secret_env_scrubbed',
27
- 'peer.inbound_disposition',
28
- 'peer.held_settled',
29
- 'peer.idle_subscription',
30
- 'classifier.denial_limit',
31
- 'classifier.fallback',
32
- 'classifier.role_defaulted',
33
- 'classifier.contract_broken',
34
- 'checkpoint.execution_outcome_unrecorded',
35
- 'delegation.transcript_integrity',
36
- 'delegation.ask_unresolvable',
37
- 'mcp.injection_dropped',
38
- 'mcp.revocation_probe_failed',
39
- 'mcp.server_redialed',
40
- 'workflow.governance_key_stripped',
41
- 'workflow.agent_option_ignored',
42
- 'memory.session_polluted',
43
- 'memory.harvest_quarantined',
44
- 'memory.delegation_static_mark_waived',
45
- 'memory.content_class_declared',
46
- 'memory.hold_opened',
47
- 'memory.hold_released',
48
- 'memory.hold_disposed',
49
- 'memory.consolidation_recommended',
50
- 'memory.consolidation_committed',
51
- 'memory.consolidation_conflict',
52
- 'memory.consolidation_incomplete',
53
- 'memory.consolidation_refused',
54
- 'memory.consolidation_withheld',
55
- 'memory.restore_withheld',
56
- 'memory.project_scope_absent',
57
- 'route.fallback_to_primary',
58
- 'route.classifier_unroutable',
59
- 'route.base_url_changed_key_unchanged',
60
- 'route.response_model_mismatch',
61
- 'task.user_steer_undrained',
62
- 'task.user_followup_undrained',
63
- 'steering.parked_input_blocked',
64
- 'task.turn_interrupted',
65
- 'task.halt_unconsumed',
66
- 'task.late_approval',
67
- 'task.interrupt_unconsumed',
68
- 'approval.read_root_granted',
69
- 'approval.read_root_grant_rejected',
70
- 'memory.capture_opted_out',
71
- 'memory.capture_optout_unpersisted',
72
- 'skills.listing_truncated',
73
- 'agents.listing_truncated',
74
- 'tool_result.offload_put_failed',
75
- ]);
1
+ import { CORE_ENGINE_NOTICE_CODES, CORE_MCP_INJECTION_DROP_REASONS, CORE_NOTICE_AUDIENCE } from './generated/engineNoticeTables.js';
2
+ export const ENGINE_NOTICE_CODES = CORE_ENGINE_NOTICE_CODES;
76
3
  const CATALOG = new Set(ENGINE_NOTICE_CODES);
77
4
  export const SERVER_NOTICE_AUDIENCE = Object.freeze({
78
5
  'instructions.source_changed': 'user',
79
6
  'memory.layer_locked_legacy': 'operator',
7
+ 'session.records_skipped': 'user',
80
8
  });
81
9
  function audienceRow(table, code) {
82
10
  return Object.hasOwn(table, code) ? table[code] : undefined;
@@ -84,92 +12,13 @@ function audienceRow(table, code) {
84
12
  export function engineNoticeInCatalog(code) {
85
13
  return typeof code === 'string' && (CATALOG.has(code) || Object.hasOwn(SERVER_NOTICE_AUDIENCE, code));
86
14
  }
87
- export const ENGINE_NOTICE_AUDIENCE = Object.freeze({
88
- 'config.autocompact_window_clamped': 'operator',
89
- 'config.env_timeout_discarded': 'operator',
90
- 'config.materialize_env_discarded': 'operator',
91
- 'config.models_swapped': 'operator',
92
- 'config.context_settings_swapped': 'operator',
93
- 'config.read_face_swapped': 'operator',
94
- 'config.read_face_deployment_clamped': 'operator',
95
- 'config.write_face_swapped': 'operator',
96
- 'config.write_face_deployment_clamped': 'operator',
97
- 'config.tool_model_gate_removed': 'operator',
98
- 'config.tool_model_gate_unknown_class': 'operator',
99
- 'config.tool_model_gate_env_invalid': 'operator',
100
- 'config.artifact_host_invalid': 'operator',
101
- 'config.task_root_not_canonical': 'operator',
102
- 'config.write_protection_target_view_absent': 'operator',
103
- 'config.write_protection_unresolved': 'operator',
104
- 'config.execution_env_capability_invalid': 'operator',
105
- 'config.tool_card_undeclared': 'operator',
106
- 'config.tool_face_undeclared': 'operator',
107
- 'config.tool_face_invalid': 'operator',
108
- 'config.forward_sink_failed': 'operator',
109
- 'config.durable_gate_unavailable': 'user',
110
- 'config.peer_admission_out_of_range': 'operator',
111
- 'config.peer_lane_unmounted': 'operator',
112
- 'config.secret_env_scrubbed': 'operator',
113
- 'peer.inbound_disposition': 'user',
114
- 'peer.held_settled': 'user',
115
- 'peer.idle_subscription': 'user',
116
- 'classifier.denial_limit': 'user',
117
- 'classifier.fallback': 'operator',
118
- 'classifier.role_defaulted': 'operator',
119
- 'classifier.contract_broken': 'operator',
120
- 'checkpoint.execution_outcome_unrecorded': 'operator',
121
- 'delegation.transcript_integrity': 'operator',
122
- 'delegation.ask_unresolvable': 'user',
123
- 'mcp.injection_dropped': 'user',
124
- 'mcp.revocation_probe_failed': 'operator',
125
- 'mcp.server_redialed': 'operator',
126
- 'workflow.governance_key_stripped': 'operator',
127
- 'workflow.agent_option_ignored': 'operator',
128
- 'memory.session_polluted': 'user',
129
- 'memory.harvest_quarantined': 'user',
130
- 'memory.delegation_static_mark_waived': 'user',
131
- 'memory.content_class_declared': 'operator',
132
- 'memory.hold_opened': 'user',
133
- 'memory.hold_released': 'user',
134
- 'memory.hold_disposed': 'user',
135
- 'memory.consolidation_recommended': 'operator',
136
- 'memory.consolidation_committed': 'operator',
137
- 'memory.consolidation_conflict': 'operator',
138
- 'memory.consolidation_incomplete': 'operator',
139
- 'memory.consolidation_refused': 'operator',
140
- 'memory.consolidation_withheld': 'operator',
141
- 'memory.restore_withheld': 'operator',
142
- 'memory.project_scope_absent': 'operator',
143
- 'route.fallback_to_primary': 'operator',
144
- 'route.classifier_unroutable': 'operator',
145
- 'route.base_url_changed_key_unchanged': 'operator',
146
- 'route.response_model_mismatch': 'operator',
147
- 'task.user_steer_undrained': 'user',
148
- 'task.user_followup_undrained': 'user',
149
- 'steering.parked_input_blocked': 'user',
150
- 'task.turn_interrupted': 'user',
151
- 'task.halt_unconsumed': 'user',
152
- 'task.late_approval': 'user',
153
- 'task.interrupt_unconsumed': 'user',
154
- 'approval.read_root_granted': 'user',
155
- 'approval.read_root_grant_rejected': 'user',
156
- 'memory.capture_opted_out': 'user',
157
- 'memory.capture_optout_unpersisted': 'user',
158
- 'skills.listing_truncated': 'operator',
159
- 'agents.listing_truncated': 'operator',
160
- 'tool_result.offload_put_failed': 'operator',
161
- });
15
+ export const ENGINE_NOTICE_AUDIENCE = CORE_NOTICE_AUDIENCE;
162
16
  export function noticeAudienceOf(code) {
163
17
  if (typeof code !== 'string')
164
18
  return 'operator';
165
19
  return audienceRow(ENGINE_NOTICE_AUDIENCE, code) ?? audienceRow(SERVER_NOTICE_AUDIENCE, code) ?? 'operator';
166
20
  }
167
- export const MCP_INJECTION_DROP_REASONS = Object.freeze([
168
- 'malformed_entry',
169
- 'name_reserved_by_deployment',
170
- 'gate_closed',
171
- 'over_cap',
172
- ]);
21
+ export const MCP_INJECTION_DROP_REASONS = CORE_MCP_INJECTION_DROP_REASONS;
173
22
  const DROP_REASONS = new Set(MCP_INJECTION_DROP_REASONS);
174
23
  export function readMcpInjectionDrop(notice) {
175
24
  if (typeof notice !== 'object' || notice === null || Array.isArray(notice))
@@ -384,6 +233,44 @@ export function readInstructionsSourceChanged(notice) {
384
233
  return undefined;
385
234
  }
386
235
  }
236
+ function countReading(v) {
237
+ return typeof v === 'number' && Number.isInteger(v) && v >= 0 ? v : 'unknown';
238
+ }
239
+ export function readSessionRecordsSkipped(notice) {
240
+ if (typeof notice !== 'object' || notice === null || Array.isArray(notice))
241
+ return undefined;
242
+ try {
243
+ const n = notice;
244
+ if (n.code !== 'session.records_skipped')
245
+ return undefined;
246
+ const d = n.detail;
247
+ if (typeof d !== 'object' || d === null || Array.isArray(d))
248
+ return undefined;
249
+ const o = d;
250
+ const own = (k) => (Object.hasOwn(o, k) ? o[k] : undefined);
251
+ const sid = own('sessionId');
252
+ const sessionId = typeof sid === 'string' && sid.length > 0 ? sid : undefined;
253
+ if (sessionId === undefined)
254
+ return undefined;
255
+ return { dropped: countReading(own('dropped')), entriesKept: countReading(own('entriesKept')), sessionId };
256
+ }
257
+ catch {
258
+ return undefined;
259
+ }
260
+ }
261
+ export function sessionRecordsSkippedNote(facts) {
262
+ let kept;
263
+ try {
264
+ kept = facts !== null && typeof facts === 'object' ? facts.entriesKept : undefined;
265
+ }
266
+ catch {
267
+ kept = undefined;
268
+ }
269
+ if (kept !== 0)
270
+ return undefined;
271
+ return ("None of this session's earlier entries could be read, so this turn runs with an empty context — the model sees nothing of the earlier conversation. " +
272
+ 'If that history matters, whoever operates this engine has to repair the stored log of this session.');
273
+ }
387
274
  export const ENGINE_NOTICE_FACT_READERS = Object.freeze({
388
275
  'mcp.injection_dropped': readMcpInjectionDrop,
389
276
  'delegation.ask_unresolvable': readAskUnresolvable,
@@ -393,6 +280,7 @@ export const ENGINE_NOTICE_FACT_READERS = Object.freeze({
393
280
  'instructions.source_changed': readInstructionsSourceChanged,
394
281
  'approval.read_root_granted': readReadRootGrantNotice,
395
282
  'approval.read_root_grant_rejected': readReadRootGrantNotice,
283
+ 'session.records_skipped': readSessionRecordsSkipped,
396
284
  });
397
285
  const _factReaderTablePin = true;
398
286
  void _factReaderTablePin;
@@ -0,0 +1,43 @@
1
+ import type { AgentClient } from '@sema-agent/sdk';
2
+ import { type EngineWireClientConfig, type EngineWireInjection } from './engineWireSdk.js';
3
+ import { type EngineWireTarget } from './engineWireTarget.js';
4
+ export declare const INJECTED_WIRE_SETTLE_MS = 60000;
5
+ export type EngineWireTargetClientOptions = Pick<EngineWireClientConfig, 'timeoutMs' | 'maxRetries'>;
6
+ export interface EngineWireInjected<C> {
7
+ kind: 'injected';
8
+ client: C;
9
+ capsBaseUrl: string | undefined;
10
+ }
11
+ export interface EngineWireFromTarget {
12
+ kind: 'target';
13
+ target: EngineWireTarget;
14
+ make: (opts?: EngineWireTargetClientOptions) => AgentClient | null;
15
+ }
16
+ export interface EngineWireInjectedUnusable {
17
+ kind: 'injected-unusable';
18
+ }
19
+ export interface EngineWireNoTarget {
20
+ kind: 'no-target';
21
+ }
22
+ export type EngineWireResolution<C> = EngineWireInjected<C> | EngineWireFromTarget | EngineWireInjectedUnusable | EngineWireNoTarget;
23
+ export declare function engineWireFor<C extends object>(wire: EngineWireInjection<C> | undefined, sessionKey: string, usable: (client: object) => client is C): EngineWireResolution<C>;
24
+ export declare function clientHasVerbs(client: object, verbs: ReadonlyArray<ReadonlyArray<string>>): boolean;
25
+ export interface LinkedAbortSignal {
26
+ signal: AbortSignal;
27
+ dispose: () => void;
28
+ }
29
+ export declare function linkedAbortSignal(caller: AbortSignal | null | undefined, deadline: AbortSignal): LinkedAbortSignal;
30
+ export declare function injectedDeadlineDetail(ms?: number): string;
31
+ export declare class EngineWireNoAnswerError extends Error {
32
+ constructor(message: string);
33
+ }
34
+ export declare function cancelledWaitDetail(): string;
35
+ export declare class EngineWireCancelledError extends Error {
36
+ constructor();
37
+ }
38
+ export declare function connectionLostDetail(): string;
39
+ export type EngineWireNoAnswerKind = 'deadline' | 'time-limit' | 'connection-lost' | 'cancelled';
40
+ export declare function noAnswerKindOf(e: object | null | undefined): EngineWireNoAnswerKind | null;
41
+ export declare function noAnswerDetailFrom(e: object | null | undefined): string | null;
42
+ export declare function sendOnce<T>(signal: AbortSignal | null | undefined, run: () => Promise<T>): Promise<T>;
43
+ export declare function settleInjected<T>(ms: number, signal: AbortSignal | null | undefined, run: (signal: AbortSignal) => Promise<T>): Promise<T>;
@@ -0,0 +1,399 @@
1
+ import { settleWithinDeadline } from './abortableSleep.js';
2
+ import { makeEngineWireClient } from './engineWireSdk.js';
3
+ import { engineWireTargetFor } from './engineWireTarget.js';
4
+ export const INJECTED_WIRE_SETTLE_MS = 60_000;
5
+ export function engineWireFor(wire, sessionKey, usable) {
6
+ if (wire !== undefined) {
7
+ let client;
8
+ let capsBaseUrl;
9
+ try {
10
+ if (wire === null || typeof wire !== 'object')
11
+ return { kind: 'injected-unusable' };
12
+ client = wire.client;
13
+ capsBaseUrl = wire.capsBaseUrl;
14
+ }
15
+ catch {
16
+ return { kind: 'injected-unusable' };
17
+ }
18
+ if (client === null || typeof client !== 'object')
19
+ return { kind: 'injected-unusable' };
20
+ const candidate = client;
21
+ if (!usable(candidate))
22
+ return { kind: 'injected-unusable' };
23
+ return { kind: 'injected', client: candidate, capsBaseUrl: typeof capsBaseUrl === 'string' && capsBaseUrl !== '' ? capsBaseUrl : undefined };
24
+ }
25
+ const installed = engineWireTargetFor(sessionKey);
26
+ if (!installed)
27
+ return { kind: 'no-target' };
28
+ const target = Object.freeze({
29
+ baseUrl: installed.baseUrl,
30
+ ...(installed.token !== undefined ? { token: installed.token } : {}),
31
+ ...(installed.principal !== undefined ? { principal: installed.principal } : {}),
32
+ });
33
+ return {
34
+ kind: 'target',
35
+ target,
36
+ make: (opts) => makeEngineWireClient({
37
+ baseUrl: target.baseUrl,
38
+ ...(target.token ? { token: target.token } : {}),
39
+ principal: target.principal,
40
+ ...(opts?.timeoutMs !== undefined ? { timeoutMs: opts.timeoutMs } : {}),
41
+ ...(opts?.maxRetries !== undefined ? { maxRetries: opts.maxRetries } : {}),
42
+ }),
43
+ };
44
+ }
45
+ export function clientHasVerbs(client, verbs) {
46
+ try {
47
+ if (client === null || typeof client !== 'object')
48
+ return false;
49
+ for (const path of verbs) {
50
+ let cur = client;
51
+ for (const seg of path) {
52
+ if (cur === null || (typeof cur !== 'object' && typeof cur !== 'function'))
53
+ return false;
54
+ cur = cur[seg];
55
+ }
56
+ if (typeof cur !== 'function')
57
+ return false;
58
+ }
59
+ return true;
60
+ }
61
+ catch {
62
+ return false;
63
+ }
64
+ }
65
+ function callerSignalOf(signal) {
66
+ return signal === null ? undefined : signal;
67
+ }
68
+ function quietlyRemoveAbortListener(signal, listener) {
69
+ try {
70
+ signal.removeEventListener('abort', listener);
71
+ }
72
+ catch {
73
+ }
74
+ }
75
+ export function linkedAbortSignal(caller, deadline) {
76
+ const from = callerSignalOf(caller);
77
+ if (from === undefined)
78
+ return { signal: deadline, dispose: () => { } };
79
+ if (typeof AbortSignal.any === 'function')
80
+ return { signal: AbortSignal.any([from, deadline]), dispose: () => { } };
81
+ const ac = new AbortController();
82
+ if (from.aborted || deadline.aborted) {
83
+ ac.abort();
84
+ return { signal: ac.signal, dispose: () => { } };
85
+ }
86
+ const onAbort = () => ac.abort();
87
+ from.addEventListener('abort', onAbort, { once: true });
88
+ deadline.addEventListener('abort', onAbort, { once: true });
89
+ return {
90
+ signal: ac.signal,
91
+ dispose: () => {
92
+ quietlyRemoveAbortListener(from, onAbort);
93
+ quietlyRemoveAbortListener(deadline, onAbort);
94
+ },
95
+ };
96
+ }
97
+ export function injectedDeadlineDetail(ms) {
98
+ const within = ms === undefined ? 'the time limit this client allows' : `${ms} ms`;
99
+ return `no answer from the engine within ${within} — the request was abandoned (it may still have been received)`;
100
+ }
101
+ const NO_ANSWER_BRAND = Symbol.for('@sema-agent/client-core:engine-wire-no-answer');
102
+ const CANCELLED_BRAND = Symbol.for('@sema-agent/client-core:engine-wire-cancelled');
103
+ function branded(e, brand) {
104
+ return Object.prototype.hasOwnProperty.call(e, brand) && e[brand] === true;
105
+ }
106
+ export class EngineWireNoAnswerError extends Error {
107
+ constructor(message) {
108
+ super(message);
109
+ this.name = 'EngineWireNoAnswerError';
110
+ Object.defineProperty(this, NO_ANSWER_BRAND, { value: true, enumerable: false });
111
+ }
112
+ }
113
+ export function cancelledWaitDetail() {
114
+ return 'no answer from the engine — the wait was cancelled after the request was sent (cancelling stops only the wait, not the request: it may still have been received)';
115
+ }
116
+ export class EngineWireCancelledError extends Error {
117
+ constructor() {
118
+ super(cancelledWaitDetail());
119
+ this.name = 'EngineWireCancelledError';
120
+ Object.defineProperty(this, CANCELLED_BRAND, { value: true, enumerable: false });
121
+ }
122
+ }
123
+ const NOT_SENT_MARK = Symbol.for('@sema-agent/client-core:engine-wire-not-sent');
124
+ function markNotSent(error) {
125
+ try {
126
+ if (error !== null && (typeof error === 'object' || typeof error === 'function') && Object.isExtensible(error)) {
127
+ Object.defineProperty(error, NOT_SENT_MARK, { value: true, enumerable: false, configurable: true, writable: false });
128
+ }
129
+ }
130
+ catch {
131
+ }
132
+ return error;
133
+ }
134
+ function clearNotSent(error) {
135
+ try {
136
+ if (error !== null && (typeof error === 'object' || typeof error === 'function') && Object.prototype.hasOwnProperty.call(error, NOT_SENT_MARK)) {
137
+ delete error[NOT_SENT_MARK];
138
+ }
139
+ }
140
+ catch {
141
+ }
142
+ return error;
143
+ }
144
+ function markedNotSent(e) {
145
+ return Object.prototype.hasOwnProperty.call(e, NOT_SENT_MARK) && e[NOT_SENT_MARK] === true;
146
+ }
147
+ export function connectionLostDetail() {
148
+ return 'no answer from the engine — the connection failed before an answer came back (the request may still have been received)';
149
+ }
150
+ function isPreSendCode(code, syscall) {
151
+ switch (code) {
152
+ case 'ECONNREFUSED':
153
+ case 'ENOTFOUND':
154
+ case 'EAI_AGAIN':
155
+ case 'UND_ERR_CONNECT_TIMEOUT':
156
+ case 'ERR_INVALID_URL':
157
+ case 'ERR_INVALID_CHAR':
158
+ case 'ERR_HTTP_INVALID_HEADER_VALUE':
159
+ case 'ERR_INVALID_ARG_TYPE':
160
+ case 'ERR_TLS_CERT_ALTNAME_FORMAT':
161
+ case 'ERR_TLS_CERT_ALTNAME_INVALID':
162
+ case 'ERR_TLS_DH_PARAM_SIZE':
163
+ case 'ERR_TLS_HANDSHAKE_TIMEOUT':
164
+ case 'ERR_TLS_INVALID_CONTEXT':
165
+ case 'ERR_TLS_INVALID_PROTOCOL_METHOD':
166
+ case 'ERR_TLS_INVALID_PROTOCOL_VERSION':
167
+ case 'ERR_TLS_PROTOCOL_VERSION_CONFLICT':
168
+ case 'CERT_CHAIN_TOO_LONG':
169
+ case 'CERT_HAS_EXPIRED':
170
+ case 'CERT_NOT_YET_VALID':
171
+ case 'CERT_REJECTED':
172
+ case 'CERT_REVOKED':
173
+ case 'CERT_SIGNATURE_FAILURE':
174
+ case 'CERT_UNTRUSTED':
175
+ case 'CRL_HAS_EXPIRED':
176
+ case 'CRL_NOT_YET_VALID':
177
+ case 'CRL_SIGNATURE_FAILURE':
178
+ case 'DEPTH_ZERO_SELF_SIGNED_CERT':
179
+ case 'ERROR_IN_CERT_NOT_AFTER_FIELD':
180
+ case 'ERROR_IN_CERT_NOT_BEFORE_FIELD':
181
+ case 'ERROR_IN_CRL_LAST_UPDATE_FIELD':
182
+ case 'ERROR_IN_CRL_NEXT_UPDATE_FIELD':
183
+ case 'HOSTNAME_MISMATCH':
184
+ case 'INVALID_CA':
185
+ case 'INVALID_PURPOSE':
186
+ case 'PATH_LENGTH_EXCEEDED':
187
+ case 'SELF_SIGNED_CERT_IN_CHAIN':
188
+ case 'UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY':
189
+ case 'UNABLE_TO_DECRYPT_CERT_SIGNATURE':
190
+ case 'UNABLE_TO_DECRYPT_CRL_SIGNATURE':
191
+ case 'UNABLE_TO_GET_CRL':
192
+ case 'UNABLE_TO_GET_ISSUER_CERT':
193
+ case 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY':
194
+ case 'UNABLE_TO_VERIFY_LEAF_SIGNATURE':
195
+ return true;
196
+ case 'EHOSTUNREACH':
197
+ case 'ENETUNREACH':
198
+ case 'ETIMEDOUT':
199
+ return syscall === 'connect';
200
+ default:
201
+ return false;
202
+ }
203
+ }
204
+ function allAttemptsFailedBeforeSend(errors) {
205
+ if (!Array.isArray(errors) || errors.length === 0 || errors.length > 16)
206
+ return false;
207
+ return errors.every((x) => x !== null && typeof x === 'object' && isPreSendCode(x.code, x.syscall));
208
+ }
209
+ function failedBeforeSend(e) {
210
+ let cur = e;
211
+ for (let depth = 0; depth < 4 && cur !== null && typeof cur === 'object'; depth++) {
212
+ const o = cur;
213
+ if (isPreSendCode(o.code, o.syscall))
214
+ return true;
215
+ if (allAttemptsFailedBeforeSend(o.errors))
216
+ return true;
217
+ cur = cur.cause;
218
+ }
219
+ return false;
220
+ }
221
+ export function noAnswerKindOf(e) {
222
+ try {
223
+ if (e === null || typeof e !== 'object')
224
+ return null;
225
+ if (e instanceof EngineWireNoAnswerError || branded(e, NO_ANSWER_BRAND))
226
+ return 'deadline';
227
+ if (e instanceof EngineWireCancelledError || branded(e, CANCELLED_BRAND))
228
+ return 'cancelled';
229
+ if (markedNotSent(e))
230
+ return null;
231
+ const name = e.name;
232
+ if (name === 'TimeoutError')
233
+ return 'time-limit';
234
+ if ((e instanceof TypeError || name === 'TypeError') && !failedBeforeSend(e))
235
+ return 'connection-lost';
236
+ return null;
237
+ }
238
+ catch {
239
+ return null;
240
+ }
241
+ }
242
+ export function noAnswerDetailFrom(e) {
243
+ const kind = noAnswerKindOf(e);
244
+ if (kind === 'deadline') {
245
+ try {
246
+ return e.message;
247
+ }
248
+ catch {
249
+ return injectedDeadlineDetail();
250
+ }
251
+ }
252
+ if (kind === 'time-limit')
253
+ return injectedDeadlineDetail();
254
+ if (kind === 'connection-lost')
255
+ return connectionLostDetail();
256
+ if (kind === 'cancelled')
257
+ return cancelledWaitDetail();
258
+ return null;
259
+ }
260
+ function signalAborted(signal) {
261
+ try {
262
+ return signal !== undefined && signal !== null && signal.aborted === true;
263
+ }
264
+ catch {
265
+ return false;
266
+ }
267
+ }
268
+ function abortedBeforeSendError() {
269
+ const e = new Error('This operation was aborted');
270
+ e.name = 'AbortError';
271
+ return e;
272
+ }
273
+ function answeredByEngine(e) {
274
+ try {
275
+ if (e === null || typeof e !== 'object')
276
+ return false;
277
+ const o = e;
278
+ return typeof o.status === 'number' || typeof o.errorCode === 'string';
279
+ }
280
+ catch {
281
+ return false;
282
+ }
283
+ }
284
+ const SETTLED_BY_PACKAGE_BRAND = Symbol.for('@sema-agent/client-core:engine-wire-settled');
285
+ function settledByPackage(value) {
286
+ try {
287
+ return value !== null && typeof value === 'object' && branded(value, SETTLED_BY_PACKAGE_BRAND);
288
+ }
289
+ catch {
290
+ return false;
291
+ }
292
+ }
293
+ function abortReasonIfAborted(signal) {
294
+ try {
295
+ return signal !== undefined && signal.aborted === true ? { value: signal.reason } : undefined;
296
+ }
297
+ catch {
298
+ return undefined;
299
+ }
300
+ }
301
+ export async function sendOnce(signal, run) {
302
+ const callerSignal = callerSignalOf(signal);
303
+ const abortedBefore = signalAborted(callerSignal);
304
+ const reasonBefore = abortedBefore ? abortReasonIfAborted(callerSignal) : undefined;
305
+ let returned;
306
+ try {
307
+ returned = run();
308
+ }
309
+ catch (error) {
310
+ throw markNotSent(error);
311
+ }
312
+ const innerSettled = settledByPackage(returned);
313
+ try {
314
+ return await Promise.resolve(returned);
315
+ }
316
+ catch (error) {
317
+ if (!innerSettled)
318
+ clearNotSent(error);
319
+ if (abortedBefore) {
320
+ if (reasonBefore !== undefined && error === reasonBefore.value && !answeredByEngine(error))
321
+ throw markNotSent(error);
322
+ throw error;
323
+ }
324
+ if (signalAborted(callerSignal) &&
325
+ !answeredByEngine(error) &&
326
+ noAnswerKindOf(error) !== 'deadline' &&
327
+ noAnswerKindOf(error) !== 'cancelled' &&
328
+ !provablyNotSent(error)) {
329
+ throw new EngineWireCancelledError();
330
+ }
331
+ throw error;
332
+ }
333
+ }
334
+ function provablyNotSent(e) {
335
+ try {
336
+ return e !== null && typeof e === 'object' && (markedNotSent(e) || failedBeforeSend(e));
337
+ }
338
+ catch {
339
+ return false;
340
+ }
341
+ }
342
+ export function settleInjected(ms, signal, run) {
343
+ const settled = settleInjectedOnce(ms, signal, run);
344
+ Object.defineProperty(settled, SETTLED_BY_PACKAGE_BRAND, { value: true, enumerable: false });
345
+ return settled;
346
+ }
347
+ async function settleInjectedOnce(ms, signal, run) {
348
+ const callerSignal = callerSignalOf(signal);
349
+ if (signalAborted(callerSignal))
350
+ throw abortedBeforeSendError();
351
+ let captured;
352
+ let cancelled = false;
353
+ let detach = () => { };
354
+ let unlink = () => { };
355
+ const got = await settleWithinDeadline(ms, (deadline) => {
356
+ let pending;
357
+ try {
358
+ const linked = linkedAbortSignal(callerSignal, deadline);
359
+ unlink = linked.dispose;
360
+ pending = Promise.resolve(run(linked.signal));
361
+ }
362
+ catch (error) {
363
+ captured = { error: markNotSent(error) };
364
+ throw error;
365
+ }
366
+ const verb = pending.catch((error) => {
367
+ captured = { error: clearNotSent(error) };
368
+ throw error;
369
+ });
370
+ if (callerSignal === undefined)
371
+ return verb;
372
+ return new Promise((resolve, reject) => {
373
+ const onAbort = () => {
374
+ cancelled = true;
375
+ reject(new EngineWireCancelledError());
376
+ };
377
+ try {
378
+ callerSignal.addEventListener('abort', onAbort, { once: true });
379
+ detach = () => quietlyRemoveAbortListener(callerSignal, onAbort);
380
+ }
381
+ catch {
382
+ }
383
+ if (signalAborted(callerSignal))
384
+ onAbort();
385
+ verb.then(resolve, reject);
386
+ });
387
+ });
388
+ detach();
389
+ unlink();
390
+ if (got.kind === 'value')
391
+ return got.value;
392
+ if (got.kind === 'deadline')
393
+ throw new EngineWireNoAnswerError(injectedDeadlineDetail(ms));
394
+ if (cancelled)
395
+ throw new EngineWireCancelledError();
396
+ if (captured !== undefined)
397
+ throw captured.error;
398
+ throw new Error(got.detail);
399
+ }
@@ -7,6 +7,10 @@ export declare function isLoopbackWireUrl(url: string): boolean;
7
7
  export declare function resolveWireAuth(baseUrl: string | undefined, token?: string): WireAuthToken;
8
8
  export declare function wireAuthTokenFor(baseUrl: string, token?: string): WireAuthToken;
9
9
  export type EngineProbeClient = Pick<AgentClient, 'capabilities' | 'scenarioCapabilities'>;
10
+ export interface EngineWireInjection<C> {
11
+ client: C;
12
+ capsBaseUrl?: string;
13
+ }
10
14
  export type EngineProbeOpts = {
11
15
  fetchImpl?: typeof fetch;
12
16
  timeoutMs?: number;