@sema-agent/core 7.16.0 → 7.17.1
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 +209 -0
- package/dist/agents/builtin-agents.d.ts +3 -3
- package/dist/agents/cross-session-envelope.d.ts +0 -1
- package/dist/agents/cross-session-envelope.js +0 -1
- package/dist/agents/peer-notices.d.ts +0 -9
- package/dist/agents/peer-notices.js +0 -63
- package/dist/agents/subagent.js +7 -15
- package/dist/brain/request-params.d.ts +2 -2
- package/dist/config/defaults.d.ts +0 -7
- package/dist/config/defaults.js +0 -2
- package/dist/core/artifact-host.d.ts +218 -0
- package/dist/core/artifact-host.js +92 -0
- package/dist/core/ask-origin.d.ts +29 -3
- package/dist/core/ask-origin.js +17 -9
- package/dist/core/ask-question.d.ts +25 -0
- package/dist/core/ask-question.js +4 -0
- package/dist/core/ask-unresolvable-notice.d.ts +30 -21
- package/dist/core/ask-unresolvable-notice.js +16 -8
- package/dist/core/auto-compaction.d.ts +10 -10
- package/dist/core/auto-mode-arming.d.ts +2 -2
- package/dist/core/background-agent-store.d.ts +5 -5
- package/dist/core/background-shell.d.ts +1 -1
- package/dist/core/checkpoint-execution-record.d.ts +0 -3
- package/dist/core/checkpoint-execution-record.js +0 -4
- package/dist/core/checkpoint-store.d.ts +71 -99
- package/dist/core/checkpoint-store.js +9 -16
- package/dist/core/context-edit.d.ts +36 -104
- package/dist/core/context-edit.js +37 -60
- package/dist/core/effective-path-target.d.ts +68 -8
- package/dist/core/effective-path-target.js +42 -30
- package/dist/core/engine-notice.d.ts +46 -32
- package/dist/core/env-budget.d.ts +31 -0
- package/dist/core/env-budget.js +39 -0
- package/dist/core/exec-output-tail.d.ts +5 -5
- package/dist/core/file-history-store.js +3 -6
- package/dist/core/fs-write-gate-policy.d.ts +1 -1
- package/dist/core/fs-write-gate-policy.js +3 -3
- package/dist/core/gate-lanes.js +9 -15
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hands-band.d.ts +1 -1
- package/dist/core/hooks.d.ts +18 -17
- package/dist/core/lsp-session.d.ts +1 -1
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/lsp.js +5 -4
- package/dist/core/mcp.d.ts +5 -5
- package/dist/core/mcp.js +4 -48
- package/dist/core/memory-engine/engine.js +2 -1
- package/dist/core/memory-engine/layout.d.ts +18 -6
- package/dist/core/memory-engine/layout.js +40 -21
- package/dist/core/memory-recall.d.ts +0 -8
- package/dist/core/memory.d.ts +1 -1
- package/dist/core/oracle-isolation.js +2 -2
- package/dist/core/parent-spec-seat.d.ts +66 -0
- package/dist/core/parent-spec-seat.js +47 -0
- package/dist/core/permission-rule-model.d.ts +11 -6
- package/dist/core/permission-rule-model.js +53 -37
- package/dist/core/permission-rules.js +8 -3
- package/dist/core/physical-path.d.ts +37 -0
- package/dist/core/physical-path.js +30 -0
- package/dist/core/protocol-naming.d.ts +2 -2
- package/dist/core/remote-env.d.ts +1 -1
- package/dist/core/retired-keys.d.ts +19 -0
- package/dist/core/retired-keys.js +15 -0
- package/dist/core/runner/active-skill-scope.js +3 -3
- package/dist/core/runner/assemble-result.d.ts +15 -13
- package/dist/core/runner/assemble-result.js +5 -4
- package/dist/core/runner/compaction-call-options.d.ts +25 -89
- package/dist/core/runner/contracts.d.ts +11 -10
- package/dist/core/runner/gate-exit.js +15 -1
- package/dist/core/runner/halt-attribution.d.ts +35 -0
- package/dist/core/runner/halt-attribution.js +16 -0
- package/dist/core/runner/memory-consolidation.d.ts +0 -2
- package/dist/core/runner/memory-consolidation.js +0 -1
- package/dist/core/runner/prepare-artifact.d.ts +52 -0
- package/dist/core/runner/prepare-artifact.js +63 -0
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
- package/dist/core/runner/prepare-caps-and-workflow.js +2 -3
- package/dist/core/runner/prepare-config-doors.d.ts +3 -3
- package/dist/core/runner/prepare-config-doors.js +5 -2
- package/dist/core/runner/prepare-context-lane.d.ts +2 -2
- package/dist/core/runner/prepare-context-lane.js +2 -13
- package/dist/core/runner/prepare-file-history.d.ts +1 -1
- package/dist/core/runner/prepare-file-history.js +3 -52
- package/dist/core/runner/prepare-hands-readface.d.ts +4 -7
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +5 -2
- package/dist/core/runner/prepare-inherited-gate.js +7 -8
- package/dist/core/runner/prepare-memory.d.ts +4 -6
- package/dist/core/runner/prepare-memory.js +4 -2
- package/dist/core/runner/prepare-policy-chain.d.ts +3 -3
- package/dist/core/runner/prepare-policy-chain.js +15 -30
- package/dist/core/runner/prepare-prompt-assembly.js +1 -1
- package/dist/core/runner/prepare-question-face.js +2 -1
- package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
- package/dist/core/runner/prepare-suspend-saga.js +0 -2
- package/dist/core/runner/prepare-task.js +12 -11
- package/dist/core/runner/prepare-wiring-manifest.js +9 -7
- package/dist/core/runner/resume-admission.js +2 -1
- package/dist/core/runner/resume-internals-and-config.js +4 -0
- package/dist/core/runner/retired-runner-deps.d.ts +3 -0
- package/dist/core/runner/retired-runner-deps.js +7 -0
- package/dist/core/runner/run-harness-handlers.js +5 -3
- package/dist/core/runner/run-settle-and-teardown.d.ts +1 -1
- package/dist/core/runner/run-settle-and-teardown.js +3 -1
- package/dist/core/runner/session-file-state-replay.js +3 -3
- package/dist/core/runner/session-rule-policy.js +3 -4
- package/dist/core/runner/stream-halt-verbs.js +1 -1
- package/dist/core/runner/stream-steer-verb.js +1 -4
- package/dist/core/runner/workspace-path.js +3 -0
- package/dist/core/runner-deps.d.ts +30 -49
- package/dist/core/safe-notify.d.ts +1 -1
- package/dist/core/sensitive-path-policy.d.ts +1 -1
- package/dist/core/sensitive-path-policy.js +11 -12
- package/dist/core/session.d.ts +2 -2
- package/dist/core/skill-tool-specifier.d.ts +1 -1
- package/dist/core/skills-directory.d.ts +1 -1
- package/dist/core/skills-directory.js +4 -3
- package/dist/core/spec-contract.js +5 -4
- package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
- package/dist/core/strategy-store.d.ts +8 -11
- package/dist/core/task-event.d.ts +20 -17
- package/dist/core/task-limits.d.ts +1 -1
- package/dist/core/task-notification.d.ts +5 -5
- package/dist/core/task-registry-agent.d.ts +5 -5
- package/dist/core/task-registry-monitor.d.ts +2 -2
- package/dist/core/task-registry-shared.d.ts +32 -28
- package/dist/core/task-registry-shared.js +4 -13
- package/dist/core/task-registry.d.ts +8 -8
- package/dist/core/task-result.d.ts +37 -37
- package/dist/core/task-spec.d.ts +5 -5
- package/dist/core/task-stream.d.ts +16 -11
- package/dist/core/tool-catalog-entries.d.ts +1 -0
- package/dist/core/tool-catalog-entries.js +6 -1
- package/dist/core/tool-conformance.d.ts +0 -2
- package/dist/core/tool-conformance.js +1 -3
- package/dist/core/tool-errors.d.ts +5 -0
- package/dist/core/tool-errors.js +1 -0
- package/dist/core/tool-policy.d.ts +66 -22
- package/dist/core/tool-policy.js +31 -5
- package/dist/core/tool-result-budget.d.ts +1 -1
- package/dist/core/tool-result-store.d.ts +11 -11
- package/dist/core/tool-spec.d.ts +34 -38
- package/dist/core/tools.d.ts +2 -2
- package/dist/core/trace.d.ts +12 -15
- package/dist/core/untrusted-text.d.ts +1 -1
- package/dist/core/wiring-manifest.d.ts +4 -3
- package/dist/core/workflow-journal-store.d.ts +11 -11
- package/dist/engine/execution-env/node-execution-env.d.ts +3 -2
- package/dist/engine/execution-env/node-execution-env.js +8 -5
- package/dist/engine/harness/agent-harness.d.ts +47 -4
- package/dist/engine/harness/agent-harness.js +52 -9
- package/dist/engine/loop/agent-loop.js +15 -8
- package/dist/engine/loop/types.d.ts +5 -0
- package/dist/index.d.ts +20 -14
- package/dist/index.js +16 -10
- package/dist/internal/harness.d.ts +1 -0
- package/dist/orchestration/run-spec.d.ts +3 -0
- package/dist/orchestration/run-spec.js +3 -3
- package/dist/orchestration/run-workflow-tool.d.ts +12 -6
- package/dist/orchestration/run-workflow-tool.js +23 -5
- package/dist/orchestration/workflow-primitives.d.ts +4 -2
- package/dist/orchestration/workflow-primitives.js +1 -4
- package/dist/orchestration/workflow-script-store.js +9 -25
- package/dist/orchestration/workflow-types.d.ts +34 -4
- package/dist/orchestration/workflow-types.js +2 -0
- package/dist/orchestration/workflow.d.ts +39 -7
- package/dist/orchestration/workflow.js +237 -113
- package/dist/prompt-assembly/assemble.d.ts +2 -2
- package/dist/prompt-assembly/assemble.js +9 -9
- package/dist/prompt-assembly/composer.d.ts +6 -7
- package/dist/prompt-assembly/composer.js +10 -10
- package/dist/prompt-assembly/epoch.js +1 -1
- package/dist/prompt-assembly/event-registry.d.ts +0 -21
- package/dist/prompt-assembly/packs/sema-default.js +30 -30
- package/dist/prompt-assembly/types.d.ts +14 -14
- package/dist/prompts/coordinator.d.ts +0 -13
- package/dist/prompts/coordinator.js +0 -3
- package/dist/stores/cc/task-list-store.js +2 -10
- package/dist/stores/file/checkpoint-store.js +1 -5
- package/dist/stores/file/file-history-store.js +2 -2
- package/dist/stores/file/fs-atomic.d.ts +15 -18
- package/dist/stores/file/fs-atomic.js +4 -14
- package/dist/stores/file/mailbox-store.d.ts +7 -11
- package/dist/stores/file/mailbox-store.js +4 -11
- package/dist/stores/file/permission-rule-store.d.ts +4 -35
- package/dist/stores/file/permission-rule-store.js +4 -148
- package/dist/tools/artifact/artifact-text.d.ts +62 -0
- package/dist/tools/artifact/artifact-text.js +68 -0
- package/dist/tools/artifact/artifact-tool.d.ts +52 -0
- package/dist/tools/artifact/artifact-tool.js +351 -0
- package/dist/tools/artifact/local-stub.d.ts +26 -0
- package/dist/tools/artifact/local-stub.js +297 -0
- package/dist/tools/fs/bash-readonly-classifier.d.ts +90 -8
- package/dist/tools/fs/bash-readonly-classifier.js +294 -70
- package/dist/tools/fs/fs-bash.d.ts +14 -10
- package/dist/tools/fs/fs-bash.js +50 -33
- package/dist/tools/fs/fs-search-tools.js +5 -2
- package/dist/tools/fs/fs-shared.d.ts +2 -0
- package/dist/tools/fs/fs-shared.js +3 -11
- package/dist/tools/fs/index.d.ts +4 -0
- package/dist/tools/fs/index.js +4 -1
- package/dist/tools/fs/safety.d.ts +117 -1
- package/dist/tools/fs/safety.js +131 -31
- package/dist/tools/fs/search.js +8 -6
- package/package.json +2 -1
- package/test/export-surface.snapshot.json +119 -39
package/dist/agents/subagent.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { isAbsolute } from "node:path";
|
|
3
|
+
import { applyParentSpecSeat, parentSpecSeatOfCtx } from "../core/parent-spec-seat.js";
|
|
4
|
+
import { stripSpawnTurnQuestionFace } from "../core/ask-question.js";
|
|
3
5
|
import { withDelegationProvenance } from "../core/tool-policy.js";
|
|
4
6
|
import { errorResult } from "../core/tools.js";
|
|
5
7
|
import { isHighSurrogate, isLowSurrogate } from "../core/surrogate-safe-slice.js";
|
|
@@ -448,10 +450,6 @@ function unparkedDurablePauseReason(d) {
|
|
|
448
450
|
function errorKindClause(c) {
|
|
449
451
|
return c !== undefined ? ` (error_kind: ${c.errorKind}, retryable: ${c.retryable})` : "";
|
|
450
452
|
}
|
|
451
|
-
function stripSpawnTurnQuestionFace(spec) {
|
|
452
|
-
const { onQuestion: spawnTurnQuestionFace, ...rest } = spec;
|
|
453
|
-
return { spec: rest, internalsFlag: spawnTurnQuestionFace !== undefined ? { questionFaceStripped: true } : {} };
|
|
454
|
-
}
|
|
455
453
|
const FAILED_SESSION_RETAIN_TTL_MS = 15 * 60 * 1000;
|
|
456
454
|
const PARTIAL_FINDINGS_MAX_CHARS = 1200;
|
|
457
455
|
const BG_NOTIFY_DRAIN_WINDOW_MS = 2_000;
|
|
@@ -1487,6 +1485,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
1487
1485
|
prepareArguments: (args) => foldGeneralPurposeAlias(args, generalPurposeShadowed),
|
|
1488
1486
|
execute: async (args, ctx) => {
|
|
1489
1487
|
const a = foldGeneralPurposeAlias(args, generalPurposeShadowed);
|
|
1488
|
+
const parentSpecSeat = parentSpecSeatOfCtx(ctx);
|
|
1490
1489
|
const reviveClaim = ctx.reviveClaim;
|
|
1491
1490
|
if (reviveClaim !== undefined && opts.background === undefined) {
|
|
1492
1491
|
return {
|
|
@@ -2074,6 +2073,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
2074
2073
|
...(childProvenanceRef !== undefined && provenanceRequest !== undefined ? { delegationProvenance: { ref: childProvenanceRef, contentSafety: provenanceRequest } } : {}),
|
|
2075
2074
|
...(treeScope !== undefined ? { registryScope: treeScope } : {}),
|
|
2076
2075
|
...(ctx.inheritedGateForChildren ? { inheritedGate: ctx.inheritedGateForChildren() } : {}),
|
|
2076
|
+
...(ctx.questionFaceStripped === true ? { questionFaceStripped: true } : {}),
|
|
2077
2077
|
ownOrgAdmissionRef: { current: reviveClaim !== undefined ? readDurableOrgAdmission(reviveClaim.row) : undefined },
|
|
2078
2078
|
peerSelfRef: (() => {
|
|
2079
2079
|
const ref = createPeerSelfRef(treeScope ?? "default");
|
|
@@ -2138,7 +2138,6 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
2138
2138
|
? ctx.thinkingLevel !== undefined ? { thinking: ctx.thinkingLevel } : {}
|
|
2139
2139
|
: childThinkingSeat(def?.thinking, deploymentSubagentThinking(runnerRoleMap(opts.runner)), ctx.thinkingLevel);
|
|
2140
2140
|
const provenanceAgentName = agentName ?? def?.name;
|
|
2141
|
-
const childMemoryPersistenceCapable = ctx.memoryPersistenceCapable === false ? false : (def?.memoryPersistenceCapable ?? ctx.memoryPersistenceCapable);
|
|
2142
2141
|
const childOnAsk = ctx.onAsk !== undefined
|
|
2143
2142
|
? withDelegationProvenance(ctx.onAsk, {
|
|
2144
2143
|
parentToolCallId: ctx.toolCallId,
|
|
@@ -2146,7 +2145,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
2146
2145
|
...(provenanceAgentName !== undefined ? { agentName: provenanceAgentName } : {}),
|
|
2147
2146
|
})
|
|
2148
2147
|
: undefined;
|
|
2149
|
-
const buildChildSpec = (signal) => ({
|
|
2148
|
+
const buildChildSpec = (signal) => applyParentSpecSeat({
|
|
2150
2149
|
objective: prompt,
|
|
2151
2150
|
...childSeat,
|
|
2152
2151
|
...childThinking,
|
|
@@ -2154,30 +2153,23 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
2154
2153
|
systemPrompt: childSystemPrompt,
|
|
2155
2154
|
...(def?.memory ? { memory: def.memory } : {}),
|
|
2156
2155
|
...(def?.skills?.length ? { skills: def.skills } : {}),
|
|
2157
|
-
...(
|
|
2156
|
+
...(def?.memoryPersistenceCapable !== undefined ? { memoryPersistenceCapable: def.memoryPersistenceCapable } : {}),
|
|
2158
2157
|
...(ctx.checkpointStoreForChildren !== undefined ? { checkpointStore: ctx.checkpointStoreForChildren } : {}),
|
|
2159
2158
|
...(childOnAsk !== undefined ? { onAsk: childOnAsk } : {}),
|
|
2160
|
-
...(ctx.onQuestion !== undefined ? { onQuestion: ctx.onQuestion } : {}),
|
|
2161
2159
|
...(ctx.interactiveTools === false ? { interactiveTools: false } : {}),
|
|
2162
2160
|
...(ctx.handsReadOnly === true ? { handsReadOnly: true } : {}),
|
|
2163
2161
|
...(ctx.readFace === "roots" ? { readFace: "roots" } : {}),
|
|
2164
2162
|
...(ctx.readDenyPatterns !== undefined ? { readDenyPatterns: [...ctx.readDenyPatterns] } : {}),
|
|
2165
|
-
...(childMemoryPersistenceCapable !== undefined ? { memoryPersistenceCapable: childMemoryPersistenceCapable } : {}),
|
|
2166
|
-
...(ctx.oneShot === true ? { oneShot: true } : {}),
|
|
2167
|
-
...(ctx.clientContext !== undefined ? { clientContext: ctx.clientContext } : {}),
|
|
2168
2163
|
...(ctx.excludeTools !== undefined ? { excludeTools: [...ctx.excludeTools] } : {}),
|
|
2169
2164
|
...(ctx.deferTools !== undefined ? { deferTools: [...ctx.deferTools] } : {}),
|
|
2170
2165
|
...(ctx.alwaysLoadTools !== undefined ? { alwaysLoadTools: [...ctx.alwaysLoadTools] } : {}),
|
|
2171
2166
|
...(ctx.restoreGatedTools !== undefined ? { restoreGatedTools: ctx.restoreGatedTools === true ? true : [...ctx.restoreGatedTools] } : {}),
|
|
2172
2167
|
...(ctx.promptProfile !== undefined ? { promptProfile: ctx.promptProfile } : {}),
|
|
2173
|
-
...(ctx.additionalDirectories !== undefined ? { additionalDirectories: [...ctx.additionalDirectories] } : {}),
|
|
2174
|
-
...(ctx.additionalReadDirectories !== undefined ? { additionalReadDirectories: [...ctx.additionalReadDirectories] } : {}),
|
|
2175
|
-
...(ctx.envFacts !== undefined ? { envFacts: { ...ctx.envFacts } } : {}),
|
|
2176
2168
|
...(ctx.getApiKeyAndHeaders !== undefined ? { getApiKeyAndHeaders: ctx.getApiKeyAndHeaders } : {}),
|
|
2177
2169
|
enableBlockedReport: true,
|
|
2178
2170
|
limits: childLimits,
|
|
2179
2171
|
signal,
|
|
2180
|
-
});
|
|
2172
|
+
}, parentSpecSeat);
|
|
2181
2173
|
const tryRetainChild = async (ledger, entryTtlMs, preMintedSessionId, durableProbe, releaseAnchor, internalsExtra) => {
|
|
2182
2174
|
if (!ledger)
|
|
2183
2175
|
return undefined;
|
|
@@ -43,8 +43,8 @@ export declare const AUTH_CARRIER_NAMES: ReadonlySet<string>;
|
|
|
43
43
|
* case-variant; the WINNER'S spelling and value survive (a single-spelling config — every existing
|
|
44
44
|
* deployment — is byte-identical on the wire).
|
|
45
45
|
*
|
|
46
|
-
* EXEMPT: the auth carriers (`authorization` / `x-api-key`, any case) pass through with
|
|
47
|
-
*
|
|
46
|
+
* EXEMPT: the auth carriers (`authorization` / `x-api-key`, any case) pass through with plain
|
|
47
|
+
* spread semantics (same-spelling override only, no case-fold dedup), so that the credential
|
|
48
48
|
* enforcement (`applyRouteCredentialHeaders`, route-adjudicator.ts) stays the ONE authority over
|
|
49
49
|
* auth spelling and this layer never becomes a second, subtly different one.
|
|
50
50
|
*
|
|
@@ -29,13 +29,6 @@ export declare const RETAIN_DEFAULT_MAX = 16;
|
|
|
29
29
|
* the same key (see the enforcement site for the exact retained-window semantics). */
|
|
30
30
|
export declare const DELEGATION_MAX_CONCURRENT_DEFAULT = 20;
|
|
31
31
|
export declare const DELEGATION_MAX_PER_SESSION_DEFAULT = 200;
|
|
32
|
-
/** Subagent transcript persistence — orphan adoption (CC parity: after a restart a deployment
|
|
33
|
-
* auto-adopts at most this many stale rows whose transcript mtime is inside the window; older ones
|
|
34
|
-
* stay MANUALLY continuable for the whole retention period — never deleted by the window). The
|
|
35
|
-
* TRIGGER is deployment-owned (core has no daemon and never revives runs nobody asked for); these
|
|
36
|
-
* constants are the shared vocabulary so every deployment adopts by the same numbers. */
|
|
37
|
-
export declare const ORPHAN_ADOPT_WINDOW_MS_DEFAULT: number;
|
|
38
|
-
export declare const ORPHAN_ADOPT_MAX_DEFAULT = 20;
|
|
39
32
|
/** Subagent transcript persistence — the default transcript retention period (CC
|
|
40
33
|
* cleanupPeriodDays parity). Core ships NO sweeper (design/151 ruling 2): the blessed path is the
|
|
41
34
|
* deployment calling `TaskRegistry.reapDurableAgents` with `maxAgeMs` derived from this (boot +
|
package/dist/config/defaults.js
CHANGED
|
@@ -2,8 +2,6 @@ export const RETAIN_DEFAULT_TTL_MS = 30 * 60 * 1000;
|
|
|
2
2
|
export const RETAIN_DEFAULT_MAX = 16;
|
|
3
3
|
export const DELEGATION_MAX_CONCURRENT_DEFAULT = 20;
|
|
4
4
|
export const DELEGATION_MAX_PER_SESSION_DEFAULT = 200;
|
|
5
|
-
export const ORPHAN_ADOPT_WINDOW_MS_DEFAULT = 48 * 60 * 60 * 1000;
|
|
6
|
-
export const ORPHAN_ADOPT_MAX_DEFAULT = 20;
|
|
7
5
|
export const SUBAGENT_TRANSCRIPT_RETENTION_DAYS_DEFAULT = 30;
|
|
8
6
|
export const SESSION_DEFAULT_TTL_DAYS = 7;
|
|
9
7
|
export const RUNNING_AGENT_OBSERVE_EVERY_BEATS = 4;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import type { AssertAllKeysHandled } from "./ask-origin.js";
|
|
2
|
+
/** The model-facing action words. `publish` is the default action and the one every host must declare. */
|
|
3
|
+
export declare const ARTIFACT_ACTIONS: readonly ["publish", "list", "read", "list_files", "read_file"];
|
|
4
|
+
export type ArtifactAction = (typeof ARTIFACT_ACTIONS)[number];
|
|
5
|
+
/** Which face the host serves. `"local-stub"` = publish-only local storage with `eval-stub://` links;
|
|
6
|
+
* `"hosted"` = a hosting plane that mints its own URLs. Declared by the host, never detected. */
|
|
7
|
+
export declare const ARTIFACT_PLANES: readonly ["hosted", "local-stub"];
|
|
8
|
+
export type ArtifactPlane = (typeof ARTIFACT_PLANES)[number];
|
|
9
|
+
/** The `publishContext` word a publish carries (default `"plain"`). */
|
|
10
|
+
export declare const ARTIFACT_PUBLISH_CONTEXTS: readonly ["pr_review", "workshop", "whiteboard", "prototype", "plain"];
|
|
11
|
+
export type ArtifactPublishContext = (typeof ARTIFACT_PUBLISH_CONTEXTS)[number];
|
|
12
|
+
/** The `list` scope words. */
|
|
13
|
+
export declare const ARTIFACT_LIST_SCOPES: readonly ["mine", "shared", "all"];
|
|
14
|
+
export type ArtifactListScope = (typeof ARTIFACT_LIST_SCOPES)[number];
|
|
15
|
+
/**
|
|
16
|
+
* The content-origin class of the mounted tool, derived from the declared plane: a hosted plane hands
|
|
17
|
+
* back host-controlled bytes (URLs, titles, page content) and is classified external; the local stub
|
|
18
|
+
* reads nothing back from outside the process. Plane-keyed, never implementation-keyed.
|
|
19
|
+
*/
|
|
20
|
+
export declare const ARTIFACT_PLANE_CONTENT_ORIGIN: {
|
|
21
|
+
readonly hosted: "external";
|
|
22
|
+
readonly "local-stub": "local";
|
|
23
|
+
};
|
|
24
|
+
export type ContentOriginTableCoversEveryPlane = AssertAllKeysHandled<Exclude<ArtifactPlane, keyof typeof ARTIFACT_PLANE_CONTENT_ORIGIN>>;
|
|
25
|
+
/** The host method each declared action is served by; the mount-time validator probes the method's presence. */
|
|
26
|
+
export declare const ARTIFACT_ACTION_HOST_METHOD: {
|
|
27
|
+
readonly publish: "publish";
|
|
28
|
+
readonly list: "list";
|
|
29
|
+
readonly read: "read";
|
|
30
|
+
readonly list_files: "listFiles";
|
|
31
|
+
readonly read_file: "readFile";
|
|
32
|
+
};
|
|
33
|
+
export type HostMethodTableCoversEveryAction = AssertAllKeysHandled<Exclude<ArtifactAction, keyof typeof ARTIFACT_ACTION_HOST_METHOD>>;
|
|
34
|
+
/** The typed failure words a host outcome may carry (`ok: false`). */
|
|
35
|
+
export declare const ARTIFACT_HOST_FAILURE_CODES: readonly ["conflict", "url_foreign", "forbidden", "payload_too_large", "not_found", "force_refused", "refused"];
|
|
36
|
+
export type ArtifactHostFailureCode = (typeof ARTIFACT_HOST_FAILURE_CODES)[number];
|
|
37
|
+
/** The tool-result `details.code` (and `tool_end.errorCode`) each host failure word is projected to. */
|
|
38
|
+
export declare const ARTIFACT_FAILURE_RESULT_CODE: {
|
|
39
|
+
readonly conflict: "artifact.publish_conflict";
|
|
40
|
+
readonly url_foreign: "artifact.url_foreign";
|
|
41
|
+
readonly forbidden: "artifact.forbidden";
|
|
42
|
+
readonly payload_too_large: "artifact.payload_too_large";
|
|
43
|
+
readonly not_found: "artifact.not_found";
|
|
44
|
+
readonly force_refused: "artifact.force_refused";
|
|
45
|
+
readonly refused: "artifact.refused";
|
|
46
|
+
};
|
|
47
|
+
export type ResultCodeTableCoversEveryHostFailure = AssertAllKeysHandled<Exclude<ArtifactHostFailureCode, keyof typeof ARTIFACT_FAILURE_RESULT_CODE>>;
|
|
48
|
+
/** The one result code that is not a host word: the host threw, timed out, or answered outside its contract. */
|
|
49
|
+
export declare const ARTIFACT_HOST_ERROR_CODE = "artifact.host_error";
|
|
50
|
+
export type ArtifactResultCode = (typeof ARTIFACT_FAILURE_RESULT_CODE)[ArtifactHostFailureCode] | typeof ARTIFACT_HOST_ERROR_CODE;
|
|
51
|
+
/** The `details.type` card the Artifact tool mints on every result. */
|
|
52
|
+
export declare const ARTIFACT_CARD = "artifact";
|
|
53
|
+
/**
|
|
54
|
+
* What a host declares at mount time. Invariants (a violation refuses the mount and announces
|
|
55
|
+
* `config.artifact_host_invalid`): `actions` non-empty, duplicate-free, within {@link ARTIFACT_ACTIONS},
|
|
56
|
+
* containing `"publish"`; `plane: "local-stub"` ⇒ `actions` is exactly `["publish"]`;
|
|
57
|
+
* `defaultVisibility` is `"private"`; both byte limits are positive finite integers; `multiFile` is a
|
|
58
|
+
* boolean; every declared action's host method exists; `plane: "local-stub"` ⇒ `storageDir` is a non-empty
|
|
59
|
+
* absolute path.
|
|
60
|
+
*/
|
|
61
|
+
export interface ArtifactHostCapabilities {
|
|
62
|
+
plane: ArtifactPlane;
|
|
63
|
+
actions: ReadonlyArray<ArtifactAction>;
|
|
64
|
+
/** The on-disk store of a `"local-stub"` plane (required there; ignored on `"hosted"`). Contract: the store
|
|
65
|
+
* must lie OUTSIDE every root the run may write or read (the task root, `additionalDirectories`,
|
|
66
|
+
* `additionalReadDirectories`) — a store the model can reach through the fs tools is not a trust boundary;
|
|
67
|
+
* the engine refuses the mount (`config.artifact_host_invalid`) when it is inside one. */
|
|
68
|
+
storageDir?: string;
|
|
69
|
+
/** The only value this version mounts: a page is private until its owner shares it. */
|
|
70
|
+
defaultVisibility: "private";
|
|
71
|
+
maxFileBytes: number;
|
|
72
|
+
maxTotalBytes: number;
|
|
73
|
+
/** `false` ⇒ the publish arm takes one `file_path` only (`files[]` leaves the schema). */
|
|
74
|
+
multiFile: boolean;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Engine-minted call attribution and idempotency keys — closure-supplied, never a tool parameter.
|
|
78
|
+
* `taskId` / `sessionId` / `agentName` are audit attribution, never an authorization subject: a host
|
|
79
|
+
* instance is bound to one principal at construction. `runId` and `attemptId` are engine-minted trusted
|
|
80
|
+
* keys: `runId` is the same value `onMount` received; `attemptId` is one opaque value per tool call,
|
|
81
|
+
* stable across any host retry of that call, so a host MUST replay the first outcome for a repeated
|
|
82
|
+
* `attemptId` (a fresh publish never mints a second page, an update never advances twice).
|
|
83
|
+
*/
|
|
84
|
+
export interface ArtifactCallContext {
|
|
85
|
+
taskId: string;
|
|
86
|
+
sessionId?: string;
|
|
87
|
+
agentName?: string;
|
|
88
|
+
runId: string;
|
|
89
|
+
attemptId: string;
|
|
90
|
+
}
|
|
91
|
+
export interface ArtifactFileContent {
|
|
92
|
+
path: string;
|
|
93
|
+
content: Uint8Array;
|
|
94
|
+
mediaType?: string;
|
|
95
|
+
}
|
|
96
|
+
export interface ArtifactPublishRequest {
|
|
97
|
+
slug?: string;
|
|
98
|
+
/** Update locator. Present without `baseVersion` ⇒ the host applies last-write-wins. */
|
|
99
|
+
url?: string;
|
|
100
|
+
files: ReadonlyArray<ArtifactFileContent>;
|
|
101
|
+
/** Reserved on the seam; the model face does not expose it in this version. A host MAY refuse it. */
|
|
102
|
+
removeFiles?: ReadonlyArray<string>;
|
|
103
|
+
title?: string;
|
|
104
|
+
description?: string;
|
|
105
|
+
favicon?: string;
|
|
106
|
+
label?: string;
|
|
107
|
+
baseVersion?: string;
|
|
108
|
+
force?: boolean;
|
|
109
|
+
publishContext: ArtifactPublishContext;
|
|
110
|
+
}
|
|
111
|
+
/** The reference shape every publish / list / read result carries. */
|
|
112
|
+
export interface ArtifactRef {
|
|
113
|
+
url: string;
|
|
114
|
+
slug: string;
|
|
115
|
+
version: string;
|
|
116
|
+
title?: string;
|
|
117
|
+
}
|
|
118
|
+
export interface ArtifactListRow extends ArtifactRef {
|
|
119
|
+
owner: "mine" | "shared";
|
|
120
|
+
updatedAt: string;
|
|
121
|
+
}
|
|
122
|
+
export interface ArtifactConflictSnapshot {
|
|
123
|
+
files: ReadonlyArray<ArtifactFileContent>;
|
|
124
|
+
title?: string;
|
|
125
|
+
description?: string;
|
|
126
|
+
favicon?: string;
|
|
127
|
+
label?: string;
|
|
128
|
+
}
|
|
129
|
+
export type ArtifactPublishOutcome = {
|
|
130
|
+
ok: true;
|
|
131
|
+
ref: ArtifactRef;
|
|
132
|
+
} | {
|
|
133
|
+
ok: false;
|
|
134
|
+
code: "conflict";
|
|
135
|
+
currentVersion: string;
|
|
136
|
+
current: ArtifactConflictSnapshot | "reread";
|
|
137
|
+
} | {
|
|
138
|
+
ok: false;
|
|
139
|
+
code: Exclude<ArtifactHostFailureCode, "conflict">;
|
|
140
|
+
message: string;
|
|
141
|
+
};
|
|
142
|
+
export type ArtifactListOutcome = {
|
|
143
|
+
ok: true;
|
|
144
|
+
rows: ReadonlyArray<ArtifactListRow>;
|
|
145
|
+
truncated: boolean;
|
|
146
|
+
} | {
|
|
147
|
+
ok: false;
|
|
148
|
+
code: "refused";
|
|
149
|
+
message: string;
|
|
150
|
+
};
|
|
151
|
+
export type ArtifactReadOutcome = {
|
|
152
|
+
ok: true;
|
|
153
|
+
ref: ArtifactRef;
|
|
154
|
+
content: string;
|
|
155
|
+
isolatedSummary: boolean;
|
|
156
|
+
} | {
|
|
157
|
+
ok: false;
|
|
158
|
+
code: "not_found" | "forbidden";
|
|
159
|
+
message: string;
|
|
160
|
+
};
|
|
161
|
+
export type ArtifactFilesOutcome = {
|
|
162
|
+
ok: true;
|
|
163
|
+
entries: ReadonlyArray<{
|
|
164
|
+
path: string;
|
|
165
|
+
bytes: number;
|
|
166
|
+
mediaType?: string;
|
|
167
|
+
}>;
|
|
168
|
+
} | {
|
|
169
|
+
ok: false;
|
|
170
|
+
code: "not_found" | "forbidden";
|
|
171
|
+
message: string;
|
|
172
|
+
};
|
|
173
|
+
export type ArtifactFileOutcome = {
|
|
174
|
+
ok: true;
|
|
175
|
+
file: ArtifactFileContent;
|
|
176
|
+
} | {
|
|
177
|
+
ok: false;
|
|
178
|
+
code: "not_found" | "forbidden";
|
|
179
|
+
message: string;
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* The hosting seat. Atomicity contract: no half version is ever observable — a reader sees the old
|
|
183
|
+
* complete version or the new complete version, never a mix of files / metadata / version number.
|
|
184
|
+
* The commit itself may be uncertain from the engine's side (the answer was lost after the host
|
|
185
|
+
* committed); the `attemptId` replay rule above is what makes a retry of that call converge.
|
|
186
|
+
*/
|
|
187
|
+
export interface ArtifactHost {
|
|
188
|
+
capabilities(): ArtifactHostCapabilities;
|
|
189
|
+
/** Called at every materialization of a run (prepare and resume) with the engine-minted run id. */
|
|
190
|
+
onMount?(runId: string): void;
|
|
191
|
+
publish(req: ArtifactPublishRequest, ctx: ArtifactCallContext): Promise<ArtifactPublishOutcome>;
|
|
192
|
+
list?(req: {
|
|
193
|
+
scope: ArtifactListScope;
|
|
194
|
+
limit: number;
|
|
195
|
+
}, ctx: ArtifactCallContext): Promise<ArtifactListOutcome>;
|
|
196
|
+
read?(req: {
|
|
197
|
+
url: string;
|
|
198
|
+
}, ctx: ArtifactCallContext): Promise<ArtifactReadOutcome>;
|
|
199
|
+
listFiles?(req: {
|
|
200
|
+
url: string;
|
|
201
|
+
}, ctx: ArtifactCallContext): Promise<ArtifactFilesOutcome>;
|
|
202
|
+
readFile?(req: {
|
|
203
|
+
url: string;
|
|
204
|
+
path: string;
|
|
205
|
+
}, ctx: ArtifactCallContext): Promise<ArtifactFileOutcome>;
|
|
206
|
+
}
|
|
207
|
+
export type ArtifactHostCapabilitiesVerdict = {
|
|
208
|
+
ok: true;
|
|
209
|
+
capabilities: ArtifactHostCapabilities;
|
|
210
|
+
} | {
|
|
211
|
+
ok: false;
|
|
212
|
+
problem: string;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Read and validate a host's declaration. Every invariant of {@link ArtifactHostCapabilities} is judged
|
|
216
|
+
* here and nowhere else; a `problem` names the first violated one in operator-facing words.
|
|
217
|
+
*/
|
|
218
|
+
export declare function readArtifactHostCapabilities(host: unknown): ArtifactHostCapabilitiesVerdict;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { isAbsolute } from "node:path";
|
|
2
|
+
export const ARTIFACT_ACTIONS = ["publish", "list", "read", "list_files", "read_file"];
|
|
3
|
+
export const ARTIFACT_PLANES = ["hosted", "local-stub"];
|
|
4
|
+
export const ARTIFACT_PUBLISH_CONTEXTS = ["pr_review", "workshop", "whiteboard", "prototype", "plain"];
|
|
5
|
+
export const ARTIFACT_LIST_SCOPES = ["mine", "shared", "all"];
|
|
6
|
+
export const ARTIFACT_PLANE_CONTENT_ORIGIN = {
|
|
7
|
+
hosted: "external",
|
|
8
|
+
"local-stub": "local",
|
|
9
|
+
};
|
|
10
|
+
export const ARTIFACT_ACTION_HOST_METHOD = {
|
|
11
|
+
publish: "publish",
|
|
12
|
+
list: "list",
|
|
13
|
+
read: "read",
|
|
14
|
+
list_files: "listFiles",
|
|
15
|
+
read_file: "readFile",
|
|
16
|
+
};
|
|
17
|
+
export const ARTIFACT_HOST_FAILURE_CODES = ["conflict", "url_foreign", "forbidden", "payload_too_large", "not_found", "force_refused", "refused"];
|
|
18
|
+
export const ARTIFACT_FAILURE_RESULT_CODE = {
|
|
19
|
+
conflict: "artifact.publish_conflict",
|
|
20
|
+
url_foreign: "artifact.url_foreign",
|
|
21
|
+
forbidden: "artifact.forbidden",
|
|
22
|
+
payload_too_large: "artifact.payload_too_large",
|
|
23
|
+
not_found: "artifact.not_found",
|
|
24
|
+
force_refused: "artifact.force_refused",
|
|
25
|
+
refused: "artifact.refused",
|
|
26
|
+
};
|
|
27
|
+
export const ARTIFACT_HOST_ERROR_CODE = "artifact.host_error";
|
|
28
|
+
export const ARTIFACT_CARD = "artifact";
|
|
29
|
+
const isPositiveInt = (v) => typeof v === "number" && Number.isSafeInteger(v) && v > 0;
|
|
30
|
+
const wordOf = (set, v) => typeof v === "string" && set.includes(v);
|
|
31
|
+
export function readArtifactHostCapabilities(host) {
|
|
32
|
+
if (host === null || typeof host !== "object")
|
|
33
|
+
return { ok: false, problem: "artifactHost is not an object" };
|
|
34
|
+
const h = host;
|
|
35
|
+
if (typeof h.capabilities !== "function")
|
|
36
|
+
return { ok: false, problem: "artifactHost.capabilities is not a function" };
|
|
37
|
+
let raw;
|
|
38
|
+
try {
|
|
39
|
+
raw = h.capabilities.call(host);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
return { ok: false, problem: `artifactHost.capabilities() threw: ${err instanceof Error ? err.message : String(err)}` };
|
|
43
|
+
}
|
|
44
|
+
if (raw === null || typeof raw !== "object")
|
|
45
|
+
return { ok: false, problem: "artifactHost.capabilities() did not return an object" };
|
|
46
|
+
const c = raw;
|
|
47
|
+
const plane = c["plane"];
|
|
48
|
+
if (!wordOf(ARTIFACT_PLANES, plane))
|
|
49
|
+
return { ok: false, problem: `capabilities.plane must be one of ${ARTIFACT_PLANES.join(" | ")}` };
|
|
50
|
+
const actions = c["actions"];
|
|
51
|
+
if (!Array.isArray(actions) || actions.length === 0)
|
|
52
|
+
return { ok: false, problem: "capabilities.actions must be a non-empty array" };
|
|
53
|
+
for (const a of actions)
|
|
54
|
+
if (!wordOf(ARTIFACT_ACTIONS, a))
|
|
55
|
+
return { ok: false, problem: `capabilities.actions carries a word outside ${ARTIFACT_ACTIONS.join(" | ")}` };
|
|
56
|
+
if (new Set(actions).size !== actions.length)
|
|
57
|
+
return { ok: false, problem: "capabilities.actions carries a duplicate" };
|
|
58
|
+
if (!actions.includes("publish"))
|
|
59
|
+
return { ok: false, problem: 'capabilities.actions must include "publish"' };
|
|
60
|
+
if (plane === "local-stub" && (actions.length !== 1 || actions[0] !== "publish"))
|
|
61
|
+
return { ok: false, problem: 'a "local-stub" plane must declare exactly ["publish"]' };
|
|
62
|
+
if (c["defaultVisibility"] !== "private")
|
|
63
|
+
return { ok: false, problem: 'capabilities.defaultVisibility must be "private"' };
|
|
64
|
+
if (!isPositiveInt(c["maxFileBytes"]))
|
|
65
|
+
return { ok: false, problem: "capabilities.maxFileBytes must be a positive integer" };
|
|
66
|
+
if (!isPositiveInt(c["maxTotalBytes"]))
|
|
67
|
+
return { ok: false, problem: "capabilities.maxTotalBytes must be a positive integer" };
|
|
68
|
+
if (typeof c["multiFile"] !== "boolean")
|
|
69
|
+
return { ok: false, problem: "capabilities.multiFile must be a boolean" };
|
|
70
|
+
const storageDir = c["storageDir"];
|
|
71
|
+
if (plane === "local-stub" && (typeof storageDir !== "string" || storageDir.length === 0 || !isAbsolute(storageDir)))
|
|
72
|
+
return { ok: false, problem: 'a "local-stub" plane must declare its absolute storageDir' };
|
|
73
|
+
if (storageDir !== undefined && typeof storageDir !== "string")
|
|
74
|
+
return { ok: false, problem: "capabilities.storageDir must be a string when present" };
|
|
75
|
+
for (const a of actions) {
|
|
76
|
+
const method = ARTIFACT_ACTION_HOST_METHOD[a];
|
|
77
|
+
if (typeof host[method] !== "function")
|
|
78
|
+
return { ok: false, problem: `capabilities.actions declares "${a}" but artifactHost.${method} is not a function` };
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
ok: true,
|
|
82
|
+
capabilities: Object.freeze({
|
|
83
|
+
plane,
|
|
84
|
+
actions: Object.freeze([...actions]),
|
|
85
|
+
defaultVisibility: "private",
|
|
86
|
+
maxFileBytes: c["maxFileBytes"],
|
|
87
|
+
maxTotalBytes: c["maxTotalBytes"],
|
|
88
|
+
multiFile: c["multiFile"],
|
|
89
|
+
...(typeof storageDir === "string" ? { storageDir } : {}),
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
@@ -246,11 +246,14 @@ export declare function classifierMayAnswer(origin: AskOrigin): boolean;
|
|
|
246
246
|
* the same way every other per-call fact does: the gate stamps it on the surviving ask, the
|
|
247
247
|
* synchronous sites read it off the decision they spread, and the park leg threads its own parameter.
|
|
248
248
|
*/
|
|
249
|
-
export declare function persistedRuleMandateOf(marks:
|
|
249
|
+
export declare function persistedRuleMandateOf(marks: MandateMarks): "operator_always" | "tool_marks" | "probe_mandate" | "probe_unanswered" | undefined;
|
|
250
|
+
/** The mark inputs of the two mandate derivations — properties of the tool SEAT (`egress`, `shellGated`,
|
|
251
|
+
* `irreversibility`) beside the two per-call facts the gate stamps. */
|
|
252
|
+
export interface MandateMarks {
|
|
250
253
|
egress?: boolean;
|
|
251
254
|
shellGated?: boolean;
|
|
252
255
|
irreversibility?: "never" | "maybe" | "always";
|
|
253
|
-
/**
|
|
256
|
+
/** The surviving ask's engine-stamped `probeMandated` — see
|
|
254
257
|
* {@link import("./types.js").ReversibilityVerdict.mandated}. */
|
|
255
258
|
probeMandated?: boolean;
|
|
256
259
|
/** The pass's own record that the probe was consulted and did not answer (`GatePass.probeUnanswered`):
|
|
@@ -258,7 +261,30 @@ export declare function persistedRuleMandateOf(marks: {
|
|
|
258
261
|
* not see the pass and never passes it — a card may offer a rule the lane then discloses as shadowed
|
|
259
262
|
* (loud, never a silent override), the same drift window the `matchedAskRule` conjunct already has. */
|
|
260
263
|
probeUnanswered?: boolean;
|
|
261
|
-
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* The SAFETY AXIS of one ask — what makes its durable park NON-BUDGETABLE (`irreversible_ask`), judged
|
|
267
|
+
* from the same mark inputs as the rule-lane mandate plus the gate's own record of which tighten minted the
|
|
268
|
+
* ask. `egress` is the tool's static external-write mark, as it always was. `irreversible` is a mandate of
|
|
269
|
+
* THIS call: the tool's own tier (`tool_marks` — the deployment declared the tool may be irreversible,
|
|
270
|
+
* and a policy or hook asking first does not un-declare it), the operator's per-call doctrine
|
|
271
|
+
* (`operator_always`), the probe's structural verdict (`probe_mandate` / `probe_unanswered`), OR — under a
|
|
272
|
+
* shell-seat-installed `"maybe"` tier — the shell gate's own tighten having minted this ask (the doctrine's
|
|
273
|
+
* probe judged THIS command not reversible). A policy ask on a shell-gated tool that the doctrine's probe
|
|
274
|
+
* did not tighten and did not mandate is a plain ask: the tier was the probe's instrument, not a risk
|
|
275
|
+
* label, and the park stays the budgetable kind. Before this derivation the static tier alone set the bit,
|
|
276
|
+
* so every policy ask on Bash under `shellGate:"classify"` parked non-budgetable.
|
|
277
|
+
*
|
|
278
|
+
* Deliberately NOT the rule-lane predicate verbatim: a shell tighten's ask is rule-clearable (a person's
|
|
279
|
+
* past yes to this command shape stands) yet non-budgetable (a budget's mechanical yes is not a person's).
|
|
280
|
+
* The two derivations share every other row through {@link irreversibilityMandateOf}.
|
|
281
|
+
*/
|
|
282
|
+
export declare function safetyAxisOf(marks: MandateMarks & {
|
|
283
|
+
readonly tightened: AskOriginFacts["tightened"];
|
|
284
|
+
}): {
|
|
285
|
+
egress: boolean;
|
|
286
|
+
irreversible: boolean;
|
|
287
|
+
} | undefined;
|
|
262
288
|
/** The PROBE half of the mandated family (the deployment's read boundary, judged per call): neither a standing rule
|
|
263
289
|
* nor the classifier clears these two words; `tool_marks`/`operator_always` bind the rule lane only (`safety_tighten`). */
|
|
264
290
|
export declare function probeBoundaryMandate(word: ReturnType<typeof persistedRuleMandateOf>): boolean;
|
package/dist/core/ask-origin.js
CHANGED
|
@@ -68,19 +68,27 @@ export function classifierMayAnswer(origin) {
|
|
|
68
68
|
return CLASSIFIER_MAY_ANSWER[origin];
|
|
69
69
|
}
|
|
70
70
|
export function persistedRuleMandateOf(marks) {
|
|
71
|
+
const word = irreversibilityMandateOf(marks);
|
|
72
|
+
return probeBoundaryMandate(word) ? word : marks.egress === true ? "tool_marks" : word;
|
|
73
|
+
}
|
|
74
|
+
function irreversibilityMandateOf(marks) {
|
|
71
75
|
return marks.probeMandated === true
|
|
72
76
|
? "probe_mandate"
|
|
73
77
|
: marks.probeUnanswered === true
|
|
74
78
|
? "probe_unanswered"
|
|
75
|
-
: marks.
|
|
76
|
-
? "
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
:
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
: marks.shellGated === true
|
|
80
|
+
? marks.irreversibility === "always"
|
|
81
|
+
? "operator_always"
|
|
82
|
+
: undefined
|
|
83
|
+
: marks.irreversibility === "always" || marks.irreversibility === "maybe"
|
|
84
|
+
? "tool_marks"
|
|
85
|
+
: undefined;
|
|
86
|
+
}
|
|
87
|
+
export function safetyAxisOf(marks) {
|
|
88
|
+
const egress = marks.egress === true;
|
|
89
|
+
const irreversible = irreversibilityMandateOf(marks) !== undefined ||
|
|
90
|
+
(marks.shellGated === true && marks.irreversibility === "maybe" && marks.tightened === "shell_gate");
|
|
91
|
+
return egress || irreversible ? { egress, irreversible } : undefined;
|
|
84
92
|
}
|
|
85
93
|
export function probeBoundaryMandate(word) {
|
|
86
94
|
return word === "probe_mandate" || word === "probe_unanswered";
|
|
@@ -348,3 +348,28 @@ source?: {
|
|
|
348
348
|
principal?: string;
|
|
349
349
|
sourceTaskId?: string;
|
|
350
350
|
}, opts?: AskUserQuestionToolOptions): AgentTool;
|
|
351
|
+
/**
|
|
352
|
+
* The ONE producer of the "engine stripped the spawn turn's question face" fact. The strip (removing `onQuestion`
|
|
353
|
+
* from a child spec — or from the parent SPEC seat a child is built from — when the child OUTLIVES the request that
|
|
354
|
+
* spawned it) and the disclosure flag (`RunInternals.questionFaceStripped` → the wiring manifest's
|
|
355
|
+
* `question.wired: "stripped_bg_lane"` + the posture door's exemption) are PAIR-PRODUCED from this single expression —
|
|
356
|
+
* never inferred from spec shape, never minted anywhere else. Three families ride it: the Agent tool's session-scoped
|
|
357
|
+
* background lanes (spec-override form), its retain snapshots (destructure-drop form; the flag then rides
|
|
358
|
+
* `internalsSnapshot`, so a revived leg keeps the exemption), and the Workflow tool (submit-and-return: every agent it
|
|
359
|
+
* spawns outlives the launching request, so the host's seat is stripped before it reaches the launch site). WHY:
|
|
360
|
+
* `spec.onQuestion` is by contract a per-REQUEST lane torn down with its turn; handing it to a leg that runs hours later
|
|
361
|
+
* would strand the child asking into a closed surface (`AskUserQuestion` awaits the answer). A key REMOVED and a key set
|
|
362
|
+
* `undefined` resolve identically through the engine's `spec.onQuestion ?? deps.onQuestion` reads — a process-level
|
|
363
|
+
* `RunnerDeps.onQuestion` still reaches the child; only the turn-bound value drops. Trust posture: RunInternals is a
|
|
364
|
+
* PUBLIC trusted-caller parameter, so the flag is an HONESTY device (the engine disclosing its own strip), not a
|
|
365
|
+
* security gate. The flag states "a face WAS removed here" — minted only when one actually existed (an inherently
|
|
366
|
+
* faceless lane reads `absent`, not `stripped_bg_lane`, and collects no exemption).
|
|
367
|
+
*/
|
|
368
|
+
export declare function stripSpawnTurnQuestionFace<S extends {
|
|
369
|
+
onQuestion?: OnQuestion;
|
|
370
|
+
}>(spec: S): {
|
|
371
|
+
spec: Omit<S, "onQuestion">;
|
|
372
|
+
internalsFlag: {
|
|
373
|
+
questionFaceStripped?: true;
|
|
374
|
+
};
|
|
375
|
+
};
|
|
@@ -378,3 +378,7 @@ export function createAskUserQuestionTool(onQuestion, source, opts) {
|
|
|
378
378
|
},
|
|
379
379
|
});
|
|
380
380
|
}
|
|
381
|
+
export function stripSpawnTurnQuestionFace(spec) {
|
|
382
|
+
const { onQuestion: spawnTurnQuestionFace, ...rest } = spec;
|
|
383
|
+
return { spec: rest, internalsFlag: spawnTurnQuestionFace !== undefined ? { questionFaceStripped: true } : {} };
|
|
384
|
+
}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `delegation.ask_unresolvable` — the one mint of the notice the gate raises when an `ask` reached its
|
|
3
|
-
* final deny with NOBODY having judged it
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
3
|
+
* final deny with NOBODY having judged it. Three ways that happens, one event class ("a call was denied
|
|
4
|
+
* fail-closed because its approval could not be resolved"), one closed cause set:
|
|
5
|
+
* · `approver_unavailable` — the approver consulted for the call (the run's own seat, or an ancestor's
|
|
6
|
+
* frozen seat on a delegated child) answered the ROUTING question `unavailable` and no durable park
|
|
7
|
+
* took the call afterwards (`tool_end.gate.settlement.kind:"approver_unavailable"`);
|
|
8
|
+
* · `no_approver_wired` — no approver (or, for a question, no question face) is wired for this run, or
|
|
9
|
+
* the seat is the deny posture string: the headless auto-deny (`settlement.kind:"no_approver"`);
|
|
10
|
+
* · `mandate_unreconstructible` — an inherited durable-approval mandate binds the ask and THIS leg has no
|
|
11
|
+
* park facility to honor it, so the delegated child refuses in-fold rather than let a synchronous layer
|
|
12
|
+
* resolve what its ancestor bound to a park (an in-fold deny; no settlement rides the frame).
|
|
13
|
+
* The deny itself is older than this notice and stands unchanged (the model reads the sentence as its
|
|
14
|
+
* tool result); what was missing was any face a PERSON watching notices could see — an operator reading
|
|
15
|
+
* notices alone saw nothing, and the person whose work was refused learned it only from a transcript.
|
|
10
16
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* this factory: one call, one notice, once per tool call.
|
|
17
|
+
* ONE exit composes it: the gate's single deny exit (`exitGate`), which reads the settlement the deny
|
|
18
|
+
* carries or the cause an in-fold arm attested, after every park re-route has had its attempt. That exit is
|
|
19
|
+
* the only caller of this factory: one call, one notice, once per tool call.
|
|
15
20
|
*
|
|
16
21
|
* Audience `"user"`: the refused work is the user's own (their run, or a delegation their run made), and
|
|
17
22
|
* the recovery — a checkpoint store with a durable approval opt-in so such asks can wait for a person, or
|
|
@@ -22,17 +27,21 @@
|
|
|
22
27
|
* is pure.
|
|
23
28
|
*/
|
|
24
29
|
import type { EngineNotice } from "./engine-notice.js";
|
|
25
|
-
|
|
30
|
+
/** WHY the ask could not be resolved — the closed set (see the module note for each word). */
|
|
31
|
+
export declare const ASK_UNRESOLVABLE_CAUSES: readonly ["approver_unavailable", "no_approver_wired", "mandate_unreconstructible"];
|
|
32
|
+
export type AskUnresolvableCause = (typeof ASK_UNRESOLVABLE_CAUSES)[number];
|
|
33
|
+
/** Membership test for {@link AskUnresolvableCause} — the word rides a notice detail across process boundaries. */
|
|
34
|
+
export declare function isAskUnresolvableCause(v: unknown): v is AskUnresolvableCause;
|
|
26
35
|
/** What the gate knows at the deny exit — facts only, no words of the engine's vocabulary composed. */
|
|
27
36
|
export interface AskUnresolvableFacts {
|
|
28
37
|
/** The session whose call was refused — the notice's routing key, required (see module note). */
|
|
29
38
|
readonly sessionId: string;
|
|
30
39
|
/** The tool the ask was for (the message quotes it verbatim). */
|
|
31
40
|
readonly toolName: string;
|
|
32
|
-
/** The refused call's id — the correlation key to the `tool_end` frame carrying the same
|
|
41
|
+
/** The refused call's id — the correlation key to the `tool_end` frame carrying the same deny. */
|
|
33
42
|
readonly toolCallId: string;
|
|
34
|
-
/**
|
|
35
|
-
readonly
|
|
43
|
+
/** Why the ask could not be resolved — carried as a fact from the exit, not re-derived here. */
|
|
44
|
+
readonly cause: AskUnresolvableCause;
|
|
36
45
|
/** Whether a durable approval park lane was ARMED for this run (`true`: the park had its one attempt and
|
|
37
46
|
* did not take the call — it declined or failed; `false`: no park lane at all, the usual shape). */
|
|
38
47
|
readonly parkLaneExisted: boolean;
|
|
@@ -41,12 +50,12 @@ export interface AskUnresolvableFacts {
|
|
|
41
50
|
* Compose the `delegation.ask_unresolvable` notice from the gate's deny-exit facts.
|
|
42
51
|
*
|
|
43
52
|
* @contract delegation.ask_unresolvable.single_mint — the `delegation.ask_unresolvable` notice is composed
|
|
44
|
-
* by CORE from the gate's deny-exit FACTS (session, tool, call id, the
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* shaped into a notice that would route nowhere.
|
|
53
|
+
* by CORE from the gate's deny-exit FACTS (session, tool, call id, the cause, whether a park lane existed)
|
|
54
|
+
* at the ONE deny exit every unresolvable arm reaches; no other site spells the code or the sentence, and
|
|
55
|
+
* an empty session or tool name, or a cause outside the closed set, is refused at the mint with a
|
|
56
|
+
* `TypeError` rather than shaped into a notice that would route nowhere or say nothing.
|
|
48
57
|
*
|
|
49
|
-
* `detail: { sessionId, toolName, toolCallId,
|
|
50
|
-
*
|
|
58
|
+
* `detail: { sessionId, toolName, toolCallId, cause, parkLaneExisted }` — `sessionId` is lifted onto the
|
|
59
|
+
* typed key by {@link import("./engine-notice.js").deliverEngineNotice}, the one throat.
|
|
51
60
|
*/
|
|
52
61
|
export declare function askUnresolvableNotice(facts: AskUnresolvableFacts): EngineNotice;
|