@sema-agent/client-core 0.87.0 → 0.89.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 +177 -0
- package/README.md +20 -15
- package/dist/adapter/activeRunSelfHeal.js +4 -2
- package/dist/adapter/downstream/eventToSdkMessage.js +17 -2
- package/dist/adapter/downstream/wiringManifestView.d.ts +11 -0
- package/dist/adapter/downstream/wiringManifestView.js +28 -0
- package/dist/controlRouter.d.ts +7 -1
- package/dist/controlRouter.js +43 -1
- package/dist/disableSkillsWire.d.ts +17 -0
- package/dist/disableSkillsWire.js +52 -0
- package/dist/displayUntrusted.d.ts +4 -0
- package/dist/displayUntrusted.js +1742 -591
- package/dist/engineErrorCodes.d.ts +2 -0
- package/dist/engineErrorCodes.js +1 -0
- package/dist/engineNoticeCodes.d.ts +44 -1
- package/dist/engineNoticeCodes.js +211 -39
- package/dist/engineWireFor.d.ts +1 -0
- package/dist/engineWireFor.js +1 -1
- package/dist/gateOutcome.d.ts +4 -0
- package/dist/gateOutcome.js +5 -0
- package/dist/generated/engineFactTables.d.ts +1 -0
- package/dist/generated/engineFactTables.js +3 -0
- package/dist/generated/engineNoticeTables.d.ts +3 -0
- package/dist/generated/engineNoticeTables.js +110 -0
- package/dist/hitl/crashConverged.d.ts +1 -1
- package/dist/hitl/crashConverged.js +6 -1
- package/dist/hitl/planReviewWire.js +30 -10
- package/dist/hitl/toolApprovalWire.d.ts +6 -2
- package/dist/hitl/toolApprovalWire.js +30 -0
- package/dist/hooksWireCaps.js +80 -12
- package/dist/index.d.ts +12 -3
- package/dist/index.js +8 -3
- package/dist/pluginHooksWire.d.ts +46 -4
- package/dist/pluginHooksWire.js +277 -24
- package/dist/promptDelivery.d.ts +20 -0
- package/dist/promptDelivery.js +153 -0
- package/dist/providerRejection.d.ts +6 -0
- package/dist/providerRejection.js +52 -0
- package/dist/registryConflict.d.ts +3 -0
- package/dist/registryConflict.js +44 -0
- package/dist/request/taskRequest.d.ts +3 -0
- package/dist/request/taskRequest.js +64 -8
- package/dist/resumeRefusalCopy.d.ts +7 -0
- package/dist/resumeRefusalCopy.js +45 -1
- package/dist/runTerminal.d.ts +6 -0
- package/dist/runTerminal.js +23 -0
- package/dist/seam.d.ts +4 -0
- package/dist/seatContract.d.ts +9 -1
- package/dist/seatContract.js +10 -0
- package/dist/sessionMemoryErase.d.ts +76 -0
- package/dist/sessionMemoryErase.js +432 -0
- package/dist/subagent/engineSubagentResume.js +2 -1
- package/dist/subagent/engineSubagentSteer.d.ts +8 -1
- package/dist/subagent/engineSubagentSteer.js +26 -3
- package/docs/INTEGRATION-CLIENTS.md +767 -14
- package/package.json +3 -3
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { activeRunBusySignal } from './adapter/runStream.js';
|
|
2
|
+
import { selfHealSubmissionDisposition } from './adapter/activeRunSelfHeal.js';
|
|
3
|
+
const uuidOk = (u) => typeof u === 'string' && u.length > 0;
|
|
4
|
+
function cleanBatch(batch) {
|
|
5
|
+
if (!Array.isArray(batch))
|
|
6
|
+
return [];
|
|
7
|
+
const out = [];
|
|
8
|
+
const seen = new Set();
|
|
9
|
+
try {
|
|
10
|
+
for (const u of batch) {
|
|
11
|
+
if (!uuidOk(u) || seen.has(u))
|
|
12
|
+
continue;
|
|
13
|
+
seen.add(u);
|
|
14
|
+
out.push(u);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
function readRecord(rec) {
|
|
23
|
+
if (typeof rec !== 'object' || rec === null || Array.isArray(rec))
|
|
24
|
+
return undefined;
|
|
25
|
+
try {
|
|
26
|
+
const u = rec.u;
|
|
27
|
+
const s = rec.s;
|
|
28
|
+
return uuidOk(u) && (s === 'a' || s === 'd') ? { u, s } : undefined;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const PRE_RUN_FRAME_TYPES = new Set(['meta', 'approval_request', 'approval_revoke']);
|
|
35
|
+
function frameProvesDelivery(event) {
|
|
36
|
+
if (typeof event !== 'object' || event === null || Array.isArray(event))
|
|
37
|
+
return false;
|
|
38
|
+
try {
|
|
39
|
+
const type = event.type;
|
|
40
|
+
if (typeof type !== 'string' || type.length === 0 || PRE_RUN_FRAME_TYPES.has(type))
|
|
41
|
+
return false;
|
|
42
|
+
if (type === 'done') {
|
|
43
|
+
const result = event.result;
|
|
44
|
+
if (typeof result === 'object' && result !== null && !Array.isArray(result) && result.status === undefined) {
|
|
45
|
+
const r = result;
|
|
46
|
+
if (activeRunBusySignal({ type: 'failed', errorCode: r.errorCode, activeTaskId: r.activeTaskId }) !== null)
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return activeRunBusySignal(event) === null;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function outcomeProvesDelivery(outcome) {
|
|
57
|
+
if (typeof outcome !== 'object' || outcome === null || Array.isArray(outcome))
|
|
58
|
+
return false;
|
|
59
|
+
try {
|
|
60
|
+
return selfHealSubmissionDisposition(outcome) === 'handed-off';
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function createPromptDeliveryLedger() {
|
|
67
|
+
const attemptedSet = new Set();
|
|
68
|
+
const deliveredSet = new Set();
|
|
69
|
+
const batchOfMap = new Map();
|
|
70
|
+
const log = [];
|
|
71
|
+
const add = (u, s, into) => {
|
|
72
|
+
const set = s === 'a' ? attemptedSet : deliveredSet;
|
|
73
|
+
if (set.has(u))
|
|
74
|
+
return;
|
|
75
|
+
set.add(u);
|
|
76
|
+
const rec = Object.freeze({ u, s });
|
|
77
|
+
log.push(rec);
|
|
78
|
+
into.push(rec);
|
|
79
|
+
};
|
|
80
|
+
const markDelivered = (batchUuids) => {
|
|
81
|
+
const added = [];
|
|
82
|
+
for (const u of cleanBatch(batchUuids))
|
|
83
|
+
add(u, 'd', added);
|
|
84
|
+
return Object.freeze(added);
|
|
85
|
+
};
|
|
86
|
+
return Object.freeze({
|
|
87
|
+
attempted(batchUuids) {
|
|
88
|
+
const batch = Object.freeze(cleanBatch(batchUuids));
|
|
89
|
+
const added = [];
|
|
90
|
+
for (const u of batch) {
|
|
91
|
+
batchOfMap.set(u, batch);
|
|
92
|
+
add(u, 'a', added);
|
|
93
|
+
}
|
|
94
|
+
return Object.freeze(added);
|
|
95
|
+
},
|
|
96
|
+
deliveredByFrame(batchUuids, event) {
|
|
97
|
+
return frameProvesDelivery(event) ? markDelivered(batchUuids) : Object.freeze([]);
|
|
98
|
+
},
|
|
99
|
+
deliveredBySteerReceipt(batchUuids, outcome) {
|
|
100
|
+
return outcomeProvesDelivery(outcome) ? markDelivered(batchUuids) : Object.freeze([]);
|
|
101
|
+
},
|
|
102
|
+
isAttempted: (uuid) => uuidOk(uuid) && attemptedSet.has(uuid),
|
|
103
|
+
isDelivered: (uuid) => uuidOk(uuid) && deliveredSet.has(uuid),
|
|
104
|
+
knownUndelivered: (uuid) => uuidOk(uuid) && attemptedSet.has(uuid) && !deliveredSet.has(uuid),
|
|
105
|
+
batchOf: (uuid) => (uuidOk(uuid) ? batchOfMap.get(uuid) : undefined),
|
|
106
|
+
toRecords: () => Object.freeze([...log]),
|
|
107
|
+
fromRecords(records) {
|
|
108
|
+
const added = [];
|
|
109
|
+
if (!Array.isArray(records))
|
|
110
|
+
return Object.freeze(added);
|
|
111
|
+
let list;
|
|
112
|
+
try {
|
|
113
|
+
list = [...records];
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return Object.freeze(added);
|
|
117
|
+
}
|
|
118
|
+
for (const raw of list) {
|
|
119
|
+
const rec = readRecord(raw);
|
|
120
|
+
if (rec !== undefined)
|
|
121
|
+
add(rec.u, rec.s, added);
|
|
122
|
+
}
|
|
123
|
+
return Object.freeze(added);
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function uuidOfMessage(m) {
|
|
128
|
+
if (typeof m !== 'object' || m === null)
|
|
129
|
+
return undefined;
|
|
130
|
+
try {
|
|
131
|
+
const u = m.uuid;
|
|
132
|
+
return uuidOk(u) ? u : undefined;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function assertLedger(ledger, fn) {
|
|
139
|
+
if (typeof ledger !== 'object' || ledger === null || typeof ledger.knownUndelivered !== 'function') {
|
|
140
|
+
throw new TypeError(`${fn}: the first argument must be a ledger from createPromptDeliveryLedger()`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
export function promptKnownUndelivered(ledger, message) {
|
|
144
|
+
assertLedger(ledger, 'promptKnownUndelivered');
|
|
145
|
+
const u = uuidOfMessage(message);
|
|
146
|
+
return u !== undefined && ledger.knownUndelivered(u);
|
|
147
|
+
}
|
|
148
|
+
export function withoutUndeliveredPrompts(ledger, messages) {
|
|
149
|
+
assertLedger(ledger, 'withoutUndeliveredPrompts');
|
|
150
|
+
if (!Array.isArray(messages))
|
|
151
|
+
return [];
|
|
152
|
+
return messages.filter((m) => !promptKnownUndelivered(ledger, m));
|
|
153
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type RunTerminalFailureDetail } from './runTerminal.js';
|
|
2
|
+
export interface ProviderRejectionResend {
|
|
3
|
+
resend: 'edit_and_resend' | 'not_by_editing';
|
|
4
|
+
text: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function providerRejectionResend(detail: RunTerminalFailureDetail | null | undefined): ProviderRejectionResend | undefined;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { readRunTerminal } from './runTerminal.js';
|
|
2
|
+
const PROVIDER_STATUS_TIERS = Object.freeze([
|
|
3
|
+
Object.freeze([400, 400, 'invalid_request']),
|
|
4
|
+
Object.freeze([401, 401, 'authentication_failed']),
|
|
5
|
+
Object.freeze([403, 403, 'authentication_failed']),
|
|
6
|
+
Object.freeze([404, 404, 'model_not_found']),
|
|
7
|
+
Object.freeze([413, 413, 'invalid_request']),
|
|
8
|
+
Object.freeze([422, 422, 'invalid_request']),
|
|
9
|
+
Object.freeze([429, 429, 'rate_limit']),
|
|
10
|
+
Object.freeze([500, 599, 'server_error']),
|
|
11
|
+
]);
|
|
12
|
+
const UNTIERED = 'unknown';
|
|
13
|
+
function providerStatusTier(status) {
|
|
14
|
+
for (const [lo, hi, tier] of PROVIDER_STATUS_TIERS)
|
|
15
|
+
if (status >= lo && status <= hi)
|
|
16
|
+
return tier;
|
|
17
|
+
return UNTIERED;
|
|
18
|
+
}
|
|
19
|
+
const EDITABLE_TIER = 'invalid_request';
|
|
20
|
+
const NOT_BY_EDITING_TAIL = new Map([
|
|
21
|
+
['authentication_failed', ': check the provider credentials or access for this account.'],
|
|
22
|
+
['model_not_found', ': the model is not available from this provider — choose another model.'],
|
|
23
|
+
['rate_limit', ': the provider is rate-limiting this account — wait and try again.'],
|
|
24
|
+
['server_error', ': the provider reported an internal error — try again later.'],
|
|
25
|
+
[UNTIERED, ' for a reason that editing it will not fix — check the provider account or try again later.'],
|
|
26
|
+
]);
|
|
27
|
+
const PROVIDER_REJECTED = 'provider_rejected';
|
|
28
|
+
export function providerRejectionResend(detail) {
|
|
29
|
+
let read;
|
|
30
|
+
try {
|
|
31
|
+
const r = readRunTerminal({ terminal: { kind: 'failed', detail } });
|
|
32
|
+
read = r !== null && r.kind === 'failed' && Object.hasOwn(r, 'detail') ? r.detail : undefined;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
if (read === undefined || !Object.hasOwn(read, 'kind') || read.kind !== PROVIDER_REJECTED)
|
|
38
|
+
return undefined;
|
|
39
|
+
const status = Object.hasOwn(read, 'status') ? read.status : undefined;
|
|
40
|
+
if (status === undefined)
|
|
41
|
+
return undefined;
|
|
42
|
+
const tier = providerStatusTier(status);
|
|
43
|
+
return tier === EDITABLE_TIER
|
|
44
|
+
? {
|
|
45
|
+
resend: 'edit_and_resend',
|
|
46
|
+
text: `The model provider rejected this request as sent (HTTP ${status}). Change it — for example shorten it or remove an attachment — and send it again.`,
|
|
47
|
+
}
|
|
48
|
+
: {
|
|
49
|
+
resend: 'not_by_editing',
|
|
50
|
+
text: `The model provider refused this request (HTTP ${status})${NOT_BY_EDITING_TAIL.get(tier) ?? NOT_BY_EDITING_TAIL.get(UNTIERED) ?? ''}`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const SCOPE_GONE_CODE = 'scope_gone';
|
|
2
|
+
const nonBlank = (v) => {
|
|
3
|
+
const s = typeof v === 'string' ? v.trim() : '';
|
|
4
|
+
return s === '' ? undefined : s;
|
|
5
|
+
};
|
|
6
|
+
export function classifyRegistryConflict(status, body) {
|
|
7
|
+
if (status !== 409)
|
|
8
|
+
return 'none';
|
|
9
|
+
try {
|
|
10
|
+
const b = (typeof body === 'object' && body !== null ? body : {});
|
|
11
|
+
const error = b.error;
|
|
12
|
+
const objectForm = typeof error === 'object' && error !== null ? error.code : undefined;
|
|
13
|
+
const code = nonBlank(b.errorCode) ?? nonBlank(objectForm) ?? (typeof error === 'string' ? error : undefined);
|
|
14
|
+
return code === SCOPE_GONE_CODE ? 'gone' : 'conflict';
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return 'gone';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const SCOPE_GONE_ERROR_NAMES = Object.freeze(['ScopeGoneError', 'ControlScopeGoneError']);
|
|
21
|
+
export function isScopeGoneError(err) {
|
|
22
|
+
if ((typeof err !== 'object' && typeof err !== 'function') || err === null)
|
|
23
|
+
return false;
|
|
24
|
+
let status;
|
|
25
|
+
try {
|
|
26
|
+
status = err.status;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (status !== 409)
|
|
32
|
+
return false;
|
|
33
|
+
try {
|
|
34
|
+
const o = err;
|
|
35
|
+
const body = o.body;
|
|
36
|
+
if (body !== undefined && body !== null && classifyRegistryConflict(409, body) === 'gone')
|
|
37
|
+
return true;
|
|
38
|
+
const name = o.name;
|
|
39
|
+
return typeof name === 'string' && SCOPE_GONE_ERROR_NAMES.includes(name);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -50,6 +50,8 @@ export interface TaskRequestInput {
|
|
|
50
50
|
memory?: 'off';
|
|
51
51
|
fileHistory?: 'disabled';
|
|
52
52
|
inheritEnv?: InheritEnvWord;
|
|
53
|
+
requireExistingSession?: TaskRequest['requireExistingSession'];
|
|
54
|
+
disableSkills?: true;
|
|
53
55
|
rewind?: Record<string, unknown>;
|
|
54
56
|
repo?: string;
|
|
55
57
|
council?: boolean;
|
|
@@ -73,6 +75,7 @@ export interface TaskRequestOmission {
|
|
|
73
75
|
export declare function taskRequestOmissionCauseDetail(cause: unknown): string;
|
|
74
76
|
export declare const TASK_REQUEST_OMISSION_CAUSE_NOTICES: Readonly<Record<TaskRequestOmissionCause, string>>;
|
|
75
77
|
export declare function taskRequestOmissionCauseNotice(cause: unknown): string;
|
|
78
|
+
export declare function taskRequestOmissionCausePhrase(cause: unknown): string;
|
|
76
79
|
export interface TaskRequestAssembly {
|
|
77
80
|
readonly request: TaskRequestLike;
|
|
78
81
|
readonly omitted: readonly TaskRequestOmission[];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { refuseBadDisableSkills, refuseDisableSkillsConflict } from '../disableSkillsWire.js';
|
|
1
2
|
export const REQUEST_FIELD_MATRIX = [
|
|
2
3
|
{ field: 'objective', lanes: ['interactive', 'print', 'utility'], live: false, why: '本 turn 的真实输入,每条车道都必需', whyUtilityLane: '恒座:三条车道都必须带上本次提交的模型面输入' },
|
|
3
4
|
{ field: 'sessionId', lanes: ['interactive', 'print', 'utility'], live: false, why: '单命名空间(TP-A Step 2):壳 id 即引擎 session id;print 在非 live 下保留 mock 常量', whyUtilityLane: '恒座:side-channel 提交走**独立**会话 id(壳另铸一个,绝不复用用户会话那一个 —— 复用会把这次提交的转录混进用户会话)' },
|
|
@@ -24,6 +25,8 @@ export const REQUEST_FIELD_MATRIX = [
|
|
|
24
25
|
{ field: 'memory', lanes: ['interactive', 'print', 'utility'], live: true, why: '这一次运行不挂记忆面的**请求级**开关(server §12.7 body 键,单成员闭集 "off");每条车道都是提交面 ⇒ 都能声明。与 memoryCapture(采集面)不是一个轴、可并存;与 memoryWrite:false(只读平面)也不是一个轴', whyUtilityLane: '有座:side-channel 提交不需要挂记忆面(不挂记忆段 / 索引 / 三只记忆工具),省 token 且零记忆写入;与 memoryCapture 不是一个轴,两条都带' },
|
|
25
26
|
{ field: 'fileHistory', lanes: ['interactive', 'print'], live: true, why: '「这一次运行别捕获文件历史」的**请求级声明**(server 7.104.0 提交体键,单成员闭集 "disabled";`POST /v1/tasks` · `/v1/tasks/stream` · `/v1/runs` 同收,子代继承)。两条用户车道都是提交面、都跑在用户的文件上 ⇒ 都能声明;「本会话不捕获」= 每个提交都带(续跑腿重放同一个体)。🔴 只在能力读数 `on-optional` 时发(老 server 对表外键 400),值由片段口 `fileHistoryDeclarationField` 唯一铸出。与 rewind 还原键同交 ⇒ 上游 400 `request.field_conflict`', whyUtilityLane: '无座:side-channel 强制零工具面(`excludeAllTools`),不会改任何文件 ⇒ 没有可捕获的东西;带上它只会在不认识这一键的老 server 上给这条提交多一种 400' },
|
|
26
27
|
{ field: 'inheritEnv', lanes: ['interactive', 'print'], live: true, why: '模型驱动的宿主 shell「继承多少用户环境」的**请求级声明**(server 7.106.0 提交体键,两词闭集 "all" / "scrub";`POST /v1/tasks` · `/v1/tasks/stream` · `/v1/runs` 同收,续跑腿重放同判)。两条用户车道都是提交面、都可能在用户机器上跑 shell ⇒ 都能声明。本层两词原样透传、不按车道 / 部署预判(非 host 车道 × "all" 400、托管 × "all" 422 归上游判)。🔴 缺席 = 缺省清洗且清掉本会话上一条声明 ⇒ 要「本会话整份继承」就每个提交都带。🔴 只在服务端版本 ≥ 7.106.0 时发(老 server 对表外键整条 400),值由片段口 `inheritEnvDeclaration` 唯一铸出', whyUtilityLane: '无座:side-channel 强制零工具面(`excludeAllTools`),没有模型驱动的 shell 去继承环境;带上它只会在不认这一键的老服务端上给这条提交多一种 400' },
|
|
28
|
+
{ field: 'requireExistingSession', lanes: ['interactive', 'print'], live: true, why: '「只续已有会话」的**请求级断言**(sdk `TaskRequest.requireExistingSession`):`true` 且会话不在 ⇒ 服务端在任何东西跑起来之前拒(会话不在 / 没给会话 id 两形),而**不是**静默新开一个同 id 的空会话;缺席 / `false` = 历史的「找不到就新开」。两条用户车道都有「续某个会话」的入口 ⇒ 都能声明。本层只认字面 `true`(`false` 与缺席同义、不发);非布尔坏值响亮拒(上游对它 400);`true` 而入参没有可续的会话 id ⇒ 装配期按名响亮拒,不留给上游。上游两形的拒绝经 `requireExistingSessionRefusalFromError` 归成一句', whyUtilityLane: '无座:side-channel 每一次提交都走壳另铸的**独立**会话 id(见 sessionId 那一行),从不续任何已有会话 ⇒「必须已存在」对它没有意义,带上去只会让每一次提交都被拒' },
|
|
29
|
+
{ field: 'disableSkills', lanes: ['interactive', 'print'], live: true, why: '「这一发一只技能都不装」的**请求级声明**(出厂技能、调用方给的技能、子代定义里的技能一个都不进引擎;其余工具照挂 —— 与 excludeAllTools 是两件事,两键同带各自生效)。两条用户车道都是提交面 ⇒ 都能声明。本层只认字面 true(false 与缺席同义、不发);非布尔坏值响亮拒(上游对它 400);与非空 skills 或任一非空 agents[].skills 同在 ⇒ 装配期按名响亮拒(上游对这一组合 400),兜底层落 agents 之后同判。🔴 只在能力位读数为真时发(老服务端对表外键整条 400),值由片段口 disableSkillsDeclaration 唯一铸出', whyUtilityLane: '无座:同 skills 一行 —— side-channel 是零工具面,装不装技能都无从谈起' },
|
|
27
30
|
{ field: 'finalVerification', lanes: ['print'], live: true, why: 'P1-1 终验:无人值守车道才需要引擎自证;交互 REPL 由人当场看结果。#106 裁 B(让位+告知)后交互面默认关', whyUtilityLane: '无座:终验让引擎再跑一轮自证,而 side-channel 要的是一次小提交的即时答案;「无人值守才需要引擎自证」这条理由在本车道上让位给「小预算优先」' },
|
|
28
31
|
{ field: 'limits', lanes: ['print', 'utility'], live: true, why: 'P2-3-b:`-p` 的预算护栏(--max-* flag 族),交互 REPL 由人随时 Esc', whyUtilityLane: '有座:side-channel 必须带预算护栏(墙钟 / 输出 token / 轮数)—— 它同样没有人看着,而且没有后续回合可以中断' },
|
|
29
32
|
{ field: 'interactiveTools', lanes: ['print', 'utility'], live: true, why: '[909]B 件3:无人值守 stamp false,从 roster 源头灭掉 AskUserQuestion/plan 门。交互车道 stamp false 等于自废武功', whyUtilityLane: '有座:side-channel 绝不该弹交互问答 / plan 门(没有人在看这条提交)。它与 excludeAllTools 是**两条独立**的收紧声明、在这条车道上**并存**(本车道强制带卸载声明,见 `refuseUtilityWithoutToolUnload`;这一位是它旁边那条「连问都别问」的声明,不是它的降级替身)' },
|
|
@@ -75,18 +78,40 @@ export function taskRequestOmissionCauseDetail(cause) {
|
|
|
75
78
|
const word = typeof cause === 'string' && cause.length > 0 ? cause : '(none)';
|
|
76
79
|
return `a cause this build does not know (${word}) — this build does not know this cause: receipt causes come from this build's own frozen vocabulary, so a word outside it was not produced here; check whatever supplied it`;
|
|
77
80
|
}
|
|
78
|
-
|
|
79
|
-
upstream_absent:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
const TASK_REQUEST_OMISSION_CAUSE_NOTICE_PARTS = Object.freeze({
|
|
82
|
+
upstream_absent: {
|
|
83
|
+
lead: 'Not sent with this request',
|
|
84
|
+
reason: 'this version has no way to send this setting in any request, so giving it or leaving it out makes no difference to what is sent',
|
|
85
|
+
},
|
|
86
|
+
other_channel: {
|
|
87
|
+
lead: 'Not sent from here',
|
|
88
|
+
reason: 'that part of the request belongs to a separate step, so what goes out for it, if anything, is decided there rather than by the value given here',
|
|
89
|
+
},
|
|
90
|
+
off_lane: {
|
|
91
|
+
lead: 'Not sent with this request',
|
|
92
|
+
reason: 'this kind of request does not carry this setting, so giving it or leaving it out makes no difference to what this request sends',
|
|
93
|
+
},
|
|
94
|
+
not_live: {
|
|
95
|
+
lead: 'Not sent with this request',
|
|
96
|
+
reason: 'the request was marked as not going to a live engine (for example an offline or test run), and this setting is only sent on requests that go to one',
|
|
97
|
+
},
|
|
83
98
|
});
|
|
84
|
-
const
|
|
99
|
+
const TASK_REQUEST_OMISSION_UNKNOWN_CAUSE_LEAD = 'Not sent with this request';
|
|
100
|
+
const TASK_REQUEST_OMISSION_UNKNOWN_CAUSE_REASON = 'for a reason this version does not recognize';
|
|
101
|
+
const wholeOmissionNotice = (p) => `${p.lead}: ${p.reason}.`;
|
|
102
|
+
export const TASK_REQUEST_OMISSION_CAUSE_NOTICES = Object.freeze(Object.fromEntries(TASK_REQUEST_OMISSION_CAUSES.map((cause) => [cause, wholeOmissionNotice(TASK_REQUEST_OMISSION_CAUSE_NOTICE_PARTS[cause])])));
|
|
103
|
+
const TASK_REQUEST_OMISSION_UNKNOWN_CAUSE_NOTICE = `${TASK_REQUEST_OMISSION_UNKNOWN_CAUSE_LEAD}, ${TASK_REQUEST_OMISSION_UNKNOWN_CAUSE_REASON}.`;
|
|
104
|
+
const omissionNoticePartsOf = (cause) => typeof cause === 'string' && Object.hasOwn(TASK_REQUEST_OMISSION_CAUSE_NOTICE_PARTS, cause)
|
|
105
|
+
? TASK_REQUEST_OMISSION_CAUSE_NOTICE_PARTS[cause]
|
|
106
|
+
: undefined;
|
|
85
107
|
export function taskRequestOmissionCauseNotice(cause) {
|
|
86
|
-
return
|
|
108
|
+
return omissionNoticePartsOf(cause) !== undefined
|
|
87
109
|
? TASK_REQUEST_OMISSION_CAUSE_NOTICES[cause]
|
|
88
110
|
: TASK_REQUEST_OMISSION_UNKNOWN_CAUSE_NOTICE;
|
|
89
111
|
}
|
|
112
|
+
export function taskRequestOmissionCausePhrase(cause) {
|
|
113
|
+
return omissionNoticePartsOf(cause)?.reason ?? TASK_REQUEST_OMISSION_UNKNOWN_CAUSE_REASON;
|
|
114
|
+
}
|
|
90
115
|
const row = (field) => ({ via: 'matrix', field });
|
|
91
116
|
const INPUT_KEY_ROUTES = {
|
|
92
117
|
objective: { via: 'always' },
|
|
@@ -139,6 +164,8 @@ const INPUT_KEY_ROUTES = {
|
|
|
139
164
|
memory: row('memory'),
|
|
140
165
|
fileHistory: row('fileHistory'),
|
|
141
166
|
inheritEnv: row('inheritEnv'),
|
|
167
|
+
requireExistingSession: row('requireExistingSession'),
|
|
168
|
+
disableSkills: row('disableSkills'),
|
|
142
169
|
rewind: row('resumeAt/resumeAtMode/restoreFiles/rewindFilesTo'),
|
|
143
170
|
repo: row('repo'),
|
|
144
171
|
council: row('council'),
|
|
@@ -211,6 +238,8 @@ const VALUE_LEVEL_IN_PLAY = Object.freeze({
|
|
|
211
238
|
memoryCapture: (v) => v === 'off',
|
|
212
239
|
memory: (v) => v === 'off',
|
|
213
240
|
fileHistory: (v) => v === FILE_HISTORY_DISABLED,
|
|
241
|
+
requireExistingSession: (v) => v === true,
|
|
242
|
+
disableSkills: (v) => v === true,
|
|
214
243
|
rewind: (v) => typeof v === 'object' && v !== null && rewindSubKeys().some((k) => hasOwn(v, k) && present(v[k])),
|
|
215
244
|
});
|
|
216
245
|
const inPlay = (key, v) => present(v) && (VALUE_LEVEL_IN_PLAY[key]?.(v) ?? true);
|
|
@@ -454,6 +483,22 @@ const refuseBadInheritEnv = (v) => {
|
|
|
454
483
|
'这一位是「模型驱动的宿主 shell 继承多少用户环境」的两词闭集声明,上游对词表外的值响亮拒;环境变量名单不是请求值。' +
|
|
455
484
|
'本层若静默删键,这一次运行会按缺省清洗跑、还清掉本会话上一条声明,而声明人不会知道。错误文本只报形状,不回显值。');
|
|
456
485
|
};
|
|
486
|
+
const refuseBadRequireExistingSession = (v) => {
|
|
487
|
+
if (v === undefined || v === null || v === true || v === false)
|
|
488
|
+
return;
|
|
489
|
+
throw new TypeError(`buildTaskRequest: requireExistingSession 只接受布尔或缺席(undefined/null)—— 收到 ${coarseShape(v)}。` +
|
|
490
|
+
'这一位是「只续已有会话、找不到就失败」的收紧断言:本层若把坏值折成缺席,这一次提交在会话不在时会静默新开一个空会话 —— 正是这一键要挡的那一形;' +
|
|
491
|
+
'上游对非布尔值同样拒收。错误文本只报形状,不回显值。');
|
|
492
|
+
};
|
|
493
|
+
const hasResumableSessionId = (sid) => typeof sid === 'string' && sid.length > 0;
|
|
494
|
+
const refuseRequireExistingWithoutSession = (requireExisting, sessionId) => {
|
|
495
|
+
if (requireExisting !== true || hasResumableSessionId(sessionId))
|
|
496
|
+
return;
|
|
497
|
+
const shape = sessionId === undefined ? '缺席' : typeof sessionId === 'string' ? '空串' : coarseShape(sessionId);
|
|
498
|
+
throw new TypeError(`buildTaskRequest: requireExistingSession: true 要求续一个已存在的会话,但 sessionId ${shape} —— 没有可续的会话。` +
|
|
499
|
+
'上游对这一形同样拒收(不会新开会话,也不会续上任何东西);本层在装配前拒,不让它走一次往返。' +
|
|
500
|
+
'处置:要续哪个会话,就把它的 id 交在 sessionId 上;要开新会话,就别带 requireExistingSession(或给 false)。错误文本只报形状,不回显值。');
|
|
501
|
+
};
|
|
457
502
|
const refuseBadMaxTokens = (v) => {
|
|
458
503
|
if (v === undefined || v === null)
|
|
459
504
|
return;
|
|
@@ -523,7 +568,7 @@ export function parseMaxCostUsd(text) {
|
|
|
523
568
|
return { ok: false, why: 'not_positive' };
|
|
524
569
|
return { ok: true, value };
|
|
525
570
|
}
|
|
526
|
-
const ACCESSOR_READ_ORDER = ['live', 'memoryCapture', 'memory', 'settings', 'maxCostUsd', 'excludeAllTools', 'maxTokens', 'outputRetries', 'fileHistory', 'inheritEnv'];
|
|
571
|
+
const ACCESSOR_READ_ORDER = ['live', 'memoryCapture', 'memory', 'settings', 'maxCostUsd', 'excludeAllTools', 'maxTokens', 'outputRetries', 'fileHistory', 'inheritEnv', 'requireExistingSession', 'disableSkills'];
|
|
527
572
|
function dataFirstSnapshot(input, afterData) {
|
|
528
573
|
let descs;
|
|
529
574
|
try {
|
|
@@ -592,6 +637,8 @@ export function assembleTaskRequest(input, lane) {
|
|
|
592
637
|
const outputRetriesIn = src.outputRetries;
|
|
593
638
|
const fileHistoryIn = src.fileHistory;
|
|
594
639
|
const inheritEnvIn = src.inheritEnv;
|
|
640
|
+
const requireExistingSessionIn = src.requireExistingSession;
|
|
641
|
+
const disableSkillsIn = src.disableSkills;
|
|
595
642
|
const INPUT_KEYS = Object.keys(INPUT_KEY_ROUTES);
|
|
596
643
|
const i = snapshotByName(src, INPUT_KEYS, {
|
|
597
644
|
live,
|
|
@@ -603,6 +650,8 @@ export function assembleTaskRequest(input, lane) {
|
|
|
603
650
|
outputRetries: outputRetriesIn,
|
|
604
651
|
fileHistory: fileHistoryIn,
|
|
605
652
|
inheritEnv: inheritEnvIn,
|
|
653
|
+
requireExistingSession: requireExistingSessionIn,
|
|
654
|
+
disableSkills: disableSkillsIn,
|
|
606
655
|
settings: settingsIn,
|
|
607
656
|
});
|
|
608
657
|
const SETTINGS_KEYS = Object.keys(SETTINGS_KEY_ROUTES);
|
|
@@ -615,6 +664,8 @@ export function assembleTaskRequest(input, lane) {
|
|
|
615
664
|
refuseBadOutputRetries(outputRetriesIn);
|
|
616
665
|
refuseBadFileHistory(fileHistoryIn);
|
|
617
666
|
refuseBadInheritEnv(inheritEnvIn);
|
|
667
|
+
refuseBadRequireExistingSession(requireExistingSessionIn);
|
|
668
|
+
refuseBadDisableSkills(disableSkillsIn, 'buildTaskRequest');
|
|
618
669
|
const rewindRoute = INPUT_KEY_ROUTES.rewind;
|
|
619
670
|
const RETIRED_REWIND_FILES_KEY = 'rewindFiles';
|
|
620
671
|
const REWIND_KEYS = rewindRoute.via === 'matrix' ? rewindRoute.field.split('/') : [];
|
|
@@ -698,6 +749,8 @@ export function assembleTaskRequest(input, lane) {
|
|
|
698
749
|
'想问某个键有没有座 ⇒ taskRequestSeatOf(key, lane)。`settings` 快照里的开放集子键放进 settings.resolved。' +
|
|
699
750
|
'错误文本只报键名,不回显值。');
|
|
700
751
|
}
|
|
752
|
+
refuseRequireExistingWithoutSession(requireExistingSessionIn, i.sessionId);
|
|
753
|
+
refuseDisableSkillsConflict(disableSkillsIn, i.skills, Reflect.get(src, 'agents'), 'buildTaskRequest');
|
|
701
754
|
refuseUtilityWithoutToolUnload(lane, excludeAllToolsIn);
|
|
702
755
|
const carries = (route, value, key) => {
|
|
703
756
|
if (route.via === 'always')
|
|
@@ -772,6 +825,8 @@ export function assembleTaskRequest(input, lane) {
|
|
|
772
825
|
...(on('memory') ? { memory: 'off' } : {}),
|
|
773
826
|
...(on('fileHistory') ? { fileHistory: FILE_HISTORY_DISABLED } : {}),
|
|
774
827
|
...(on('inheritEnv') ? { inheritEnv: inheritEnvIn } : {}),
|
|
828
|
+
...(on('requireExistingSession') ? { requireExistingSession: true } : {}),
|
|
829
|
+
...(on('disableSkills') ? { disableSkills: true } : {}),
|
|
775
830
|
...(Object.keys(settingsOut).length > 0 ? { settings: settingsOut } : {}),
|
|
776
831
|
};
|
|
777
832
|
return Object.freeze({ request: out, omitted: Object.freeze([...omitted, ...lateOmitted]) });
|
|
@@ -795,6 +850,7 @@ export function applyLiveRequestDefaults(req, host) {
|
|
|
795
850
|
out.retainSubagentSessions = true;
|
|
796
851
|
if (out.agents === undefined && host.agents !== undefined)
|
|
797
852
|
out.agents = host.agents;
|
|
853
|
+
refuseDisableSkillsConflict(out.disableSkills, out.skills, out.agents, 'applyLiveRequestDefaults');
|
|
798
854
|
if (typeof out.scenario === 'string' && host.mockScenarioKeys?.has(out.scenario)) {
|
|
799
855
|
delete out.scenario;
|
|
800
856
|
}
|
|
@@ -21,6 +21,13 @@ export declare function resumePolicyBlockFromError(err: unknown): ResumePolicyBl
|
|
|
21
21
|
export declare function resumePolicyBlockContent(detail: ResumePolicyBlockDetail): string;
|
|
22
22
|
export { resumeReopenFromError, resumeReopenContent } from './hitl/suspendedReopen.js';
|
|
23
23
|
export type { ResumeReopenDetail } from './hitl/suspendedReopen.js';
|
|
24
|
+
export type RequireExistingSessionRefusalForm = 'session_not_found' | 'session_id_missing';
|
|
25
|
+
export interface RequireExistingSessionRefusalDetail {
|
|
26
|
+
readonly code: string;
|
|
27
|
+
readonly form: RequireExistingSessionRefusalForm;
|
|
28
|
+
}
|
|
29
|
+
export declare function requireExistingSessionRefusalFromError(err: unknown): RequireExistingSessionRefusalDetail | null;
|
|
30
|
+
export declare function requireExistingSessionRefusalContent(detail: Pick<RequireExistingSessionRefusalDetail, 'form'>): string;
|
|
24
31
|
export interface ResumeContextUnavailableDetail {
|
|
25
32
|
code: typeof RESUME_CONTEXT_UNAVAILABLE;
|
|
26
33
|
staleAfterSec?: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readErrorNumber, readErrorString } from './wireFailureShape.js';
|
|
2
|
-
import { RESUME_CONTEXT_UNAVAILABLE, RESUME_PLACEMENT_MISMATCH, RESUME_PREFLIGHT_REJECTED, RESUME_POLICY_FOLD_CODE, PARKED_RESUME_STARTUP_FAILED, isStatusDerivedCoarseCode, } from './engineErrorCodes.js';
|
|
2
|
+
import { RESUME_CONTEXT_UNAVAILABLE, RESUME_PLACEMENT_MISMATCH, RESUME_PREFLIGHT_REJECTED, RESUME_POLICY_FOLD_CODE, PARKED_RESUME_STARTUP_FAILED, isStatusDerivedCoarseCode, RESUME_SESSION_NOT_FOUND, } from './engineErrorCodes.js';
|
|
3
3
|
import { capForDisplay } from './fleetTaskDesc.js';
|
|
4
4
|
import { resumeRetryLaterFromError } from './wireErrorTriage.js';
|
|
5
5
|
export const RESUME_REFUSAL_CODES = Object.freeze([
|
|
@@ -86,6 +86,50 @@ export function resumePolicyBlockContent(detail) {
|
|
|
86
86
|
].join(' · ');
|
|
87
87
|
}
|
|
88
88
|
export { resumeReopenFromError, resumeReopenContent } from './hitl/suspendedReopen.js';
|
|
89
|
+
const RESUME_SESSION_NOT_FOUND_TAIL = `(${RESUME_SESSION_NOT_FOUND})`;
|
|
90
|
+
const REQUIRE_EXISTING_BY_STATUS = new Map([
|
|
91
|
+
[404, Object.freeze({ form: 'session_not_found', coarse: 'not_found.resource' })],
|
|
92
|
+
[422, Object.freeze({ form: 'session_id_missing', coarse: 'request.unprocessable' })],
|
|
93
|
+
]);
|
|
94
|
+
export function requireExistingSessionRefusalFromError(err) {
|
|
95
|
+
if (typeof err !== 'object' || err === null)
|
|
96
|
+
return null;
|
|
97
|
+
try {
|
|
98
|
+
const o = err;
|
|
99
|
+
const status = o['status'];
|
|
100
|
+
const byStatus = typeof status === 'number' ? REQUIRE_EXISTING_BY_STATUS.get(status) : undefined;
|
|
101
|
+
if (byStatus === undefined)
|
|
102
|
+
return null;
|
|
103
|
+
const code = o['errorCode'];
|
|
104
|
+
if (code === RESUME_SESSION_NOT_FOUND)
|
|
105
|
+
return Object.freeze({ code: RESUME_SESSION_NOT_FOUND, form: byStatus.form });
|
|
106
|
+
if (code !== byStatus.coarse)
|
|
107
|
+
return null;
|
|
108
|
+
const message = o['message'];
|
|
109
|
+
return typeof message === 'string' && message.endsWith(RESUME_SESSION_NOT_FOUND_TAIL)
|
|
110
|
+
? Object.freeze({ code: RESUME_SESSION_NOT_FOUND, form: byStatus.form })
|
|
111
|
+
: null;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const REQUIRE_EXISTING_SESSION_SENTENCES = Object.freeze({
|
|
118
|
+
session_not_found: 'The engine did not continue this conversation: the conversation it was asked to continue does not exist there (it may have expired, been removed, or never been created on that engine), and this request asked to continue only an existing one, so no new conversation was started · Start a new conversation, or pick another one to continue',
|
|
119
|
+
session_id_missing: 'The engine did not continue this conversation: this request asked to continue only an existing conversation but named none, so there was nothing to continue and no new conversation was started · Name the conversation to continue, or start a new one',
|
|
120
|
+
});
|
|
121
|
+
const REQUIRE_EXISTING_SESSION_GENERIC = 'The engine did not continue this conversation: this request asked to continue only an existing conversation and there was none it could continue, so no new conversation was started · Start a new conversation, or pick another one to continue';
|
|
122
|
+
export function requireExistingSessionRefusalContent(detail) {
|
|
123
|
+
try {
|
|
124
|
+
const form = detail?.form;
|
|
125
|
+
return typeof form === 'string' && Object.hasOwn(REQUIRE_EXISTING_SESSION_SENTENCES, form)
|
|
126
|
+
? REQUIRE_EXISTING_SESSION_SENTENCES[form]
|
|
127
|
+
: REQUIRE_EXISTING_SESSION_GENERIC;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return REQUIRE_EXISTING_SESSION_GENERIC;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
89
133
|
export function resumeContextUnavailableFromError(err) {
|
|
90
134
|
if (typeof err !== 'object' || err === null)
|
|
91
135
|
return null;
|
package/dist/runTerminal.d.ts
CHANGED
|
@@ -11,6 +11,11 @@ export interface RunTerminalPausedRead extends RunTerminalPause {
|
|
|
11
11
|
code?: string;
|
|
12
12
|
flatStatus?: string;
|
|
13
13
|
}
|
|
14
|
+
export interface RunTerminalFailureDetail {
|
|
15
|
+
kind: string;
|
|
16
|
+
status?: number;
|
|
17
|
+
code?: string;
|
|
18
|
+
}
|
|
14
19
|
export type RunTerminalRead = {
|
|
15
20
|
kind: 'completed';
|
|
16
21
|
plane: RunTerminalPlane;
|
|
@@ -20,6 +25,7 @@ export type RunTerminalRead = {
|
|
|
20
25
|
code?: string;
|
|
21
26
|
message?: string;
|
|
22
27
|
nestedPause?: RunTerminalPause;
|
|
28
|
+
detail?: RunTerminalFailureDetail;
|
|
23
29
|
} | {
|
|
24
30
|
kind: 'blocked';
|
|
25
31
|
plane: RunTerminalPlane;
|
package/dist/runTerminal.js
CHANGED
|
@@ -20,6 +20,27 @@ function pauseOf(v) {
|
|
|
20
20
|
...(restoreMode !== undefined ? { restoreMode } : {}),
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
+
const PROVIDER_REJECTED_DETAIL_KIND = 'provider_rejected';
|
|
24
|
+
function failureDetailOf(cause) {
|
|
25
|
+
try {
|
|
26
|
+
const own = (o, k) => (Object.prototype.hasOwnProperty.call(o, k) ? o[k] : undefined);
|
|
27
|
+
const v = own(cause, 'detail');
|
|
28
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
29
|
+
return undefined;
|
|
30
|
+
const kind = str(own(v, 'kind'));
|
|
31
|
+
if (kind === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
const rawStatus = own(v, 'status');
|
|
34
|
+
const status = typeof rawStatus === 'number' && Number.isInteger(rawStatus) && rawStatus >= 100 && rawStatus <= 599 ? rawStatus : undefined;
|
|
35
|
+
if (kind === PROVIDER_REJECTED_DETAIL_KIND && (status === undefined || status < 400))
|
|
36
|
+
return undefined;
|
|
37
|
+
const code = str(own(v, 'code'));
|
|
38
|
+
return { kind, ...(status !== undefined ? { status } : {}), ...(code !== undefined ? { code } : {}) };
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
23
44
|
const FLAT_PAUSED_STATUSES = ['suspended', 'needs_review'];
|
|
24
45
|
export function readRunTerminal(result) {
|
|
25
46
|
if (typeof result !== 'object' || result === null || Array.isArray(result))
|
|
@@ -44,12 +65,14 @@ export function readRunTerminal(result) {
|
|
|
44
65
|
const code = str(c.code);
|
|
45
66
|
const message = str(c.message);
|
|
46
67
|
const nestedPause = c.nestedPause !== undefined ? pauseOf(c.nestedPause) : undefined;
|
|
68
|
+
const detail = failureDetailOf(c);
|
|
47
69
|
return {
|
|
48
70
|
kind: 'failed',
|
|
49
71
|
plane: 'cause',
|
|
50
72
|
...(code !== undefined ? { code } : {}),
|
|
51
73
|
...(message !== undefined ? { message } : {}),
|
|
52
74
|
...(nestedPause !== undefined ? { nestedPause } : {}),
|
|
75
|
+
...(detail !== undefined ? { detail } : {}),
|
|
53
76
|
};
|
|
54
77
|
}
|
|
55
78
|
case 'blocked': {
|
package/dist/seam.d.ts
CHANGED
|
@@ -173,6 +173,10 @@ export interface WiringManifestChromeEvent {
|
|
|
173
173
|
autoConsolidation?: WiringManifestAutoConsolidationView;
|
|
174
174
|
readDeny?: WiringManifestReadDenyView;
|
|
175
175
|
hands?: WiringManifestHandsView;
|
|
176
|
+
fileHistory?: string;
|
|
177
|
+
instructions?: {
|
|
178
|
+
readonly selected: readonly string[];
|
|
179
|
+
};
|
|
176
180
|
eventId?: string;
|
|
177
181
|
}
|
|
178
182
|
export interface TextSegmentCommittedRow {
|
package/dist/seatContract.d.ts
CHANGED
|
@@ -61,6 +61,8 @@ export interface ToolPermissionRequest {
|
|
|
61
61
|
mandate?: ApprovalMandateWord;
|
|
62
62
|
origin?: string;
|
|
63
63
|
ruleOffersAbsence?: string;
|
|
64
|
+
askClass?: string;
|
|
65
|
+
classes?: readonly string[];
|
|
64
66
|
}
|
|
65
67
|
declare const SEAT_EVENT_TYPE_TUPLE: readonly ["start", "close", "session_updated", "message", "stream_event", "chrome_event", "error", "tool_permission_resolved"];
|
|
66
68
|
export type SeatEventType = (typeof SEAT_EVENT_TYPE_TUPLE)[number];
|
|
@@ -261,7 +263,7 @@ export declare const SEAT_METHOD_NAMES: readonly ["start", "sendMessage", "inter
|
|
|
261
263
|
export declare const SEAT_STORE_PROPS: readonly ["sessionsStateStore", "focusedSessionStateStore", "settingsStateStore"];
|
|
262
264
|
export declare const SEAT_EVENT_METHOD_NAMES: readonly ["onEvent", "onToolPermissionRequest"];
|
|
263
265
|
export declare const LOCAL_SESSION_EVENT_KEYS: readonly ["type", "sessionId", "message", "messages", "error", "errorCategory", "code", "request", "data", "sources", "permissionMode", "session", "userMessageUuid", "hasPreClearSession", "requestId", "outcome", "chrome"];
|
|
264
|
-
export declare const TOOL_PERMISSION_REQUEST_KEYS: readonly ["requestId", "sessionId", "toolName", "toolCallId", "input", "message", "toctouBinding", "createdAtMs", "governanceForced", "delegation", "mandated", "mandate", "origin", "ruleOffersAbsence"];
|
|
266
|
+
export declare const TOOL_PERMISSION_REQUEST_KEYS: readonly ["requestId", "sessionId", "toolName", "toolCallId", "input", "message", "toctouBinding", "createdAtMs", "governanceForced", "delegation", "mandated", "mandate", "origin", "ruleOffersAbsence", "askClass", "classes"];
|
|
265
267
|
export declare const LOCAL_SESSION_RECORD_KEYS: readonly ["sessionId", "engineSessionId", "model", "title", "isRunning", "createdAt", "lastActivityAt", "queuedMessages", "parked"];
|
|
266
268
|
export declare const SEND_MESSAGE_REQUEST_KEYS: readonly ["sessionId", "text", "model", "userMessageUuid", "permissionMode", "attachmentIds", "reasoningEffort", "retainBackgroundProcesses", "forwardSubagentEvents", "retainSubagentSessions", "settings", "scenario"];
|
|
267
269
|
export declare const SEAT_SEND_MESSAGE_KEY_ORIGINS: {
|
|
@@ -333,6 +335,12 @@ export declare const SEAT_VALIDATOR_KEY_COVERAGE: {
|
|
|
333
335
|
}, {
|
|
334
336
|
readonly key: "origin";
|
|
335
337
|
readonly why: "喂姿态谓词 askSurvivesPosture 的安全位(CC-203),按开集读(非空串原文字节、词表不校);权威窄读在卡口与过境口 toolPermissionRequestAskBits,座位门不设第二判官(为一个位拒掉整条 request = 把安全 ask 丢给引擎 TTL deny)。坏形的两种失效方向:非串 / 空串读成缺席 ⇒ 宿主报了没命中时姿态谓词可答可以放(放宽方向:真出身若是必问词就丢了);表外串读成不认识的词 ⇒ 答 unknown,宿主退回自己的规则(不放宽)。不经过境口自铸座位请求的宿主要自己按同一把窄读。";
|
|
338
|
+
}, {
|
|
339
|
+
readonly key: "askClass";
|
|
340
|
+
readonly why: "展示位(CC-284),权威成对窄读在卡口与过境口 toolPermissionRequestAskBits(与 classes 同在同缺、首员等于 askClass、不判成员、不重排);座位门不设第二判官,理由同 mandated(为一个展示位拒掉整条 request = 把安全 ask 丢给引擎超时拒)。坏形读成缺席 ⇒ 卡上不显示问类,不改决断;缺席不是「普通问」。不经过境口自铸座位请求的宿主要自己按同一把成对窄读。";
|
|
341
|
+
}, {
|
|
342
|
+
readonly key: "classes";
|
|
343
|
+
readonly why: "与 askClass 同一对(CC-284),同在同缺、同一只成对窄读(非空、每员非空串、无重复、首员等于 askClass;开集、原样顺序);座位门不设第二判官,理由同 askClass。";
|
|
336
344
|
}, {
|
|
337
345
|
readonly key: "ruleOffersAbsence";
|
|
338
346
|
readonly why: "喂强制判据口 approvalIsMandated 的位(CC-203;寄存行那条腿的强制只以缺席词 mandated 表达),按开集读(非空串原文字节、词表不校);权威窄读在卡口与过境口,座位门不设第二判官,理由同 mandated。坏形读成缺席 ⇒ 这一路不判强制(放宽方向:寄存行上的强制就丢了;另两路 mandated / mandate 照判);表外串只是不等于 mandated。不经过境口自铸座位请求的宿主要自己按同一把窄读。";
|