@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.
- package/CHANGELOG.md +22 -0
- package/README.md +7 -5
- package/dist/adapt/toolCards.d.ts +15 -0
- package/dist/adapt/toolCards.js +34 -19
- package/dist/adapter/activeRunSelfHeal.d.ts +3 -0
- package/dist/adapter/activeRunSelfHeal.js +37 -7
- package/dist/adapter/downstream/eventToSdkMessage.js +7 -4
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +44 -5
- package/dist/adapter/runStream.js +33 -4
- package/dist/adapter/types.d.ts +2 -0
- package/dist/agentsWireCaps.d.ts +1 -0
- package/dist/agentsWireCaps.js +110 -29
- package/dist/decideFailureNote.d.ts +1 -0
- package/dist/decideFailureNote.js +8 -0
- package/dist/engineNoticeCodes.js +2 -0
- package/dist/executionLaneCapability.js +3 -0
- package/dist/fileHistoryCaptureCapability.d.ts +18 -0
- package/dist/fileHistoryCaptureCapability.js +58 -0
- package/dist/gateOutcome.js +2 -0
- package/dist/hitl/askGateWire.d.ts +1 -1
- package/dist/hitl/askGateWire.js +1 -1
- package/dist/hitl/hitlHostSurface.js +2 -3
- package/dist/hitl/parkResolver.d.ts +1 -0
- package/dist/hitl/parkResolver.js +11 -7
- package/dist/hitl/planReviewWire.js +7 -1
- package/dist/hitl/toolApprovalWire.js +3 -7
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/modelIdentityResolvability.d.ts +31 -0
- package/dist/modelIdentityResolvability.js +145 -0
- package/dist/printToolResultFrame.js +15 -1
- package/dist/resumeRefusalCopy.d.ts +12 -0
- package/dist/resumeRefusalCopy.js +45 -1
- package/dist/seam.d.ts +2 -0
- package/dist/toolResult.d.ts +2 -2
- package/dist/toolResult.js +7 -6
- package/docs/INTEGRATION-CLIENTS.md +123 -10
- 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 {
|
|
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:
|
|
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:
|
|
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:
|
|
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;
|
package/dist/toolResult.d.ts
CHANGED
|
@@ -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;
|
package/dist/toolResult.js
CHANGED
|
@@ -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
|
-
|
|
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);
|