@sema-agent/client-core 0.82.7 → 0.83.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.
- package/CHANGELOG.md +55 -0
- package/README.md +11 -6
- package/dist/adapt/arms.d.ts +3 -2
- package/dist/adapt/arms.js +16 -11
- package/dist/adapt/ids.js +12 -8
- package/dist/adapt/textStream.d.ts +3 -2
- package/dist/adapt/toolCards.d.ts +2 -3
- package/dist/adapt/toolCards.js +1 -1
- package/dist/adapt.d.ts +1 -1
- package/dist/adapt.js +13 -6
- package/dist/adapter/activeRunSelfHeal.js +34 -17
- package/dist/adapter/downstream/eventToSdkMessage.js +1 -1
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -4
- package/dist/adapter/downstream/terminalToSdkResult.js +43 -5
- package/dist/adapter/runStream.js +6 -6
- package/dist/clientSlice.d.ts +0 -5
- package/dist/engineNoticeCodes.js +4 -0
- package/dist/fleet/fleetRowAgentType.d.ts +0 -1
- package/dist/fleet/fleetRowAgentType.js +0 -3
- package/dist/hitl/approvalResolution.js +2 -0
- package/dist/hitl/frameRouter.d.ts +3 -2
- package/dist/hitl/toolApprovalWire.d.ts +1 -0
- package/dist/hitl/toolApprovalWire.js +56 -10
- package/dist/hooksWireCaps.js +27 -1
- package/dist/host.d.ts +1 -0
- package/dist/liveInitToolFace.d.ts +4 -2
- package/dist/liveInitToolFace.js +2 -2
- package/dist/model/catalogLoader.d.ts +1 -6
- package/dist/panelRunningHistory.d.ts +3 -2
- package/dist/peerFrames.d.ts +0 -1
- package/dist/printInitToolFace.js +1 -1
- package/dist/request/printNotification.js +26 -26
- package/dist/seam.d.ts +8 -2
- package/dist/seam.js +18 -7
- package/dist/systemReminderTag.d.ts +0 -1
- package/dist/systemReminderTag.js +0 -3
- package/dist/toolResult.js +1 -0
- package/dist/uuidV5.d.ts +3 -0
- package/dist/uuidV5.js +178 -0
- package/dist/webSearchWireCaps.d.ts +0 -3
- package/dist/webSearchWireCaps.js +21 -51
- package/dist/wireFailureShape.d.ts +2 -1
- package/docs/INTEGRATION-CLIENTS.md +421 -11
- package/package.json +2 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AgentEvent, DeniedBy, TaskStats } from '@sema-agent/sdk';
|
|
2
2
|
import { type CcToolDenialKind } from '../../gateVocabulary.js';
|
|
3
3
|
import { type SDKMessage, type EmitContext } from '../types.js';
|
|
4
|
+
import type { TerminalReason } from '@sema-agent/agent-types';
|
|
4
5
|
import { type SemaModelUsage } from './turnUsageToModelUsage.js';
|
|
5
6
|
export interface SemaFlatUsage {
|
|
6
7
|
readonly inputTokens: number;
|
|
@@ -90,15 +91,12 @@ export declare function subagentUsageIsPartial(row: {
|
|
|
90
91
|
} | null | undefined, opts?: {
|
|
91
92
|
readonly tablePartial?: boolean;
|
|
92
93
|
}): boolean;
|
|
93
|
-
export interface SemaNestedUsageByTask {
|
|
94
|
-
readonly rows: Readonly<Record<string, SemaSubagentUsageRow>>;
|
|
95
|
-
readonly partial: boolean;
|
|
96
|
-
}
|
|
97
94
|
export interface SemaTerminalModelUsage extends SemaModelUsage {
|
|
98
95
|
readonly _sema_total_input_tokens?: number;
|
|
99
96
|
readonly _sema_usage_basis?: string;
|
|
100
97
|
readonly _sema_cache_write_tokens_long?: number;
|
|
101
98
|
}
|
|
99
|
+
export declare function terminalReasonForResult(msg: SDKMessage): TerminalReason | undefined;
|
|
102
100
|
export declare function doneToSdkResult(ev: Extract<AgentEvent, {
|
|
103
101
|
type: 'done';
|
|
104
102
|
}>, ctx: EmitContext, observed?: TerminalStreamObserved): SDKMessage;
|
|
@@ -413,6 +413,41 @@ function subtypeForErrorCode(code) {
|
|
|
413
413
|
return 'error_max_structured_output_retries';
|
|
414
414
|
return 'error_during_execution';
|
|
415
415
|
}
|
|
416
|
+
function terminalReasonOf(subtype, isError) {
|
|
417
|
+
switch (subtype) {
|
|
418
|
+
case 'success':
|
|
419
|
+
return isError === false ? 'completed' : undefined;
|
|
420
|
+
case 'error_max_turns':
|
|
421
|
+
return 'max_turns';
|
|
422
|
+
case 'error_max_budget_usd':
|
|
423
|
+
return 'budget_exhausted';
|
|
424
|
+
case 'error_max_structured_output_retries':
|
|
425
|
+
return 'structured_output_retry_exhausted';
|
|
426
|
+
default:
|
|
427
|
+
return undefined;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function terminalReasonParts(subtype, isError) {
|
|
431
|
+
const reason = terminalReasonOf(subtype, isError);
|
|
432
|
+
return reason !== undefined ? { terminal_reason: reason } : {};
|
|
433
|
+
}
|
|
434
|
+
export function terminalReasonForResult(msg) {
|
|
435
|
+
try {
|
|
436
|
+
const m = msg;
|
|
437
|
+
if (typeof m !== 'object' || m === null || Array.isArray(m))
|
|
438
|
+
return undefined;
|
|
439
|
+
const rec = m;
|
|
440
|
+
if (rec.type !== 'result')
|
|
441
|
+
return undefined;
|
|
442
|
+
return terminalReasonOf(rec.subtype, rec.is_error);
|
|
443
|
+
}
|
|
444
|
+
catch {
|
|
445
|
+
return undefined;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
function selectedModelParts(model) {
|
|
449
|
+
return typeof model === 'string' && model.length > 0 ? { _sema_selected_model: model } : {};
|
|
450
|
+
}
|
|
416
451
|
function salvagedTextOf(r) {
|
|
417
452
|
const salvagedOutput = r.salvagedOutput;
|
|
418
453
|
return typeof r.result === 'string' && r.result.trim().length > 0
|
|
@@ -449,9 +484,11 @@ function errorResult(ctx, parts) {
|
|
|
449
484
|
...reemitEffectiveFacts(parts.facts),
|
|
450
485
|
...nestedUsageByTaskParts(parts.stats, parts.observed?.nestedUsageByTask),
|
|
451
486
|
errors: [...parts.errors],
|
|
452
|
-
...(parts.
|
|
453
|
-
...(parts.
|
|
454
|
-
...(parts.
|
|
487
|
+
...terminalReasonParts(parts.subtype, true),
|
|
488
|
+
...(parts.errorCode !== undefined && parts.errorCode.length > 0 ? { _sema_error_code: parts.errorCode } : {}),
|
|
489
|
+
...(parts.degraded !== undefined ? { _sema_model_degraded: parts.degraded } : {}),
|
|
490
|
+
...selectedModelParts(parts.model),
|
|
491
|
+
...(parts.salvagedResult !== undefined ? { _sema_salvaged_result: parts.salvagedResult } : {}),
|
|
455
492
|
...(parts.outcomeUnknown === true ? { _sema_outcome: 'unknown' } : {}),
|
|
456
493
|
});
|
|
457
494
|
}
|
|
@@ -556,16 +593,17 @@ export function doneToSdkResult(ev, ctx, observed) {
|
|
|
556
593
|
num_turns: stats?.turns ?? 0,
|
|
557
594
|
result: r.result ?? '',
|
|
558
595
|
...structuredOutputParts(r),
|
|
559
|
-
...(degraded !== undefined ? { degraded } : {}),
|
|
596
|
+
...(degraded !== undefined ? { _sema_model_degraded: degraded } : {}),
|
|
560
597
|
stop_reason: null,
|
|
561
598
|
total_cost_usd: costOrNull(stats),
|
|
562
599
|
usage: flattenUsage(stats),
|
|
563
600
|
modelUsage: modelUsageFor(stats, r.model),
|
|
564
601
|
...permissionDenialParts(stats, observed),
|
|
602
|
+
...terminalReasonParts('success', false),
|
|
565
603
|
...costFactParts(stats, observed),
|
|
566
604
|
...effectiveFactParts(rec),
|
|
567
605
|
...nestedUsageByTaskParts(stats, observed?.nestedUsageByTask),
|
|
568
|
-
...(
|
|
606
|
+
...selectedModelParts(r.model),
|
|
569
607
|
});
|
|
570
608
|
}
|
|
571
609
|
export function failedToSdkResult(ev, ctx, observed) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { eventSeq, } from './types.js';
|
|
1
|
+
import { eventSeq, stamp, } from './types.js';
|
|
2
2
|
import { eventToSdkMessage, turnEndUsage } from './downstream/eventToSdkMessage.js';
|
|
3
3
|
import { turnUsageToModelUsage } from './downstream/turnUsageToModelUsage.js';
|
|
4
4
|
import { readRunCostFacts, terminalToSdkResult, TOOL_INPUT_JOIN_MAX_CALLS } from './downstream/terminalToSdkResult.js';
|
|
@@ -97,14 +97,14 @@ export function isModelOutputErrorRowText(text) {
|
|
|
97
97
|
}
|
|
98
98
|
export const OUTCOME_UNKNOWN_ROW_PREFIX = 'Outcome unknown';
|
|
99
99
|
function syntheticTerminalRow(ctx, text) {
|
|
100
|
-
return {
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
return stamp(ctx, {
|
|
101
|
+
uuid: undefined,
|
|
102
|
+
session_id: undefined,
|
|
103
103
|
type: 'assistant',
|
|
104
104
|
message: { role: 'assistant', model: '<synthetic>', content: [{ type: 'text', text }] },
|
|
105
105
|
parent_tool_use_id: null,
|
|
106
|
-
|
|
107
|
-
};
|
|
106
|
+
_sema_api_error_message: true,
|
|
107
|
+
});
|
|
108
108
|
}
|
|
109
109
|
export function isOutcomeUnknownRowText(text) {
|
|
110
110
|
return text.trimStart().startsWith(`${OUTCOME_UNKNOWN_ROW_PREFIX}:`);
|
package/dist/clientSlice.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export const ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
3
3
|
'config.env_timeout_discarded',
|
|
4
4
|
'config.materialize_env_discarded',
|
|
5
5
|
'config.models_swapped',
|
|
6
|
+
'config.context_settings_swapped',
|
|
6
7
|
'config.read_face_swapped',
|
|
7
8
|
'config.read_face_deployment_clamped',
|
|
8
9
|
'config.write_face_swapped',
|
|
@@ -22,6 +23,7 @@ export const ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
22
23
|
'config.durable_gate_unavailable',
|
|
23
24
|
'config.peer_admission_out_of_range',
|
|
24
25
|
'config.peer_lane_unmounted',
|
|
26
|
+
'config.secret_env_scrubbed',
|
|
25
27
|
'peer.inbound_disposition',
|
|
26
28
|
'peer.held_settled',
|
|
27
29
|
'peer.idle_subscription',
|
|
@@ -78,6 +80,7 @@ export const ENGINE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
78
80
|
'config.env_timeout_discarded': 'operator',
|
|
79
81
|
'config.materialize_env_discarded': 'operator',
|
|
80
82
|
'config.models_swapped': 'operator',
|
|
83
|
+
'config.context_settings_swapped': 'operator',
|
|
81
84
|
'config.read_face_swapped': 'operator',
|
|
82
85
|
'config.read_face_deployment_clamped': 'operator',
|
|
83
86
|
'config.write_face_swapped': 'operator',
|
|
@@ -97,6 +100,7 @@ export const ENGINE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
97
100
|
'config.durable_gate_unavailable': 'user',
|
|
98
101
|
'config.peer_admission_out_of_range': 'operator',
|
|
99
102
|
'config.peer_lane_unmounted': 'operator',
|
|
103
|
+
'config.secret_env_scrubbed': 'operator',
|
|
100
104
|
'peer.inbound_disposition': 'user',
|
|
101
105
|
'peer.held_settled': 'user',
|
|
102
106
|
'peer.idle_subscription': 'user',
|
|
@@ -70,6 +70,8 @@ function fsLegResolution(outcome, kind) {
|
|
|
70
70
|
}
|
|
71
71
|
if (stage === 'input')
|
|
72
72
|
return { kind: 'not_sent', cause: 'no_input', ...call, ...detail };
|
|
73
|
+
if (stage === 'card' && pick(outcome, 'editRefused') === true)
|
|
74
|
+
return { kind: 'not_sent', cause: 'edit_refused', ...call, ...detail };
|
|
73
75
|
if (stage === 'card')
|
|
74
76
|
return { kind: 'not_sent', cause: 'card_unavailable', ...call, ...detail };
|
|
75
77
|
if (stage === 'decide') {
|
|
@@ -24,7 +24,7 @@ export interface AskGateWireDeps {
|
|
|
24
24
|
onToolApprovalOutcome?: (frame: ToolApprovalFrame, outcome: ToolApprovalFrameOutcome) => void | Promise<void>;
|
|
25
25
|
onDecideOperation?: DecideOperationObserver;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
type GateKind = 'ask' | 'fs';
|
|
28
28
|
export interface GatePark {
|
|
29
29
|
gate: GateKind;
|
|
30
30
|
pendingDone?: AgentEvent | undefined;
|
|
@@ -55,10 +55,11 @@ export interface FrameRouterCtx {
|
|
|
55
55
|
}
|
|
56
56
|
export declare function isAskTool(toolName: string | undefined): boolean;
|
|
57
57
|
export declare function isHostProgressFrame(ev: AgentEvent): boolean;
|
|
58
|
-
|
|
58
|
+
interface HeldFlushInterruptEvidence {
|
|
59
59
|
terminal?: AgentEvent | undefined;
|
|
60
60
|
signal?: AbortSignal | undefined;
|
|
61
61
|
gateAbortedByUser?: boolean | undefined;
|
|
62
62
|
}
|
|
63
63
|
export declare function flushHeldWithInterruptRewrite(led: GateLedger, evidence: HeldFlushInterruptEvidence): Generator<AgentEvent>;
|
|
64
64
|
export declare function routeFrame(ev: AgentEvent, ctx: FrameRouterCtx): Promise<FrameAction>;
|
|
65
|
+
export {};
|
|
@@ -39,6 +39,7 @@ export type FsApprovalOutcome = {
|
|
|
39
39
|
retryExhausted?: true;
|
|
40
40
|
currentPending?: GateCurrentPending | undefined;
|
|
41
41
|
denyAttributionRefusal?: DenyAttributionRefusalDetail | undefined;
|
|
42
|
+
editRefused?: true;
|
|
42
43
|
};
|
|
43
44
|
export interface FsApprovalWireDeps {
|
|
44
45
|
client: HitlClientLike;
|
|
@@ -140,15 +140,46 @@ function logAfterDecided(msg) {
|
|
|
140
140
|
catch {
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
|
+
const ARGS_OMITTED_PATH_RECOVERED_NOTE = 'tool arguments exceeded the wire cap and were omitted — only the target path was recovered (from the approval question); ' +
|
|
144
|
+
'the rest of the arguments, such as the content to write, is not shown, so you are deciding without seeing it. ' +
|
|
145
|
+
'Edits are not accepted on this card: there is no original input to edit';
|
|
146
|
+
const ARGS_OMITTED_NOTHING_RECOVERED_NOTE = 'tool arguments exceeded the wire cap and were omitted, and nothing could be recovered from the approval question — ' +
|
|
147
|
+
'you are deciding without seeing what this call will do; deny it if you are not sure. ' +
|
|
148
|
+
'Edits are not accepted on this card: there is no original input to edit';
|
|
149
|
+
const PARK_ROW_ARGS_ABSENT_NOTE = "this request's tool arguments are not available on this surface — neither the event stream nor the pending approval record " +
|
|
150
|
+
'carries them, so you are deciding without seeing them; deny it if you are not sure what it will do. ' +
|
|
151
|
+
'Edits are not accepted on this card: there is no original input to edit';
|
|
152
|
+
const PARK_ROW_ARGS_TRUNCATED_NOTE = "this request's tool arguments were too large to keep on the pending approval record and were replaced by a size marker, " +
|
|
153
|
+
'so you are deciding without seeing them; deny it if you are not sure what it will do. ' +
|
|
154
|
+
'Edits are not accepted on this card: there is no original input to edit';
|
|
155
|
+
const PARK_EDIT_REFUSED_REASON = "the card returned an edited approval, but this request's tool arguments are not available on this surface " +
|
|
156
|
+
'(missing, or replaced by a size marker on the pending approval record), so the edit cannot be applied — nothing was sent; ' +
|
|
157
|
+
'approve or deny it as it is';
|
|
158
|
+
function isParkRowInputSizeMarker(v) {
|
|
159
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
160
|
+
return false;
|
|
161
|
+
const keys = Object.keys(v);
|
|
162
|
+
if (keys.length !== 2 || !keys.includes('truncated') || !keys.includes('bytes'))
|
|
163
|
+
return false;
|
|
164
|
+
const o = v;
|
|
165
|
+
return o.truncated === true && typeof o.bytes === 'number' && Number.isFinite(o.bytes) && o.bytes >= 0;
|
|
166
|
+
}
|
|
143
167
|
export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signal, parkGatedCallId) {
|
|
144
168
|
const found = await findPendingForTask(deps.client, taskId, (toolName) => toolName !== undefined && (toolNameIsFsWrite(toolName) || toolNameIsShellExec(toolName)), signal ? { signal } : undefined, parkGatedCallId, (row) => askParkRowArm(row) === 'tool-gate');
|
|
145
169
|
if (!found.ok)
|
|
146
170
|
return { kind: 'failed', stage: 'fetch', reason: found.reason, ...(found.code !== undefined ? { code: found.code } : {}) };
|
|
147
171
|
const { pending, gatedCallId } = found;
|
|
148
172
|
const toolName = typeof pending.toolName === 'string' ? pending.toolName : '';
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
173
|
+
const streamArgs = gatedCallId !== undefined ? argsByCall.get(gatedCallId) : undefined;
|
|
174
|
+
const rowInput = pending.input;
|
|
175
|
+
const rowArgsGap = streamArgs !== undefined && streamArgs !== null
|
|
176
|
+
? undefined
|
|
177
|
+
: rowInput === undefined || rowInput === null
|
|
178
|
+
? 'absent'
|
|
179
|
+
: isParkRowInputSizeMarker(rowInput)
|
|
180
|
+
? 'truncated'
|
|
181
|
+
: undefined;
|
|
182
|
+
const args = streamArgs !== undefined && streamArgs !== null ? streamArgs : rowArgsGap !== undefined ? {} : rowInput;
|
|
152
183
|
if (typeof args !== 'object' || args === null) {
|
|
153
184
|
return { kind: 'failed', stage: 'input', gatedCallId, reason: 'gate has no tool input payload' };
|
|
154
185
|
}
|
|
@@ -165,8 +196,15 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
165
196
|
args,
|
|
166
197
|
callKey,
|
|
167
198
|
...(signal ? { signal } : {}),
|
|
199
|
+
...(rowArgsGap !== undefined
|
|
200
|
+
? {
|
|
201
|
+
argsUnavailable: true,
|
|
202
|
+
wireNote: rowArgsGap === 'truncated' ? PARK_ROW_ARGS_TRUNCATED_NOTE : PARK_ROW_ARGS_ABSENT_NOTE,
|
|
203
|
+
}
|
|
204
|
+
: {}),
|
|
168
205
|
...(pending.governanceForced === true ? { governanceForced: true } : {}),
|
|
169
206
|
...(pending.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
207
|
+
...(pending.mandated === true ? { mandated: true } : {}),
|
|
170
208
|
...(pending.gateKind === 'irreversible_ask' ? { irreversibleParkGate: true } : {}),
|
|
171
209
|
...(pending.hasBidiControls === true ? { hasBidiControls: true } : {}),
|
|
172
210
|
...(ruleOffersReadOnly !== undefined ? { ruleOffersReadOnly } : {}),
|
|
@@ -184,6 +222,11 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
184
222
|
? { toolCallId: pending.toolCallId }
|
|
185
223
|
: {}),
|
|
186
224
|
});
|
|
225
|
+
if (rowArgsGap !== undefined && card.kind === 'allow' && card.updatedInput !== undefined) {
|
|
226
|
+
hostLog('error', `liveToolApprovalWire: approval card for ${gatedCallId ?? `task ${taskId}`} returned an edited approval, but the tool input is ${rowArgsGap === 'truncated' ? 'a size marker on the pending row' : 'missing from both the stream and the pending row'} — nothing sent (the park stays pending)`);
|
|
227
|
+
surfaceEditRefusedOnBlindAsk();
|
|
228
|
+
return { kind: 'failed', stage: 'card', gatedCallId, reason: PARK_EDIT_REFUSED_REASON, editRefused: true };
|
|
229
|
+
}
|
|
187
230
|
const decideSpan = bridge.openDecideOperation();
|
|
188
231
|
const decideOpts = { ...(signal ? { signal } : {}), operation: decideSpan };
|
|
189
232
|
try {
|
|
@@ -733,10 +776,14 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
733
776
|
? frame.args
|
|
734
777
|
: undefined;
|
|
735
778
|
let wireNote;
|
|
779
|
+
let argsFallback = false;
|
|
736
780
|
if (typeof args !== 'object' || args === null) {
|
|
781
|
+
argsFallback = true;
|
|
782
|
+
const p = pathFromGateMessage(frame.message);
|
|
783
|
+
args = p !== undefined ? { file_path: p } : {};
|
|
737
784
|
if (frame.argsOmitted === true) {
|
|
738
|
-
wireNote =
|
|
739
|
-
hostLog('debug', `liveToolApprovalWire: frame ${approvalId} args omitted (>16KiB wire cap) — card falls back to message-derived path`);
|
|
785
|
+
wireNote = p !== undefined ? ARGS_OMITTED_PATH_RECOVERED_NOTE : ARGS_OMITTED_NOTHING_RECOVERED_NOTE;
|
|
786
|
+
hostLog('debug', `liveToolApprovalWire: frame ${approvalId} args omitted (>16KiB wire cap) — card falls back to ${p !== undefined ? 'the message-derived path' : 'an empty input (no path could be derived from the message)'}`);
|
|
740
787
|
}
|
|
741
788
|
if (lane?.argsUnavailable === true) {
|
|
742
789
|
wireNote =
|
|
@@ -744,9 +791,8 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
744
791
|
'so you are deciding without seeing them; deny it if you are not sure what it will do. ' +
|
|
745
792
|
'Edits are not accepted on this card: there is no original input to edit';
|
|
746
793
|
}
|
|
747
|
-
const p = pathFromGateMessage(frame.message);
|
|
748
|
-
args = p !== undefined ? { file_path: p } : {};
|
|
749
794
|
}
|
|
795
|
+
const argsNotRealInput = argsFallback || lane?.argsUnavailable === true;
|
|
750
796
|
const ruleOffers = readRuleOfferSupply(frame.ruleOffers, frame.ruleSuggestions);
|
|
751
797
|
const denialLimitFallback = readDenialLimitFallback(frame.denialLimitFallback);
|
|
752
798
|
const card = await surfaceApprovalCard({
|
|
@@ -759,7 +805,7 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
759
805
|
...(signal ? { signal } : {}),
|
|
760
806
|
...(isFromSubagent(frame) ? { workerBadge: subagentBadgeFor(frame) } : {}),
|
|
761
807
|
...(wireNote !== undefined ? { wireNote } : {}),
|
|
762
|
-
...(
|
|
808
|
+
...(argsNotRealInput ? { argsUnavailable: true } : {}),
|
|
763
809
|
...(frame.governanceForced === true ? { governanceForced: true } : {}),
|
|
764
810
|
...(lane?.windowIsCurrent === true
|
|
765
811
|
? {
|
|
@@ -791,8 +837,8 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
791
837
|
...((k) => (k !== undefined ? { ruleStoreUnreadable: k } : {}))(readRuleStoreUnreadable(frame.ruleStoreUnreadable)),
|
|
792
838
|
...(typeof frame.origin === 'string' && frame.origin !== '' ? { origin: frame.origin } : {}),
|
|
793
839
|
});
|
|
794
|
-
if (
|
|
795
|
-
hostLog('error', `liveToolApprovalWire: ${approvalId} card returned an edited approval on
|
|
840
|
+
if (argsNotRealInput && card.kind === 'allow' && card.updatedInput !== undefined) {
|
|
841
|
+
hostLog('error', `liveToolApprovalWire: ${approvalId} card returned an edited approval on a card whose arguments are not the tool's real input (${lane?.argsUnavailable === true ? 'args-unavailable ask' : 'arguments omitted or absent on the frame'}) — nothing sent (the ask stays pending)`);
|
|
796
842
|
surfaceEditRefusedOnBlindAsk();
|
|
797
843
|
return { decision: 'unresolved', editRefused: true };
|
|
798
844
|
}
|
package/dist/hooksWireCaps.js
CHANGED
|
@@ -12,6 +12,26 @@ function hooksLockedToPluginOnly(policyValue) {
|
|
|
12
12
|
return policyValue.includes('hooks');
|
|
13
13
|
return false;
|
|
14
14
|
}
|
|
15
|
+
let warnedNoMergedReader = new WeakSet();
|
|
16
|
+
const NO_MERGED_READER_WARNING = 'client-core: the installed settings port does not implement mergedDisableAllHooks() — ' +
|
|
17
|
+
'a disableAllHooks set in user, project, local or flag settings is not applied to hooks sent to the engine ' +
|
|
18
|
+
'(only a managed-settings disableAllHooks is). Implement SettingsPort.mergedDisableAllHooks() to return ' +
|
|
19
|
+
'the effective merged value.';
|
|
20
|
+
function nonManagedDisableAllHooks(settings) {
|
|
21
|
+
try {
|
|
22
|
+
if (typeof settings.mergedDisableAllHooks === 'function')
|
|
23
|
+
return settings.mergedDisableAllHooks() === true;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
hostLog('debug', `hooksWireCaps: merged disableAllHooks read threw — fail-closed (only policySettings hooks projected to the engine): ${String(err)}`);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
if (!warnedNoMergedReader.has(settings)) {
|
|
30
|
+
warnedNoMergedReader.add(settings);
|
|
31
|
+
hostLog('warn', NO_MERGED_READER_WARNING);
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
15
35
|
function hooksOfSource(source) {
|
|
16
36
|
try {
|
|
17
37
|
const s = hostSettings()?.getSettingsForSource(source);
|
|
@@ -52,7 +72,12 @@ export function hooksForWire() {
|
|
|
52
72
|
if (pluginOnlyHooks) {
|
|
53
73
|
hostLog('debug', 'hooksWireCaps: strictPluginOnlyCustomization locks the hooks surface (managed) — only policySettings hooks projected to the engine');
|
|
54
74
|
}
|
|
55
|
-
const
|
|
75
|
+
const managedByPolicy = policy?.allowManagedHooksOnly === true || pluginOnlyHooks;
|
|
76
|
+
const disabledByNonManaged = !managedByPolicy && nonManagedDisableAllHooks(settings);
|
|
77
|
+
if (disabledByNonManaged) {
|
|
78
|
+
hostLog('debug', 'hooksWireCaps: disableAllHooks (merged, non-managed) — only policySettings hooks projected to the engine');
|
|
79
|
+
}
|
|
80
|
+
const managedOnly = managedByPolicy || disabledByNonManaged;
|
|
56
81
|
const sources = managedOnly
|
|
57
82
|
? ['policySettings']
|
|
58
83
|
: ['policySettings', ...EDITABLE_HOOK_SOURCES];
|
|
@@ -75,6 +100,7 @@ export function hooksForWire() {
|
|
|
75
100
|
}
|
|
76
101
|
export function __resetHooksWireCapsForTests() {
|
|
77
102
|
__resetGoalStopHookForTests();
|
|
103
|
+
warnedNoMergedReader = new WeakSet();
|
|
78
104
|
}
|
|
79
105
|
export function fleetHookFailureNoticeCapable(baseUrl) {
|
|
80
106
|
return engineCapNestedTrue(baseUrl, 'fleet', 'hookFailureNotice');
|
package/dist/host.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export type SettingsDocument = Record<string, unknown>;
|
|
|
4
4
|
export interface SettingsPort {
|
|
5
5
|
getSettingsForSource(source: string): SettingsDocument | null;
|
|
6
6
|
shouldSkipHookDueToTrust(hook?: unknown): boolean;
|
|
7
|
+
mergedDisableAllHooks?(): boolean | undefined;
|
|
7
8
|
}
|
|
8
9
|
export interface FsPort {
|
|
9
10
|
getScratchpadDir(): string | undefined;
|
|
@@ -15,7 +15,9 @@ export declare function probeScenarioTools(baseUrl: string, scenario: string, op
|
|
|
15
15
|
tools: string[];
|
|
16
16
|
toolset?: string;
|
|
17
17
|
} | null>;
|
|
18
|
-
export
|
|
18
|
+
export interface LiveInitToolFaceOptions {
|
|
19
19
|
fetchImpl?: typeof fetch;
|
|
20
20
|
timeoutMs?: number;
|
|
21
|
-
|
|
21
|
+
webSearchStamped?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function resolveLiveInitToolFace(argv: readonly string[], env: EnvLike, opts?: LiveInitToolFaceOptions): Promise<LiveInitToolFace | null>;
|
package/dist/liveInitToolFace.js
CHANGED
|
@@ -2,7 +2,7 @@ import { makeEngineWireClient, resolveWireAuth } from './engineWireSdk.js';
|
|
|
2
2
|
import { hostLog } from './host.js';
|
|
3
3
|
import { scenarioForPrint } from './scenarioWire.js';
|
|
4
4
|
import { resolveHeadlessInteractiveTools } from './interactiveToolsWire.js';
|
|
5
|
-
import {
|
|
5
|
+
import { webSearchVerdictFromEnv } from './webSearchWireCaps.js';
|
|
6
6
|
export const ENGINE_HANDS_BAND = [
|
|
7
7
|
'Bash',
|
|
8
8
|
'Read',
|
|
@@ -105,7 +105,7 @@ export async function resolveLiveInitToolFace(argv, env, opts) {
|
|
|
105
105
|
}
|
|
106
106
|
let webSearch = false;
|
|
107
107
|
try {
|
|
108
|
-
webSearch =
|
|
108
|
+
webSearch = typeof opts?.webSearchStamped === 'boolean' ? opts.webSearchStamped : webSearchVerdictFromEnv(env).kind === 'honored';
|
|
109
109
|
}
|
|
110
110
|
catch {
|
|
111
111
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type EnvLike } from '../hostEnv.js';
|
|
2
|
-
import { type ModelCatalogResult
|
|
2
|
+
import { type ModelCatalogResult } from './catalog.js';
|
|
3
3
|
import type { ProviderPreset } from './providerPresets.js';
|
|
4
4
|
export declare const DEFAULT_CATALOG_SOURCES: readonly string[];
|
|
5
5
|
export declare const CATALOG_DEFAULT_HOSTS: readonly string[];
|
|
@@ -12,11 +12,6 @@ export interface CatalogSourceAttempt {
|
|
|
12
12
|
shaChecked?: boolean;
|
|
13
13
|
detail?: string;
|
|
14
14
|
}
|
|
15
|
-
export interface CatalogCacheEnvelope {
|
|
16
|
-
fetchedAt?: number;
|
|
17
|
-
sourceUrl: string;
|
|
18
|
-
catalog: OnlineCatalogDoc;
|
|
19
|
-
}
|
|
20
15
|
export interface CatalogCachePort {
|
|
21
16
|
read(path: string): string | null | Promise<string | null>;
|
|
22
17
|
writeAtomic(path: string, text: string): void | Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare function notePanelRowRunning(taskId: string): void;
|
|
2
2
|
export declare function retirePanelRowRunning(taskId: string): void;
|
|
3
|
-
|
|
3
|
+
interface PanelRowEndedIdentity {
|
|
4
4
|
cycleSeq?: number;
|
|
5
5
|
startedAt?: number;
|
|
6
6
|
}
|
|
@@ -11,7 +11,7 @@ export declare function holdNewbornTerminalRow(taskId: string, ev: object): void
|
|
|
11
11
|
export declare function peekHeldNewbornTerminalRow<T extends object>(taskId: string): T | undefined;
|
|
12
12
|
export declare function takeHeldNewbornTerminalRow<T extends object>(taskId: string): T | undefined;
|
|
13
13
|
export declare function dropHeldNewbornTerminalRow(taskId: string): void;
|
|
14
|
-
|
|
14
|
+
interface HeldNewbornTerminalRef {
|
|
15
15
|
readonly taskId: string;
|
|
16
16
|
readonly transcriptId?: string;
|
|
17
17
|
readonly parentToolCallId?: string;
|
|
@@ -19,3 +19,4 @@ export interface HeldNewbornTerminalRef {
|
|
|
19
19
|
export declare function heldNewbornTerminalRefs(): HeldNewbornTerminalRef[];
|
|
20
20
|
export declare function __resetPanelRunningHistoryForTests(): void;
|
|
21
21
|
export declare function __panelRunningHistorySize(): number;
|
|
22
|
+
export {};
|
package/dist/peerFrames.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export declare const AGENT_MESSAGE_TAG = "agent-message";
|
|
2
2
|
export declare const CROSS_SESSION_MESSAGE_TAG = "cross-session-message";
|
|
3
3
|
export declare const PEER_FRAME_LANES: readonly ["agent_message", "cross_session_message", "cross_session_notice"];
|
|
4
|
-
export type PeerFrameLane = (typeof PEER_FRAME_LANES)[number];
|
|
5
4
|
export declare const CROSS_SESSION_NOTICE_KINDS: readonly ["delivery_notice", "idle_notice"];
|
|
6
5
|
export type CrossSessionNoticeKind = (typeof CROSS_SESSION_NOTICE_KINDS)[number];
|
|
7
6
|
export declare const PEER_MODE_CLASSES: readonly ["bypass", "prompting"];
|
|
@@ -19,7 +19,7 @@ export function printInitRosterSignal(message) {
|
|
|
19
19
|
if (type === 'result')
|
|
20
20
|
return { kind: 'no-roster', reason: 'run-ended' };
|
|
21
21
|
if (type === 'assistant') {
|
|
22
|
-
return rec.
|
|
22
|
+
return rec._sema_api_error_message === true ? { kind: 'no-roster', reason: 'run-ended' } : { kind: 'no-roster', reason: 'model-activity-first' };
|
|
23
23
|
}
|
|
24
24
|
if (type === 'stream_event' || type === 'retry_status')
|
|
25
25
|
return { kind: 'no-roster', reason: 'model-activity-first' };
|
|
@@ -10,19 +10,19 @@ export const PRINT_NOTIFICATION_FIELD_MATRIX = [
|
|
|
10
10
|
{ field: 'tool_use_id', from: 'toolUseId', cc: true, why: 'CC 逐字 snake 名(wire 是 camel);把通知钉回发起它的那次工具调用' },
|
|
11
11
|
{ field: 'output_file', from: 'output_file', cc: true, why: 'CC 逐字;后台输出落盘路径' },
|
|
12
12
|
{ field: 'usage', from: 'usage', cc: true, why: 'CC 逐字 optional;计量面(交互面 XML 反而不读它 —— 那是渲染面口径)' },
|
|
13
|
-
{ field: '
|
|
14
|
-
{ field: '
|
|
15
|
-
{ field: '
|
|
16
|
-
{ field: '
|
|
17
|
-
{ field: '
|
|
18
|
-
{ field: '
|
|
19
|
-
{ field: '
|
|
20
|
-
{ field: '
|
|
21
|
-
{ field: '
|
|
22
|
-
{ field: '
|
|
23
|
-
{ field: '
|
|
24
|
-
{ field: '
|
|
25
|
-
{ field: '
|
|
13
|
+
{ field: '_sema_stopped_by', from: 'stoppedBy', cc: false, why: '🔴 残局归因核心位:谁停的(用户/上限/引擎)。修前 `-p` 出口零携带' },
|
|
14
|
+
{ field: '_sema_resumable', from: 'resumable', cc: false, why: '🔴 残局归因:还能不能 resume —— 自动化要靠它决定重试还是放弃' },
|
|
15
|
+
{ field: '_sema_partial', from: 'partial', cc: false, why: 'server 1.258:被终止子代的残果(消费方须渲成不完整,不得当完整结果)' },
|
|
16
|
+
{ field: '_sema_exit_code', from: 'exitCode', cc: false, why: '后台 bash 退出码(137=OOM 这类归因只在这一位上)' },
|
|
17
|
+
{ field: '_sema_diagnostics', from: 'diagnostics', cc: false, why: '引擎侧诊断串(UNTRUSTED,service 已 redact)' },
|
|
18
|
+
{ field: '_sema_result', from: 'result', cc: false, why: '完成结果正文(#49 C1:帧带 result 必入 XML,print 出口同理不得独漏)' },
|
|
19
|
+
{ field: '_sema_lines', from: 'lines', cc: false, why: '尾部输出行(UNTRUSTED);交互面折进 <output-lines>' },
|
|
20
|
+
{ field: '_sema_recent_steps', from: 'recentSteps', cc: false, why: '结构化残局步骤 {tool,target,outcome}[] —— **原样透传**,不降级成交互面那份显示串(SDK 消费方要结构)' },
|
|
21
|
+
{ field: '_sema_edited_files', from: 'editedFiles', cc: false, why: '结构化改档清单 {path,edits}[];同上原样透传' },
|
|
22
|
+
{ field: '_sema_task_type', from: 'task_type', cc: false, why: 'lane 位(external/background_agent/…)—— 去重键的分域依据,消费方要能自己算同一把键;CC 的 task_type 只在 task_started / task_progress 子型上且词表不同,故不占 CC 名' },
|
|
23
|
+
{ field: '_sema_source', from: 'source', cc: false, why: 'external lane 的来源标识(交互面渲成开标签 from= 属性)' },
|
|
24
|
+
{ field: '_sema_seq', from: 'seq', cc: false, why: '停机周期/批次计数([508]②)—— 与 task_id+status 一起构成去重键' },
|
|
25
|
+
{ field: '_sema_injected', from: 'injected', cc: false, why: '[1818]§四:本帧**不**证明 XML 已进模型上下文;消费方须按此位判,不得按帧到达判' },
|
|
26
26
|
];
|
|
27
27
|
const PRINT_FRAME_KEYS = new Set(PRINT_NOTIFICATION_FIELD_MATRIX.map(r => r.field));
|
|
28
28
|
export function taskNotificationToPrintFrame(n, identity = {}) {
|
|
@@ -39,19 +39,19 @@ export function taskNotificationToPrintFrame(n, identity = {}) {
|
|
|
39
39
|
...(f.toolUseId !== undefined ? { tool_use_id: f.toolUseId } : {}),
|
|
40
40
|
...(f.outputFile !== undefined ? { output_file: f.outputFile } : {}),
|
|
41
41
|
...(n.usage !== undefined ? { usage: n.usage } : {}),
|
|
42
|
-
...(f.stoppedBy !== undefined ? {
|
|
43
|
-
...(f.resumable !== undefined ? {
|
|
44
|
-
...(f.partial !== undefined ? {
|
|
45
|
-
...(f.exitCode !== undefined ? {
|
|
46
|
-
...(f.diagnostics !== undefined ? {
|
|
47
|
-
...(f.result !== undefined ? {
|
|
48
|
-
...(f.lines !== undefined ? {
|
|
49
|
-
...(nonEmptyList(n.recentSteps) ? {
|
|
50
|
-
...(nonEmptyList(n.editedFiles) ? {
|
|
51
|
-
...(f.taskType !== undefined ? {
|
|
52
|
-
...(f.externalSource !== undefined ? {
|
|
53
|
-
...(typeof n.seq === 'number' || typeof n.seq === 'string' ? {
|
|
54
|
-
...(typeof n.injected === 'boolean' ? {
|
|
42
|
+
...(f.stoppedBy !== undefined ? { _sema_stopped_by: f.stoppedBy } : {}),
|
|
43
|
+
...(f.resumable !== undefined ? { _sema_resumable: f.resumable } : {}),
|
|
44
|
+
...(f.partial !== undefined ? { _sema_partial: f.partial } : {}),
|
|
45
|
+
...(f.exitCode !== undefined ? { _sema_exit_code: f.exitCode } : {}),
|
|
46
|
+
...(f.diagnostics !== undefined ? { _sema_diagnostics: f.diagnostics } : {}),
|
|
47
|
+
...(f.result !== undefined ? { _sema_result: f.result } : {}),
|
|
48
|
+
...(f.lines !== undefined ? { _sema_lines: f.lines } : {}),
|
|
49
|
+
...(nonEmptyList(n.recentSteps) ? { _sema_recent_steps: n.recentSteps } : {}),
|
|
50
|
+
...(nonEmptyList(n.editedFiles) ? { _sema_edited_files: n.editedFiles } : {}),
|
|
51
|
+
...(f.taskType !== undefined ? { _sema_task_type: f.taskType } : {}),
|
|
52
|
+
...(f.externalSource !== undefined ? { _sema_source: f.externalSource } : {}),
|
|
53
|
+
...(typeof n.seq === 'number' || typeof n.seq === 'string' ? { _sema_seq: n.seq } : {}),
|
|
54
|
+
...(typeof n.injected === 'boolean' ? { _sema_injected: n.injected } : {}),
|
|
55
55
|
...(identity.uuid !== undefined ? { uuid: identity.uuid } : {}),
|
|
56
56
|
...(identity.session_id !== undefined ? { session_id: identity.session_id } : {}),
|
|
57
57
|
};
|
package/dist/seam.d.ts
CHANGED
|
@@ -149,7 +149,7 @@ export type ChromeEvent = {
|
|
|
149
149
|
} | ({
|
|
150
150
|
kind: 'run_cost_reconciled';
|
|
151
151
|
laneProof: LaneProof;
|
|
152
|
-
} & RunCostReconcile) | HumanInputChromeEvent | MessageCommittedChromeEvent | EngineNoticeChromeEvent | TextSegmentEndChromeEvent | ThinkingSegmentEndChromeEvent | ToolDisclosureChromeEvent | ToolProgressChromeEvent | ToolRosterDeltaChromeEvent | ContextUsageChromeEvent | CompactionOutcomeChromeEvent | PromptAssembledChromeEvent | WiringManifestChromeEvent | ResultTextDivergedChromeEvent | ApprovalRequestChromeEvent | ApprovalRevokeChromeEvent;
|
|
152
|
+
} & RunCostReconcile) | HumanInputChromeEvent | MessageCommittedChromeEvent | EngineNoticeChromeEvent | TextSegmentEndChromeEvent | ThinkingSegmentEndChromeEvent | ToolDisclosureChromeEvent | ToolProgressChromeEvent | ToolRosterDeltaChromeEvent | ContextUsageChromeEvent | CompactionOutcomeChromeEvent | PromptAssembledChromeEvent | MemorySavedChromeEvent | WiringManifestChromeEvent | ResultTextDivergedChromeEvent | ApprovalRequestChromeEvent | ApprovalRevokeChromeEvent;
|
|
153
153
|
export interface WiringManifestChromeEvent {
|
|
154
154
|
kind: 'wiring_manifest';
|
|
155
155
|
laneProof: LaneProof;
|
|
@@ -204,6 +204,12 @@ export interface CompactionOutcomeChromeEvent {
|
|
|
204
204
|
reason?: string;
|
|
205
205
|
eventId?: string;
|
|
206
206
|
}
|
|
207
|
+
export interface MemorySavedChromeEvent {
|
|
208
|
+
kind: 'memory_saved';
|
|
209
|
+
laneProof: LaneProof;
|
|
210
|
+
id: string;
|
|
211
|
+
notes: string[];
|
|
212
|
+
}
|
|
207
213
|
export interface PromptAssembledChromeEvent {
|
|
208
214
|
kind: 'prompt_assembled';
|
|
209
215
|
laneProof: LaneProof;
|
|
@@ -330,4 +336,4 @@ export declare function deriveTranscriptId(frame: {
|
|
|
330
336
|
id?: unknown;
|
|
331
337
|
seq?: unknown;
|
|
332
338
|
toolCallId?: unknown;
|
|
333
|
-
}, ctx: Pick<AdapterContext, 'uuid'
|
|
339
|
+
}, ctx: Pick<AdapterContext, 'uuid'>, suffix?: string): string;
|