@sema-agent/client-core 0.82.0 → 0.82.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 (39) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +7 -5
  3. package/dist/adapt/toolCards.d.ts +15 -0
  4. package/dist/adapt/toolCards.js +34 -19
  5. package/dist/adapter/activeRunSelfHeal.d.ts +3 -0
  6. package/dist/adapter/activeRunSelfHeal.js +37 -7
  7. package/dist/adapter/downstream/eventToSdkMessage.js +7 -4
  8. package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -0
  9. package/dist/adapter/downstream/terminalToSdkResult.js +44 -5
  10. package/dist/adapter/runStream.js +33 -4
  11. package/dist/adapter/types.d.ts +2 -0
  12. package/dist/agentsWireCaps.d.ts +1 -0
  13. package/dist/agentsWireCaps.js +110 -29
  14. package/dist/decideFailureNote.d.ts +1 -0
  15. package/dist/decideFailureNote.js +8 -0
  16. package/dist/engineNoticeCodes.js +2 -0
  17. package/dist/executionLaneCapability.js +3 -0
  18. package/dist/fileHistoryCaptureCapability.d.ts +18 -0
  19. package/dist/fileHistoryCaptureCapability.js +58 -0
  20. package/dist/gateOutcome.js +2 -0
  21. package/dist/hitl/askGateWire.d.ts +1 -1
  22. package/dist/hitl/askGateWire.js +1 -1
  23. package/dist/hitl/hitlHostSurface.js +2 -3
  24. package/dist/hitl/parkResolver.d.ts +1 -0
  25. package/dist/hitl/parkResolver.js +11 -7
  26. package/dist/hitl/planReviewWire.js +7 -1
  27. package/dist/hitl/toolApprovalWire.js +3 -7
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.js +2 -0
  30. package/dist/modelIdentityResolvability.d.ts +31 -0
  31. package/dist/modelIdentityResolvability.js +145 -0
  32. package/dist/printToolResultFrame.js +15 -1
  33. package/dist/resumeRefusalCopy.d.ts +12 -0
  34. package/dist/resumeRefusalCopy.js +45 -1
  35. package/dist/seam.d.ts +2 -0
  36. package/dist/toolResult.d.ts +2 -2
  37. package/dist/toolResult.js +7 -6
  38. package/docs/INTEGRATION-CLIENTS.md +123 -10
  39. package/package.json +3 -3
@@ -4,6 +4,7 @@ import { makeEngineWireClient } from '../engineWireSdk.js';
4
4
  import { engineWireTarget } from '../engineWireTarget.js';
5
5
  import { enqueuePlanReviewOutcome } from '../notifications.js';
6
6
  import { corruptStoredRowContent, corruptStoredRowWhere } from '../wireErrorTriage.js';
7
+ import { decideFailureNote } from '../decideFailureNote.js';
7
8
  import { isPlanReviewModeAfter } from './hitlBridge.js';
8
9
  import { engineCapString } from '../engineCapsCache.js';
9
10
  import { planReviewQuestionId, REOPEN_ID_TAIL } from './gateIdentity.js';
@@ -337,7 +338,7 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
337
338
  const msg = e instanceof Error ? e.message : String(e);
338
339
  hostLog('debug', `planReviewWire: ${decision} → ${status} ${msg.slice(0, 200)}`);
339
340
  effect = status >= 400 && status < 500 ? 'not_applied' : 'unconfirmed';
340
- outcome = `The plan_review decision failed: HTTP ${status} ${msg}`.trim();
341
+ outcome = `${`The plan_review decision failed: HTTP ${status} ${msg}`.trim()}${decideFailureNote(e)}`;
341
342
  }
