@sema-agent/client-core 0.112.0 → 0.113.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 +153 -0
- package/README.md +37 -24
- package/dist/adapt/arms.js +7 -1
- package/dist/adapt/textStream.d.ts +2 -0
- package/dist/adapt/textStream.js +27 -1
- package/dist/adapter/activeRunSelfHeal.d.ts +7 -5
- package/dist/adapter/activeRunSelfHeal.js +38 -66
- package/dist/adapter/downstream/eventToSdkMessage.js +4 -0
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +8 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +36 -1
- package/dist/adapter/runStream.d.ts +2 -12
- package/dist/adapter/runStream.js +46 -19
- package/dist/agentSession/engineAgentRegistryRead.js +2 -1
- package/dist/agentSession/engineSessionBackgroundStop.js +2 -2
- package/dist/attachmentOutcome.d.ts +35 -0
- package/dist/attachmentOutcome.js +192 -0
- package/dist/attachmentPathPlan.d.ts +67 -0
- package/dist/attachmentPathPlan.js +203 -0
- package/dist/attachmentRoute.d.ts +9 -1
- package/dist/attachmentRoute.js +23 -2
- package/dist/declared/supportFloorDeclared.d.ts +1 -1
- package/dist/declared/supportFloorDeclared.js +1 -0
- package/dist/deviceRebind.js +2 -3
- package/dist/displayUntrusted.js +126 -19
- package/dist/engineAddress.d.ts +1 -1
- package/dist/engineAddress.js +9 -6
- package/dist/engineErrorCodes.d.ts +3 -0
- package/dist/engineErrorCodes.js +4 -0
- package/dist/engineNoticeCodes.d.ts +34 -4
- package/dist/engineNoticeCodes.js +133 -6
- package/dist/engineUnavailable.d.ts +4 -2
- package/dist/engineUnavailable.js +99 -17
- package/dist/fleet/fleetLedger.d.ts +9 -3
- package/dist/fleet/fleetLedger.js +112 -16
- package/dist/fleet/fleetProjection.d.ts +5 -0
- package/dist/fleet/fleetProjection.js +9 -1
- package/dist/gateVocabulary.d.ts +7 -0
- package/dist/gateVocabulary.js +40 -14
- package/dist/generated/engineFactTables.d.ts +4 -2
- package/dist/generated/engineFactTables.js +198 -2
- package/dist/generated/engineNoticeTables.js +56 -8
- package/dist/generated/settingsSchemaFns.d.ts +7 -0
- package/dist/generated/settingsSchemaFns.js +11 -0
- package/dist/generated/settingsSchemaHash.d.ts +1 -0
- package/dist/generated/settingsSchemaHash.js +58 -0
- package/dist/generated/settingsSchemaOwnKeyRead.js +6 -1
- package/dist/generated/settingsSchemaTables.d.ts +3 -2
- package/dist/generated/settingsSchemaTables.js +14 -0
- package/dist/generated/settingsSchemaTightenVerdict.d.ts +1 -0
- package/dist/generated/settingsSchemaTightenVerdict.js +125 -0
- package/dist/headlessPermissionModeWire.d.ts +7 -2
- package/dist/headlessPermissionModeWire.js +77 -8
- package/dist/hitl/approvalDecisionDoor.d.ts +24 -0
- package/dist/hitl/approvalDecisionDoor.js +77 -0
- package/dist/hitl/approvalDelivery.d.ts +6 -0
- package/dist/hitl/approvalDelivery.js +57 -7
- package/dist/hitl/approvalResolution.d.ts +6 -3
- package/dist/hitl/approvalResolution.js +24 -2
- package/dist/hitl/approvalsFeed.js +1 -1
- package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
- package/dist/hitl/decisionSend.d.ts +7 -4
- package/dist/hitl/decisionSend.js +90 -41
- package/dist/hitl/frameRouter.d.ts +3 -3
- package/dist/hitl/frameRouter.js +5 -0
- package/dist/hitl/hitlBridge.d.ts +1 -0
- package/dist/hitl/hitlBridge.js +17 -4
- package/dist/hitl/hitlHostSurface.d.ts +3 -2
- package/dist/hitl/hitlHostSurface.js +5 -3
- package/dist/hitl/legacyApprovalShapes.d.ts +142 -0
- package/dist/hitl/legacyApprovalShapes.js +1 -0
- package/dist/hitl/livePendingAsk.d.ts +4 -4
- package/dist/hitl/livePendingAsk.js +5 -3
- package/dist/hitl/parkResolver.js +1 -1
- package/dist/hitl/persistedRulesWire.js +2 -2
- package/dist/hitl/planReviewCard.d.ts +4 -2
- package/dist/hitl/planReviewCard.js +66 -1
- package/dist/hitl/planReviewWire.d.ts +34 -2
- package/dist/hitl/planReviewWire.js +326 -150
- package/dist/hitl/sessionPolicyWire.js +16 -7
- package/dist/hitl/subagentSource.d.ts +1 -0
- package/dist/hitl/subagentSource.js +11 -0
- package/dist/hitl/toolApprovalWire.d.ts +34 -10
- package/dist/hitl/toolApprovalWire.js +182 -33
- package/dist/hookMatcherVerdict.d.ts +2 -1
- package/dist/hookMatcherVerdict.js +3 -2
- package/dist/hooksReaderGenerations.d.ts +8 -0
- package/dist/hooksReaderGenerations.js +49 -0
- package/dist/hooksWireCaps.js +43 -18
- package/dist/hostSettingsSource.d.ts +1 -1
- package/dist/hostSettingsSource.js +2 -2
- package/dist/hostTurnSettings.d.ts +2 -2
- package/dist/hostTurnSettings.js +87 -47
- package/dist/humanTurn.d.ts +2 -1
- package/dist/humanTurn.js +44 -13
- package/dist/humanTurnRead.d.ts +7 -0
- package/dist/humanTurnRead.js +23 -14
- package/dist/humanTurnSentences.js +3 -0
- package/dist/i18n/messages.en.d.ts +93 -5
- package/dist/i18n/messages.en.js +100 -12
- package/dist/i18n/messages.zh.js +110 -15
- package/dist/index.d.ts +29 -15
- package/dist/index.js +17 -9
- package/dist/liveModelCatalog.js +1 -0
- package/dist/liveQuestionStore.d.ts +2 -0
- package/dist/liveQuestionStore.js +7 -2
- package/dist/localConfig/kernel.d.ts +2 -1
- package/dist/localConfig/kernel.js +12 -18
- package/dist/localConfig/mcp/edit.js +25 -27
- package/dist/localConfig/mcp/servers.js +5 -8
- package/dist/localConfig/modelPool.d.ts +6 -1
- package/dist/localConfig/modelPool.js +104 -27
- package/dist/localConfig/modelPoolWords.d.ts +2 -0
- package/dist/localConfig/modelPoolWords.js +1 -0
- package/dist/localConfig/settingsWrite.js +1 -14
- package/dist/localConfig/skills.js +9 -16
- package/dist/localEngineSpawn.d.ts +29 -1
- package/dist/localEngineSpawn.js +62 -1
- package/dist/mcpLiveness.d.ts +1 -1
- package/dist/mcpProbeWire.js +2 -2
- package/dist/mcpReconnect.js +2 -2
- package/dist/model/catalogLoader.js +3 -17
- package/dist/model/onboardJudgement.d.ts +8 -0
- package/dist/model/onboardJudgement.js +8 -3
- package/dist/model/onboardSteps.d.ts +19 -0
- package/dist/model/onboardSteps.js +76 -0
- package/dist/notifications.js +20 -12
- package/dist/ownKey.d.ts +4 -0
- package/dist/ownKey.js +61 -0
- package/dist/pathShape.d.ts +14 -0
- package/dist/pathShape.js +44 -0
- package/dist/planReviewCardFacts.d.ts +3 -0
- package/dist/planReviewCardFacts.js +20 -3
- package/dist/planReviewOutcomeCause.d.ts +2 -0
- package/dist/planReviewOutcomeCause.js +12 -0
- package/dist/pluginHooksWire.d.ts +20 -8
- package/dist/pluginHooksWire.js +204 -86
- package/dist/prepareRefusal.d.ts +2 -0
- package/dist/prepareRefusal.js +11 -1
- package/dist/request/taskRequest.js +3 -1
- package/dist/resultFrameKeys.d.ts +1 -0
- package/dist/resultFrameKeys.js +3 -0
- package/dist/resumeRefusalCopy.js +3 -1
- package/dist/retryStatus.d.ts +11 -1
- package/dist/retryStatus.js +15 -4
- package/dist/runTerminal.d.ts +1 -0
- package/dist/runTerminal.js +15 -1
- package/dist/sdkWireTransit.d.ts +1 -1
- package/dist/seatContract.d.ts +12 -3
- package/dist/seatContract.js +24 -13
- package/dist/sessionEngine.js +1 -1
- package/dist/sessionHooksRoster.js +8 -6
- package/dist/sessionIdSegment.d.ts +0 -1
- package/dist/sessionIdSegment.js +1 -3
- package/dist/sessionMemoryErase.js +2 -2
- package/dist/sessionMemoryStatus.js +2 -1
- package/dist/sessionOccupant.d.ts +29 -0
- package/dist/sessionOccupant.js +78 -0
- package/dist/settingsHooksSalvage.d.ts +4 -1
- package/dist/settingsHooksSalvage.js +22 -9
- package/dist/skillOverrideChain.d.ts +3 -0
- package/dist/skillOverrideChain.js +31 -4
- package/dist/skillsWireCaps.d.ts +16 -2
- package/dist/skillsWireCaps.js +47 -20
- package/dist/subagent/agentStateDetail.js +32 -8
- package/dist/subagent/engineCompactWire.js +48 -36
- package/dist/subagent/engineDelegatedPrompt.d.ts +3 -2
- package/dist/subagent/engineDelegatedPrompt.js +65 -28
- package/dist/subagentEditOutcomes.d.ts +9 -0
- package/dist/subagentEditOutcomes.js +43 -0
- package/dist/supportFloor.d.ts +2 -1
- package/dist/supportFloor.js +1 -1
- package/dist/toolResult.js +4 -2
- package/dist/toolRoster.d.ts +1 -0
- package/dist/toolRoster.js +1 -0
- package/dist/usageAnalytics.js +2 -1
- package/dist/userAttachmentEnvelope.d.ts +11 -0
- package/dist/userAttachmentEnvelope.js +7 -2
- package/dist/userAttachmentSeat.d.ts +7 -1
- package/dist/userAttachmentSeat.js +44 -7
- package/dist/wiringInstructionsAttribution.js +8 -2
- package/docs/INTEGRATION-CLIENTS.md +1654 -16
- package/package.json +5 -5
|
@@ -2,7 +2,7 @@ import { requestCoordinateText } from './requestCoordinate.js';
|
|
|
2
2
|
import { displayUntrusted } from './displayUntrusted.js';
|
|
3
3
|
import { msg, renderMessage } from './i18n/translate.js';
|
|
4
4
|
import { appendOwnElement } from './ownKey.js';
|
|
5
|
-
import { SETTINGS_CLASSIFY_HOOKS_CONFIG, } from './generated/settingsSchemaFns.js';
|
|
5
|
+
import { SETTINGS_CLASSIFY_HOOKS_CONFIG, SETTINGS_HOOK_EVENTS, } from './generated/settingsSchemaFns.js';
|
|
6
6
|
const _tuplePins = [true, true, true, true, true, true];
|
|
7
7
|
void _tuplePins;
|
|
8
8
|
const _classifierPins = [true, true, true, true, true, true];
|
|
@@ -113,13 +113,13 @@ export function salvageSettingsHooksEntries(doc) {
|
|
|
113
113
|
});
|
|
114
114
|
}
|
|
115
115
|
const READER_GROUP_WIRE_KEYS = ['source'];
|
|
116
|
-
const READER_COMMAND_WIRE_KEYS = ['plugin'
|
|
117
|
-
function unreadOf(raw, carried, wireKeys,
|
|
116
|
+
const READER_COMMAND_WIRE_KEYS = ['plugin'];
|
|
117
|
+
function unreadOf(raw, carried, wireKeys, reads) {
|
|
118
118
|
const out = [];
|
|
119
119
|
for (const k of Object.keys(raw)) {
|
|
120
120
|
if (own(raw, k) === undefined || wireKeys.includes(k))
|
|
121
121
|
continue;
|
|
122
|
-
if (Object.hasOwn(carried, k)
|
|
122
|
+
if (reads(k, Object.hasOwn(carried, k)))
|
|
123
123
|
continue;
|
|
124
124
|
appendOwnElement(out, k);
|
|
125
125
|
}
|
|
@@ -136,7 +136,7 @@ function carriedGroupOf(event, group) {
|
|
|
136
136
|
export function hooksGroupUnreadKeys(event, group) {
|
|
137
137
|
const raw = group;
|
|
138
138
|
const carried = carriedGroupOf(event, { ...raw, hooks: [] });
|
|
139
|
-
return carried === undefined ? undefined : unreadOf(raw, carried, READER_GROUP_WIRE_KEYS,
|
|
139
|
+
return carried === undefined ? undefined : unreadOf(raw, carried, READER_GROUP_WIRE_KEYS, (_key, carriedByCopy) => carriedByCopy);
|
|
140
140
|
}
|
|
141
141
|
export function hooksGroupAuthoredSource(group) {
|
|
142
142
|
try {
|
|
@@ -153,14 +153,27 @@ export function hooksGroupAuthoredSource(group) {
|
|
|
153
153
|
return 'unreadable';
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
|
-
export function
|
|
157
|
-
const
|
|
158
|
-
const g = carriedGroupOf(event, { hooks: [raw] });
|
|
156
|
+
export function hooksEntryContractView(event, entry) {
|
|
157
|
+
const g = carriedGroupOf(event, { hooks: [entry] });
|
|
159
158
|
const entries = g === undefined ? undefined : own(g, 'hooks');
|
|
160
159
|
const carried = Array.isArray(entries) ? entries[0] : undefined;
|
|
160
|
+
return isRecord(carried) ? carried : undefined;
|
|
161
|
+
}
|
|
162
|
+
export function hooksEntryUnreadKeys(event, entry, reader) {
|
|
163
|
+
const raw = entry;
|
|
164
|
+
const carried = hooksEntryContractView(event, raw);
|
|
161
165
|
if (!isRecord(carried))
|
|
162
166
|
return undefined;
|
|
163
|
-
|
|
167
|
+
const type = own(carried, 'type');
|
|
168
|
+
const entryType = typeof type === 'string' ? type : '';
|
|
169
|
+
return unreadOf(raw, carried, entryType === 'command' ? READER_COMMAND_WIRE_KEYS : [], (key, carriedByCopy) => reader.reads(entryType, key, carriedByCopy));
|
|
170
|
+
}
|
|
171
|
+
const GUARD_HOOK_EVENTS = new Set(SETTINGS_HOOK_EVENTS.filter((event) => {
|
|
172
|
+
const r = SETTINGS_CLASSIFY_HOOKS_CONFIG({ hooks: { [event]: 1 } });
|
|
173
|
+
return r.outcome === 'rejected' && r.rejections.some((x) => x.code === 'guard-event-not-array');
|
|
174
|
+
}));
|
|
175
|
+
export function isGuardHookEvent(event) {
|
|
176
|
+
return typeof event === 'string' && GUARD_HOOK_EVENTS.has(event);
|
|
164
177
|
}
|
|
165
178
|
export function hooksKeyCoordinateText(path) {
|
|
166
179
|
return requestCoordinateText('settings', path, (seg) => labelOf(seg));
|
|
@@ -47,6 +47,7 @@ export interface SkillOverrideLock {
|
|
|
47
47
|
readonly source: SkillOverrideLockSource;
|
|
48
48
|
readonly value: SkillOverrideState;
|
|
49
49
|
}
|
|
50
|
+
export declare const LIST_BUDGET = 4096;
|
|
50
51
|
export interface ShapedSkillSubject {
|
|
51
52
|
readonly name: string;
|
|
52
53
|
readonly origin: SkillOrigin;
|
|
@@ -75,6 +76,8 @@ export declare function secondaryNamesOf(s: ShapedSkillSubject): string[];
|
|
|
75
76
|
export declare function effectiveOfShaped(L: ShapedSkillLayers, s: ShapedSkillSubject): SkillOverrideEffective;
|
|
76
77
|
export declare function lockOfShaped(L: ShapedSkillLayers, s: ShapedSkillSubject): SkillOverrideLock | undefined;
|
|
77
78
|
export declare function skillOverrideEffectiveOf(layers: SkillOverrideLayers, skill: SkillOverrideSubject): SkillOverrideEffective | undefined;
|
|
79
|
+
export type SkillOverrideTightening = 'none' | 'plain' | 'managed';
|
|
80
|
+
export declare function skillOverrideTighteningOf(layers: SkillOverrideLayers): SkillOverrideTightening;
|
|
78
81
|
export declare function skillOverrideLockOf(layers: SkillOverrideLayers, skill: SkillOverrideSubject): SkillOverrideLock | undefined;
|
|
79
82
|
export declare function ownValueIn(ov: object | undefined, s: ShapedSkillSubject): SkillOverrideState | undefined;
|
|
80
83
|
export declare function stateAt(ov: object | undefined, key: string | undefined): SkillOverrideState | undefined;
|
|
@@ -7,9 +7,8 @@ export const SKILL_OVERRIDE_DECIDERS = Object.freeze([...SKILL_OVERRIDE_LAYERS,
|
|
|
7
7
|
export const SKILL_OVERRIDE_LOCK_SOURCES = Object.freeze(['policy', 'flag', 'plugin', 'skill-author', 'reserved-name']);
|
|
8
8
|
const MANAGED = ['policySettings', 'flagSettings'];
|
|
9
9
|
const PLAIN = ['localSettings', 'projectSettings', 'userSettings'];
|
|
10
|
-
const MERGED = ['policySettings', 'flagSettings', 'localSettings', 'projectSettings', 'userSettings'];
|
|
11
10
|
const RANK = { on: 0, 'name-only': 1, 'user-invocable-only': 2, off: 3 };
|
|
12
|
-
const LIST_BUDGET = 4096;
|
|
11
|
+
export const LIST_BUDGET = 4096;
|
|
13
12
|
function own(v, key) {
|
|
14
13
|
if (typeof v !== 'object' || v === null)
|
|
15
14
|
return undefined;
|
|
@@ -91,7 +90,7 @@ export function shapeSkillLayers(v) {
|
|
|
91
90
|
const session = own(v, 'session');
|
|
92
91
|
const enabled = (layer) => layer === 'policySettings' || layer === 'flagSettings' || !disabled.has(layer);
|
|
93
92
|
let fromSettings = false;
|
|
94
|
-
for (const l of
|
|
93
|
+
for (const l of SKILL_OVERRIDE_LAYERS) {
|
|
95
94
|
if (!enabled(l))
|
|
96
95
|
continue;
|
|
97
96
|
const b = own(own(v, l), 'disableBundledSkills');
|
|
@@ -151,7 +150,7 @@ function reservedTighten(ov, s, by) {
|
|
|
151
150
|
return r === undefined || r.value === 'on' ? undefined : r;
|
|
152
151
|
}
|
|
153
152
|
function mergedAt(L, key) {
|
|
154
|
-
for (const l of
|
|
153
|
+
for (const l of SKILL_OVERRIDE_LAYERS) {
|
|
155
154
|
if (!L.enabled(l))
|
|
156
155
|
continue;
|
|
157
156
|
const h = hitAt(L.docs[l], key, l);
|
|
@@ -324,6 +323,34 @@ export function skillOverrideEffectiveOf(layers, skill) {
|
|
|
324
323
|
return undefined;
|
|
325
324
|
}
|
|
326
325
|
}
|
|
326
|
+
function recordTightens(rec) {
|
|
327
|
+
if (rec === undefined)
|
|
328
|
+
return false;
|
|
329
|
+
const keys = Reflect.ownKeys(rec);
|
|
330
|
+
if (keys.length > LIST_BUDGET)
|
|
331
|
+
return true;
|
|
332
|
+
for (const k of keys) {
|
|
333
|
+
if (typeof k !== 'string')
|
|
334
|
+
continue;
|
|
335
|
+
const v = own(rec, k);
|
|
336
|
+
if (isState(v) && v !== 'on')
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
export function skillOverrideTighteningOf(layers) {
|
|
342
|
+
try {
|
|
343
|
+
const L = shapeSkillLayers(layers);
|
|
344
|
+
if (MANAGED.some((l) => recordTightens(L.docs[l])))
|
|
345
|
+
return 'managed';
|
|
346
|
+
if (PLAIN.some((l) => L.enabled(l) && recordTightens(L.docs[l])) || recordTightens(L.session))
|
|
347
|
+
return 'plain';
|
|
348
|
+
return 'none';
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
return 'managed';
|
|
352
|
+
}
|
|
353
|
+
}
|
|
327
354
|
export function skillOverrideLockOf(layers, skill) {
|
|
328
355
|
try {
|
|
329
356
|
const s = shapeSkillSubject(skill);
|
package/dist/skillsWireCaps.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SkillSpec } from '@sema-agent/sdk';
|
|
2
2
|
import { type SkillToolListsReading } from './skillToolListsCapability.js';
|
|
3
|
-
import { type SkillOverrideLayers, type SkillOverrideSubject } from './skillOverrideChain.js';
|
|
3
|
+
import { type SkillOrigin, type SkillOverrideLayers, type SkillOverrideSubject } from './skillOverrideChain.js';
|
|
4
4
|
export interface SkillCmdLike {
|
|
5
5
|
type?: string;
|
|
6
6
|
name?: string;
|
|
@@ -23,6 +23,17 @@ export interface SkillSpecsOptions {
|
|
|
23
23
|
skillToolLists?: SkillToolListsReading;
|
|
24
24
|
skillOverrides?: SkillOverrideLayers;
|
|
25
25
|
}
|
|
26
|
+
export type SkillCmdWithSubject = SkillCmdLike & {
|
|
27
|
+
skillOverrideSubject: SkillOverrideSubject;
|
|
28
|
+
};
|
|
29
|
+
export declare const SKILL_WITHHELD_REASONS: readonly ["identity_unreadable"];
|
|
30
|
+
export type SkillWithheldReason = (typeof SKILL_WITHHELD_REASONS)[number];
|
|
31
|
+
export interface SkillWithheldRow {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly origin: SkillOrigin;
|
|
34
|
+
readonly reason: SkillWithheldReason;
|
|
35
|
+
}
|
|
36
|
+
export declare function skillCommandsWithheldOf(cmds: readonly SkillCmdLike[], opts?: SkillSpecsOptions): readonly SkillWithheldRow[];
|
|
26
37
|
export declare function skillBaseDirOf(skillRoot: string | undefined, platform?: 'posix' | 'win32'): string | undefined;
|
|
27
38
|
export type SkillToolListKey = 'allowedTools' | 'disallowedTools';
|
|
28
39
|
export type SkillToolListsVerdict = {
|
|
@@ -38,4 +49,7 @@ export type SkillToolListsVerdict = {
|
|
|
38
49
|
readonly detail: string;
|
|
39
50
|
};
|
|
40
51
|
export declare function skillToolListsVerdict(source: object, reading: SkillToolListsReading | undefined): SkillToolListsVerdict;
|
|
41
|
-
export declare function skillCommandsToSpecs(cmds: SkillCmdLike[], resolveBody: (cmd: SkillCmdLike) => string | null, opts?: SkillSpecsOptions
|
|
52
|
+
export declare function skillCommandsToSpecs(cmds: SkillCmdLike[], resolveBody: (cmd: SkillCmdLike) => string | null, opts?: SkillSpecsOptions & {
|
|
53
|
+
skillOverrides?: undefined;
|
|
54
|
+
}): SkillSpecOnWire[];
|
|
55
|
+
export declare function skillCommandsToSpecs(cmds: SkillCmdWithSubject[], resolveBody: (cmd: SkillCmdWithSubject) => string | null, opts: SkillSpecsOptions): SkillSpecOnWire[];
|
package/dist/skillsWireCaps.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { skillToolListsAvailable } from './skillToolListsCapability.js';
|
|
2
2
|
import { msg, renderMessage } from './i18n/translate.js';
|
|
3
3
|
import { appendOwnElement } from './ownKey.js';
|
|
4
|
-
import {
|
|
4
|
+
import { pathShapeOf, PATH_LENGTH_LIMIT } from './pathShape.js';
|
|
5
|
+
import { skillOverrideEffectiveOf, skillOverrideTighteningOf, } from './skillOverrideChain.js';
|
|
5
6
|
export function toCappedSpec(name, description, whenToUse, body) {
|
|
6
7
|
const n = name.trim();
|
|
7
8
|
const c = body.trim();
|
|
@@ -13,29 +14,54 @@ export function toCappedSpec(name, description, whenToUse, body) {
|
|
|
13
14
|
return { name: n, description: desc, content: c };
|
|
14
15
|
}
|
|
15
16
|
const ORIGIN_OF_SOURCE = { plugin: 'plugin', builtin: 'builtin', bundled: 'bundled', mcp: 'mcp' };
|
|
17
|
+
function originOfCommand(cmd) {
|
|
18
|
+
const src = typeof cmd.source === 'string' && Object.hasOwn(ORIGIN_OF_SOURCE, cmd.source) ? ORIGIN_OF_SOURCE[cmd.source] : undefined;
|
|
19
|
+
return src ?? 'skills';
|
|
20
|
+
}
|
|
16
21
|
function overrideSubjectOf(cmd, name) {
|
|
17
22
|
if (cmd.skillOverrideSubject !== undefined)
|
|
18
23
|
return cmd.skillOverrideSubject;
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
return { name, origin: originOfCommand(cmd) };
|
|
25
|
+
}
|
|
26
|
+
export const SKILL_WITHHELD_REASONS = Object.freeze(['identity_unreadable']);
|
|
27
|
+
function identityNeedsSubject(cmd, name) {
|
|
28
|
+
if (name.includes(':'))
|
|
29
|
+
return true;
|
|
30
|
+
const s = cmd.source;
|
|
31
|
+
return s === 'mcp' || s === 'plugin' || s === 'commands';
|
|
32
|
+
}
|
|
33
|
+
function readOverrideIdentity(cmd, name, layers, tightening) {
|
|
34
|
+
if (cmd.skillOverrideSubject === undefined) {
|
|
35
|
+
if (tightening === 'managed' || (tightening === 'plain' && identityNeedsSubject(cmd, name)))
|
|
36
|
+
return { kind: 'withheld', reason: 'identity_unreadable' };
|
|
37
|
+
}
|
|
38
|
+
const effective = skillOverrideEffectiveOf(layers, overrideSubjectOf(cmd, name));
|
|
39
|
+
return effective === undefined ? { kind: 'withheld', reason: 'identity_unreadable' } : { kind: 'read', effective };
|
|
40
|
+
}
|
|
41
|
+
export function skillCommandsWithheldOf(cmds, opts) {
|
|
42
|
+
const rows = [];
|
|
43
|
+
const layers = opts?.skillOverrides;
|
|
44
|
+
if (layers === undefined)
|
|
45
|
+
return Object.freeze(rows);
|
|
46
|
+
const tightening = skillOverrideTighteningOf(layers);
|
|
47
|
+
for (const cmd of cmds) {
|
|
48
|
+
if (cmd.type !== 'prompt' || cmd.disableModelInvocation)
|
|
49
|
+
continue;
|
|
50
|
+
const name = (cmd.name ?? '').trim();
|
|
51
|
+
const read = readOverrideIdentity(cmd, name, layers, tightening);
|
|
52
|
+
if (read.kind === 'withheld')
|
|
53
|
+
appendOwnElement(rows, Object.freeze({ name, origin: originOfCommand(cmd), reason: read.reason }));
|
|
54
|
+
}
|
|
55
|
+
return Object.freeze(rows);
|
|
21
56
|
}
|
|
22
57
|
export function skillBaseDirOf(skillRoot, platform = 'posix') {
|
|
23
|
-
if (skillRoot === undefined || skillRoot.length
|
|
24
|
-
return undefined;
|
|
25
|
-
if (skillRoot.includes('\u0000'))
|
|
26
|
-
return undefined;
|
|
27
|
-
if (platform === 'win32') {
|
|
28
|
-
if (!(/^[A-Za-z]:[\\/]/.test(skillRoot) || /^\\\\[^\\/]+[\\/][^\\/]+/.test(skillRoot)))
|
|
29
|
-
return undefined;
|
|
30
|
-
if (skillRoot.split(/[\\/]/).includes('..'))
|
|
31
|
-
return undefined;
|
|
32
|
-
return skillRoot;
|
|
33
|
-
}
|
|
34
|
-
if (!skillRoot.startsWith('/'))
|
|
58
|
+
if (skillRoot === undefined || skillRoot.length > PATH_LENGTH_LIMIT)
|
|
35
59
|
return undefined;
|
|
36
|
-
|
|
60
|
+
const shape = pathShapeOf(skillRoot);
|
|
61
|
+
if (shape === undefined || shape.hasParentSegment)
|
|
37
62
|
return undefined;
|
|
38
|
-
|
|
63
|
+
const rooted = platform === 'win32' ? shape.kind === 'drive' || shape.kind === 'unc' : shape.kind === 'posix';
|
|
64
|
+
return rooted ? skillRoot : undefined;
|
|
39
65
|
}
|
|
40
66
|
const SKILL_TOOL_LIST_READ_BUDGET = 100_000;
|
|
41
67
|
function readSkillToolList(key, source) {
|
|
@@ -123,6 +149,7 @@ export function skillToolListsVerdict(source, reading) {
|
|
|
123
149
|
}
|
|
124
150
|
export function skillCommandsToSpecs(cmds, resolveBody, opts) {
|
|
125
151
|
const specs = [];
|
|
152
|
+
const tightening = opts?.skillOverrides !== undefined ? skillOverrideTighteningOf(opts.skillOverrides) : 'none';
|
|
126
153
|
const seen = new Set();
|
|
127
154
|
const reading = opts?.skillToolLists;
|
|
128
155
|
for (const cmd of cmds) {
|
|
@@ -130,10 +157,10 @@ export function skillCommandsToSpecs(cmds, resolveBody, opts) {
|
|
|
130
157
|
continue;
|
|
131
158
|
let nameOnly = false;
|
|
132
159
|
if (opts?.skillOverrides !== undefined) {
|
|
133
|
-
const
|
|
134
|
-
if (
|
|
160
|
+
const read = readOverrideIdentity(cmd, (cmd.name ?? '').trim(), opts.skillOverrides, tightening);
|
|
161
|
+
if (read.kind === 'withheld' || read.effective.value === 'off' || read.effective.value === 'user-invocable-only')
|
|
135
162
|
continue;
|
|
136
|
-
nameOnly =
|
|
163
|
+
nameOnly = read.effective.value === 'name-only';
|
|
137
164
|
}
|
|
138
165
|
const body = resolveBody(cmd);
|
|
139
166
|
if (!body)
|
|
@@ -12,6 +12,16 @@ function own(v, key) {
|
|
|
12
12
|
}
|
|
13
13
|
const finite = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : undefined);
|
|
14
14
|
const word = (v) => (typeof v === 'string' && v.trim() !== '' ? displayUntrusted(v, { max: 64 }) : undefined);
|
|
15
|
+
function ownSlotAbsent(v, key) {
|
|
16
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
17
|
+
return true;
|
|
18
|
+
try {
|
|
19
|
+
return Object.getOwnPropertyDescriptor(v, key) === undefined;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
15
25
|
function span(ms) {
|
|
16
26
|
const s = Math.floor(ms / 1000);
|
|
17
27
|
if (s < 60)
|
|
@@ -29,13 +39,27 @@ export function subagentStateDetail(carrier) {
|
|
|
29
39
|
const readAt = finite(own(st, 'readAt'));
|
|
30
40
|
const last = finite(own(st, 'lastActivityAt'));
|
|
31
41
|
const activity = readAt !== undefined && last !== undefined && last <= readAt ? `last activity ${span(readAt - last)} ago` : 'last activity unknown';
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
const deadlineClause = (holder) => {
|
|
43
|
+
const deadline = finite(own(holder, 'deadline'));
|
|
44
|
+
return deadline === undefined || readAt === undefined ? '' : deadline > readAt ? ` (deadline in ${span(deadline - readAt)})` : ' (deadline passed)';
|
|
45
|
+
};
|
|
46
|
+
let parkPart = '';
|
|
47
|
+
if (!ownSlotAbsent(st, 'park')) {
|
|
48
|
+
const park = own(st, 'park');
|
|
49
|
+
const parkState = word(own(park, 'state'));
|
|
50
|
+
if (parkState !== undefined) {
|
|
51
|
+
const gate = own(park, 'gate');
|
|
52
|
+
const gateKind = word(own(gate, 'kind'));
|
|
53
|
+
const limitReason = gateKind === 'resource_limit' ? word(own(gate, 'reason')) : undefined;
|
|
54
|
+
const on = gateKind === undefined ? '' : ` on ${gateKind}${limitReason !== undefined ? `: ${limitReason}` : ''}`;
|
|
55
|
+
parkPart = ` · park ${parkState}${on}${deadlineClause(park)}`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
const approval = own(st, 'approval');
|
|
60
|
+
const approvalState = word(own(approval, 'state'));
|
|
61
|
+
if (approvalState !== undefined)
|
|
62
|
+
parkPart = ` · approval ${approvalState}${deadlineClause(approval)}`;
|
|
39
63
|
}
|
|
40
|
-
return `Subagent state: ${status} · ${activity}${
|
|
64
|
+
return `Subagent state: ${status} · ${activity}${parkPart}`;
|
|
41
65
|
}
|
|
@@ -12,10 +12,16 @@ function usableCompactClient(client) {
|
|
|
12
12
|
return clientHasVerbs(client, [['capabilities'], ['runs', 'compact']]);
|
|
13
13
|
}
|
|
14
14
|
const COMPACT_PROBE_SETTLE_MS = 5000;
|
|
15
|
-
const
|
|
16
|
-
|
|
15
|
+
const pendingCompactRequests = new Map();
|
|
16
|
+
function armCompactRequests(sessionKey, requests) {
|
|
17
|
+
const queued = pendingCompactRequests.get(sessionKey);
|
|
18
|
+
if (queued === undefined)
|
|
19
|
+
pendingCompactRequests.set(sessionKey, [...requests]);
|
|
20
|
+
else
|
|
21
|
+
queued.push(...requests);
|
|
22
|
+
}
|
|
17
23
|
export function isEngineCompactPending(sessionKey = DEFAULT_SESSION_KEY) {
|
|
18
|
-
return
|
|
24
|
+
return pendingCompactRequests.has(sessionKey);
|
|
19
25
|
}
|
|
20
26
|
function probeManualCompactCapability(wire) {
|
|
21
27
|
const base = wire.kind === 'injected' ? wire.capsBaseUrl : wire.target.baseUrl;
|
|
@@ -32,8 +38,7 @@ function probeManualCompactCapability(wire) {
|
|
|
32
38
|
kickEngineCapsProbe(base, () => client.capabilities());
|
|
33
39
|
}
|
|
34
40
|
export function __resetEngineCompactArmForTests() {
|
|
35
|
-
|
|
36
|
-
pendingCompactSinks.clear();
|
|
41
|
+
pendingCompactRequests.clear();
|
|
37
42
|
}
|
|
38
43
|
function deferFire(ms, fn, why, sessionKey) {
|
|
39
44
|
const timers = hostTimersFor(sessionKey);
|
|
@@ -73,13 +78,23 @@ function emitCompactOutcome(sink, outcome) {
|
|
|
73
78
|
function callSinkIsolated(sink, outcome) {
|
|
74
79
|
invokeHostCallbackIsolated('engineCompactWire: onSettled sink', () => sink(outcome));
|
|
75
80
|
}
|
|
76
|
-
function
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
function settleCompactRequests(requests, outcome) {
|
|
82
|
+
for (const r of requests)
|
|
83
|
+
emitCompactOutcome(r.sink, outcome);
|
|
84
|
+
}
|
|
85
|
+
function settleNotRunning(sessionKey, requests, outcome) {
|
|
86
|
+
const renewed = [];
|
|
87
|
+
for (const r of requests) {
|
|
88
|
+
if (r.continued)
|
|
89
|
+
emitCompactOutcome(r.sink, outcome);
|
|
90
|
+
else
|
|
91
|
+
renewed.push({ sink: r.sink, continued: true });
|
|
92
|
+
}
|
|
93
|
+
if (renewed.length > 0) {
|
|
94
|
+
armCompactRequests(sessionKey, renewed);
|
|
95
|
+
hostLog('debug', `engineCompactWire: 409 compact.not_running —— ${renewed.length} 只请求记回本槽待发(下一条 run 续一次)`);
|
|
96
|
+
}
|
|
97
|
+
surfaceCompactNotRunning(sessionKey, renewed.length > 0 ? 'will_retry' : 'final');
|
|
83
98
|
}
|
|
84
99
|
function compactFailureOutcomeOf(e) {
|
|
85
100
|
const shape = wireFailureShapeOf(e);
|
|
@@ -98,10 +113,12 @@ function compactFailureOutcomeOf(e) {
|
|
|
98
113
|
return { kind: 'failed', detail: noAnswer, unconfirmed: true };
|
|
99
114
|
return { kind: 'failed', detail: wireFailureTextsOf(e).reason };
|
|
100
115
|
}
|
|
101
|
-
|
|
116
|
+
const COMPACT_404_RETRIES = 5;
|
|
117
|
+
const COMPACT_404_FIRST_RETRY_MS = 100;
|
|
118
|
+
async function postCompact(shot, requests, retriesUsed = 0) {
|
|
102
119
|
const client = shot.client();
|
|
103
120
|
if (!client) {
|
|
104
|
-
|
|
121
|
+
settleCompactRequests(requests, { kind: 'offline' });
|
|
105
122
|
return;
|
|
106
123
|
}
|
|
107
124
|
const taskId = shot.taskId;
|
|
@@ -109,7 +126,7 @@ async function postCompact(shot, sink, retriesLeft = 1) {
|
|
|
109
126
|
const fire = (signal) => client.runs.compact(taskId, { ...(shot.session !== undefined ? { session: shot.session } : {}), ...(signal ? { signal } : {}) });
|
|
110
127
|
const ack = shot.injected ? await settleInjected(INJECTED_WIRE_SETTLE_MS, undefined, fire) : await fire(undefined);
|
|
111
128
|
hostLog('debug', `engineCompactWire: POST compact ${taskId} → ok${ack?.status ? ` (${ack.status})` : ''}`);
|
|
112
|
-
|
|
129
|
+
settleCompactRequests(requests, { kind: 'accepted' });
|
|
113
130
|
}
|
|
114
131
|
catch (e) {
|
|
115
132
|
const outcome = compactFailureOutcomeOf(e);
|
|
@@ -119,13 +136,16 @@ async function postCompact(shot, sink, retriesLeft = 1) {
|
|
|
119
136
|
else {
|
|
120
137
|
hostLog('debug', `engineCompactWire: compact fire failed (best-effort): ${wireFailureTextsOf(e).log}`);
|
|
121
138
|
}
|
|
122
|
-
if (outcome.kind === 'refused' && outcome.status === 404 &&
|
|
123
|
-
|
|
139
|
+
if (outcome.kind === 'refused' && outcome.status === 404 && retriesUsed < COMPACT_404_RETRIES) {
|
|
140
|
+
const waitMs = COMPACT_404_FIRST_RETRY_MS * 2 ** retriesUsed;
|
|
141
|
+
if (deferFire(waitMs, () => void postCompact(shot, requests, retriesUsed + 1), '404 短梯重试', shot.sessionKey))
|
|
124
142
|
return;
|
|
125
143
|
}
|
|
126
|
-
if (outcome.kind === 'refused' && outcome.errorCode === COMPACT_NOT_RUNNING)
|
|
127
|
-
|
|
128
|
-
|
|
144
|
+
if (outcome.kind === 'refused' && outcome.errorCode === COMPACT_NOT_RUNNING) {
|
|
145
|
+
settleNotRunning(shot.sessionKey, requests, outcome);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
settleCompactRequests(requests, outcome);
|
|
129
149
|
}
|
|
130
150
|
}
|
|
131
151
|
export function requestEngineCompact(sessionKey = DEFAULT_SESSION_KEY, opts) {
|
|
@@ -141,37 +161,29 @@ export function requestEngineCompact(sessionKey = DEFAULT_SESSION_KEY, opts) {
|
|
|
141
161
|
const taskId = activeEngineRunIdFor(sessionKey);
|
|
142
162
|
const rawSink = opts?.onSettled;
|
|
143
163
|
const sink = typeof rawSink === 'function' ? rawSink : undefined;
|
|
164
|
+
const request = { sink, continued: false };
|
|
144
165
|
if (taskId) {
|
|
145
166
|
const shot = freezeCompactShot(taskId, sessionKey, wire);
|
|
146
167
|
if (shot !== null)
|
|
147
|
-
void postCompact(shot,
|
|
168
|
+
void postCompact(shot, [request]);
|
|
148
169
|
else
|
|
149
170
|
emitCompactOutcome(sink, { kind: 'offline' });
|
|
150
171
|
return 'fired';
|
|
151
172
|
}
|
|
152
|
-
|
|
153
|
-
if (sink !== undefined) {
|
|
154
|
-
const sinks = pendingCompactSinks.get(sessionKey);
|
|
155
|
-
if (sinks === undefined)
|
|
156
|
-
pendingCompactSinks.set(sessionKey, [sink]);
|
|
157
|
-
else
|
|
158
|
-
sinks.push(sink);
|
|
159
|
-
}
|
|
173
|
+
armCompactRequests(sessionKey, [request]);
|
|
160
174
|
return 'armed';
|
|
161
175
|
}
|
|
162
|
-
const BOUND_FIRE_DELAY_MS = 1500;
|
|
163
176
|
export function onEngineTaskBound(taskId, sessionKey = DEFAULT_SESSION_KEY, opts) {
|
|
164
177
|
const wire = engineWireFor(opts?.wire, sessionKey, usableCompactClient);
|
|
165
178
|
if (wire.kind !== 'no-target' && wire.kind !== 'injected-unusable')
|
|
166
179
|
probeManualCompactCapability(wire);
|
|
167
|
-
|
|
180
|
+
const requests = pendingCompactRequests.get(sessionKey);
|
|
181
|
+
if (requests === undefined)
|
|
168
182
|
return;
|
|
169
183
|
const shot = freezeCompactShot(taskId, sessionKey, wire);
|
|
170
184
|
if (shot === null)
|
|
171
185
|
return;
|
|
172
|
-
const
|
|
173
|
-
if (deferFire(
|
|
174
|
-
|
|
175
|
-
pendingCompactSinks.delete(sessionKey);
|
|
176
|
-
}
|
|
186
|
+
const batch = [...requests];
|
|
187
|
+
if (deferFire(0, () => void postCompact(shot, batch), 'bind 后发射', sessionKey))
|
|
188
|
+
pendingCompactRequests.delete(sessionKey);
|
|
177
189
|
}
|
|
@@ -12,13 +12,14 @@ export declare function delegatedPromptText(content: unknown): string | undefine
|
|
|
12
12
|
export declare function pickDelegatedPrompt(messages: readonly unknown[]): string | undefined;
|
|
13
13
|
type TranscriptWindowReader = (transcriptId: string) => Promise<readonly unknown[] | null>;
|
|
14
14
|
export declare function __setTranscriptWindowReaderForTests(r: TranscriptWindowReader | null): void;
|
|
15
|
-
export declare const DELEGATED_PROMPT_ABSENCE_CAUSES: readonly ["
|
|
15
|
+
export declare const DELEGATED_PROMPT_ABSENCE_CAUSES: readonly ["anchor_unreported", "not_in_store", "forbidden", "prompt_absent", "unknown"];
|
|
16
16
|
export type DelegatedPromptAbsenceCause = (typeof DELEGATED_PROMPT_ABSENCE_CAUSES)[number];
|
|
17
17
|
export interface DelegatedPromptAbsence {
|
|
18
18
|
readonly cause: DelegatedPromptAbsenceCause;
|
|
19
19
|
readonly text: string;
|
|
20
20
|
}
|
|
21
21
|
export declare function delegatedPromptAbsenceSentence(cause: DelegatedPromptAbsenceCause | string, lang?: UiLanguage): string;
|
|
22
|
+
export declare function standingDelegatedPromptAbsence(taskId: string, lang?: UiLanguage): DelegatedPromptAbsence | undefined;
|
|
22
23
|
export interface DelegatedPromptFetch {
|
|
23
24
|
prompt?: string;
|
|
24
25
|
outcome: 'hit' | 'skipped' | 'unreadable' | 'absent';
|
|
@@ -26,5 +27,5 @@ export interface DelegatedPromptFetch {
|
|
|
26
27
|
}
|
|
27
28
|
export declare function fetchDelegatedPrompt(taskId: string, opts?: {
|
|
28
29
|
wire?: DelegatedPromptWire;
|
|
29
|
-
}): Promise<DelegatedPromptFetch>;
|
|
30
|
+
}, lang?: UiLanguage): Promise<DelegatedPromptFetch>;
|
|
30
31
|
export {};
|
|
@@ -115,9 +115,9 @@ async function readTranscriptWindow(transcriptId, sessionKey, injectedWire) {
|
|
|
115
115
|
const msgs = rec.messages;
|
|
116
116
|
return Array.isArray(msgs) ? msgs : null;
|
|
117
117
|
}
|
|
118
|
-
export const DELEGATED_PROMPT_ABSENCE_CAUSES = Object.freeze(['
|
|
118
|
+
export const DELEGATED_PROMPT_ABSENCE_CAUSES = Object.freeze(['anchor_unreported', 'not_in_store', 'forbidden', 'prompt_absent', 'unknown']);
|
|
119
119
|
const ABSENCE_KEY = {
|
|
120
|
-
|
|
120
|
+
anchor_unreported: 'session.subagent.delegatedPrompt.absence.anchorUnreported',
|
|
121
121
|
not_in_store: 'session.subagent.delegatedPrompt.absence.notInStore',
|
|
122
122
|
forbidden: 'session.subagent.delegatedPrompt.absence.forbidden',
|
|
123
123
|
prompt_absent: 'session.subagent.delegatedPrompt.absence.promptAbsent',
|
|
@@ -127,46 +127,83 @@ export function delegatedPromptAbsenceSentence(cause, lang) {
|
|
|
127
127
|
const known = typeof cause === 'string' && Object.hasOwn(ABSENCE_KEY, cause);
|
|
128
128
|
return renderMessage(msg(known ? ABSENCE_KEY[cause] : ABSENCE_KEY.unknown), lang);
|
|
129
129
|
}
|
|
130
|
-
function absenceOf(cause) {
|
|
131
|
-
return Object.freeze({ cause, text: delegatedPromptAbsenceSentence(cause) });
|
|
130
|
+
function absenceOf(cause, lang) {
|
|
131
|
+
return Object.freeze({ cause, text: delegatedPromptAbsenceSentence(cause, lang) });
|
|
132
132
|
}
|
|
133
|
-
function
|
|
133
|
+
function causeOfThrown(e) {
|
|
134
134
|
const status = readThrownSlot(e, 'status');
|
|
135
135
|
if (status === 404)
|
|
136
|
-
return
|
|
136
|
+
return 'not_in_store';
|
|
137
137
|
if (status === 401 || status === 403)
|
|
138
|
-
return
|
|
139
|
-
return
|
|
138
|
+
return 'forbidden';
|
|
139
|
+
return 'unknown';
|
|
140
140
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
141
|
+
function anchorlessCause(anchor) {
|
|
142
|
+
return anchor === undefined ? 'anchor_unreported' : 'unknown';
|
|
143
|
+
}
|
|
144
|
+
export function standingDelegatedPromptAbsence(taskId, lang) {
|
|
145
|
+
if (typeof taskId !== 'string' || taskId === '')
|
|
146
|
+
return undefined;
|
|
147
|
+
const anchor = getEngineTranscriptId(taskId);
|
|
148
|
+
if (!isSessionIdPathSegment(anchor))
|
|
149
|
+
return absenceOf(anchorlessCause(anchor), lang);
|
|
150
|
+
const mark = promptHydrateInFlight.get(taskId);
|
|
151
|
+
return mark !== undefined && mark.anchor === anchor && (mark.phase === 'absent' || mark.phase === 'failed') ? absenceOf(mark.cause, lang) : undefined;
|
|
152
|
+
}
|
|
153
|
+
async function readDelegatedPrompt(taskId, transcriptId, wire, lang) {
|
|
150
154
|
let msgs = null;
|
|
155
|
+
let prompt;
|
|
151
156
|
try {
|
|
152
|
-
msgs = await readTranscriptWindow(transcriptId, resolveOwnerContext(taskId).key,
|
|
157
|
+
msgs = await readTranscriptWindow(transcriptId, resolveOwnerContext(taskId).key, wire);
|
|
158
|
+
prompt = msgs ? pickDelegatedPrompt(msgs) : undefined;
|
|
153
159
|
}
|
|
154
160
|
catch (e) {
|
|
155
|
-
promptHydrateInFlight.delete(taskId);
|
|
156
161
|
hostLog('debug', `[delegated-prompt] ${taskId} transcript ${transcriptId} read failed: ${String(e).slice(0, 160)}`);
|
|
157
|
-
return { outcome: 'unreadable', absence:
|
|
162
|
+
return { outcome: 'unreadable', absence: absenceOf(causeOfThrown(e), lang) };
|
|
158
163
|
}
|
|
159
|
-
const prompt = msgs ? pickDelegatedPrompt(msgs) : undefined;
|
|
160
164
|
if (!prompt) {
|
|
161
|
-
if (msgs === null)
|
|
162
|
-
promptHydrateInFlight.delete(taskId);
|
|
163
165
|
hostLog('debug', `[delegated-prompt] ${taskId} transcript ${transcriptId}: ${msgs === null ? 'transcript unreadable (retryable)' : 'no delegated user message (final)'}`);
|
|
164
166
|
if (msgs === null)
|
|
165
|
-
return { outcome: 'unreadable', absence: absenceOf('unknown') };
|
|
166
|
-
|
|
167
|
-
promptHydrateInFlight.set(taskId, settled);
|
|
168
|
-
return { outcome: 'absent', absence: settled };
|
|
167
|
+
return { outcome: 'unreadable', absence: absenceOf('unknown', lang) };
|
|
168
|
+
return { outcome: 'absent', absence: absenceOf('prompt_absent', lang) };
|
|
169
169
|
}
|
|
170
170
|
hostLog('debug', `[delegated-prompt] ${taskId} <- transcript ${transcriptId} (${prompt.length} chars) head=${JSON.stringify(prompt.slice(0, 60))}`);
|
|
171
|
-
return {
|
|
171
|
+
return { outcome: 'hit', prompt };
|
|
172
|
+
}
|
|
173
|
+
function markOf(anchor, r) {
|
|
174
|
+
if (r.outcome === 'hit')
|
|
175
|
+
return { anchor, phase: 'hit' };
|
|
176
|
+
return { anchor, phase: r.outcome === 'absent' ? 'absent' : 'failed', cause: r.absence.cause };
|
|
177
|
+
}
|
|
178
|
+
function landed(taskId, mine, next) {
|
|
179
|
+
if (promptHydrateInFlight.get(taskId) !== mine)
|
|
180
|
+
return false;
|
|
181
|
+
if (getEngineTranscriptId(taskId) !== mine.anchor) {
|
|
182
|
+
promptHydrateInFlight.delete(taskId);
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
promptHydrateInFlight.set(taskId, next);
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
export async function fetchDelegatedPrompt(taskId, opts, lang) {
|
|
189
|
+
const transcriptId = getEngineTranscriptId(taskId);
|
|
190
|
+
const held = promptHydrateInFlight.get(taskId);
|
|
191
|
+
if (held !== undefined) {
|
|
192
|
+
if (held.anchor !== transcriptId)
|
|
193
|
+
promptHydrateInFlight.delete(taskId);
|
|
194
|
+
else if (held.phase === 'flying' || held.phase === 'hit')
|
|
195
|
+
return { outcome: 'skipped' };
|
|
196
|
+
else if (held.phase === 'absent')
|
|
197
|
+
return { outcome: 'skipped', absence: absenceOf(held.cause, lang) };
|
|
198
|
+
}
|
|
199
|
+
if (!isSessionIdPathSegment(transcriptId))
|
|
200
|
+
return { outcome: 'skipped', absence: absenceOf(anchorlessCause(transcriptId), lang) };
|
|
201
|
+
const mine = { anchor: transcriptId, phase: 'flying' };
|
|
202
|
+
promptHydrateInFlight.set(taskId, mine);
|
|
203
|
+
const read = await readDelegatedPrompt(taskId, transcriptId, opts?.wire, lang);
|
|
204
|
+
if (!landed(taskId, mine, markOf(transcriptId, read))) {
|
|
205
|
+
hostLog('debug', `[delegated-prompt] ${taskId} dropped=${transcriptId}`);
|
|
206
|
+
return { outcome: 'skipped' };
|
|
207
|
+
}
|
|
208
|
+
return read;
|
|
172
209
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
2
|
+
export interface SubagentEditOutcomes {
|
|
3
|
+
readonly attempted: number;
|
|
4
|
+
readonly succeeded: number;
|
|
5
|
+
readonly refused: number;
|
|
6
|
+
readonly failed: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function subagentEditOutcomesOf(toolStats: {} | null | undefined): SubagentEditOutcomes | undefined;
|
|
9
|
+
export declare function subagentEditOutcomesSentence(outcomes: SubagentEditOutcomes | null | undefined, lang?: UiLanguage): string | undefined;
|