@sema-agent/client-core 0.93.1 → 0.94.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 +213 -0
- package/README.md +30 -19
- package/dist/adapt/arms.js +8 -5
- package/dist/adapter/downstream/terminalToSdkResult.js +2 -3
- package/dist/agentSession/engineSessionBackgroundStop.js +2 -1
- package/dist/agentsWireCaps.d.ts +15 -0
- package/dist/agentsWireCaps.js +111 -1
- package/dist/approvalReachWire.d.ts +18 -0
- package/dist/approvalReachWire.js +58 -0
- package/dist/approvalsStreamLiveCapability.js +16 -11
- package/dist/callerCwdCapability.d.ts +16 -0
- package/dist/callerCwdCapability.js +47 -0
- package/dist/controlRouter.js +3 -10
- package/dist/coreValuePorts.d.ts +64 -1
- package/dist/coreValuePorts.js +30 -0
- package/dist/detachWire.d.ts +1 -4
- package/dist/detachWire.js +1 -1
- package/dist/deviceExecutorManagementCapability.js +39 -34
- package/dist/deviceFlowPolling.d.ts +5 -0
- package/dist/deviceFlowPolling.js +28 -0
- package/dist/displayUntrusted.js +652 -21
- package/dist/engineErrorCodes.d.ts +5 -1
- package/dist/engineErrorCodes.js +9 -12
- package/dist/engineNoticeCodes.d.ts +22 -2
- package/dist/engineNoticeCodes.js +73 -6
- package/dist/engineRefusedToolName.d.ts +1 -0
- package/dist/engineRefusedToolName.js +8 -0
- package/dist/executionLaneCapability.js +14 -9
- package/dist/fileHistoryCaptureCapability.js +14 -9
- package/dist/fileHistoryLegNotice.d.ts +11 -0
- package/dist/fileHistoryLegNotice.js +50 -13
- package/dist/fleet/fleetLedger.js +5 -0
- package/dist/gateOutcome.d.ts +2 -1
- package/dist/gateOutcome.js +3 -0
- package/dist/gateVocabulary.js +1 -1
- package/dist/generated/engineAskFaceTables.d.ts +3 -0
- package/dist/generated/engineAskFaceTables.js +12 -0
- package/dist/generated/engineFactTables.d.ts +4 -2
- package/dist/generated/engineFactTables.js +13 -0
- package/dist/generated/engineNoticeTables.d.ts +5 -0
- package/dist/generated/engineNoticeTables.js +7 -0
- package/dist/generated/sdkFactTables.d.ts +3 -0
- package/dist/generated/sdkFactTables.js +17 -0
- package/dist/generated/settingsSchemaTables.d.ts +3 -0
- package/dist/generated/settingsSchemaTables.js +3 -0
- package/dist/headlessPermissionModeWire.d.ts +2 -2
- package/dist/headlessPermissionModeWire.js +11 -21
- package/dist/hitl/approvalHolds.d.ts +36 -0
- package/dist/hitl/approvalHolds.js +89 -0
- package/dist/hitl/approvalOutcomeNote.js +2 -1
- package/dist/hitl/approvalResolution.js +9 -1
- package/dist/hitl/approvalsFeed.js +5 -0
- package/dist/hitl/askGateWire.js +3 -0
- package/dist/hitl/automaticAnswerVerdict.d.ts +8 -2
- package/dist/hitl/automaticAnswerVerdict.js +69 -21
- package/dist/hitl/decisionRefusal.d.ts +19 -0
- package/dist/hitl/decisionRefusal.js +63 -0
- package/dist/hitl/frameRouter.d.ts +10 -0
- package/dist/hitl/frameRouter.js +59 -3
- package/dist/hitl/gateLedger.d.ts +3 -0
- package/dist/hitl/gateLedger.js +17 -0
- package/dist/hitl/hitlBridge.d.ts +2 -2
- package/dist/hitl/hitlBridge.js +8 -10
- package/dist/hitl/hitlHostSurface.d.ts +3 -0
- package/dist/hitl/hitlHostSurface.js +14 -4
- package/dist/hitl/localAllowRule.js +2 -1
- package/dist/hitl/noAllowCause.d.ts +9 -0
- package/dist/hitl/noAllowCause.js +26 -0
- package/dist/hitl/parkResolver.js +6 -3
- package/dist/hitl/parkRowBirthWait.js +2 -1
- package/dist/hitl/persistedRulesWire.d.ts +6 -1
- package/dist/hitl/persistedRulesWire.js +12 -4
- package/dist/hitl/planReviewWire.d.ts +0 -1
- package/dist/hitl/planReviewWire.js +30 -9
- package/dist/hitl/sessionPolicyDeliverable.d.ts +1 -1
- package/dist/hitl/sessionPolicyDeliverable.js +3 -8
- package/dist/hitl/sessionPolicyWire.js +1 -1
- package/dist/hitl/toolApprovalWire.d.ts +27 -2
- package/dist/hitl/toolApprovalWire.js +258 -23
- package/dist/humanTurnRead.d.ts +15 -1
- package/dist/humanTurnRead.js +28 -2
- package/dist/index.d.ts +18 -6
- package/dist/index.js +14 -5
- package/dist/limitsWire.d.ts +0 -1
- package/dist/limitsWire.js +2 -10
- package/dist/liveModelCatalog.d.ts +14 -0
- package/dist/liveModelCatalog.js +61 -0
- package/dist/mcpProbeCapability.js +14 -9
- package/dist/mcpReconnect.js +13 -8
- package/dist/memoryComplianceCapability.js +15 -10
- package/dist/memoryOriginCapability.js +15 -10
- package/dist/modelIdentityResolvability.d.ts +4 -2
- package/dist/modelIdentityResolvability.js +31 -4
- package/dist/outputStyleSeatCapability.d.ts +16 -0
- package/dist/outputStyleSeatCapability.js +47 -0
- package/dist/ownKey.d.ts +1 -0
- package/dist/ownKey.js +10 -0
- package/dist/peerLaneCapability.js +16 -11
- package/dist/permissionRuleIssue.js +1 -1
- package/dist/permissionRulesWriteCapability.js +16 -11
- package/dist/permissionsAllowGrantCapability.d.ts +2 -0
- package/dist/permissionsAllowGrantCapability.js +38 -16
- package/dist/permissionsDeclaration.d.ts +10 -1
- package/dist/permissionsDeclaration.js +97 -15
- package/dist/protocolSegment.d.ts +1 -0
- package/dist/protocolSegment.js +13 -1
- package/dist/request/taskRequest.d.ts +11 -3
- package/dist/request/taskRequest.js +13 -1
- package/dist/resultFrameKeys.d.ts +4 -0
- package/dist/resultFrameKeys.js +13 -0
- package/dist/resumeRefusalCopy.js +6 -16
- package/dist/retryStatus.js +6 -4
- package/dist/rewindArchiveCapability.js +13 -8
- package/dist/{hitl/rosterMountedNames.d.ts → rosterMountedNames.d.ts} +1 -1
- package/dist/runCancelContext.js +2 -1
- package/dist/sealedKeyCapability.js +19 -14
- package/dist/seatContract.d.ts +33 -5
- package/dist/seatContract.js +143 -2
- package/dist/sessionPolicyCapability.js +15 -10
- package/dist/sessionReadRedactionCapability.d.ts +16 -0
- package/dist/sessionReadRedactionCapability.js +47 -0
- package/dist/sessionSyncFileHistoryCapability.js +14 -9
- package/dist/skillToolListsCapability.js +14 -9
- package/dist/sqlEngineCapability.js +18 -13
- package/dist/steerPriorityCapability.js +21 -16
- package/dist/subagent/agentStateDetail.d.ts +1 -0
- package/dist/subagent/agentStateDetail.js +41 -0
- package/dist/subagent/engineCompactWire.d.ts +15 -0
- package/dist/subagent/engineCompactWire.js +75 -13
- package/dist/supportFloor.js +1 -1
- package/dist/taskRequestWords.d.ts +2 -4
- package/dist/taskRequestWords.js +3 -2
- package/dist/types/engineState.d.ts +1 -1
- package/dist/userAttachmentEnvelope.d.ts +22 -1
- package/dist/userAttachmentEnvelope.js +90 -2
- package/dist/userInvokedSkillsCapability.js +14 -9
- package/dist/webSearchBackendCapability.js +21 -16
- package/dist/wireErrorTriage.d.ts +11 -0
- package/dist/wireErrorTriage.js +35 -0
- package/dist/wireFailureShape.d.ts +6 -0
- package/dist/wireFailureShape.js +30 -3
- package/dist/wireRefusalCopy.d.ts +6 -1
- package/dist/wireRefusalCopy.js +22 -8
- package/dist/wiringInstructionsAttribution.d.ts +10 -0
- package/dist/wiringInstructionsAttribution.js +67 -0
- package/dist/workflowClient.js +22 -1
- package/dist/workflowsJournalCapability.js +14 -9
- package/dist/writeProtectionCapability.js +28 -23
- package/docs/INTEGRATION-CLIENTS.md +719 -45
- package/package.json +5 -5
- package/dist/askSurvivesStandingAnswer.d.ts +0 -13
- package/dist/askSurvivesStandingAnswer.js +0 -53
- package/dist/hitl/askSurvivesPosture.d.ts +0 -20
- package/dist/hitl/askSurvivesPosture.js +0 -48
- /package/dist/{hitl/rosterMountedNames.js → rosterMountedNames.js} +0 -0
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
2
|
import { createEngineCapReader } from './engineCapReader.js';
|
|
3
3
|
export function projectSkillToolListsCapability(caps) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
try {
|
|
5
|
+
if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
|
|
6
|
+
return undefined;
|
|
7
|
+
if (!Object.hasOwn(caps, 'skillToolLists'))
|
|
8
|
+
return { kind: 'not_reported' };
|
|
9
|
+
const v = caps.skillToolLists;
|
|
10
|
+
if (v === undefined)
|
|
11
|
+
return { kind: 'not_reported' };
|
|
12
|
+
if (typeof v !== 'boolean')
|
|
13
|
+
return undefined;
|
|
14
|
+
return v ? { kind: 'present' } : { kind: 'absent' };
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
12
17
|
return undefined;
|
|
13
|
-
|
|
18
|
+
}
|
|
14
19
|
}
|
|
15
20
|
const reader = createEngineCapReader({
|
|
16
21
|
name: 'skillToolLists',
|
|
@@ -2,21 +2,26 @@ import { capForDisplay } from './fleetTaskDesc.js';
|
|
|
2
2
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
3
3
|
import { capsGenerationOf, createEngineCapReader } from './engineCapReader.js';
|
|
4
4
|
export function projectSqlEngineCapability(caps) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
try {
|
|
6
|
+
if (caps === null || typeof caps !== 'object')
|
|
7
|
+
return undefined;
|
|
8
|
+
if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
|
|
9
|
+
return undefined;
|
|
10
|
+
const gen = capsGenerationOf(caps);
|
|
11
|
+
if (gen.generation === 'new') {
|
|
12
|
+
const store = gen.store;
|
|
13
|
+
if (!Object.hasOwn(store, 'sql'))
|
|
14
|
+
return { kind: 'none' };
|
|
15
|
+
const nested = store.sql;
|
|
16
|
+
if (nested === undefined)
|
|
17
|
+
return { kind: 'none' };
|
|
18
|
+
return projectSqlEngineView(nested);
|
|
19
|
+
}
|
|
20
|
+
return { kind: 'not_reported' };
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
8
23
|
return undefined;
|
|
9
|
-
const gen = capsGenerationOf(caps);
|
|
10
|
-
if (gen.generation === 'new') {
|
|
11
|
-
const store = gen.store;
|
|
12
|
-
if (!Object.hasOwn(store, 'sql'))
|
|
13
|
-
return { kind: 'none' };
|
|
14
|
-
const nested = store.sql;
|
|
15
|
-
if (nested === undefined)
|
|
16
|
-
return { kind: 'none' };
|
|
17
|
-
return projectSqlEngineView(nested);
|
|
18
24
|
}
|
|
19
|
-
return { kind: 'not_reported' };
|
|
20
25
|
}
|
|
21
26
|
function projectSqlEngineView(sql) {
|
|
22
27
|
if (sql === null || typeof sql !== 'object')
|
|
@@ -2,23 +2,28 @@ import { capForDisplay } from './fleetTaskDesc.js';
|
|
|
2
2
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
3
3
|
import { createEngineCapReader } from './engineCapReader.js';
|
|
4
4
|
export function projectSteerPriorityCapability(caps) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
5
|
+
try {
|
|
6
|
+
if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
|
|
7
|
+
return undefined;
|
|
8
|
+
if (!Object.hasOwn(caps, 'fleet'))
|
|
9
|
+
return { kind: 'not_reported' };
|
|
10
|
+
const fleet = caps.fleet;
|
|
11
|
+
if (fleet === undefined || fleet === false)
|
|
12
|
+
return { kind: 'not_reported' };
|
|
13
|
+
if (fleet === null || typeof fleet !== 'object' || Array.isArray(fleet))
|
|
14
|
+
return undefined;
|
|
15
|
+
if (!Object.hasOwn(fleet, 'steerPriority'))
|
|
16
|
+
return { kind: 'not_reported' };
|
|
17
|
+
const v = fleet.steerPriority;
|
|
18
|
+
if (v === undefined)
|
|
19
|
+
return { kind: 'not_reported' };
|
|
20
|
+
if (typeof v !== 'string' || v.length === 0)
|
|
21
|
+
return undefined;
|
|
22
|
+
return { kind: 'present', word: v };
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
20
25
|
return undefined;
|
|
21
|
-
|
|
26
|
+
}
|
|
22
27
|
}
|
|
23
28
|
const reader = createEngineCapReader({
|
|
24
29
|
name: 'fleet.steerPriority',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function subagentStateDetail(carrier: unknown): string | undefined;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { displayUntrusted } from '../displayUntrusted.js';
|
|
2
|
+
function own(v, key) {
|
|
3
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
4
|
+
return undefined;
|
|
5
|
+
try {
|
|
6
|
+
const d = Object.getOwnPropertyDescriptor(v, key);
|
|
7
|
+
return d !== undefined && 'value' in d ? d.value : undefined;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const finite = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : undefined);
|
|
14
|
+
const word = (v) => (typeof v === 'string' && v.trim() !== '' ? displayUntrusted(v, { max: 64 }) : undefined);
|
|
15
|
+
function span(ms) {
|
|
16
|
+
const s = Math.floor(ms / 1000);
|
|
17
|
+
if (s < 60)
|
|
18
|
+
return `${String(s)} s`;
|
|
19
|
+
const m = Math.floor(s / 60);
|
|
20
|
+
if (m < 60)
|
|
21
|
+
return `${String(m)} min`;
|
|
22
|
+
return `${String(Math.floor(m / 60))} h`;
|
|
23
|
+
}
|
|
24
|
+
export function subagentStateDetail(carrier) {
|
|
25
|
+
const st = own(carrier, 'agentState');
|
|
26
|
+
const status = word(own(st, 'status'));
|
|
27
|
+
if (status === undefined)
|
|
28
|
+
return undefined;
|
|
29
|
+
const readAt = finite(own(st, 'readAt'));
|
|
30
|
+
const last = finite(own(st, 'lastActivityAt'));
|
|
31
|
+
const activity = readAt !== undefined && last !== undefined && last <= readAt ? `last activity ${span(readAt - last)} ago` : 'last activity unknown';
|
|
32
|
+
const approval = own(st, 'approval');
|
|
33
|
+
const approvalState = word(own(approval, 'state'));
|
|
34
|
+
let approvalPart = '';
|
|
35
|
+
if (approvalState !== undefined) {
|
|
36
|
+
const deadline = finite(own(approval, 'deadline'));
|
|
37
|
+
const when = deadline === undefined || readAt === undefined ? '' : deadline > readAt ? ` (deadline in ${span(deadline - readAt)})` : ' (deadline passed)';
|
|
38
|
+
approvalPart = ` · approval ${approvalState}${when}`;
|
|
39
|
+
}
|
|
40
|
+
return `Subagent state: ${status} · ${activity}${approvalPart}`;
|
|
41
|
+
}
|
|
@@ -5,11 +5,26 @@ export type EngineCompactWireClient = {
|
|
|
5
5
|
runs: Pick<AgentClient['runs'], 'compact'>;
|
|
6
6
|
};
|
|
7
7
|
export type EngineCompactWire = EngineWireInjection<EngineCompactWireClient>;
|
|
8
|
+
export type EngineCompactOutcome = {
|
|
9
|
+
readonly kind: 'accepted';
|
|
10
|
+
} | {
|
|
11
|
+
readonly kind: 'refused';
|
|
12
|
+
readonly status: number;
|
|
13
|
+
readonly errorCode?: string;
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: 'failed';
|
|
16
|
+
readonly detail: string;
|
|
17
|
+
readonly status?: number;
|
|
18
|
+
readonly unconfirmed?: true;
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: 'offline';
|
|
21
|
+
};
|
|
8
22
|
export declare function isEngineCompactPending(sessionKey?: string): boolean;
|
|
9
23
|
export declare function resetManualCompactCapability(): void;
|
|
10
24
|
export declare function __resetEngineCompactArmForTests(): void;
|
|
11
25
|
export declare function requestEngineCompact(sessionKey?: string, opts?: {
|
|
12
26
|
wire?: EngineCompactWire;
|
|
27
|
+
onSettled?: (outcome: EngineCompactOutcome) => void;
|
|
13
28
|
}): 'fired' | 'armed' | 'offline' | 'unsupported';
|
|
14
29
|
export declare function onEngineTaskBound(taskId: string, sessionKey?: string, opts?: {
|
|
15
30
|
wire?: EngineCompactWire;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { hostLog, hostTimersFor } from '../host.js';
|
|
2
|
-
import {
|
|
2
|
+
import { COMPACT_NOT_RUNNING, isUnavailableFaceCode } from '../engineErrorCodes.js';
|
|
3
|
+
import { surfaceCompactNotRunning } from '../hitl/hitlHostSurface.js';
|
|
4
|
+
import { wireFailureShapeOf, wireFailureTextsOf } from '../wireFailureShape.js';
|
|
5
|
+
import { clientHasVerbs, engineWireFor, INJECTED_WIRE_SETTLE_MS, noAnswerDetailFrom, settleInjected, } from '../engineWireFor.js';
|
|
3
6
|
import { activeEngineRunIdFor, engineSessionParamFor } from '../engineSessionParam.js';
|
|
4
7
|
import { DEFAULT_SESSION_KEY } from '../sessionSlot.js';
|
|
5
8
|
function usableCompactClient(client) {
|
|
@@ -7,6 +10,7 @@ function usableCompactClient(client) {
|
|
|
7
10
|
}
|
|
8
11
|
const COMPACT_PROBE_SETTLE_MS = 5000;
|
|
9
12
|
const pendingCompactKeys = new Set();
|
|
13
|
+
const pendingCompactSinks = new Map();
|
|
10
14
|
export function isEngineCompactPending(sessionKey = DEFAULT_SESSION_KEY) {
|
|
11
15
|
return pendingCompactKeys.has(sessionKey);
|
|
12
16
|
}
|
|
@@ -49,6 +53,7 @@ export function resetManualCompactCapability() {
|
|
|
49
53
|
}
|
|
50
54
|
export function __resetEngineCompactArmForTests() {
|
|
51
55
|
pendingCompactKeys.clear();
|
|
56
|
+
pendingCompactSinks.clear();
|
|
52
57
|
}
|
|
53
58
|
function deferFire(ms, fn, why, sessionKey) {
|
|
54
59
|
const timers = hostTimersFor(sessionKey);
|
|
@@ -80,26 +85,70 @@ function freezeCompactShot(taskId, sessionKey, wire) {
|
|
|
80
85
|
...(sid !== undefined ? { session: sid } : {}),
|
|
81
86
|
};
|
|
82
87
|
}
|
|
83
|
-
|
|
88
|
+
function emitCompactOutcome(sink, outcome) {
|
|
89
|
+
if (sink === undefined)
|
|
90
|
+
return;
|
|
91
|
+
void Promise.resolve().then(() => callSinkIsolated(sink, outcome));
|
|
92
|
+
}
|
|
93
|
+
function callSinkIsolated(sink, outcome) {
|
|
94
|
+
try {
|
|
95
|
+
sink(outcome);
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
hostLog('debug', `engineCompactWire: onSettled sink threw (ignored): ${wireFailureTextsOf(e).log}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function fanOutCompactSinks(sinks) {
|
|
102
|
+
if (sinks === undefined || sinks.length === 0)
|
|
103
|
+
return undefined;
|
|
104
|
+
return (outcome) => {
|
|
105
|
+
for (const s of sinks)
|
|
106
|
+
callSinkIsolated(s, outcome);
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function compactFailureOutcomeOf(e) {
|
|
110
|
+
const shape = wireFailureShapeOf(e);
|
|
111
|
+
const status = typeof shape.status === 'number' && Number.isFinite(shape.status) ? shape.status : undefined;
|
|
112
|
+
const code = shape.errorCode !== undefined && shape.errorCode !== '' ? shape.errorCode : undefined;
|
|
113
|
+
if (status !== undefined) {
|
|
114
|
+
if ((status >= 400 && status < 500) || isUnavailableFaceCode(code)) {
|
|
115
|
+
return { kind: 'refused', status, ...(code !== undefined ? { errorCode: code } : {}) };
|
|
116
|
+
}
|
|
117
|
+
return { kind: 'failed', status, detail: wireFailureTextsOf(e).reason };
|
|
118
|
+
}
|
|
119
|
+
const noAnswer = typeof e === 'object' && e !== null ? noAnswerDetailFrom(e) : null;
|
|
120
|
+
if (noAnswer !== null)
|
|
121
|
+
return { kind: 'failed', detail: noAnswer, unconfirmed: true };
|
|
122
|
+
return { kind: 'failed', detail: wireFailureTextsOf(e).reason };
|
|
123
|
+
}
|
|
124
|
+
async function postCompact(shot, sink, retriesLeft = 1) {
|
|
84
125
|
const client = shot.client();
|
|
85
|
-
if (!client)
|
|
126
|
+
if (!client) {
|
|
127
|
+
emitCompactOutcome(sink, { kind: 'offline' });
|
|
86
128
|
return;
|
|
129
|
+
}
|
|
87
130
|
const taskId = shot.taskId;
|
|
88
131
|
try {
|
|
89
132
|
const fire = (signal) => client.runs.compact(taskId, { ...(shot.session !== undefined ? { session: shot.session } : {}), ...(signal ? { signal } : {}) });
|
|
90
133
|
const ack = shot.injected ? await settleInjected(INJECTED_WIRE_SETTLE_MS, undefined, fire) : await fire(undefined);
|
|
91
134
|
hostLog('debug', `engineCompactWire: POST compact ${taskId} → ok${ack?.status ? ` (${ack.status})` : ''}`);
|
|
135
|
+
emitCompactOutcome(sink, { kind: 'accepted' });
|
|
92
136
|
}
|
|
93
137
|
catch (e) {
|
|
94
|
-
const
|
|
95
|
-
if (
|
|
96
|
-
hostLog('debug', `engineCompactWire: POST compact ${taskId} → ${status}`);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
return;
|
|
138
|
+
const outcome = compactFailureOutcomeOf(e);
|
|
139
|
+
if (outcome.kind === 'refused' || (outcome.kind === 'failed' && outcome.status !== undefined)) {
|
|
140
|
+
hostLog('debug', `engineCompactWire: POST compact ${taskId} → ${outcome.status}`);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
hostLog('debug', `engineCompactWire: compact fire failed (best-effort): ${wireFailureTextsOf(e).log}`);
|
|
101
144
|
}
|
|
102
|
-
|
|
145
|
+
if (outcome.kind === 'refused' && outcome.status === 404 && retriesLeft > 0) {
|
|
146
|
+
if (deferFire(2000, () => void postCompact(shot, sink, retriesLeft - 1), '404 单次重试', shot.sessionKey))
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (outcome.kind === 'refused' && outcome.errorCode === COMPACT_NOT_RUNNING)
|
|
150
|
+
surfaceCompactNotRunning(shot.sessionKey);
|
|
151
|
+
emitCompactOutcome(sink, outcome);
|
|
103
152
|
}
|
|
104
153
|
}
|
|
105
154
|
export function requestEngineCompact(sessionKey = DEFAULT_SESSION_KEY, opts) {
|
|
@@ -113,13 +162,24 @@ export function requestEngineCompact(sessionKey = DEFAULT_SESSION_KEY, opts) {
|
|
|
113
162
|
return 'unsupported';
|
|
114
163
|
}
|
|
115
164
|
const taskId = activeEngineRunIdFor(sessionKey);
|
|
165
|
+
const rawSink = opts?.onSettled;
|
|
166
|
+
const sink = typeof rawSink === 'function' ? rawSink : undefined;
|
|
116
167
|
if (taskId) {
|
|
117
168
|
const shot = freezeCompactShot(taskId, sessionKey, wire);
|
|
118
169
|
if (shot !== null)
|
|
119
|
-
void postCompact(shot);
|
|
170
|
+
void postCompact(shot, sink);
|
|
171
|
+
else
|
|
172
|
+
emitCompactOutcome(sink, { kind: 'offline' });
|
|
120
173
|
return 'fired';
|
|
121
174
|
}
|
|
122
175
|
pendingCompactKeys.add(sessionKey);
|
|
176
|
+
if (sink !== undefined) {
|
|
177
|
+
const sinks = pendingCompactSinks.get(sessionKey);
|
|
178
|
+
if (sinks === undefined)
|
|
179
|
+
pendingCompactSinks.set(sessionKey, [sink]);
|
|
180
|
+
else
|
|
181
|
+
sinks.push(sink);
|
|
182
|
+
}
|
|
123
183
|
return 'armed';
|
|
124
184
|
}
|
|
125
185
|
const BOUND_FIRE_DELAY_MS = 1500;
|
|
@@ -132,7 +192,9 @@ export function onEngineTaskBound(taskId, sessionKey = DEFAULT_SESSION_KEY, opts
|
|
|
132
192
|
const shot = freezeCompactShot(taskId, sessionKey, wire);
|
|
133
193
|
if (shot === null)
|
|
134
194
|
return;
|
|
135
|
-
|
|
195
|
+
const sink = fanOutCompactSinks(pendingCompactSinks.get(sessionKey));
|
|
196
|
+
if (deferFire(BOUND_FIRE_DELAY_MS, () => void postCompact(shot, sink), 'bind 后发射', sessionKey)) {
|
|
136
197
|
pendingCompactKeys.delete(sessionKey);
|
|
198
|
+
pendingCompactSinks.delete(sessionKey);
|
|
137
199
|
}
|
|
138
200
|
}
|
package/dist/supportFloor.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { TaskRequest } from '@sema-agent/sdk';
|
|
2
2
|
export type TaskRequestReasoningEffort = NonNullable<TaskRequest['reasoningEffort']>;
|
|
3
3
|
export declare const REASONING_EFFORT_WORDS: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
4
|
-
type
|
|
5
|
-
export
|
|
6
|
-
export declare const PERMISSION_MODE_WORDS: readonly ["default", "plan", "acceptEdits", "bypassPermissions", "auto", "dontAsk"];
|
|
4
|
+
export type TaskRequestPermissionMode = NonNullable<TaskRequest['permissionMode']>;
|
|
5
|
+
export declare const PERMISSION_MODE_WORDS: readonly ["default", "acceptEdits", "plan", "auto", "bypassPermissions", "dontAsk"];
|
|
7
6
|
export interface RetiredAttachmentsKey {
|
|
8
7
|
readonly key: string;
|
|
9
8
|
readonly why: string;
|
|
@@ -11,4 +10,3 @@ export interface RetiredAttachmentsKey {
|
|
|
11
10
|
readonly remedy: string;
|
|
12
11
|
}
|
|
13
12
|
export declare function retiredAttachmentsKeyOf(nameOrToken: string, form?: 'token' | 'key'): RetiredAttachmentsKey | undefined;
|
|
14
|
-
export {};
|
package/dist/taskRequestWords.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { CORE_PERMISSION_MODES } from './generated/engineFactTables.js';
|
|
1
2
|
export const REASONING_EFFORT_WORDS = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
2
|
-
export const PERMISSION_MODE_WORDS =
|
|
3
|
-
const _taskRequestWordPins = [true, true, true, true];
|
|
3
|
+
export const PERMISSION_MODE_WORDS = CORE_PERMISSION_MODES;
|
|
4
|
+
const _taskRequestWordPins = [true, true, true, true, true, true];
|
|
4
5
|
void _taskRequestWordPins;
|
|
5
6
|
export function retiredAttachmentsKeyOf(nameOrToken, form = 'token') {
|
|
6
7
|
const lower = nameOrToken.trim().toLowerCase();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { EngineHealth } from '@sema-agent/sdk';
|
|
2
|
-
export interface HealthResponse extends Pick<EngineHealth, 'status' | 'model' | 'sessionBackend' | 'sessions' | 'instanceId' | 'dataRoot' | 'configHash' | 'pid' | 'port' | 'restartRequired' | 'version'> {
|
|
2
|
+
export interface HealthResponse extends Pick<EngineHealth, 'status' | 'model' | 'sessionBackend' | 'sessions' | 'instanceId' | 'dataRoot' | 'configHash' | 'pid' | 'port' | 'restartRequired' | 'version' | 'restart'> {
|
|
3
3
|
}
|
|
4
4
|
export interface EnginePortFile {
|
|
5
5
|
port: number;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { type DescriptorView } from './humanTurnRead.js';
|
|
2
2
|
export type UserAttachmentSource = 'at-mention' | 'compact-restore';
|
|
3
|
-
export type UserAttachmentNotIncludedReason = 'too-large' | 'unreadable' | 'read-denied';
|
|
3
|
+
export type UserAttachmentNotIncludedReason = 'too-large' | 'unreadable' | 'read-denied' | 'approval-required' | 'server-not-connected' | 'resource-not-listed' | 'read-failed';
|
|
4
|
+
export type UserAttachmentMcpResourcePart = {
|
|
5
|
+
readonly kind: 'text';
|
|
6
|
+
readonly text: string;
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: 'binary';
|
|
9
|
+
readonly mimeType: string | null;
|
|
10
|
+
};
|
|
4
11
|
export interface UserAttachmentNotebookCell {
|
|
5
12
|
readonly cellType?: string;
|
|
6
13
|
readonly source?: string;
|
|
@@ -54,6 +61,20 @@ export type UserAttachmentDescriptor = {
|
|
|
54
61
|
readonly path: string;
|
|
55
62
|
readonly sizeBytes: number | null;
|
|
56
63
|
readonly reason: UserAttachmentNotIncludedReason;
|
|
64
|
+
} | {
|
|
65
|
+
readonly kind: 'not-included';
|
|
66
|
+
readonly target: 'mcp-resource';
|
|
67
|
+
readonly server: string;
|
|
68
|
+
readonly uri: string;
|
|
69
|
+
readonly name: string;
|
|
70
|
+
readonly reason: UserAttachmentNotIncludedReason;
|
|
71
|
+
} | {
|
|
72
|
+
readonly kind: 'mcp-resource';
|
|
73
|
+
readonly server: string;
|
|
74
|
+
readonly uri: string;
|
|
75
|
+
readonly name: string;
|
|
76
|
+
readonly parts: readonly UserAttachmentMcpResourcePart[];
|
|
77
|
+
readonly truncated: boolean;
|
|
57
78
|
};
|
|
58
79
|
export declare function showAttachmentName(s: string): string;
|
|
59
80
|
export declare function mintEnvelopeOf(d: DescriptorView, imageDelivery: 'attached' | 'not-attached'): string;
|
|
@@ -162,16 +162,93 @@ const NOT_INCLUDED_REASON = Object.freeze({
|
|
|
162
162
|
'too-large': "it is larger than the client's size limit for attaching files",
|
|
163
163
|
unreadable: 'the client could not read it',
|
|
164
164
|
'read-denied': "the user's permission rules do not allow reading it",
|
|
165
|
+
'approval-required': "this deployment's rules require approval before it is read, so the client did not attach it without asking",
|
|
166
|
+
'server-not-connected': 'the MCP server it comes from is not connected',
|
|
167
|
+
'resource-not-listed': 'the MCP server does not list that resource',
|
|
168
|
+
'read-failed': 'reading it from the MCP server failed',
|
|
165
169
|
});
|
|
166
170
|
function targetWhat(target) {
|
|
167
171
|
return target === 'directory' ? 'a directory' : target === 'file' ? 'a file' : 'a file or directory';
|
|
168
172
|
}
|
|
173
|
+
function mcpWhere(server, uri) {
|
|
174
|
+
return `Server: ${showAttachmentName(server)}. URI: ${showAttachmentName(uri)}`;
|
|
175
|
+
}
|
|
176
|
+
function mintMcpResource(d) {
|
|
177
|
+
const l1 = firstLine('at-mention', 'an MCP resource', d.name);
|
|
178
|
+
const texts = d.parts.flatMap((p) => (p.kind === 'text' ? [p.text] : []));
|
|
179
|
+
const binaries = d.parts.flatMap((p) => (p.kind === 'binary' ? [p.mimeType] : []));
|
|
180
|
+
const typed = [...new Set(binaries.filter((t) => t !== null))];
|
|
181
|
+
const binaryNote = binaries.length > 0
|
|
182
|
+
? `${plural(binaries.length, 'binary part', 'binary parts')}${typed.length > 0 ? ` (${typed.map(showAttachmentName).join(', ')})` : ''} ${binaries.length === 1 ? 'is' : 'are'} not included.`
|
|
183
|
+
: null;
|
|
184
|
+
const truncNote = d.truncated ? 'The client shortened the text; the rest is not included.' : null;
|
|
185
|
+
if (texts.length === 0) {
|
|
186
|
+
return [`${l1}\n${mcpWhere(d.server, d.uri)} (no text parts). The client read it from that server; it has no text to include.`, binaryNote, truncNote].filter((s) => s !== null).join(' ');
|
|
187
|
+
}
|
|
188
|
+
let anyEscaped = false;
|
|
189
|
+
const body = texts
|
|
190
|
+
.join('\n')
|
|
191
|
+
.split('\n')
|
|
192
|
+
.map((line, i) => {
|
|
193
|
+
const shown = showBodyLine(line);
|
|
194
|
+
if (shown.escaped)
|
|
195
|
+
anyEscaped = true;
|
|
196
|
+
return `${i + 1}\t${shown.text}`;
|
|
197
|
+
});
|
|
198
|
+
const head = [
|
|
199
|
+
l1,
|
|
200
|
+
`${mcpWhere(d.server, d.uri)} (${plural(texts.length, 'text part', 'text parts')}). The client read it from that server and copied the text between the two fence lines below. ${dataNote('at-mention', "the resource's contents")}`,
|
|
201
|
+
];
|
|
202
|
+
if (binaryNote !== null)
|
|
203
|
+
head.push(binaryNote);
|
|
204
|
+
if (truncNote !== null)
|
|
205
|
+
head.push(truncNote);
|
|
206
|
+
if (anyEscaped)
|
|
207
|
+
head.push(ESCAPE_NOTE);
|
|
208
|
+
return fenced(head, body);
|
|
209
|
+
}
|
|
169
210
|
function mintNotIncluded(d) {
|
|
211
|
+
if (d.target === 'mcp-resource') {
|
|
212
|
+
return `${firstLine('at-mention', 'an MCP resource', d.name)}\n${mcpWhere(d.server, d.uri)}. It is not included in this message: ${NOT_INCLUDED_REASON[d.reason]}.`;
|
|
213
|
+
}
|
|
170
214
|
const size = sizePart(d.sizeBytes);
|
|
171
215
|
return (`${firstLine('at-mention', targetWhat(d.target), d.name)}\n` +
|
|
172
216
|
`Full path: ${showAttachmentName(d.path)}${size !== null ? ` (${size})` : ''}. It is not included in this message: ${NOT_INCLUDED_REASON[d.reason]}.`);
|
|
173
217
|
}
|
|
174
|
-
|
|
218
|
+
const TAG_OPEN = '<attachment';
|
|
219
|
+
const TAG_CLOSE = '</attachment>';
|
|
220
|
+
function attributeValue(s) {
|
|
221
|
+
let out = '';
|
|
222
|
+
for (const c of s) {
|
|
223
|
+
switch (c) {
|
|
224
|
+
case '&':
|
|
225
|
+
out += '&';
|
|
226
|
+
break;
|
|
227
|
+
case '"':
|
|
228
|
+
out += '"';
|
|
229
|
+
break;
|
|
230
|
+
case '<':
|
|
231
|
+
out += '<';
|
|
232
|
+
break;
|
|
233
|
+
case '>':
|
|
234
|
+
out += '>';
|
|
235
|
+
break;
|
|
236
|
+
default:
|
|
237
|
+
out += c;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return out;
|
|
241
|
+
}
|
|
242
|
+
function pathOf(d) {
|
|
243
|
+
if (d.kind === 'mcp-resource' || (d.kind === 'not-included' && d.target === 'mcp-resource'))
|
|
244
|
+
return undefined;
|
|
245
|
+
return d.path;
|
|
246
|
+
}
|
|
247
|
+
function tagAttributes(d) {
|
|
248
|
+
const path = pathOf(d);
|
|
249
|
+
return path === undefined ? '' : ` path="${attributeValue(showAttachmentName(path))}"`;
|
|
250
|
+
}
|
|
251
|
+
function envelopeInner(d, imageDelivery) {
|
|
175
252
|
switch (d.kind) {
|
|
176
253
|
case 'text':
|
|
177
254
|
return mintText(d);
|
|
@@ -185,10 +262,18 @@ export function mintEnvelopeOf(d, imageDelivery) {
|
|
|
185
262
|
return mintDirectory(d);
|
|
186
263
|
case 'not-included':
|
|
187
264
|
return mintNotIncluded(d);
|
|
265
|
+
case 'mcp-resource':
|
|
266
|
+
return mintMcpResource(d);
|
|
188
267
|
}
|
|
189
268
|
}
|
|
190
|
-
export function
|
|
269
|
+
export function mintEnvelopeOf(d, imageDelivery) {
|
|
270
|
+
return `${TAG_OPEN}${tagAttributes(d)}>\n${envelopeInner(d, imageDelivery)}\n${TAG_CLOSE}`;
|
|
271
|
+
}
|
|
272
|
+
function referenceSentence(d) {
|
|
191
273
|
const name = showAttachmentName(d.name);
|
|
274
|
+
if (d.kind === 'mcp-resource' || (d.kind === 'not-included' && d.target === 'mcp-resource')) {
|
|
275
|
+
return `The user mentioned the MCP resource ${name} (${showAttachmentName(d.uri)} on the server ${showAttachmentName(d.server)}) in this message; its contents are not included here.`;
|
|
276
|
+
}
|
|
192
277
|
const path = showAttachmentName(d.path);
|
|
193
278
|
const what = d.kind === 'directory' ? 'directory' : d.kind === 'not-included' ? targetWhat(d.target).replace(/^an? /, '') : 'file';
|
|
194
279
|
if (d.kind !== 'directory' && d.kind !== 'not-included' && d.source === 'compact-restore') {
|
|
@@ -196,6 +281,9 @@ export function mintReferenceOf(d) {
|
|
|
196
281
|
}
|
|
197
282
|
return `The user mentioned the ${what} ${name} (${path}) in this message; its contents are not included here.`;
|
|
198
283
|
}
|
|
284
|
+
export function mintReferenceOf(d) {
|
|
285
|
+
return `${TAG_OPEN}${tagAttributes(d)} />\n${referenceSentence(d)}`;
|
|
286
|
+
}
|
|
199
287
|
export function mintUserAttachmentEnvelope(descriptor) {
|
|
200
288
|
const d = readDescriptor(descriptor, 'required');
|
|
201
289
|
if (d === undefined)
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
2
|
import { createEngineCapReader } from './engineCapReader.js';
|
|
3
3
|
export function projectUserInvokedSkillsCapability(caps) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
try {
|
|
5
|
+
if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
|
|
6
|
+
return undefined;
|
|
7
|
+
if (!Object.hasOwn(caps, 'userInvokedSkills'))
|
|
8
|
+
return { kind: 'not_reported' };
|
|
9
|
+
const v = caps.userInvokedSkills;
|
|
10
|
+
if (v === undefined)
|
|
11
|
+
return { kind: 'not_reported' };
|
|
12
|
+
if (typeof v !== 'boolean')
|
|
13
|
+
return undefined;
|
|
14
|
+
return v ? { kind: 'present' } : { kind: 'absent' };
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
12
17
|
return undefined;
|
|
13
|
-
|
|
18
|
+
}
|
|
14
19
|
}
|
|
15
20
|
const reader = createEngineCapReader({
|
|
16
21
|
name: 'userInvokedSkills',
|
|
@@ -3,23 +3,28 @@ import { engineWireTarget } from './engineWireTarget.js';
|
|
|
3
3
|
import { createEngineCapReader } from './engineCapReader.js';
|
|
4
4
|
export const WEB_SEARCH_BACKEND_NONE = 'none';
|
|
5
5
|
export function projectWebSearchBackendCapability(caps) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
try {
|
|
7
|
+
if (caps === null || typeof caps !== 'object')
|
|
8
|
+
return undefined;
|
|
9
|
+
if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
|
|
10
|
+
return undefined;
|
|
11
|
+
if (!Object.hasOwn(caps, 'webSearch'))
|
|
12
|
+
return { kind: 'not_reported' };
|
|
13
|
+
const ws = caps.webSearch;
|
|
14
|
+
if (ws === undefined)
|
|
15
|
+
return { kind: 'not_reported' };
|
|
16
|
+
if (ws === null || typeof ws !== 'object' || Array.isArray(ws))
|
|
17
|
+
return undefined;
|
|
18
|
+
const backend = ws.backend;
|
|
19
|
+
if (typeof backend !== 'string' || backend === '')
|
|
20
|
+
return undefined;
|
|
21
|
+
if (backend === WEB_SEARCH_BACKEND_NONE)
|
|
22
|
+
return { kind: 'none' };
|
|
23
|
+
return { kind: 'present', view: { backend } };
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
19
26
|
return undefined;
|
|
20
|
-
|
|
21
|
-
return { kind: 'none' };
|
|
22
|
-
return { kind: 'present', view: { backend } };
|
|
27
|
+
}
|
|
23
28
|
}
|
|
24
29
|
const reader = createEngineCapReader({
|
|
25
30
|
name: 'webSearch.backend',
|
|
@@ -28,6 +28,17 @@ export declare function drainingRetryDelayMs(err: unknown, attempt: number, opts
|
|
|
28
28
|
ladder?: readonly number[];
|
|
29
29
|
retryAfterCapMs?: number;
|
|
30
30
|
}): number;
|
|
31
|
+
export declare function isInStreamDrainingEnd(frame: unknown): boolean;
|
|
32
|
+
export declare const STREAM_DRAINING_RECONNECT_MAX = 3;
|
|
33
|
+
export type StreamDrainingGiveUp = 'not_draining_end' | 'attempts_exhausted';
|
|
34
|
+
export type StreamDrainingDecision = {
|
|
35
|
+
readonly reconnectAfterMs: number;
|
|
36
|
+
} | {
|
|
37
|
+
readonly giveUp: StreamDrainingGiveUp;
|
|
38
|
+
};
|
|
39
|
+
export declare function streamDrainingDecision(frame: unknown, attempt: number, opts?: {
|
|
40
|
+
ladder?: readonly number[];
|
|
41
|
+
}): StreamDrainingDecision;
|
|
31
42
|
export interface ScenarioDenyDetail {
|
|
32
43
|
allowlist: string[];
|
|
33
44
|
}
|