342
343
  else {
343
344
  outcome = `The plan_review decision could not reach the engine: ${String(e)}`;
@@ -382,6 +383,11 @@ export function reopenPlanReviewCard(taskId, opts) {
382
383
  if (typeof taskId !== 'string' || taskId.length === 0) {
383
384
  return receiptMs === undefined ? { reopened: false } : Promise.resolve({ reopened: false });
384
385
  }
386
+ if (decideInFlight.has(taskId)) {
387
+ hostLog('debug', `planReviewWire: reopen for task ${taskId} refused — a decision for this task is in flight (its answer is still being delivered)`);
388
+ const refused = { reopened: false, _sema_decisionInFlight: true };
389
+ return receiptMs === undefined ? refused : Promise.resolve(refused);
390
+ }
385
391
  const sessionKey = opts?.sessionKey ?? DEFAULT_SESSION_KEY;
386
392
  if (!hasQuestionOverlayFor(sessionKey)) {
387
393
  return receiptMs === undefined ? { reopened: false } : Promise.resolve({ reopened: false });
@@ -7,7 +7,7 @@ import { observeCancelByDeny, surfaceRememberNotApplied, surfaceEditNotForwarded
7
7
  import { approvalCallKey, liveFrameCallKey } from './gateIdentity.js';
8
8
  import { isRuleStoreUnreadableKind } from '../gateVocabulary.js';
9
9
  import { denyAttributionRefusalFromError } from '../wireRefusalCopy.js';
10
- import { corruptStoredRowContent, corruptStoredRowWhere } from '../wireErrorTriage.js';
10
+ import { decideFailureNote } from '../decideFailureNote.js';
11
11
  import { readDecideReceipt } from '../decideReceipt.js';
12
12
  import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS, RULE_OFFERS_ABSENCE_REASONS, DENIAL_LIMIT_KINDS, } from '@sema-agent/sdk';
13
13
  export function isFsApprovalGate(gate) {
@@ -29,10 +29,6 @@ export function isToolApprovalGate(gate) {
29
29
  return true;
30
30
  return typeof gate?.toolName === 'string' && toolNameIsShellExec(gate.toolName);
31
31
  }
32
- function withCorruptStoredRow(reason, err) {
33
- const where = corruptStoredRowWhere(err);
34
- return where === undefined ? reason : `${reason} — ${corruptStoredRowContent(where)}`;
35
- }
36
32
  export function structurallyEqual(a, b) {
37
33
  if (a === b)
38
34
  return true;
@@ -204,7 +200,7 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
204
200
  kind: 'failed',
205
201
  stage: 'decide',
206
202
  gatedCallId,
207
- reason: withCorruptStoredRow(`decide(approve) failed: ${String(e)}`, e),
203
+ reason: `decide(approve) failed: ${String(e)}${decideFailureNote(e)}`,
208
204
  ...(e instanceof DecideTransportRetryExhaustedError ? { retryExhausted: true } : {}),
209
205
  ...(currentPending !== undefined ? { currentPending } : {}),
210
206
  ...(wireCode !== undefined ? { errorCode: wireCode } : {}),
@@ -261,7 +257,7 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
261
257
  kind: 'failed',
262
258
  stage: 'decide',
263
259
  gatedCallId,
264
- reason: withCorruptStoredRow(`decide(deny) failed: ${String(e)}`, e),
260
+ reason: `decide(deny) failed: ${String(e)}${decideFailureNote(e)}`,
265
261
  ...(e instanceof DecideTransportRetryExhaustedError ? { retryExhausted: true } : {}),
266
262
  ...(currentPending !== undefined ? { currentPending } : {}),
267
263
  ...(wireCode !== undefined ? { errorCode: wireCode } : {}),
package/dist/index.d.ts CHANGED
@@ -78,6 +78,7 @@ export * from './retainBackgroundWireCaps.js';
78
78
  export * from './oneShotWireCaps.js';
79
79
  export * from './rewindWireCaps.js';
80
80
  export * from './rewindArchiveCapability.js';
81
+ export * from './fileHistoryCaptureCapability.js';
81
82
  export * from './registryQuotaUsage.js';
82
83
  export * from './selfOrchestrationWireCaps.js';
83
84
  export * from './skillsWireCaps.js';
@@ -86,6 +87,7 @@ export * from './selfOrchestrationDenial.js';
86
87
  export * from './webSearchWireCaps.js';
87
88
  export * from './liveModelCatalog.js';
88
89
  export * from './modelBudgetRule.js';
90
+ export * from './modelIdentityResolvability.js';
89
91
  export * from './sessionModelLatch.js';
90
92
  export * from './effortWire.js';
91
93
  export * from './adapter/types.js';
package/dist/index.js CHANGED
@@ -77,6 +77,7 @@ export * from './retainBackgroundWireCaps.js';
77
77
  export * from './oneShotWireCaps.js';
78
78
  export * from './rewindWireCaps.js';
79
79
  export * from './rewindArchiveCapability.js';
80
+ export * from './fileHistoryCaptureCapability.js';
80
81
  export * from './registryQuotaUsage.js';
81
82
  export * from './selfOrchestrationWireCaps.js';
82
83
  export * from './skillsWireCaps.js';
@@ -85,6 +86,7 @@ export * from './selfOrchestrationDenial.js';
85
86
  export * from './webSearchWireCaps.js';
86
87
  export * from './liveModelCatalog.js';
87
88
  export * from './modelBudgetRule.js';
89
+ export * from './modelIdentityResolvability.js';
88
90
  export * from './sessionModelLatch.js';
89
91
  export * from './effortWire.js';
90
92
  export * from './adapter/types.js';
@@ -0,0 +1,31 @@
1
+ type ModelIdentityLaneTuple = readonly [
2
+ 'processEnv',
3
+ 'settingsEnv',
4
+ 'modelCatalogFile',
5
+ 'followedSettingsFile',
6
+ 'followedProviderEnv'
7
+ ];
8
+ export type ModelIdentityLane = ModelIdentityLaneTuple[number];
9
+ export type ModelIdentityLaneReading = 'complete' | 'partial' | 'absent' | 'unreadable';
10
+ export type ModelIdentityLanes = {
11
+ [L in ModelIdentityLane]: L extends 'modelCatalogFile' ? Exclude<ModelIdentityLaneReading, 'complete'> : ModelIdentityLaneReading;
12
+ };
13
+ export type EngineAnswerObservation = 'answered' | 'not_observed' | 'unreachable';
14
+ export interface LocalEngineModelIdentityReading {
15
+ engine: 'local';
16
+ lanes: ModelIdentityLanes;
17
+ engineAnswer?: EngineAnswerObservation;
18
+ }
19
+ export interface RemoteEngineModelIdentityReading {
20
+ engine: 'remote';
21
+ engineAnswer: EngineAnswerObservation;
22
+ }
23
+ export type ModelIdentityReading = LocalEngineModelIdentityReading | RemoteEngineModelIdentityReading;
24
+ export type ModelIdentityResolvability = 'resolvable' | 'not_resolvable' | 'unknown';
25
+ export type ModelSetupDecision = 'offer_setup' | 'explain_unconfigured' | 'proceed';
26
+ export declare function modelIdentityResolvability(reading: ModelIdentityReading): ModelIdentityResolvability;
27
+ export declare function modelIdentityDetail(reading: ModelIdentityReading): string;
28
+ export declare function modelSetupDecision(identity: ModelIdentityResolvability, hostCanConfigureModel: boolean): ModelSetupDecision;
29
+ export declare function modelSetupNotice(decision: ModelSetupDecision): string | null;
30
+ export declare function observedEngineAnswer(baseUrl?: string | undefined): EngineAnswerObservation;
31
+ export {};
@@ -0,0 +1,145 @@
1
+ import { engineCapValue } from './engineCapsCache.js';
2
+ import { engineWireTarget } from './engineWireTarget.js';
3
+ function laneOrder() {
4
+ return ['processEnv', 'settingsEnv', 'modelCatalogFile', 'followedSettingsFile', 'followedProviderEnv'];
5
+ }
6
+ function malformed() {
7
+ return { verdict: 'unknown', why: 'malformed' };
8
+ }
9
+ function own(o, key) {
10
+ if (!Object.hasOwn(o, key))
11
+ return undefined;
12
+ return { v: o[key] };
13
+ }
14
+ function isPlainObject(v) {
15
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
16
+ }
17
+ function laneState(lanes, lane) {
18
+ const hit = own(lanes, lane);
19
+ if (hit === undefined)
20
+ return 'not_reported';
21
+ const v = hit.v;
22
+ const _catalogPin = true;
23
+ void _catalogPin;
24
+ if (v === 'complete')
25
+ return lane === 'modelCatalogFile' ? 'unusable' : v;
26
+ return v === 'partial' || v === 'absent' || v === 'unreadable' ? v : 'unusable';
27
+ }
28
+ function analyse(reading) {
29
+ try {
30
+ if (!isPlainObject(reading))
31
+ return malformed();
32
+ const answer = own(reading, 'engineAnswer')?.v;
33
+ if (answer === 'answered')
34
+ return { verdict: 'resolvable', why: 'engine_answered' };
35
+ const engine = own(reading, 'engine')?.v;
36
+ if (engine === 'remote') {
37
+ return { verdict: 'unknown', why: 'remote', answer: answer === 'unreachable' ? 'unreachable' : 'not_observed' };
38
+ }
39
+ if (engine !== 'local')
40
+ return malformed();
41
+ const lanesHit = own(reading, 'lanes')?.v;
42
+ const order = laneOrder();
43
+ if (!isPlainObject(lanesHit))
44
+ return { verdict: 'unknown', why: 'lanes', unreadable: [], unreported: [...order], unusable: [] };
45
+ const partial = [];
46
+ const unreadable = [];
47
+ const unreported = [];
48
+ const unusable = [];
49
+ for (const lane of order) {
50
+ const s = laneState(lanesHit, lane);
51
+ if (s === 'complete')
52
+ return { verdict: 'resolvable', why: 'lane', lane };
53
+ if (s === 'partial')
54
+ partial.push(lane);
55
+ else if (s === 'unreadable')
56
+ unreadable.push(lane);
57
+ else if (s === 'not_reported')
58
+ unreported.push(lane);
59
+ else if (s === 'unusable')
60
+ unusable.push(lane);
61
+ }
62
+ if (unreadable.length > 0 || unreported.length > 0 || unusable.length > 0) {
63
+ return { verdict: 'unknown', why: 'lanes', unreadable, unreported, unusable };
64
+ }
65
+ return { verdict: 'not_resolvable', partial };
66
+ }
67
+ catch {
68
+ return malformed();
69
+ }
70
+ }
71
+ export function modelIdentityResolvability(reading) {
72
+ return analyse(reading).verdict;
73
+ }
74
+ function laneLabel(lane) {
75
+ switch (lane) {
76
+ case 'processEnv':
77
+ return 'the environment this client was started with';
78
+ case 'settingsEnv':
79
+ return "this client's settings file";
80
+ case 'modelCatalogFile':
81
+ return 'the local model catalog file';
82
+ case 'followedSettingsFile':
83
+ return "another tool's settings file that this client follows";
84
+ case 'followedProviderEnv':
85
+ return 'the provider environment variables this client follows';
86
+ }
87
+ }
88
+ function joinPhrases(xs) {
89
+ if (xs.length <= 1)
90
+ return xs.join('');
91
+ return `${xs.slice(0, -1).join(', ')} and ${xs[xs.length - 1]}`;
92
+ }
93
+ export function modelIdentityDetail(reading) {
94
+ const a = analyse(reading);
95
+ switch (a.verdict) {
96
+ case 'resolvable':
97
+ if (a.why === 'engine_answered') {
98
+ return 'the engine is up and answering, and it does not start without a model name, so it has one — whether its gateway accepts that name is a separate check';
99
+ }
100
+ return `${laneLabel(a.lane)} supplies a model name, so the local engine can start with it — whether its gateway accepts that name is a separate check`;
101
+ case 'not_resolvable':
102
+ if (a.partial.length > 0) {
103
+ const labels = joinPhrases(a.partial.map(laneLabel));
104
+ return `no model name is configured for the local engine — ${labels} ${a.partial.length > 1 ? 'carry' : 'carries'} part of a model configuration (such as a gateway address or a credential) but no model name, and the engine does not start without one`;
105
+ }
106
+ return 'no model name is configured for the local engine — none of the places this client reads supplies one, and the engine does not start without it';
107
+ case 'unknown':
108
+ if (a.why === 'remote') {
109
+ return a.answer === 'unreachable'
110
+ ? 'the engine runs elsewhere and did not answer — it may be unreachable or may have failed to start; its model configuration lives with that deployment, so whether it has a model name is unknown'
111
+ : 'the engine runs elsewhere and has not been seen answering yet — its model configuration lives with that deployment, so whether it has a model name is unknown';
112
+ }
113
+ if (a.why === 'lanes') {
114
+ const parts = [
115
+ ...a.unreadable.map((l) => `${laneLabel(l)} could not be read`),
116
+ ...a.unreported.map((l) => `${laneLabel(l)} was not reported`),
117
+ ...a.unusable.map((l) => `${laneLabel(l)} gave no usable reading`),
118
+ ];
119
+ return `whether the local engine has a model name is unknown — ${joinPhrases(parts)}, and no other place this client reads provides one`;
120
+ }
121
+ return "this reading of the engine's model configuration could not be interpreted, so whether the engine has a model name is unknown";
122
+ }
123
+ }
124
+ export function modelSetupDecision(identity, hostCanConfigureModel) {
125
+ if (identity !== 'not_resolvable')
126
+ return 'proceed';
127
+ if (hostCanConfigureModel === true)
128
+ return 'offer_setup';
129
+ if (hostCanConfigureModel === false)
130
+ return 'explain_unconfigured';
131
+ return 'proceed';
132
+ }
133
+ export function modelSetupNotice(decision) {
134
+ switch (decision) {
135
+ case 'offer_setup':
136
+ return 'no model name is configured for the engine, and it does not start without one — opening model setup';
137
+ case 'explain_unconfigured':
138
+ return 'this engine has no model configured, and it cannot be configured from this client — ask whoever runs the engine to set one up';
139
+ default:
140
+ return null;
141
+ }
142
+ }
143
+ export function observedEngineAnswer(baseUrl = engineWireTarget()?.baseUrl) {
144
+ return engineCapValue(baseUrl, 'version').kind === 'unobserved' ? 'not_observed' : 'answered';
145
+ }
@@ -1,6 +1,8 @@
1
1
  import { isCcToolDenialKind } from './gateVocabulary.js';
2
2
  export { flattenWireOutput as flattenToolOutput } from './adapt/wireShapes.js';
3
3
  import { flattenWireOutput } from './adapt/wireShapes.js';
4
+ import { parseModelFacingBash } from './toolResult.js';
5
+ import { toolResultEnvelopeParts, toolResultOutcomeOf } from './adapt/toolCards.js';
4
6
  function bashExitCodeFailed(toolName, text, structured) {
5
7
  if (typeof toolName !== 'string' || toolName.toLowerCase() !== 'bash')
6
8
  return false;
@@ -10,6 +12,8 @@ function bashExitCodeFailed(toolName, text, structured) {
10
12
  const ec = st?.exitCode;
11
13
  if (typeof ec === 'number')
12
14
  return ec !== 0;
15
+ if (parseModelFacingBash(text)?.note !== undefined)
16
+ return false;
13
17
  const m = /^exit code: (\d+)\b/.exec(text);
14
18
  return m !== null && m[1] !== '0';
15
19
  }
@@ -17,6 +21,14 @@ export function toolEndResultToUserFrame(arm) {
17
21
  if (typeof arm.toolCallId !== 'string' || arm.toolCallId.length === 0)
18
22
  return null;
19
23
  const text = flattenWireOutput(arm.output);
24
+ const parent = typeof arm.parentToolCallId === 'string' ? arm.parentToolCallId : null;
25
+ const outcome = toolResultOutcomeOf(typeof arm.toolName === 'string' ? arm.toolName : '', {
26
+ output: arm.output,
27
+ structured: arm.structured,
28
+ truncated: arm.truncated === true,
29
+ isError: arm.isError === true,
30
+ }, undefined, parent === null ? 'leader' : 'subagent');
31
+ const envelope = toolResultEnvelopeParts(outcome);
20
32
  return {
21
33
  type: 'user',
22
34
  message: {
@@ -30,8 +42,10 @@ export function toolEndResultToUserFrame(arm) {
30
42
  },
31
43
  ],
32
44
  },
33
- parent_tool_use_id: typeof arm.parentToolCallId === 'string' ? arm.parentToolCallId : null,
45
+ parent_tool_use_id: parent,
34
46
  ...(isCcToolDenialKind(arm._sema_denial_kind) ? { _sema_denial_kind: arm._sema_denial_kind } : {}),
47
+ ...(Object.hasOwn(envelope, 'tool_use_result') ? { tool_use_result: envelope.tool_use_result } : {}),
48
+ ...(Object.hasOwn(envelope, '_sema_degraded') ? { _sema_degraded: envelope._sema_degraded } : {}),
35
49
  uuid: arm.uuid,
36
50
  session_id: arm.session_id,
37
51
  };
@@ -7,6 +7,18 @@ export interface ResumeRefusalDetail {
7
7
  }
8
8
  export declare function resumeRefusalFromError(err: unknown): ResumeRefusalDetail | null;
9
9
  export declare function resumeRefusalContent(detail: ResumeRefusalDetail): string;
10
+ export interface ResumePolicyBlockDetail {
11
+ blockedBy: {
12
+ kind: 'named';
13
+ code: string;
14
+ } | {
15
+ kind: 'absent';
16
+ } | {
17
+ kind: 'unreadable';
18
+ };
19
+ }
20
+ export declare function resumePolicyBlockFromError(err: unknown): ResumePolicyBlockDetail | null;
21
+ export declare function resumePolicyBlockContent(detail: ResumePolicyBlockDetail): string;
10
22
  export interface ResumeReopenDetail {
11
23
  code: string;
12
24
  reason: 'env_failed' | 'tool_unavailable' | 'tool_contract_mismatch';
@@ -1,5 +1,6 @@
1
1
  import { readErrorNumber, readErrorString } from './wireFailureShape.js';
2
- import { RESUME_CONTEXT_UNAVAILABLE, RESUME_PLACEMENT_MISMATCH, RESUME_PREFLIGHT_REJECTED, RESUME_REOPEN_CODES, RESUME_ENV_FAILED, RESUME_TOOL_UNAVAILABLE, } from './engineErrorCodes.js';
2
+ import { RESUME_CONTEXT_UNAVAILABLE, RESUME_PLACEMENT_MISMATCH, RESUME_PREFLIGHT_REJECTED, RESUME_REOPEN_CODES, RESUME_ENV_FAILED, RESUME_TOOL_UNAVAILABLE, RESUME_POLICY_FOLD_CODE, } from './engineErrorCodes.js';
3
+ import { capForDisplay } from './fleetTaskDesc.js';
3
4
  import { resumeRetryLaterFromError } from './wireErrorTriage.js';
4
5
  export const RESUME_REFUSAL_CODES = Object.freeze([
5
6
  RESUME_PLACEMENT_MISMATCH,
@@ -39,6 +40,49 @@ export function resumeRefusalContent(detail) {
39
40
  'The engine supplied no wait, so this refusal does not say whether the token stays redeemable');
40
41
  return parts.join(' · ');
41
42
  }
43
+ export function resumePolicyBlockFromError(err) {
44
+ if (typeof err !== 'object' || err === null)
45
+ return null;
46
+ const o = err;
47
+ let outer;
48
+ try {
49
+ outer = o['errorCode'];
50
+ }
51
+ catch {
52
+ return null;
53
+ }
54
+ if (outer !== RESUME_POLICY_FOLD_CODE)
55
+ return null;
56
+ const judge = (v) => ({
57
+ blockedBy: typeof v === 'string' && v.length > 0 ? { kind: 'named', code: v } : { kind: 'unreadable' },
58
+ });
59
+ try {
60
+ const top = o['blockedBy'];
61
+ if (top !== undefined)
62
+ return judge(top);
63
+ const extra = o['extra'];
64
+ if (typeof extra === 'object' && extra !== null && !Array.isArray(extra) && Object.hasOwn(extra, 'blockedBy')) {
65
+ return judge(extra['blockedBy']);
66
+ }
67
+ return { blockedBy: { kind: 'absent' } };
68
+ }
69
+ catch {
70
+ return { blockedBy: { kind: 'unreadable' } };
71
+ }
72
+ }
73
+ export function resumePolicyBlockContent(detail) {
74
+ const b = detail.blockedBy;
75
+ const reason = b.kind === 'named'
76
+ ? `The check that refused it: ${capForDisplay(b.code, 80)}`
77
+ : b.kind === 'absent'
78
+ ? 'The refusal did not name a more specific check'
79
+ : 'The refusal carried a more specific reason that could not be read';
80
+ return [
81
+ 'The engine refused to resume this parked work at its admission check (the engine reports that its admission policy changed since the work was first accepted)',
82
+ reason,
83
+ "This refusal does not say whether anything was consumed before it or whether a retry would pass — check the task's current state before deciding again, and ask whoever operates this deployment if it keeps happening",
84
+ ].join(' · ');
85
+ }
42
86
  export function resumeReopenFromError(err) {
43
87
  if (typeof err !== 'object' || err === null)
44
88
  return null;
package/dist/seam.d.ts CHANGED
@@ -130,6 +130,7 @@ export type ChromeEvent = {
130
130
  engineUsage?: EngineTurnUsage;
131
131
  usageMissing?: true;
132
132
  stopReason?: string;
133
+ responseModel?: string;
133
134
  } | {
134
135
  kind: 'subagent_turn_usage';
135
136
  laneProof: LaneProof;
@@ -140,6 +141,7 @@ export type ChromeEvent = {
140
141
  engineUsage?: EngineTurnUsage;
141
142
  usageMissing?: true;
142
143
  stopReason?: string;
144
+ responseModel?: string;
143
145
  } | {
144
146
  kind: 'plan_review_park';
145
147
  laneProof: LaneProof;
@@ -79,8 +79,8 @@ export interface ToolResultBody {
79
79
  degraded?: typeof TOOL_RESULT_DEGRADED_WIRE_NO_OUTPUT;
80
80
  }
81
81
  export declare function degradedToolResultBody(isError: boolean): ToolResultBody;
82
- export declare function wireOutputToBody(toolName: string, output: unknown, isError: boolean, truncated: boolean, flatten: FlattenWireOutput, structured?: unknown): ToolResultBody;
83
- export declare function structuredToToolUseResult(structured: unknown, modelText?: string): {
82
+ export declare function wireOutputToBody(toolName: string, output: unknown, isError: boolean, truncated: boolean, flatten: FlattenWireOutput, structured?: unknown, leaderLedger?: boolean): ToolResultBody;
83
+ export declare function structuredToToolUseResult(structured: unknown, modelText?: string, leaderLedger?: boolean): {
84
84
  toolUseResult: unknown;
85
85
  isError?: boolean;
86
86
  } | null;
@@ -229,7 +229,7 @@ export const TOOL_RESULT_DEGRADED_WIRE_NO_OUTPUT = 'wire_carried_no_output';
229
229
  export function degradedToolResultBody(isError) {
230
230
  return { content: '', isError, degraded: TOOL_RESULT_DEGRADED_WIRE_NO_OUTPUT };
231
231
  }
232
- export function wireOutputToBody(toolName, output, isError, truncated, flatten, structured) {
232
+ export function wireOutputToBody(toolName, output, isError, truncated, flatten, structured, leaderLedger = true) {
233
233
  const text = flatten(output);
234
234
  const name = (toolName || '').toLowerCase();
235
235
  const sType = structuredDetailType(structured);
@@ -320,7 +320,7 @@ export function wireOutputToBody(toolName, output, isError, truncated, flatten,
320
320
  }
321
321
  const wfEnvelope = parseWorkflowPollEnvelope(text);
322
322
  if (wfEnvelope) {
323
- if (WF_TERMINAL_STATUSES.has(wfEnvelope.status))
323
+ if (leaderLedger && WF_TERMINAL_STATUSES.has(wfEnvelope.status))
324
324
  markEngineWorkflowNotified(wfEnvelope.taskId);
325
325
  return wrap({
326
326
  task_id: wfEnvelope.taskId,
@@ -340,7 +340,7 @@ export function wireOutputToBody(toolName, output, isError, truncated, flatten,
340
340
  }
341
341
  return { content: truncated ? `${text}\n…(truncated)` : text, isError };
342
342
  }
343
- export function structuredToToolUseResult(structured, modelText) {
343
+ export function structuredToToolUseResult(structured, modelText, leaderLedger = true) {
344
344
  if (typeof structured !== 'object' || structured === null)
345
345
  return null;
346
346
  const s = structured;
@@ -348,7 +348,7 @@ export function structuredToToolUseResult(structured, modelText) {
348
348
  if (typeof s[k] === 'string' && s[k].length > MAX_STRUCTURED_FIELD_CHARS)
349
349
  return null;
350
350
  }
351
- if (s.type === 'workflow-run' && typeof s.workflowRunId === 'string') {
351
+ if (leaderLedger && s.type === 'workflow-run' && typeof s.workflowRunId === 'string') {
352
352
  registerOutstandingWorkflowRun(s.workflowRunId);
353
353
  }
354
354
  switch (s.type) {
@@ -586,7 +586,8 @@ export function structuredToToolUseResult(structured, modelText) {
586
586
  if (typeof s.description !== 'string' || typeof s.prompt !== 'string') {
587
587
  return null;
588
588
  }
589
- registerOutstandingBgTask(agentId, s.description, s.prompt, receipt.seq);
589
+ if (leaderLedger)
590
+ registerOutstandingBgTask(agentId, s.description, s.prompt, receipt.seq);
590
591
  return {
591
592
  toolUseResult: {
592
593
  isAsync: true,
@@ -653,7 +654,7 @@ export function structuredToToolUseResult(structured, modelText) {
653
654
  const runErrorCode = typeof s.errorCode === 'string' && s.errorCode.length > 0 ? s.errorCode : undefined;
654
655
  let output = bodyText ?? '';
655
656
  if (taskType === 'workflow') {
656
- if (WF_TERMINAL_STATUSES.has(status))
657
+ if (leaderLedger && WF_TERMINAL_STATUSES.has(status))
657
658
  markEngineWorkflowNotified(taskId);
658
659
  const jsonSrc = output.length > 0 ? output : (modelText ?? '');
659
660
  output = projectWorkflowTaskOutput(jsonSrc);