@sema-agent/client-core 0.96.0 → 0.97.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 +89 -0
- package/README.md +28 -22
- package/dist/adapter/activeRunSelfHeal.d.ts +0 -2
- package/dist/adapter/activeRunSelfHeal.js +7 -7
- package/dist/adapter/downstream/terminalToSdkResult.js +6 -2
- package/dist/agentSession/backgroundView.js +2 -15
- package/dist/agentsWireCaps.d.ts +1 -1
- package/dist/agentsWireCaps.js +16 -10
- package/dist/approvalDecidedByCapability.d.ts +2 -0
- package/dist/approvalDecidedByCapability.js +0 -1
- package/dist/approvalsStreamLiveCapability.d.ts +2 -0
- package/dist/approvalsStreamLiveCapability.js +3 -2
- package/dist/attachmentSeatCapability.d.ts +2 -0
- package/dist/attachmentSeatCapability.js +0 -1
- package/dist/callerCwdCapability.d.ts +2 -0
- package/dist/callerCwdCapability.js +0 -1
- package/dist/centerWiringCapability.d.ts +2 -0
- package/dist/centerWiringCapability.js +4 -3
- package/dist/cloudConfigWireCaps.d.ts +2 -2
- package/dist/cloudConfigWireCaps.js +192 -56
- package/dist/declared/supportFloorDeclared.js +3 -3
- package/dist/deviceExecutorManagementCapability.d.ts +2 -0
- package/dist/deviceExecutorManagementCapability.js +3 -2
- package/dist/displayUntrusted.d.ts +3 -0
- package/dist/displayUntrusted.js +15 -0
- package/dist/engineCapReader.d.ts +8 -2
- package/dist/engineCapReader.js +15 -7
- package/dist/engineCapsCache.d.ts +11 -3
- package/dist/engineCapsCache.js +54 -23
- package/dist/engineErrorCodes.d.ts +3 -0
- package/dist/engineErrorCodes.js +9 -1
- package/dist/engineNoticeCodes.js +2 -3
- package/dist/executionLaneCapability.d.ts +2 -0
- package/dist/executionLaneCapability.js +3 -2
- package/dist/fileHistoryCaptureCapability.d.ts +2 -0
- package/dist/fileHistoryCaptureCapability.js +34 -8
- package/dist/fileHistoryLegNotice.js +4 -0
- package/dist/fleet/fleetLedger.js +129 -105
- package/dist/gateOutcome.js +2 -4
- package/dist/gateVocabulary.d.ts +1 -6
- package/dist/gateVocabulary.js +2 -5
- package/dist/generated/sdkFactTables.d.ts +2 -0
- package/dist/generated/sdkFactTables.js +7 -0
- package/dist/generated/toolNameTables.d.ts +0 -1
- package/dist/generated/toolNameTables.js +0 -42
- package/dist/hitl/approvalDecisionNoteAudit.js +2 -2
- package/dist/hitl/approvalEndingCause.js +2 -7
- package/dist/hitl/approvalHolds.d.ts +16 -1
- package/dist/hitl/approvalHolds.js +52 -12
- package/dist/hitl/askGateWire.js +1 -0
- package/dist/hitl/automaticAnswerVerdict.js +5 -7
- package/dist/hitl/decisionConflict.js +4 -3
- package/dist/hitl/decisionRefusal.js +19 -12
- package/dist/hitl/frameRouter.d.ts +3 -0
- package/dist/hitl/frameRouter.js +52 -25
- package/dist/hitl/gateLedger.d.ts +0 -5
- package/dist/hitl/gateLedger.js +0 -21
- package/dist/hitl/hitlBridge.js +18 -4
- package/dist/hitl/parkResolver.js +7 -3
- package/dist/hitl/replayedApproval.d.ts +2 -3
- package/dist/hitl/replayedApproval.js +7 -16
- package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
- package/dist/hitl/sessionPolicyDeliverable.js +15 -17
- package/dist/hitl/sessionPolicyWire.d.ts +2 -0
- package/dist/hitl/sessionPolicyWire.js +15 -3
- package/dist/hitl/standingRows.d.ts +1 -0
- package/dist/hitl/standingRows.js +38 -17
- package/dist/hitl/suspendedReopen.js +2 -1
- package/dist/hitl/toolApprovalWire.d.ts +8 -8
- package/dist/hitl/toolApprovalWire.js +50 -24
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -3
- package/dist/liveModelCatalog.d.ts +13 -0
- package/dist/liveModelCatalog.js +56 -0
- package/dist/mcpProbeCapability.d.ts +2 -0
- package/dist/mcpProbeCapability.js +3 -2
- package/dist/mcpWireCaps.d.ts +1 -0
- package/dist/mcpWireCaps.js +4 -1
- package/dist/memoryComplianceCapability.d.ts +2 -0
- package/dist/memoryComplianceCapability.js +3 -2
- package/dist/memoryOriginCapability.d.ts +2 -0
- package/dist/memoryOriginCapability.js +3 -2
- package/dist/modelIdentityResolvability.js +2 -2
- package/dist/noticePresentation.js +2 -2
- package/dist/outputStyleSeatCapability.d.ts +2 -0
- package/dist/outputStyleSeatCapability.js +0 -1
- package/dist/peerLaneCapability.d.ts +2 -0
- package/dist/peerLaneCapability.js +3 -2
- package/dist/permissionModesCapability.d.ts +2 -0
- package/dist/permissionModesCapability.js +0 -1
- package/dist/permissionRulesWriteCapability.d.ts +2 -0
- package/dist/permissionRulesWriteCapability.js +3 -2
- package/dist/permissionsAllowGrantCapability.d.ts +2 -0
- package/dist/permissionsAllowGrantCapability.js +4 -2
- package/dist/permissionsDeclaration.js +19 -21
- package/dist/request/taskRequest.d.ts +1 -4
- package/dist/request/taskRequest.js +74 -19
- package/dist/resumeRefusalCopy.js +4 -4
- package/dist/rewindArchiveCapability.js +5 -0
- package/dist/rewindArchiveReading.d.ts +2 -0
- package/dist/rewindArchiveReading.js +0 -1
- package/dist/runTerminal.d.ts +33 -4
- package/dist/runTerminal.js +170 -15
- package/dist/sdkWireTransit.d.ts +2 -1
- package/dist/sdkWireTransit.js +1 -0
- package/dist/sealedKeyCapability.d.ts +2 -0
- package/dist/sealedKeyCapability.js +0 -1
- package/dist/seatContract.d.ts +7 -4
- package/dist/seatContract.js +34 -20
- package/dist/sessionPolicyCapability.d.ts +2 -0
- package/dist/sessionPolicyCapability.js +3 -2
- package/dist/sessionReadRedactionCapability.d.ts +2 -0
- package/dist/sessionReadRedactionCapability.js +0 -1
- package/dist/sessionSyncFileHistoryCapability.d.ts +2 -0
- package/dist/sessionSyncFileHistoryCapability.js +3 -2
- package/dist/skillToolListsCapability.d.ts +2 -0
- package/dist/skillToolListsCapability.js +3 -2
- package/dist/sqlEngineCapability.d.ts +2 -0
- package/dist/sqlEngineCapability.js +4 -3
- package/dist/steerPriorityCapability.d.ts +2 -0
- package/dist/steerPriorityCapability.js +3 -2
- package/dist/storePostureCapability.d.ts +2 -0
- package/dist/storePostureCapability.js +4 -3
- package/dist/toolHistoryBadTurn.js +3 -2
- package/dist/toolResult.d.ts +11 -0
- package/dist/toolResult.js +53 -0
- package/dist/userInvokedSkillsCapability.d.ts +2 -0
- package/dist/userInvokedSkillsCapability.js +3 -2
- package/dist/webSearchBackendCapability.d.ts +2 -0
- package/dist/webSearchBackendCapability.js +3 -2
- package/dist/wireErrorTriage.js +58 -34
- package/dist/wireFailureShape.d.ts +1 -1
- package/dist/wireFailureShape.js +76 -25
- package/dist/workflowsJournalCapability.d.ts +2 -0
- package/dist/workflowsJournalCapability.js +3 -2
- package/dist/writeProtectionCapability.d.ts +2 -0
- package/dist/writeProtectionCapability.js +3 -2
- package/docs/INTEGRATION-CLIENTS.md +533 -14
- package/package.json +4 -4
- package/dist/engineRefusedToolName.d.ts +0 -1
- package/dist/engineRefusedToolName.js +0 -8
- package/dist/engineWordRenames.d.ts +0 -8
- package/dist/engineWordRenames.js +0 -13
package/dist/mcpWireCaps.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export interface McpConfigLike {
|
|
|
12
12
|
headers?: Record<string, string>;
|
|
13
13
|
allowTools?: string[];
|
|
14
14
|
toolFaces?: unknown;
|
|
15
|
+
toolAxes?: unknown;
|
|
15
16
|
}
|
|
16
17
|
export declare function mcpConfigToSpec(name: string, c: McpConfigLike): McpServerSpec | null;
|
|
17
18
|
export declare function mcpConfigsToSpecs(servers: Record<string, McpConfigLike> | undefined): McpServerSpec[];
|
package/dist/mcpWireCaps.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export const MCP_CAPS = { items: 32 };
|
|
2
2
|
function transparentKeys(c) {
|
|
3
|
-
return
|
|
3
|
+
return {
|
|
4
|
+
...(c.toolFaces !== undefined ? { toolFaces: c.toolFaces } : {}),
|
|
5
|
+
...(c.toolAxes !== undefined ? { toolAxes: c.toolAxes } : {}),
|
|
6
|
+
};
|
|
4
7
|
}
|
|
5
8
|
export function mcpConfigToSpec(name, c) {
|
|
6
9
|
const n = (name ?? '').trim();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
|
-
import { createEngineCapReader } from './engineCapReader.js';
|
|
2
|
+
import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
|
|
3
3
|
import { ownDataField } from './ownKey.js';
|
|
4
4
|
export const MEMORY_ENGINE_REQUIRED_CODE = 'capability.memory_engine_required';
|
|
5
5
|
export function projectMemoryComplianceCapability(caps) {
|
|
@@ -21,7 +21,6 @@ export function projectMemoryComplianceCapability(caps) {
|
|
|
21
21
|
const reader = createEngineCapReader({
|
|
22
22
|
name: 'memoryCompliance',
|
|
23
23
|
project: projectMemoryComplianceCapability,
|
|
24
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
25
24
|
});
|
|
26
25
|
export function observedMemoryCompliance(baseUrl = engineWireTarget()?.baseUrl) {
|
|
27
26
|
return reader.observed(baseUrl);
|
|
@@ -35,6 +34,8 @@ export function memoryComplianceVerbsAvailable(reading) {
|
|
|
35
34
|
}
|
|
36
35
|
export function memoryComplianceDoctorDetail(reading) {
|
|
37
36
|
switch (reading.kind) {
|
|
37
|
+
case 'unreadable':
|
|
38
|
+
return unreadableReadingDetail('memory compliance face');
|
|
38
39
|
case 'unobserved':
|
|
39
40
|
return 'memory compliance face not observed — the engine reports it on /v1/capabilities (memoryCompliance); this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)';
|
|
40
41
|
case 'not_reported':
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
|
-
import { createEngineCapReader } from './engineCapReader.js';
|
|
2
|
+
import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
|
|
3
3
|
import { ownDataField } from './ownKey.js';
|
|
4
4
|
import { MEMORY_ENGINE_REQUIRED_CODE } from './memoryComplianceCapability.js';
|
|
5
5
|
export function projectMemoryOriginCapability(caps) {
|
|
@@ -21,7 +21,6 @@ export function projectMemoryOriginCapability(caps) {
|
|
|
21
21
|
const reader = createEngineCapReader({
|
|
22
22
|
name: 'memoryOrigin',
|
|
23
23
|
project: projectMemoryOriginCapability,
|
|
24
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
25
24
|
});
|
|
26
25
|
export function observedMemoryOrigin(baseUrl = engineWireTarget()?.baseUrl) {
|
|
27
26
|
return reader.observed(baseUrl);
|
|
@@ -35,6 +34,8 @@ export function memoryOriginVerbsAvailable(reading) {
|
|
|
35
34
|
}
|
|
36
35
|
export function memoryOriginDoctorDetail(reading) {
|
|
37
36
|
switch (reading.kind) {
|
|
37
|
+
case 'unreadable':
|
|
38
|
+
return unreadableReadingDetail('external-origin face');
|
|
38
39
|
case 'unobserved':
|
|
39
40
|
return 'external-origin face not observed — the engine reports it on /v1/capabilities (memoryOrigin); this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)';
|
|
40
41
|
case 'not_reported':
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { engineCapsLandingOf } from './engineCapsCache.js';
|
|
2
2
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
3
3
|
function laneOrder() {
|
|
4
4
|
return ['processEnv', 'settingsEnv', 'modelCatalogFile', 'followedSettingsFile', 'followedProviderEnv'];
|
|
@@ -212,5 +212,5 @@ export function modelSetupNotice(decision) {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
export function observedEngineAnswer(baseUrl = engineWireTarget()?.baseUrl) {
|
|
215
|
-
return
|
|
215
|
+
return engineCapsLandingOf(baseUrl).kind === 'not_landed' ? 'not_observed' : 'answered';
|
|
216
216
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { capDisplay, displayUntrusted } from './displayUntrusted.js';
|
|
1
|
+
import { capDisplay, DISPLAY_CAP_BACKOFF_MAX, displayUntrusted } from './displayUntrusted.js';
|
|
2
2
|
import { engineNoticeInCatalog, noticeAudienceOf } from './engineNoticeCodes.js';
|
|
3
3
|
import { guardedRead, readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
|
|
4
4
|
const DEFAULT_CUT_MARK = '…';
|
|
@@ -210,7 +210,7 @@ const PRINT_BUDGET_OPERATOR = 160;
|
|
|
210
210
|
const PRINT_PREFIX = '[sema] ';
|
|
211
211
|
const NO_TEXT_SENTENCE = 'Engine notice (no message text)';
|
|
212
212
|
const PRINT_CODE_MAX = 160;
|
|
213
|
-
const PRE_CAP_SLACK =
|
|
213
|
+
const PRE_CAP_SLACK = DISPLAY_CAP_BACKOFF_MAX + 1;
|
|
214
214
|
const PRINT_SESSION_MAX = 128;
|
|
215
215
|
function lineFace(max) {
|
|
216
216
|
return max === undefined ? { foldLines: false, mark: 'dot' } : { foldLines: false, mark: 'dot', max };
|
|
@@ -17,7 +17,6 @@ export function projectOutputStyleSeatCapability(caps) {
|
|
|
17
17
|
const reader = createEngineCapReader({
|
|
18
18
|
name: 'outputStyleSeat',
|
|
19
19
|
project: projectOutputStyleSeatCapability,
|
|
20
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
21
20
|
});
|
|
22
21
|
export function noteEngineCapsForOutputStyleSeat(baseUrl, caps, opts) {
|
|
23
22
|
reader.note(baseUrl, caps, opts);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
|
-
import { createEngineCapReader } from './engineCapReader.js';
|
|
2
|
+
import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
|
|
3
3
|
import { ownDataField } from './ownKey.js';
|
|
4
4
|
export function projectPeerLaneCapability(caps) {
|
|
5
5
|
try {
|
|
@@ -21,7 +21,6 @@ export function projectPeerLaneCapability(caps) {
|
|
|
21
21
|
const reader = createEngineCapReader({
|
|
22
22
|
name: 'peerLane',
|
|
23
23
|
project: projectPeerLaneCapability,
|
|
24
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
25
24
|
});
|
|
26
25
|
export function noteEngineCapsForPeerLane(baseUrl, caps, opts) {
|
|
27
26
|
reader.note(baseUrl, caps, opts);
|
|
@@ -38,6 +37,8 @@ export function peerLaneAvailable(reading) {
|
|
|
38
37
|
}
|
|
39
38
|
export function peerLaneDoctorDetail(reading) {
|
|
40
39
|
switch (reading.kind) {
|
|
40
|
+
case 'unreadable':
|
|
41
|
+
return unreadableReadingDetail('cross-session lane');
|
|
41
42
|
case 'unobserved':
|
|
42
43
|
return 'cross-session lane not observed — the engine reports it on /v1/capabilities (peerLane); this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)';
|
|
43
44
|
case 'not_reported':
|
|
@@ -38,7 +38,6 @@ export function projectPermissionModesCapability(caps) {
|
|
|
38
38
|
const reader = createEngineCapReader({
|
|
39
39
|
name: 'permissionModes',
|
|
40
40
|
project: projectPermissionModesCapability,
|
|
41
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
42
41
|
});
|
|
43
42
|
export function observedPermissionModes(baseUrl = engineWireTarget()?.baseUrl) {
|
|
44
43
|
return reader.observed(baseUrl);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
|
-
import { createEngineCapReader } from './engineCapReader.js';
|
|
2
|
+
import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
|
|
3
3
|
import { ownDataField } from './ownKey.js';
|
|
4
4
|
export function projectPermissionRulesWriteCapability(caps) {
|
|
5
5
|
try {
|
|
@@ -21,7 +21,6 @@ export function projectPermissionRulesWriteCapability(caps) {
|
|
|
21
21
|
const reader = createEngineCapReader({
|
|
22
22
|
name: 'permissionRulesWrite',
|
|
23
23
|
project: projectPermissionRulesWriteCapability,
|
|
24
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
25
24
|
});
|
|
26
25
|
export function noteEngineCapsForPermissionRulesWrite(baseUrl, caps, opts) {
|
|
27
26
|
reader.note(baseUrl, caps, opts);
|
|
@@ -34,6 +33,8 @@ export function permissionRulesWriteAvailable(reading) {
|
|
|
34
33
|
}
|
|
35
34
|
export function permissionRulesWriteDoctorDetail(reading) {
|
|
36
35
|
switch (reading.kind) {
|
|
36
|
+
case 'unreadable':
|
|
37
|
+
return unreadableReadingDetail('permission-rule write entry');
|
|
37
38
|
case 'unobserved':
|
|
38
39
|
return 'permission-rule write entry not observed — the engine reports it on /v1/capabilities (permissionRulesWrite); this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)';
|
|
39
40
|
case 'not_reported':
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
|
-
import { createEngineCapReader } from './engineCapReader.js';
|
|
2
|
+
import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
|
|
3
3
|
import { ownDataField } from './ownKey.js';
|
|
4
4
|
import { hasCoreValuePort } from './coreValuePorts.js';
|
|
5
5
|
const ALLOW_GRANT_CAP_PATH = ['settings', 'permissions', 'allowGrant'];
|
|
@@ -35,7 +35,6 @@ export function projectPermissionsAllowGrantCapability(caps) {
|
|
|
35
35
|
const reader = createEngineCapReader({
|
|
36
36
|
name: ALLOW_GRANT_CAP_PATH.join('.'),
|
|
37
37
|
project: projectPermissionsAllowGrantCapability,
|
|
38
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
39
38
|
});
|
|
40
39
|
export function noteEngineCapsForPermissionsAllowGrant(baseUrl, caps, opts) {
|
|
41
40
|
reader.note(baseUrl, caps, opts);
|
|
@@ -95,6 +94,9 @@ export function permissionsAllowGrantDoctorDetail(reading, settingsRead) {
|
|
|
95
94
|
if (kind === 'present' && ownReadingField(reading, 'grants') === false) {
|
|
96
95
|
return 'allow rules kept on this side — this engine says it does not read allow rules as rules of that kind, so they are not sent and matching approvals are still answered here';
|
|
97
96
|
}
|
|
97
|
+
if (kind === 'unreadable') {
|
|
98
|
+
return `${unreadableReadingDetail('how this engine reads allow rules')}; allow rules are kept on this side (not sent), and matching approvals are still answered here`;
|
|
99
|
+
}
|
|
98
100
|
if (kind === 'not_reported') {
|
|
99
101
|
return 'allow rules kept on this side — this engine does not say how it reads allow rules; sending them to an engine that reads them as an exclusive list would block every tool not on it, so they are not sent and matching approvals are still answered here';
|
|
100
102
|
}
|
|
@@ -29,19 +29,6 @@ export const PERMISSIONS_KEPT_REASONS = Object.freeze([
|
|
|
29
29
|
'duplicate',
|
|
30
30
|
'voids_allow_list',
|
|
31
31
|
]);
|
|
32
|
-
function normalizeLegacyToolName(name) {
|
|
33
|
-
switch (name) {
|
|
34
|
-
case 'Task':
|
|
35
|
-
return 'Agent';
|
|
36
|
-
case 'KillShell':
|
|
37
|
-
return 'TaskStop';
|
|
38
|
-
case 'AgentOutputTool':
|
|
39
|
-
case 'BashOutputTool':
|
|
40
|
-
return 'TaskOutput';
|
|
41
|
-
default:
|
|
42
|
-
return name;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
32
|
function unescapedIndex(str, char, fromEnd) {
|
|
46
33
|
for (let k = 0; k < str.length; k++) {
|
|
47
34
|
const i = fromEnd ? str.length - 1 - k : k;
|
|
@@ -61,17 +48,17 @@ function unescapeRuleContent(content) {
|
|
|
61
48
|
function parseRule(rule) {
|
|
62
49
|
const open = unescapedIndex(rule, '(', false);
|
|
63
50
|
if (open === -1)
|
|
64
|
-
return { toolName:
|
|
51
|
+
return { toolName: rule };
|
|
65
52
|
const close = unescapedIndex(rule, ')', true);
|
|
66
53
|
if (close === -1 || close <= open || close !== rule.length - 1)
|
|
67
|
-
return { toolName:
|
|
54
|
+
return { toolName: rule };
|
|
68
55
|
const toolName = rule.substring(0, open);
|
|
69
56
|
const rawContent = rule.substring(open + 1, close);
|
|
70
57
|
if (!toolName)
|
|
71
|
-
return { toolName:
|
|
58
|
+
return { toolName: rule };
|
|
72
59
|
if (rawContent === '' || rawContent === '*')
|
|
73
|
-
return { toolName
|
|
74
|
-
return { toolName
|
|
60
|
+
return { toolName };
|
|
61
|
+
return { toolName, ruleContent: unescapeRuleContent(rawContent) };
|
|
75
62
|
}
|
|
76
63
|
function requireRulePorts() {
|
|
77
64
|
const required = ['MCP_NAMESPACE', 'judgeRuleToolName', 'protocolOf', 'ruleToolGrammarOf', 'validatePermissionRules'];
|
|
@@ -90,7 +77,7 @@ function nameCheck(name) {
|
|
|
90
77
|
'装的必须是 core 的同名实现、原样装。判不出不等于够得着:不判就发会让整份请求被引擎拒收,不判就删会静默丢掉 deny 规则,所以这里拒绝装配。');
|
|
91
78
|
}
|
|
92
79
|
if (verdict.kind === 'retired')
|
|
93
|
-
return {
|
|
80
|
+
return { retired: verdict.currentName !== undefined ? { currentName: verdict.currentName } : {} };
|
|
94
81
|
if (verdict.kind === 'unprefixed_namespace')
|
|
95
82
|
return { issue: 'unprefixed_namespaced_name' };
|
|
96
83
|
const ns = protocolOf(name);
|
|
@@ -134,8 +121,17 @@ function judgeList(rules, behavior, allowForm = 'grant') {
|
|
|
134
121
|
}
|
|
135
122
|
const parsed = parseRule(rule);
|
|
136
123
|
if (parsed.ruleContent === undefined) {
|
|
137
|
-
|
|
138
|
-
|
|
124
|
+
let name = wholeServerRuleName(parsed.toolName);
|
|
125
|
+
let check = nameCheck(name);
|
|
126
|
+
if ('retired' in check) {
|
|
127
|
+
const successor = check.retired.currentName;
|
|
128
|
+
if (behavior === 'allow' || successor === undefined)
|
|
129
|
+
return kept('retired_tool_name');
|
|
130
|
+
name = successor;
|
|
131
|
+
check = nameCheck(name);
|
|
132
|
+
if ('retired' in check)
|
|
133
|
+
return kept('retired_tool_name');
|
|
134
|
+
}
|
|
139
135
|
if ('issue' in check)
|
|
140
136
|
return kept(check.issue);
|
|
141
137
|
if (behavior === 'allow' && 'unminted' in check)
|
|
@@ -148,6 +144,8 @@ function judgeList(rules, behavior, allowForm = 'grant') {
|
|
|
148
144
|
return behavior === 'allow' ? { sent: true, wire: name, unchecked: false } : sentFate(name, check, verdict.kind === 'unknown');
|
|
149
145
|
}
|
|
150
146
|
const check = nameCheck(parsed.toolName);
|
|
147
|
+
if ('retired' in check)
|
|
148
|
+
return kept('retired_tool_name');
|
|
151
149
|
if ('issue' in check)
|
|
152
150
|
return kept(check.issue);
|
|
153
151
|
if (ruleToolGrammarOf(parsed.toolName) === 'path' && parsed.ruleContent.startsWith('~/'))
|
|
@@ -36,6 +36,7 @@ export interface TaskRequestInput {
|
|
|
36
36
|
attachments?: Record<string, unknown>;
|
|
37
37
|
attachmentIds?: readonly string[];
|
|
38
38
|
excludeTools?: readonly string[];
|
|
39
|
+
allowTools?: readonly string[];
|
|
39
40
|
finalVerification?: boolean;
|
|
40
41
|
limits?: Record<string, unknown>;
|
|
41
42
|
interactiveTools?: false;
|
|
@@ -57,10 +58,6 @@ export interface TaskRequestInput {
|
|
|
57
58
|
disableSkills?: TaskRequest['disableSkills'];
|
|
58
59
|
rewind?: Record<string, unknown>;
|
|
59
60
|
repo?: string;
|
|
60
|
-
council?: boolean;
|
|
61
|
-
debate?: boolean;
|
|
62
|
-
rounds?: number;
|
|
63
|
-
lenses?: readonly string[];
|
|
64
61
|
settings?: {
|
|
65
62
|
resolved?: Record<string, unknown>;
|
|
66
63
|
webSearch?: Record<string, unknown>;
|
|
@@ -21,10 +21,6 @@ export const REQUEST_FIELD_MATRIX = [
|
|
|
21
21
|
{ field: 'settings.hooks', lanes: ['interactive', 'print'], live: true, why: '[495]① 用户 settings 文件 hooks 逐字上 wire', whyUtilityLane: '无座:hook 挂在工具门上(零工具面没有门),而且 side-channel 是壳自己的提交,不该继承用户那份 hook 表' },
|
|
22
22
|
{ field: 'settings.<resolved>', lanes: ['interactive', 'print'], live: true, why: 'settings resolver 的 effective 快照(hooks/env/model + 已解析权限投影)。两条车道同源:交互面 replEntry / print 面 printModeEngine 各跑一遍同一个 resolver,产物经同一个 buildWireSettingsStamp 投影。开放集(子键不可枚举)⇒ unregisteredRequestKeys 放行本车道 settings 的**表外**子键,但表内异车道子键仍点名', whyUtilityLane: '无座:这一位是**开放集 spread**(子键原样即 wire 键),摊开的是用户 settings 的已解析面(权限 / env / 模型)。side-channel 是壳自己的提交:摊上去既无用(零工具面没有工具门求值权限)又把用户的配置面带进了一条他没参与的提交。🔴 无座 ⇒ 本车道整只快照不产。🔴 **本行无座的前提由构造期校验兜住**:剥掉的是用户显式的 deny / ask,所以 `refuseUtilityWithoutToolUnload` 强制这条车道必须带字面 `excludeAllTools: true` —— 否则产出会是一条「既没卸工具、又没带用户 deny」的请求(比无人值守车道同一份输入更宽)' },
|
|
23
23
|
{ field: 'repo', lanes: ['interactive', 'print'], live: true, why: 'scan/code-review 场景的仓库坐标(passthrough;server 是权威校验方,本层不铸第二判官)', whyUtilityLane: '无座:场景键;side-channel 不走场景' },
|
|
24
|
-
{ field: 'council', lanes: ['interactive', 'print'], live: true, why: 'code-review council 形开关(server 读 `=== true`;非 true 不 stamp=与缺席同义,发小的那个)', whyUtilityLane: '无座:场景键;side-channel 不走场景' },
|
|
25
|
-
{ field: 'debate', lanes: ['interactive', 'print'], live: true, why: 'council 的 debate 变体开关(server 读 `=== true`)', whyUtilityLane: '无座:场景键;side-channel 不走场景' },
|
|
26
|
-
{ field: 'rounds', lanes: ['interactive', 'print'], live: true, why: 'debate 轮数(server clamp [1,3],非有限数被 server 归 undefined——本层原样透传不预 clamp)', whyUtilityLane: '无座:场景键;side-channel 不走场景' },
|
|
27
|
-
{ field: 'lenses', lanes: ['interactive', 'print'], live: true, why: 'code-review 镜头数(server 场景按数字读、非数字回 400;本层型面仍按旧形声明为字符串数组 —— 已知不一致,随该族退役处理)', whyUtilityLane: '无座:场景键;side-channel 不走场景' },
|
|
28
24
|
{ field: 'memoryCapture', lanes: ['interactive', 'print', 'utility'], live: true, why: '本会话永远不进长期记忆的**声明形**(server §12.4 body 键,单成员闭集 "off");每条车道都是提交面 ⇒ 都能声明。与 memoryWrite:false 不是一个轴(那是「本 run 只读平面」)。⚠️ parked 续跑腿结构性拿不到声明(决策/续跑端点从持久 body 重建 spec),那是引擎侧事实,不是本层的漏', whyUtilityLane: '有座:side-channel 提交是壳自己的一次性问答,**绝不该**进用户的长期记忆 —— 这一位正是那句声明,且它是收紧方向,带上去只会更严' },
|
|
29
25
|
{ field: 'memory', lanes: ['interactive', 'print', 'utility'], live: true, why: '这一次运行不挂记忆面的**请求级**开关(server §12.7 body 键,单成员闭集 "off");每条车道都是提交面 ⇒ 都能声明。与 memoryCapture(采集面)不是一个轴、可并存;与 memoryWrite:false(只读平面)也不是一个轴', whyUtilityLane: '有座:side-channel 提交不需要挂记忆面(不挂记忆段 / 索引 / 三只记忆工具),省 token 且零记忆写入;与 memoryCapture 不是一个轴,两条都带' },
|
|
30
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' },
|
|
@@ -41,6 +37,7 @@ export const REQUEST_FIELD_MATRIX = [
|
|
|
41
37
|
{ field: 'maxTokens', lanes: ['print', 'utility'], live: true, why: '整任务 token 预算上限声明(sdk `TaskRequest.maxTokens`,请求体**顶层**位,与 `maxCostUsd` 同属上游那一族「调用方要求的上限」:向下夹到部署上限 —— 只许要得更少)。🔴 座位集与 `maxCostUsd` 那一行**逐字相同**:同一条预算轴的两种计价单位,分开定座就是让其中一条静默漂。🔴 坏值(非数 / 非有限 / 非正 / 非整)在本层**响亮拒**:上游对这一位的坏值是安静按「调用方没给」处理并回落部署上限,不是 4xx —— 部署没设上限时这一次运行就没有 token 闸,而声明人不会知道(见 `refuseBadMaxTokens`)', whyUtilityLane: '有座:与 maxCostUsd 同轴孪生 —— 小预算是本车道的定义之一,两种计价单位都该能声明' },
|
|
42
38
|
{ field: 'attachmentIds', lanes: ['interactive'], live: true, why: '附件**字节通道**(uploadAttachment 回执 id;server ≥1.289 绑定会话并把文件物化进 run 的 attachments/)。有上传入口的端才有 id 可引用:web/desktop 有,壳走 images / 本地文件路径,`-p` 车道连 uploadAttachment 都没有 ⇒ print 缺席是**没有来源**,不是漏。🔴 与上面的 `attachments` 同名不同物(那是 turn 边界的配置键),两条永远不许合并', whyUtilityLane: '无座:预上传附件句柄要先有上传入口才有 id 可引用,而 side-channel 没有上传面' },
|
|
43
39
|
{ field: 'excludeTools', lanes: ['interactive', 'print', 'utility'], live: true, why: 'design/161 W3(2026-07-30):真 wire 键(SDK types `excludeTools`)且早在 seatContract `START_SESSION_OPTION_KEYS` 里,却是 desktop 手写 taskReq 的第 9 键、矩阵外——而 stamp 门对未登记键**静默丢弃**,真实危险形=「用户显式排除的工具被静默放回」(权限方向回归,类型层不报)。今天只有 desktop 在发;壳的工具面走 roster/interactiveTools 另一条路。0.77.0 补 print 座(三问:① wire 位与车道无关 —— sdk 具名位、提交体真收 `body.excludeTools`;② 来源 —— print 今天没有排除入口,但这是**收紧方向**的声明,传了只进回执 = 端不读回执就把用户排除的工具放回;③ 口径 —— 仍是 live 门后的位,与交互面同一行)', whyUtilityLane: '有座:逐名排除是卸载声明旁边的第二条收紧声明(两键同带各自生效)。⚠️ 它**不是** excludeAllTools 的降级替身 —— 本车道强制带卸载声明(见 `refuseUtilityWithoutToolUnload`),不认那一键的上游会把整条提交拒掉,那时正解是换车道或不发' },
|
|
40
|
+
{ field: 'allowTools', lanes: ['interactive', 'print'], live: true, why: '引擎的可用性选择器(收紧方向的声明:只给点名的工具;`[]` = 什么都不给,照发)。两条用户车道都是提交面、都有「只给这几只工具」的用户入口(终端 `--tools`)⇒ 都有座;坏形(不是串数组)在装配期响亮拒,不静默删键', whyUtilityLane: '无座:side-channel 恒带 excludeAllTools(零工具面),可用性选择器在零工具面上没有可选的东西' },
|
|
44
41
|
{ field: 'excludeAllTools', lanes: ['interactive', 'print', 'utility'], live: true, why: '0.78.0(sdk 11.x 具名位 `excludeAllTools`,server ≥7.90.0 请求面):整只工具面卸载 —— 调用方工具 / 脚手架 / 手 / MCP / A2A / skills 一个都不挂,终局必然纯文本(wire 上 `wiring_manifest.tools.count === 0`,整条流零 tool_start / tool_end / tool_disclosure)。与 excludeTools 是两种语义、刻意不折叠(`"*"` 是一个合法的工具名,「卸全部」不能写成 `excludeTools:["*"]`);两键同带各自生效。类型只收字面 `true`(server 只把 literal true 写上任务规格,`false` = 替引擎重申它自己的缺省 ⇒ 不发、与缺席同义、不进回执);坏值响亮拒(收紧方向的声明不许被打字错误安静丢掉)。每条车道都是提交面 ⇒ 都能声明。探测靠键闭集、没有能力位:没接线的 server(≤7.89.x)400 `request.body_shape` 并在 `unknownKeys` 里逐字点名,本层不替它猜;A2A 入站面不承载本键(零工具面走 skill 路由)', whyUtilityLane: '有座,而且**本车道强制**:零工具面就是这条车道的定义 —— side-channel 提交整只工具面卸载,终局必然纯文本。🔴 缺这一位(或给 `false`)⇒ 构造期响亮拒(`refuseUtilityWithoutToolUnload`):本车道上一整片「无座」的理由都压在这个前提上,其中 `settings.<resolved>` 那一行剥掉的是用户显式的 deny / ask ——前提不成立时产出会是一条「既没卸工具、又没带用户 deny」的请求' },
|
|
45
42
|
{ field: 'settings.ultracode', lanes: ['interactive'], live: true, why: 'design/111:sticky `/effort ultracode` 拨盘 + 当轮关键词嗅探,两个来源都只在交互面存在', gap: true, whyUtilityLane: '无座:sticky 拨盘与当轮关键词嗅探两个来源都只在交互面' },
|
|
46
43
|
{ field: 'systemPrompt', lanes: ['interactive', 'print', 'utility'], live: false, why: '整段替换系统提示(sdk `TaskRequest.systemPrompt`;上游字符数超限 400 响亮拒,本层原样透传)。三条车道都有来源:交互面 = CC QueryParams.systemPrompt,无人值守面 = `--system-prompt[-file]` 一类旗,side-channel 面 = 壳整段给出的那一份。与追加位 `appendSystemPrompt` 不是一个位(那一位归 live 兜底层,见 `LIVE_DEFAULT_FIELDS`)', whyUtilityLane: '有座:side-channel 提交的系统提示由壳整段给出 —— 它不是用户会话的续谈,不该继承用户那一份' },
|
|
@@ -175,10 +172,7 @@ const INPUT_KEY_ROUTES = {
|
|
|
175
172
|
disableSkills: row('disableSkills'),
|
|
176
173
|
rewind: row('resumeAt/resumeAtMode/restoreFiles/rewindFilesTo'),
|
|
177
174
|
repo: row('repo'),
|
|
178
|
-
|
|
179
|
-
debate: row('debate'),
|
|
180
|
-
rounds: row('rounds'),
|
|
181
|
-
lenses: row('lenses'),
|
|
175
|
+
allowTools: row('allowTools'),
|
|
182
176
|
settings: { via: 'settings' },
|
|
183
177
|
};
|
|
184
178
|
const SETTINGS_KEY_ROUTES = {
|
|
@@ -234,8 +228,6 @@ const rewindSubKeys = () => {
|
|
|
234
228
|
return r.via === 'matrix' ? r.field.split('/') : [];
|
|
235
229
|
};
|
|
236
230
|
const VALUE_LEVEL_IN_PLAY = Object.freeze({
|
|
237
|
-
council: (v) => v === true,
|
|
238
|
-
debate: (v) => v === true,
|
|
239
231
|
oneShot: (v) => v === true,
|
|
240
232
|
interactiveTools: (v) => v === false,
|
|
241
233
|
images: (v) => Array.isArray(v) && v.length > 0,
|
|
@@ -481,6 +473,66 @@ const withoutRetiredAttachmentsKeys = (v) => {
|
|
|
481
473
|
delete copy[key];
|
|
482
474
|
return copy;
|
|
483
475
|
};
|
|
476
|
+
const ALLOW_TOOLS_MAX_LENGTH = 65_536;
|
|
477
|
+
const ALLOW_TOOLS_UNREADABLE_ITEM = Symbol('allowTools-unreadable-item');
|
|
478
|
+
function allowToolsSnapshot(v) {
|
|
479
|
+
if (!Array.isArray(v))
|
|
480
|
+
return v;
|
|
481
|
+
let n;
|
|
482
|
+
try {
|
|
483
|
+
n = Object.getOwnPropertyDescriptor(v, 'length')?.value;
|
|
484
|
+
}
|
|
485
|
+
catch {
|
|
486
|
+
return ALLOW_TOOLS_UNREADABLE_ITEM;
|
|
487
|
+
}
|
|
488
|
+
if (typeof n !== 'number' || !Number.isSafeInteger(n) || n < 0 || n > ALLOW_TOOLS_MAX_LENGTH)
|
|
489
|
+
return ALLOW_TOOLS_UNREADABLE_ITEM;
|
|
490
|
+
const out = new Array(n);
|
|
491
|
+
for (let k = 0; k < n; k += 1) {
|
|
492
|
+
let d;
|
|
493
|
+
try {
|
|
494
|
+
d = Object.getOwnPropertyDescriptor(v, k);
|
|
495
|
+
}
|
|
496
|
+
catch {
|
|
497
|
+
out[k] = ALLOW_TOOLS_UNREADABLE_ITEM;
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (d === undefined)
|
|
501
|
+
continue;
|
|
502
|
+
out[k] = 'value' in d ? d.value : ALLOW_TOOLS_UNREADABLE_ITEM;
|
|
503
|
+
}
|
|
504
|
+
return Object.freeze(out);
|
|
505
|
+
}
|
|
506
|
+
const allowToolsCopy = (v) => {
|
|
507
|
+
if (!Array.isArray(v))
|
|
508
|
+
return [];
|
|
509
|
+
const out = [];
|
|
510
|
+
for (let k = 0; k < v.length; k += 1) {
|
|
511
|
+
const d = Object.getOwnPropertyDescriptor(v, k);
|
|
512
|
+
if (d !== undefined && 'value' in d && typeof d.value === 'string')
|
|
513
|
+
out.push(d.value);
|
|
514
|
+
}
|
|
515
|
+
return out;
|
|
516
|
+
};
|
|
517
|
+
const refuseBadAllowTools = (v) => {
|
|
518
|
+
if (v === undefined || v === null)
|
|
519
|
+
return;
|
|
520
|
+
if (Array.isArray(v)) {
|
|
521
|
+
let ok = true;
|
|
522
|
+
for (let k = 0; k < v.length; k += 1) {
|
|
523
|
+
const d = Object.getOwnPropertyDescriptor(v, k);
|
|
524
|
+
if (d === undefined || !('value' in d) || typeof d.value !== 'string') {
|
|
525
|
+
ok = false;
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
if (ok)
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
throw new TypeError('buildTaskRequest: allowTools 只接受字符串数组(`[]` = 什么都不给;缺席 = 不选择)—— ' +
|
|
533
|
+
`收到 ${coarseShape(v)}。这一位是**可用性选择器**(收紧声明):本层若把坏形静默删键,这一次运行会挂上声明人以为已经收窄掉的全部工具。` +
|
|
534
|
+
'错误文本只报形状,不回显值。');
|
|
535
|
+
};
|
|
484
536
|
const refuseBadExcludeAllTools = (v) => {
|
|
485
537
|
if (v === undefined || v === null || v === true || v === false)
|
|
486
538
|
return;
|
|
@@ -591,7 +643,8 @@ export function parseMaxCostUsd(text) {
|
|
|
591
643
|
return { ok: false, why: 'not_positive' };
|
|
592
644
|
return { ok: true, value };
|
|
593
645
|
}
|
|
594
|
-
const ACCESSOR_READ_ORDER = ['live', 'memoryCapture', 'memory', 'settings', 'maxCostUsd', 'excludeAllTools', 'maxTokens', 'outputRetries', 'fileHistory', 'inheritEnv', 'requireExistingSession', 'disableSkills', 'approvalReach'];
|
|
646
|
+
const ACCESSOR_READ_ORDER = ['live', 'memoryCapture', 'memory', 'settings', 'maxCostUsd', 'excludeAllTools', 'maxTokens', 'outputRetries', 'fileHistory', 'inheritEnv', 'requireExistingSession', 'disableSkills', 'approvalReach', 'allowTools'];
|
|
647
|
+
const MATERIALIZE_AT_READ = Object.freeze({ allowTools: (v) => allowToolsSnapshot(v) });
|
|
595
648
|
function dataFirstSnapshot(input, afterData) {
|
|
596
649
|
let descs;
|
|
597
650
|
try {
|
|
@@ -604,10 +657,10 @@ function dataFirstSnapshot(input, afterData) {
|
|
|
604
657
|
const accessors = [];
|
|
605
658
|
for (const k of Object.keys(descs)) {
|
|
606
659
|
const d = descs[k];
|
|
607
|
-
if (d === undefined || d.enumerable !== true)
|
|
660
|
+
if (d === undefined || (d.enumerable !== true && routeOfTopLevelKey(k) === undefined))
|
|
608
661
|
continue;
|
|
609
662
|
if ('value' in d)
|
|
610
|
-
bag[k] = d.value;
|
|
663
|
+
bag[k] = Object.hasOwn(MATERIALIZE_AT_READ, k) ? MATERIALIZE_AT_READ[k](d.value) : d.value;
|
|
611
664
|
else
|
|
612
665
|
accessors.push(k);
|
|
613
666
|
}
|
|
@@ -616,8 +669,10 @@ function dataFirstSnapshot(input, afterData) {
|
|
|
616
669
|
...ACCESSOR_READ_ORDER.filter((k) => accessors.includes(k)),
|
|
617
670
|
...accessors.filter((k) => !ACCESSOR_READ_ORDER.includes(k)),
|
|
618
671
|
];
|
|
619
|
-
for (const k of ordered)
|
|
620
|
-
|
|
672
|
+
for (const k of ordered) {
|
|
673
|
+
const v = Reflect.get(input, k);
|
|
674
|
+
bag[k] = Object.hasOwn(MATERIALIZE_AT_READ, k) ? MATERIALIZE_AT_READ[k](v) : v;
|
|
675
|
+
}
|
|
621
676
|
return bag;
|
|
622
677
|
}
|
|
623
678
|
export function assembleTaskRequest(input, lane) {
|
|
@@ -663,6 +718,7 @@ export function assembleTaskRequest(input, lane) {
|
|
|
663
718
|
const requireExistingSessionIn = src.requireExistingSession;
|
|
664
719
|
const disableSkillsIn = src.disableSkills;
|
|
665
720
|
const approvalReachIn = src.approvalReach;
|
|
721
|
+
const allowToolsIn = src.allowTools;
|
|
666
722
|
const INPUT_KEYS = Object.keys(INPUT_KEY_ROUTES);
|
|
667
723
|
const i = snapshotByName(src, INPUT_KEYS, {
|
|
668
724
|
live,
|
|
@@ -677,6 +733,7 @@ export function assembleTaskRequest(input, lane) {
|
|
|
677
733
|
requireExistingSession: requireExistingSessionIn,
|
|
678
734
|
disableSkills: disableSkillsIn,
|
|
679
735
|
approvalReach: approvalReachIn,
|
|
736
|
+
allowTools: allowToolsIn,
|
|
680
737
|
settings: settingsIn,
|
|
681
738
|
});
|
|
682
739
|
const SETTINGS_KEYS = Object.keys(SETTINGS_KEY_ROUTES);
|
|
@@ -692,6 +749,7 @@ export function assembleTaskRequest(input, lane) {
|
|
|
692
749
|
refuseBadRequireExistingSession(requireExistingSessionIn);
|
|
693
750
|
refuseBadDisableSkills(disableSkillsIn, 'buildTaskRequest');
|
|
694
751
|
refuseBadApprovalReach(approvalReachIn, 'buildTaskRequest');
|
|
752
|
+
refuseBadAllowTools(allowToolsIn);
|
|
695
753
|
const rewindRoute = INPUT_KEY_ROUTES.rewind;
|
|
696
754
|
const RETIRED_REWIND_FILES_KEY = 'rewindFiles';
|
|
697
755
|
const REWIND_KEYS = rewindRoute.via === 'matrix' ? rewindRoute.field.split('/') : [];
|
|
@@ -824,10 +882,7 @@ export function assembleTaskRequest(input, lane) {
|
|
|
824
882
|
...(on('enableFork') ? { enableFork: i.enableFork } : {}),
|
|
825
883
|
...(on('attachments') ? { attachments: attachmentsForWire } : {}),
|
|
826
884
|
...(on('repo') ? { repo: i.repo } : {}),
|
|
827
|
-
...(on('
|
|
828
|
-
...(on('debate') ? { debate: true } : {}),
|
|
829
|
-
...(on('rounds') ? { rounds: i.rounds } : {}),
|
|
830
|
-
...(on('lenses') ? { lenses: i.lenses } : {}),
|
|
885
|
+
...(on('allowTools') ? { allowTools: allowToolsCopy(i.allowTools) } : {}),
|
|
831
886
|
...(on('attachmentIds') ? { attachmentIds: [...(i.attachmentIds ?? [])] } : {}),
|
|
832
887
|
...(on('excludeTools') ? { excludeTools: [...(i.excludeTools ?? [])] } : {}),
|
|
833
888
|
...(on('excludeAllTools') ? { excludeAllTools: true } : {}),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readBlockedBy, readErrorNumber, readErrorString } from './wireFailureShape.js';
|
|
2
|
-
import { readOwnDataNonEmptyString } from './ownKey.js';
|
|
2
|
+
import { guardedRead, ownDataField, readOwnDataNonEmptyString } from './ownKey.js';
|
|
3
3
|
import { RESUME_CONTEXT_UNAVAILABLE, RESUME_PLACEMENT_MISMATCH, RESUME_PREFLIGHT_REJECTED, RESUME_POLICY_FOLD_CODE, PARKED_RESUME_STARTUP_FAILED, isStatusDerivedCoarseCode, RESUME_SESSION_NOT_FOUND, REQUEST_FIELD_CONFLICT, CHECKPOINT_UNSUPPORTED_VERSION, CHECKPOINT_WALLTIME_AXIS_RETIRED, CHECKPOINT_CONFIG_REFUSED, isRefusedParkCode, refusalSaysStillPending, refusalRetriableReading, } from './engineErrorCodes.js';
|
|
4
4
|
import { capForDisplay } from './fleetTaskDesc.js';
|
|
5
5
|
import { engineVersionTier } from './supportFloor.js';
|
|
@@ -11,7 +11,7 @@ export const RESUME_REFUSAL_CODES = Object.freeze([
|
|
|
11
11
|
export function resumeRefusalFromError(err) {
|
|
12
12
|
if (typeof err !== 'object' || err === null)
|
|
13
13
|
return null;
|
|
14
|
-
const code = err
|
|
14
|
+
const code = guardedRead(() => ownDataField(err, 'errorCode'));
|
|
15
15
|
if (typeof code !== 'string' || !RESUME_REFUSAL_CODES.includes(code))
|
|
16
16
|
return null;
|
|
17
17
|
if (code === RESUME_PLACEMENT_MISMATCH) {
|
|
@@ -274,8 +274,8 @@ export function refusedParkFromError(failure) {
|
|
|
274
274
|
let code;
|
|
275
275
|
let status;
|
|
276
276
|
try {
|
|
277
|
-
code = failure
|
|
278
|
-
status = failure
|
|
277
|
+
code = ownDataField(failure, 'errorCode');
|
|
278
|
+
status = ownDataField(failure, 'status');
|
|
279
279
|
}
|
|
280
280
|
catch {
|
|
281
281
|
return null;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
2
|
import { resetRewindArchiveReader, rewindArchiveReadingAt, rewindConversationAvailability, } from './rewindArchiveReading.js';
|
|
3
|
+
import { unreadableReadingDetail } from './engineCapReader.js';
|
|
3
4
|
export { projectRewindArchiveCapability, rewindConversationAvailability } from './rewindArchiveReading.js';
|
|
4
5
|
export function noteEngineCapsForRewindArchive(baseUrl, caps, opts) {
|
|
5
6
|
void baseUrl;
|
|
@@ -21,6 +22,8 @@ export function rewindCodeArchiveAvailability(reading, mode) {
|
|
|
21
22
|
}
|
|
22
23
|
export function rewindArchiveDoctorDetail(reading, mode) {
|
|
23
24
|
const lane = mode === 'both' ? 'rewind with code restore' : 'code-only rewind';
|
|
25
|
+
if (reading.kind === 'unreadable')
|
|
26
|
+
return unreadableReadingDetail(lane);
|
|
24
27
|
if (reading.kind !== 'present') {
|
|
25
28
|
return `${lane} not observed — the engine reports it on /v1/capabilities; this process has no usable capabilities reading cached for it, so whether the code archive can be restored is unknown`;
|
|
26
29
|
}
|
|
@@ -58,6 +61,8 @@ export function engineRewindRefusedNow(option, reading = observedRewindArchive()
|
|
|
58
61
|
}
|
|
59
62
|
export function rewindConversationDoctorDetail(reading) {
|
|
60
63
|
const lane = 'rewind to a message';
|
|
64
|
+
if (reading.kind === 'unreadable')
|
|
65
|
+
return unreadableReadingDetail(lane);
|
|
61
66
|
if (reading.kind !== 'present') {
|
|
62
67
|
return `${lane} not observed — the engine reports conversation anchors on /v1/capabilities; this process has no usable capabilities reading cached for it, so whether the conversation can be rewound is unknown`;
|
|
63
68
|
}
|
|
@@ -37,7 +37,6 @@ export function projectRewindArchiveCapability(caps) {
|
|
|
37
37
|
const reader = createEngineCapReader({
|
|
38
38
|
name: 'rewindArchive',
|
|
39
39
|
project: projectRewindArchiveCapability,
|
|
40
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
41
40
|
});
|
|
42
41
|
export function rewindArchiveReadingAt(baseUrl) {
|
|
43
42
|
return reader.observed(baseUrl);
|