@sema-agent/core 7.49.4 → 7.50.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 +152 -0
- package/dist/agents/observer.js +3 -10
- package/dist/agents/peer-directory.d.ts +8 -3
- package/dist/agents/peer-directory.js +5 -3
- package/dist/agents/subagent-steps.d.ts +6 -14
- package/dist/agents/subagent-steps.js +3 -17
- package/dist/brain/stream-shared.d.ts +1 -1
- package/dist/core/allow-entry.d.ts +1 -1
- package/dist/core/allow-entry.js +1 -1
- package/dist/core/ask-origin.d.ts +15 -11
- package/dist/core/ask-origin.js +6 -14
- package/dist/core/auto-mode-prompt.js +6 -2
- package/dist/core/checkpoint-store.d.ts +6 -4
- package/dist/core/checkpoint-store.js +1 -1
- package/dist/core/context-edit.d.ts +2 -2
- package/dist/core/decision-receipt.d.ts +2 -2
- package/dist/core/decision-receipt.js +30 -11
- package/dist/core/delegation-frames.d.ts +66 -18
- package/dist/core/delegation-frames.js +22 -0
- package/dist/core/engine-notice.d.ts +7 -5
- package/dist/core/frame-settlement.d.ts +6 -1
- package/dist/core/gate-fold.js +19 -13
- package/dist/core/gate-lanes.js +12 -11
- package/dist/core/gate-outcome.d.ts +2 -2
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +28 -20
- package/dist/core/human-input-projection.js +2 -0
- package/dist/core/lsp-diagnostics.d.ts +3 -0
- package/dist/core/lsp-diagnostics.js +6 -0
- package/dist/core/lsp-session.d.ts +39 -17
- package/dist/core/lsp-session.js +118 -58
- package/dist/core/lsp.d.ts +83 -3
- package/dist/core/lsp.js +146 -16
- package/dist/core/mcp.js +2 -1
- package/dist/core/media-byte-cap.d.ts +14 -0
- package/dist/core/media-byte-cap.js +15 -3
- package/dist/core/memory-engine/consolidation-driver.d.ts +23 -1
- package/dist/core/memory-engine/consolidation-driver.js +54 -6
- package/dist/core/memory-engine/consolidation-write-gate.d.ts +46 -0
- package/dist/core/memory-engine/consolidation-write-gate.js +82 -0
- package/dist/core/memory-engine/consolidation.d.ts +17 -0
- package/dist/core/memory-engine/consolidation.js +1 -0
- package/dist/core/memory-engine/distiller.d.ts +8 -2
- package/dist/core/memory-engine/distiller.js +8 -6
- package/dist/core/memory-engine/engine.d.ts +37 -4
- package/dist/core/memory-engine/engine.js +127 -38
- package/dist/core/memory-engine/file-backend.d.ts +8 -3
- package/dist/core/memory-engine/file-backend.js +44 -16
- package/dist/core/memory-engine/index.d.ts +2 -2
- package/dist/core/memory-engine/index.js +1 -1
- package/dist/core/memory-engine/landing-admission.d.ts +65 -0
- package/dist/core/memory-engine/landing-admission.js +68 -0
- package/dist/core/memory-engine/types.d.ts +23 -0
- package/dist/core/mode-policy.d.ts +3 -2
- package/dist/core/mode-policy.js +2 -0
- package/dist/core/permission-rule-model.d.ts +19 -13
- package/dist/core/permission-rule-model.js +7 -4
- package/dist/core/permission-rule-provider.d.ts +11 -0
- package/dist/core/permission-rules.d.ts +1 -1
- package/dist/core/permission-rules.js +5 -2
- package/dist/core/persisted-rule-arms.d.ts +15 -7
- package/dist/core/persisted-rule-arms.js +13 -6
- package/dist/core/posix-mode-face.d.ts +10 -0
- package/dist/core/posix-mode-face.js +3 -0
- package/dist/core/reminder-mint.d.ts +5 -0
- package/dist/core/reminder-mint.js +1 -0
- package/dist/core/retired-keys.d.ts +8 -0
- package/dist/core/retired-keys.js +4 -0
- package/dist/core/rule-lane-reads.d.ts +4 -4
- package/dist/core/rule-lane-reads.js +10 -1
- package/dist/core/runner/construction-doors.d.ts +10 -4
- package/dist/core/runner/construction-doors.js +25 -2
- package/dist/core/runner/contracts.d.ts +20 -3
- package/dist/core/runner/env-capability-census.js +1 -1
- package/dist/core/runner/gate-exit.js +2 -1
- package/dist/core/runner/memory-consolidation-driver.d.ts +6 -4
- package/dist/core/runner/memory-consolidation-driver.js +5 -2
- package/dist/core/runner/memory-consolidation-write-judge.d.ts +17 -0
- package/dist/core/runner/memory-consolidation-write-judge.js +14 -0
- package/dist/core/runner/permission-rule-lanes.d.ts +16 -22
- package/dist/core/runner/permission-rule-lanes.js +13 -43
- package/dist/core/runner/person-path-rows.d.ts +244 -0
- package/dist/core/runner/person-path-rows.js +387 -0
- package/dist/core/runner/prepare-acquire-reconcile.js +8 -1
- package/dist/core/runner/prepare-artifact.d.ts +5 -3
- package/dist/core/runner/prepare-artifact.js +2 -8
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -3
- package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
- package/dist/core/runner/prepare-context-lane.js +2 -2
- package/dist/core/runner/prepare-gate-stations.d.ts +3 -3
- package/dist/core/runner/prepare-gate-stations.js +1 -1
- package/dist/core/runner/prepare-hands-readface.d.ts +19 -10
- package/dist/core/runner/prepare-hands-readface.js +57 -43
- package/dist/core/runner/prepare-lsp.d.ts +15 -13
- package/dist/core/runner/prepare-lsp.js +11 -11
- package/dist/core/runner/prepare-policy-chain.d.ts +8 -4
- package/dist/core/runner/prepare-policy-chain.js +6 -7
- package/dist/core/runner/prepare-run-refs.js +1 -1
- package/dist/core/runner/prepare-task.js +24 -16
- package/dist/core/runner/prepare-turn-wiring.d.ts +13 -6
- package/dist/core/runner/prepare-turn-wiring.js +19 -8
- package/dist/core/runner/read-root-grant.d.ts +1 -25
- package/dist/core/runner/read-root-grant.js +1 -17
- package/dist/core/runner/retired-runner-deps.d.ts +2 -2
- package/dist/core/runner/run-brain-sinks.d.ts +1 -5
- package/dist/core/runner/run-brain-sinks.js +2 -4
- package/dist/core/runner/run-harness-handlers.js +5 -4
- package/dist/core/runner/run-identity-wiring.d.ts +4 -4
- package/dist/core/runner/run-identity-wiring.js +10 -1
- package/dist/core/runner/run-leg.d.ts +1 -1
- package/dist/core/runner/run-leg.js +22 -9
- package/dist/core/runner/run-settle-and-teardown.d.ts +0 -4
- package/dist/core/runner/run-settle-and-teardown.js +7 -4
- package/dist/core/runner/run-terminal-adoption.d.ts +1 -1
- package/dist/core/runner/run-terminal-adoption.js +1 -1
- package/dist/core/runner/run-turn-boundary.js +2 -2
- package/dist/core/runner/runtask.js +8 -8
- package/dist/core/runner/session-file-state-replay.d.ts +14 -4
- package/dist/core/runner/session-file-state-replay.js +8 -0
- package/dist/core/runner/stream-steer-verb.js +3 -0
- package/dist/core/runner/tool-end-body.d.ts +5 -4
- package/dist/core/runner/tool-end-body.js +4 -4
- package/dist/core/runner/tool-output-projection.d.ts +6 -4
- package/dist/core/runner/tool-output-projection.js +66 -47
- package/dist/core/runner-deps.d.ts +6 -3
- package/dist/core/shared-memory/types.d.ts +2 -2
- package/dist/core/shell-read-silence.d.ts +23 -0
- package/dist/core/shell-read-silence.js +18 -0
- package/dist/core/synthetic-read-verdict.d.ts +80 -21
- package/dist/core/synthetic-read-verdict.js +89 -18
- package/dist/core/task-event.d.ts +113 -25
- package/dist/core/task-spec.d.ts +44 -0
- package/dist/core/task-tool-shape.d.ts +1 -1
- package/dist/core/tool-catalog-entries.js +16 -2
- package/dist/core/tool-policy.d.ts +25 -15
- package/dist/core/tool-policy.js +9 -13
- package/dist/core/trace.d.ts +3 -2
- package/dist/core/types.d.ts +3 -3
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-text.d.ts +2 -2
- package/dist/core/user-attachment.d.ts +164 -0
- package/dist/core/user-attachment.js +437 -0
- package/dist/engine/compaction/compaction.js +10 -3
- package/dist/engine/compaction/utils.js +6 -0
- package/dist/engine/execution-env/node-execution-env.d.ts +19 -1
- package/dist/engine/execution-env/node-execution-env.js +127 -1
- package/dist/engine/harness/agent-harness.d.ts +12 -2
- package/dist/engine/harness/agent-harness.js +15 -3
- package/dist/engine/harness/types.d.ts +21 -0
- package/dist/engine/llm/content-block-render.d.ts +15 -0
- package/dist/engine/llm/content-block-render.js +10 -0
- package/dist/engine/llm/index.d.ts +1 -0
- package/dist/engine/llm/index.js +1 -0
- package/dist/engine/llm/types.d.ts +80 -4
- package/dist/engine/llm/types.js +43 -1
- package/dist/engine/session/import-validate.js +2 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +2 -1
- package/dist/internal/harness-types.d.ts +1 -1
- package/dist/internal/llm.d.ts +2 -2
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/workflow.d.ts +4 -5
- package/dist/orchestration/workflow.js +2 -2
- package/dist/prompts/default.d.ts +1 -1
- package/dist/stores/file/permission-rule-store.d.ts +13 -1
- package/dist/stores/file/permission-rule-store.js +40 -21
- package/dist/tools/artifact/artifact-tool.js +1 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
- package/dist/tools/fs/dir-entries.d.ts +4 -10
- package/dist/tools/fs/dir-entries.js +4 -11
- package/dist/tools/fs/file-read-check.js +3 -3
- package/dist/tools/fs/fs-pdf.js +2 -4
- package/dist/tools/fs/fs-read.d.ts +47 -4
- package/dist/tools/fs/fs-read.js +63 -19
- package/dist/tools/fs/fs-search-tools.d.ts +3 -3
- package/dist/tools/fs/fs-search-tools.js +7 -2
- package/dist/tools/fs/fs-write.d.ts +1 -1
- package/dist/tools/fs/fs-write.js +7 -6
- package/dist/tools/fs/index.d.ts +7 -1
- package/dist/tools/fs/index.js +56 -34
- package/dist/tools/fs/read-deny-home.d.ts +19 -1
- package/dist/tools/fs/read-deny-home.js +32 -22
- package/dist/tools/fs/read-deny.d.ts +14 -0
- package/dist/tools/fs/read-deny.js +8 -0
- package/dist/tools/fs/repo-map.d.ts +3 -2
- package/dist/tools/fs/repo-map.js +11 -3
- package/dist/tools/fs/safety.d.ts +41 -2
- package/dist/tools/fs/safety.js +12 -3
- package/dist/tools/fs/shell-read-check.d.ts +12 -3
- package/dist/tools/fs/shell-read-check.js +28 -15
- package/dist/tools/fs/shell-read-device.d.ts +1 -1
- package/dist/tools/fs/shell-read-judge.d.ts +9 -4
- package/dist/tools/fs/shell-read-judge.js +1 -1
- package/dist/tools/loop-tick.d.ts +2 -2
- package/package.json +3 -1
- package/test/export-surface.snapshot.json +39 -1
- package/wire-changes/core@7.49.5.json +104 -0
- package/wire-changes/core@7.50.0.json +1699 -0
- package/dist/core/runner/persisted-path-rows.d.ts +0 -88
- package/dist/core/runner/persisted-path-rows.js +0 -108
package/dist/internal/llm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { createAssistantMessageEventStream, ensureToolTurnInvariants, MODEL_OUTPUT_INVALID_CAUSES, snapshotActorAssertion, stampStreamDrops, streamDropsOf, stripEngineMetadata, TOOL_TURN_INCOMPLETE_CAUSES, TOOL_TURN_REPAIR_DROPS } from "../engine/llm/index.js";
|
|
1
|
+
export { createAssistantMessageEventStream, DATA_LABEL_UNSAFE, ensureToolTurnInvariants, isTextBlock, MODEL_OUTPUT_INVALID_CAUSES, quoteDataLabel, renderContentBlock, renderUserAttachmentView, snapshotActorAssertion, stampStreamDrops, streamDropsOf, stripEngineMetadata, TOOL_TURN_INCOMPLETE_CAUSES, TOOL_TURN_REPAIR_DROPS, userAttachmentOf } from "../engine/llm/index.js";
|
|
@@ -436,11 +436,10 @@ export interface RunWorkflowOptions {
|
|
|
436
436
|
parentCwd?: string;
|
|
437
437
|
/**
|
|
438
438
|
* The SPAWNING tool call's id (`run_workflow`'s own `ToolExecuteContext.toolCallId`) — threaded into every
|
|
439
|
-
* spawned agent's trusted internals (`RunInternals.parentToolCallId`) so each child
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
* progress ticks (status quo), and no id is ever fabricated.
|
|
439
|
+
* spawned agent's trusted internals (`RunInternals.parentToolCallId`) so each child's frames carry this id
|
|
440
|
+
* for attribution, the same contract as a `createSubagentTool` delegation. Set by the `run_workflow` tool
|
|
441
|
+
* wiring; a directly-started workflow (no launching tool call) leaves it unset — its children's row frames
|
|
442
|
+
* (start, ticks, terminal tick) still go out, without the attribution, and no id is ever fabricated.
|
|
444
443
|
*/
|
|
445
444
|
parentToolCallId?: string;
|
|
446
445
|
/** The HOST task's taskId — threaded as every spawned agent's `RunInternals.parentTaskId` so its
|
|
@@ -1648,7 +1648,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1648
1648
|
const runSpec = await reviewSpawnBeforeLaunch("ctx.agent", label, callKey, preReviewSpec, effectiveSignal);
|
|
1649
1649
|
const enrichedForward = opts.onForwardEvent !== undefined
|
|
1650
1650
|
? (e) => {
|
|
1651
|
-
opts.onForwardEvent(e.type === "task_progress" ? { ...e, workflowRunId: runId, workflowAgentLabel: label } : e);
|
|
1651
|
+
opts.onForwardEvent(e.type === "task_progress" || e.type === "task_started" ? { ...e, workflowRunId: runId, workflowAgentLabel: label } : e);
|
|
1652
1652
|
}
|
|
1653
1653
|
: undefined;
|
|
1654
1654
|
const baseInternals = { ...(agentOpts.isolation ? { isolation: agentOpts.isolation } : {}), ...(opts.parentCwd !== undefined ? { parentCwd: opts.parentCwd, callerRoot: opts.parentCwd } : {}), ...spawnAttribution, ...(await captureFloorSeatsNow()), ...(enrichedForward !== undefined ? { onForwardEvent: enrichedForward } : {}), delegationTaskType: "workflow", agentName: label, onWorkspaceResolved: createWorkspaceObserver(rec) };
|
|
@@ -2013,7 +2013,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
2013
2013
|
const runSpec = await reviewSpawnBeforeLaunch("ctx.agentStream", label, callKey, preReviewSpec, effectiveSignal);
|
|
2014
2014
|
const enrichedForwardS = opts.onForwardEvent !== undefined
|
|
2015
2015
|
? (e) => {
|
|
2016
|
-
opts.onForwardEvent(e.type === "task_progress" ? { ...e, workflowRunId: runId, workflowAgentLabel: label } : e);
|
|
2016
|
+
opts.onForwardEvent(e.type === "task_progress" || e.type === "task_started" ? { ...e, workflowRunId: runId, workflowAgentLabel: label } : e);
|
|
2017
2017
|
}
|
|
2018
2018
|
: undefined;
|
|
2019
2019
|
const runInternals = {
|
|
@@ -255,7 +255,7 @@ export declare const PROJECT_CONTEXT_FRAMING = "# Project context\nThe `<user_me
|
|
|
255
255
|
* relation to the specific tool results or user messages in which they appear."
|
|
256
256
|
* - LEAN (`wMy` @596743, heading **`# Harness`**) → "`<system-reminder>` tags in messages and tool
|
|
257
257
|
* results are injected by the harness, not the user."
|
|
258
|
-
* - THIRD ARM (`itp`'s `otp(model)` short-circuit → `gMy` @597111 (cli250.js:
|
|
258
|
+
* - THIRD ARM (`itp`'s `otp(model)` short-circuit → `gMy` @597111 (cli250.js:44486)): "The system may send updates,
|
|
259
259
|
* reminders, or modifications to rules via mid-conversation system turns. These are
|
|
260
260
|
* system-controlled, unlike function results." sema has NO counterpart and does not need one — the
|
|
261
261
|
* arm is selected by a per-model latch (`otp` @597208) over CC's own model registry, which a BYOM
|
|
@@ -113,15 +113,23 @@ export type RuleAdoptionFile = {
|
|
|
113
113
|
export declare function readRuleAdoptionFile(dir: string): RuleAdoptionFile | undefined;
|
|
114
114
|
/** Atomically publish the adoption marker (same write-temp → fsync → rename discipline as the store). */
|
|
115
115
|
export declare function writeRuleAdoptionFile(dir: string, content: RuleAdoptionFile): void;
|
|
116
|
+
/** What a directory vetting reads from its host. Absent ⇒ this process's platform, and a skipped judgment goes unsaid. */
|
|
117
|
+
interface DirVetting {
|
|
118
|
+
/** The platform whose permission bits are read (default: this process's — see {@link posixModeBitsMeaningful}). */
|
|
119
|
+
readonly platform?: NodeJS.Platform;
|
|
120
|
+
/** Said when the group/other-writable judgment was NOT made because the platform reports no permission bits. */
|
|
121
|
+
readonly modeBitsUnjudged?: (dir: string) => void;
|
|
122
|
+
}
|
|
116
123
|
/** One principal's rule file. */
|
|
117
124
|
declare class FileDurableRulePartition implements WritableDurableRulePartition {
|
|
118
125
|
private readonly dir;
|
|
119
126
|
private readonly file;
|
|
120
127
|
private readonly acquireWriteLock;
|
|
121
128
|
private readonly onError?;
|
|
129
|
+
private readonly vetting?;
|
|
122
130
|
readonly durability: StoreDurability;
|
|
123
131
|
readonly fidelity: StoreFidelity;
|
|
124
|
-
constructor(dir: string, file: string, acquireWriteLock: () => void, onError?: ((message: string) => void) | undefined);
|
|
132
|
+
constructor(dir: string, file: string, acquireWriteLock: () => void, onError?: ((message: string) => void) | undefined, vetting?: DirVetting | undefined);
|
|
125
133
|
/** Read and validate. Any refusal answers with an empty set AND says so — never a silent empty store. The answer's
|
|
126
134
|
* sentence names no location ({@link refusalText}); the disclosure that accompanies it does. */
|
|
127
135
|
private read;
|
|
@@ -198,9 +206,13 @@ export declare class FileDurableRulePartitionProvider implements DurableRulePart
|
|
|
198
206
|
private readonly onError?;
|
|
199
207
|
private lock;
|
|
200
208
|
private orgPersistence;
|
|
209
|
+
/** What every directory vetting of this instance reads; it says an unjudged mode check ONCE per instance. */
|
|
210
|
+
private readonly vetting;
|
|
201
211
|
constructor(dir: string, onError?: ((message: string) => void) | undefined, opts?: {
|
|
202
212
|
/** The data root whose adoption marker gates construction (design/183 I6). Absent ⇒ no root gate. */
|
|
203
213
|
dataRoot?: string;
|
|
214
|
+
/** The platform whose permission bits the directory vetting reads. Absent ⇒ this process's platform. */
|
|
215
|
+
platform?: NodeJS.Platform;
|
|
204
216
|
});
|
|
205
217
|
/** The org partition's durable home in this directory (design/182 §7.4 contract; `org.json`). Shares
|
|
206
218
|
* this provider's writer lock — an install is a write. */
|
|
@@ -2,6 +2,7 @@ import { closeSync, constants as FS, existsSync, fsyncSync, lstatSync, mkdirSync
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { createHash, randomBytes } from "node:crypto";
|
|
4
4
|
import { isRuleBehavior } from "../../core/permission-rule-model.js";
|
|
5
|
+
import { posixModeBitsMeaningful } from "../../core/posix-mode-face.js";
|
|
5
6
|
import { PERMISSION_RULE_WRITER, applySyncJoin, applyTombstones, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, foldDelta, unknownRuleWriteDeltaError, } from "../../core/permission-rule-store.js";
|
|
6
7
|
import { canonicalize } from "../../core/canonical-json.js";
|
|
7
8
|
import { BootLock, FileStoreLockError } from "./fs-atomic.js";
|
|
@@ -118,13 +119,17 @@ const EMPTY_READ = { rules: [], tombstones: [], rev: 0 };
|
|
|
118
119
|
function checksumOf(body) {
|
|
119
120
|
return `sha256:${createHash("sha256").update(canonicalize(body), "utf8").digest("hex")}`;
|
|
120
121
|
}
|
|
121
|
-
function unsafeDirFault(dir) {
|
|
122
|
+
function unsafeDirFault(dir, vetting) {
|
|
122
123
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
123
124
|
const st = lstatSync(dir);
|
|
124
125
|
if (st.isSymbolicLink() || !st.isDirectory())
|
|
125
126
|
return "is a symlink or not a directory";
|
|
126
127
|
if (typeof process.getuid === "function" && st.uid !== process.getuid())
|
|
127
128
|
return "is owned by another user";
|
|
129
|
+
if (!posixModeBitsMeaningful(vetting?.platform)) {
|
|
130
|
+
vetting?.modeBitsUnjudged?.(dir);
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
128
133
|
if ((st.mode & 0o022) !== 0)
|
|
129
134
|
return `is writable by group or others (mode ${(st.mode & 0o777).toString(8)}) — anyone who can write there can grant themselves permissions`;
|
|
130
135
|
return undefined;
|
|
@@ -135,15 +140,18 @@ function assertSafeDir(dir) {
|
|
|
135
140
|
throw new Error(`permission-rule store directory ${dir} ${fault}; refusing to use it`);
|
|
136
141
|
}
|
|
137
142
|
function refusalText(onError, sentence, location) {
|
|
143
|
+
discloseTo(onError, `${sentence} (at ${location})`);
|
|
144
|
+
return `${sentence}. The location is reported to the store's error disclosure (onError), not in this message.`;
|
|
145
|
+
}
|
|
146
|
+
function discloseTo(onError, message) {
|
|
138
147
|
try {
|
|
139
|
-
onError?.(
|
|
148
|
+
onError?.(message);
|
|
140
149
|
}
|
|
141
150
|
catch {
|
|
142
151
|
}
|
|
143
|
-
return `${sentence}. The location is reported to the store's error disclosure (onError), not in this message.`;
|
|
144
152
|
}
|
|
145
|
-
function assertSafeDirAtRequest(dir, onError, act) {
|
|
146
|
-
const fault = unsafeDirFault(dir);
|
|
153
|
+
function assertSafeDirAtRequest(dir, onError, act, vetting) {
|
|
154
|
+
const fault = unsafeDirFault(dir, vetting);
|
|
147
155
|
if (fault !== undefined)
|
|
148
156
|
throw new Error(refusalText(onError, `the permission-rule store directory ${fault}; refusing to ${act} it`, dir));
|
|
149
157
|
}
|
|
@@ -171,13 +179,15 @@ class FileDurableRulePartition {
|
|
|
171
179
|
file;
|
|
172
180
|
acquireWriteLock;
|
|
173
181
|
onError;
|
|
182
|
+
vetting;
|
|
174
183
|
durability = "durable";
|
|
175
184
|
fidelity = "json";
|
|
176
|
-
constructor(dir, file, acquireWriteLock, onError) {
|
|
185
|
+
constructor(dir, file, acquireWriteLock, onError, vetting) {
|
|
177
186
|
this.dir = dir;
|
|
178
187
|
this.file = file;
|
|
179
188
|
this.acquireWriteLock = acquireWriteLock;
|
|
180
189
|
this.onError = onError;
|
|
190
|
+
this.vetting = vetting;
|
|
181
191
|
}
|
|
182
192
|
read() {
|
|
183
193
|
const bucket = "this owner's permission-rule bucket";
|
|
@@ -185,7 +195,7 @@ class FileDurableRulePartition {
|
|
|
185
195
|
const unreadable = (sentence, location = this.file) => ({ unreadable: refusalText(this.onError, sentence, location) });
|
|
186
196
|
let raw;
|
|
187
197
|
try {
|
|
188
|
-
const dirFault = unsafeDirFault(this.dir);
|
|
198
|
+
const dirFault = unsafeDirFault(this.dir, this.vetting);
|
|
189
199
|
if (dirFault !== undefined)
|
|
190
200
|
return unreadable(`the permission-rule store directory ${dirFault}; loading zero rules`, this.dir);
|
|
191
201
|
const st = lstatSync(this.file);
|
|
@@ -228,11 +238,7 @@ class FileDurableRulePartition {
|
|
|
228
238
|
return { file: parsed };
|
|
229
239
|
}
|
|
230
240
|
disclose(message) {
|
|
231
|
-
|
|
232
|
-
this.onError?.(message);
|
|
233
|
-
}
|
|
234
|
-
catch {
|
|
235
|
-
}
|
|
241
|
+
discloseTo(this.onError, message);
|
|
236
242
|
}
|
|
237
243
|
screenDurableRows(file) {
|
|
238
244
|
const isSession = (scope) => scope?.kind === "session";
|
|
@@ -246,7 +252,7 @@ class FileDurableRulePartition {
|
|
|
246
252
|
return { rules, tombstones, quarantined };
|
|
247
253
|
}
|
|
248
254
|
write(next) {
|
|
249
|
-
assertSafeDirAtRequest(this.dir, this.onError, "write through");
|
|
255
|
+
assertSafeDirAtRequest(this.dir, this.onError, "write through", this.vetting);
|
|
250
256
|
atomicPublish(this.dir, this.file, JSON.stringify({ ...next, checksum: checksumOf(next) }, null, 2));
|
|
251
257
|
}
|
|
252
258
|
async list() {
|
|
@@ -392,11 +398,22 @@ export class FileDurableRulePartitionProvider {
|
|
|
392
398
|
onError;
|
|
393
399
|
lock;
|
|
394
400
|
orgPersistence;
|
|
401
|
+
vetting;
|
|
395
402
|
constructor(dir, onError, opts) {
|
|
396
403
|
this.dir = dir;
|
|
397
404
|
this.onError = onError;
|
|
398
405
|
if (opts?.dataRoot !== undefined)
|
|
399
406
|
assertAdoptionBootGate(opts.dataRoot, "FileDurableRulePartitionProvider");
|
|
407
|
+
let said = false;
|
|
408
|
+
this.vetting = {
|
|
409
|
+
platform: opts?.platform,
|
|
410
|
+
modeBitsUnjudged: (where) => {
|
|
411
|
+
if (said)
|
|
412
|
+
return;
|
|
413
|
+
said = true;
|
|
414
|
+
discloseTo(this.onError, `the permission-rule store directory is not checked for being writable by other accounts: this platform reports no POSIX permission bits, so who else can write there is not verified here (at ${where})`);
|
|
415
|
+
},
|
|
416
|
+
};
|
|
400
417
|
}
|
|
401
418
|
adoptionMarker() {
|
|
402
419
|
const judged = judgeRuleAdoptionFile(this.dir);
|
|
@@ -410,13 +427,13 @@ export class FileDurableRulePartitionProvider {
|
|
|
410
427
|
return this.fileOrgPersistence();
|
|
411
428
|
}
|
|
412
429
|
fileOrgPersistence() {
|
|
413
|
-
this.orgPersistence ??= new FileOrgRuleStatePersistence(this.dir, this.acquireWriteLock, this.onError);
|
|
430
|
+
this.orgPersistence ??= new FileOrgRuleStatePersistence(this.dir, this.acquireWriteLock, this.onError, this.vetting);
|
|
414
431
|
return this.orgPersistence;
|
|
415
432
|
}
|
|
416
433
|
acquireWriteLock = () => {
|
|
417
434
|
if (this.lock !== undefined)
|
|
418
435
|
return;
|
|
419
|
-
assertSafeDirAtRequest(this.dir, this.onError, "write through");
|
|
436
|
+
assertSafeDirAtRequest(this.dir, this.onError, "write through", this.vetting);
|
|
420
437
|
const lock = new BootLock(join(this.dir, "PERMISSION-RULES-WRITER-LOCK"));
|
|
421
438
|
try {
|
|
422
439
|
lock.acquire();
|
|
@@ -437,11 +454,11 @@ export class FileDurableRulePartitionProvider {
|
|
|
437
454
|
return this.readOnlySourceView(principalRuleFileName(principal), principalRuleFileName(rec.toPrincipal), "adopted" in adoption || adoption.marker.phase >= 4);
|
|
438
455
|
}
|
|
439
456
|
}
|
|
440
|
-
return new FileDurableRulePartition(this.dir, join(this.dir, principalRuleFileName(principal)), this.acquireWriteLock, this.onError);
|
|
457
|
+
return new FileDurableRulePartition(this.dir, join(this.dir, principalRuleFileName(principal)), this.acquireWriteLock, this.onError, this.vetting);
|
|
441
458
|
}
|
|
442
459
|
readOnlySourceView(sourceName, targetName, flipped) {
|
|
443
460
|
const pick = flipped ? targetName : existsSync(join(this.dir, sourceName)) ? sourceName : targetName;
|
|
444
|
-
return readOnlyRuleStoreView(new FileDurableRulePartition(this.dir, join(this.dir, pick), this.acquireWriteLock, this.onError));
|
|
461
|
+
return readOnlyRuleStoreView(new FileDurableRulePartition(this.dir, join(this.dir, pick), this.acquireWriteLock, this.onError, this.vetting));
|
|
445
462
|
}
|
|
446
463
|
forLocalOwner() {
|
|
447
464
|
const adoption = this.adoptionMarker();
|
|
@@ -451,7 +468,7 @@ export class FileDurableRulePartitionProvider {
|
|
|
451
468
|
return this.readOnlySourceView(LOCAL_OWNER_FILE, principalRuleFileName(rec.toPrincipal), "adopted" in adoption || adoption.marker.phase >= 4);
|
|
452
469
|
}
|
|
453
470
|
}
|
|
454
|
-
return new FileDurableRulePartition(this.dir, join(this.dir, LOCAL_OWNER_FILE), this.acquireWriteLock, this.onError);
|
|
471
|
+
return new FileDurableRulePartition(this.dir, join(this.dir, LOCAL_OWNER_FILE), this.acquireWriteLock, this.onError, this.vetting);
|
|
455
472
|
}
|
|
456
473
|
dispose() {
|
|
457
474
|
this.lock?.release();
|
|
@@ -462,12 +479,14 @@ class FileOrgRuleStatePersistence {
|
|
|
462
479
|
dir;
|
|
463
480
|
acquireWriteLock;
|
|
464
481
|
onError;
|
|
482
|
+
vetting;
|
|
465
483
|
file;
|
|
466
484
|
writeChain = Promise.resolve();
|
|
467
|
-
constructor(dir, acquireWriteLock, onError) {
|
|
485
|
+
constructor(dir, acquireWriteLock, onError, vetting) {
|
|
468
486
|
this.dir = dir;
|
|
469
487
|
this.acquireWriteLock = acquireWriteLock;
|
|
470
488
|
this.onError = onError;
|
|
489
|
+
this.vetting = vetting;
|
|
471
490
|
this.file = join(dir, ORG_STATE_FILE);
|
|
472
491
|
}
|
|
473
492
|
readSync() {
|
|
@@ -477,7 +496,7 @@ class FileOrgRuleStatePersistence {
|
|
|
477
496
|
const ioFault = (err) => `could not be read (${err?.code ?? err?.name ?? "unknown"})`;
|
|
478
497
|
let dirFault;
|
|
479
498
|
try {
|
|
480
|
-
dirFault = unsafeDirFault(this.dir);
|
|
499
|
+
dirFault = unsafeDirFault(this.dir, this.vetting);
|
|
481
500
|
}
|
|
482
501
|
catch (err) {
|
|
483
502
|
return refuse(`the permission-rule store directory ${ioFault(err)}`, `${this.dir}: ${thrownText(err)}`);
|
|
@@ -524,7 +543,7 @@ class FileOrgRuleStatePersistence {
|
|
|
524
543
|
}
|
|
525
544
|
installOrgStateSync(state) {
|
|
526
545
|
this.acquireWriteLock();
|
|
527
|
-
assertSafeDirAtRequest(this.dir, this.onError, "write through");
|
|
546
|
+
assertSafeDirAtRequest(this.dir, this.onError, "write through", this.vetting);
|
|
528
547
|
state = jsonForm(state);
|
|
529
548
|
const cur = this.readSync();
|
|
530
549
|
if (cur !== undefined && state.revisionHighWater < cur.revisionHighWater) {
|
|
@@ -321,7 +321,7 @@ export function createArtifactTool(opts) {
|
|
|
321
321
|
if (sharedReadApproved.has(url))
|
|
322
322
|
return Promise.resolve({ ok: true });
|
|
323
323
|
if (permissionMode !== undefined) {
|
|
324
|
-
const verdict = arbitrateByMode(permissionMode(), classifyAsk({ action: "ask", requiresRealApproval: true,
|
|
324
|
+
const verdict = arbitrateByMode(permissionMode(), classifyAsk({ action: "ask", requiresRealApproval: true, guards: ["artifact_shared_read"] }, { contentQuestion: false, markedUnresolvable: false, org: undefined, tightened: undefined, mandateMarks: {} }));
|
|
325
325
|
if (verdict.kind === "released") {
|
|
326
326
|
if (!releaseAnnounced && onNotice !== undefined) {
|
|
327
327
|
releaseAnnounced = true;
|
|
@@ -19,7 +19,7 @@ import { type ProgramRow } from "./program-read-model.js";
|
|
|
19
19
|
* auto-allow an irreversible clock jump on the full shell face).
|
|
20
20
|
*
|
|
21
21
|
* Rows 3-4 are the CC-anchored expansion — the members of CC's safe-command
|
|
22
|
-
* set (
|
|
22
|
+
* set (2.1.296 `v3e` (cli296.js:249645); `e6s` in the 223 corpus, identical in 220; the 220→245 campaign diff records
|
|
23
23
|
* no change on this face) that satisfy THIS list's curation bar (no write/mutation mode under any args)
|
|
24
24
|
* without new stdin-floor/option-value modeling: pure status/computation printers (`cal`…`sleep` — none
|
|
25
25
|
* reads stdin when bare, none takes a path it READS except realpath/readlink, which stay boundary-judged)
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* judging was cut short by an abort — the listing is a prefix, not the directory).
|
|
23
23
|
*/
|
|
24
24
|
import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
25
|
-
import type { FileError, FileKind, Result } from "../../internal/harness.js";
|
|
25
|
+
import type { FileError, FileInfo, FileKind, Result } from "../../internal/harness.js";
|
|
26
26
|
import { type HomeViewEnv, type HomeViewsCarrier } from "./read-deny-home.js";
|
|
27
27
|
/** The upstream at-mention's cap on listed entries. */
|
|
28
28
|
export declare const DIRECTORY_LISTING_MAX_ENTRIES = 1000;
|
|
@@ -55,15 +55,9 @@ export interface DirectoryListing {
|
|
|
55
55
|
/** An abort cut the judging short: `entries` / `more` / `omitted` describe a prefix of the directory. */
|
|
56
56
|
incomplete: boolean;
|
|
57
57
|
}
|
|
58
|
-
/** List one level of `dir` (a canonical directory path). A listing the environment refuses is the error.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
* A data label (a path, a file name) as a JSON string literal with every C0/C1 control, format character
|
|
62
|
-
* and line / paragraph separator written as `\uXXXX` — lossless (JSON.parse gives the original back), and
|
|
63
|
-
* one line whatever the name holds. JSON's own escaping alone leaves U+2028 / U+2029 / U+0085 and the
|
|
64
|
-
* format characters raw.
|
|
65
|
-
*/
|
|
66
|
-
export declare function quoteDataLabel(label: string): string;
|
|
58
|
+
/** List one level of `dir` (a canonical directory path). A listing the environment refuses is the error. `list` is how the
|
|
59
|
+
* entries are read (default: the environment's `listDir`; a carrier bound to a judged directory passes its bound listing). */
|
|
60
|
+
export declare function enumerateDirectory(env: ExecutionEnv, dir: string, judge: EntryDenyJudge | undefined, signal?: AbortSignal, list?: (dir: string) => Promise<Result<FileInfo[], FileError>>): Promise<Result<DirectoryListing, FileError>>;
|
|
67
61
|
/** The listing as text: one entry per line (a directory with a trailing "/"; a name that could break or
|
|
68
62
|
* hide in its line is written as {@link quoteDataLabel}), then "… and N more entries" when capped. */
|
|
69
63
|
export declare function renderDirectoryListing(l: DirectoryListing): string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { homeViewsOf } from "./read-deny-home.js";
|
|
2
|
+
import { DATA_LABEL_UNSAFE, quoteDataLabel } from "../../internal/llm.js";
|
|
2
3
|
export const DIRECTORY_LISTING_MAX_ENTRIES = 1000;
|
|
3
4
|
export function createEntryDenyJudge(env, deny, signal) {
|
|
4
5
|
const views = homeViewsOf(env, deny, signal);
|
|
@@ -10,8 +11,8 @@ export function createEntryDenyJudge(env, deny, signal) {
|
|
|
10
11
|
return view !== undefined ? deny.matchPath(view) : null;
|
|
11
12
|
};
|
|
12
13
|
}
|
|
13
|
-
export async function enumerateDirectory(env, dir, judge, signal) {
|
|
14
|
-
const listing = await
|
|
14
|
+
export async function enumerateDirectory(env, dir, judge, signal, list = (d) => env.listDir(d, signal)) {
|
|
15
|
+
const listing = await list(dir);
|
|
15
16
|
if (!listing.ok)
|
|
16
17
|
return listing;
|
|
17
18
|
const infos = [...listing.value].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
@@ -44,16 +45,8 @@ export async function enumerateDirectory(env, dir, judge, signal) {
|
|
|
44
45
|
},
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
|
-
const LABEL_UNSAFE = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;
|
|
48
|
-
export function quoteDataLabel(label) {
|
|
49
|
-
let out = "";
|
|
50
|
-
for (const ch of JSON.stringify(label)) {
|
|
51
|
-
out += LABEL_UNSAFE.test(ch) ? `\\u${ch.codePointAt(0).toString(16).padStart(4, "0")}` : ch;
|
|
52
|
-
}
|
|
53
|
-
return out;
|
|
54
|
-
}
|
|
55
48
|
export function renderDirectoryListing(l) {
|
|
56
|
-
const lines = l.entries.map((e) => `${
|
|
49
|
+
const lines = l.entries.map((e) => `${DATA_LABEL_UNSAFE.test(e.name) ? quoteDataLabel(e.name) : e.name}${e.kind === "directory" ? "/" : ""}`);
|
|
57
50
|
if (l.more > 0)
|
|
58
51
|
lines.push(`… and ${l.more} more entries`);
|
|
59
52
|
return lines.join("\n");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { effectivePathSpellingOf } from "../../core/effective-path-target.js";
|
|
2
2
|
import { pathTargetOf } from "../../core/tool-registry.js";
|
|
3
|
-
import { fitMiddle, READ_DENY_SENTENCE_PART_MAX } from "./read-deny.js";
|
|
3
|
+
import { fitMiddle, READ_DENY_SENTENCE_PART_MAX, seatForCall } from "./read-deny.js";
|
|
4
4
|
import { resolveKey, violationDetails } from "./safety.js";
|
|
5
5
|
import { readStationMemberOf } from "./shell-read-check.js";
|
|
6
6
|
import { grantOfferFor, parentDirLexically } from "./shell-read-judge.js";
|
|
@@ -27,8 +27,8 @@ export function createFileReadStation(opts) {
|
|
|
27
27
|
return null;
|
|
28
28
|
const spelled = selection.spelled;
|
|
29
29
|
return (async () => {
|
|
30
|
-
const extra = opts.roots();
|
|
31
|
-
const r = await resolveKey(opts.env, opts.rootCanonical, spelled, signal, selection.base, extra, undefined, opts.readDeny, opts.readFace);
|
|
30
|
+
const extra = seatForCall(opts.roots, callOpts.toolCallId)();
|
|
31
|
+
const r = await resolveKey(opts.env, opts.rootCanonical, spelled, signal, selection.base, extra, undefined, seatForCall(opts.readDeny, callOpts.toolCallId), opts.readFace);
|
|
32
32
|
if (r.ok || r.violation.code !== "path_not_in_root" || r.violation.target === undefined || opts.excluded?.(r.violation.target) === true || opts.exempt?.(r.violation.target) === true)
|
|
33
33
|
return VOUCH;
|
|
34
34
|
const target = r.violation.target;
|
package/dist/tools/fs/fs-pdf.js
CHANGED
|
@@ -3,13 +3,14 @@ import { MCP_IMAGE_MAX_BASE64 } from "../../core/mcp.js";
|
|
|
3
3
|
import { PDF_FALLBACK_RENDER_PAGES, PDF_INLINE_PAGE_THRESHOLD, PDF_MAX_EXTRACT_SIZE, PDF_MAX_PAGES_PER_READ, PDF_TARGET_RAW_SIZE, extractPdfPagesAsImages, extractPdfTextLayer, getPdfPageCount, parsePdfPageRange, pdfMagicMatches, } from "./pdf.js";
|
|
4
4
|
import { resolveAutoDownsampler, enoentMessage, MAX_READ_BYTES } from "./fs-shared.js";
|
|
5
5
|
import { planReminderDisclosure, renderReminderDisclosureTrailer } from "../../core/reminder-disclosure.js";
|
|
6
|
+
import { MARKED_BLOCK_AFTER_DATA } from "../../core/reminder-mint.js";
|
|
6
7
|
function pdfDisclosureTrailer(body, d) {
|
|
7
8
|
if (d === undefined)
|
|
8
9
|
return "";
|
|
9
10
|
const plan = planReminderDisclosure({ segments: [body], mark: d.mark, outlet: "pdf", defuseExactMark: false, throttle: { key: d.key, windows: d.windows } });
|
|
10
11
|
d.effects.push(plan.effects);
|
|
11
12
|
const trailer = renderReminderDisclosureTrailer(plan.verdict, d.mark);
|
|
12
|
-
return trailer !== undefined ?
|
|
13
|
+
return trailer !== undefined ? `${MARKED_BLOCK_AFTER_DATA}${trailer}` : "";
|
|
13
14
|
}
|
|
14
15
|
export { pdfModelCapabilitiesOf } from "./pdf.js";
|
|
15
16
|
async function pdfPagesToImageBlocks(pages, path, downsamplerOpt) {
|
|
@@ -47,9 +48,6 @@ export async function readPdfFile(env, path, key, pages, signal, downsamplerOpt,
|
|
|
47
48
|
return `Error (Read): ${await enoentMessage(env, key, cwd, signal, readDeny)}`;
|
|
48
49
|
return `Error (Read): cannot stat PDF "${path}" to verify its size before reading: ${meta.error.message}`;
|
|
49
50
|
}
|
|
50
|
-
if (meta.value.kind === "directory") {
|
|
51
|
-
return `Error (Read): "${path}" is a directory, not a file; use glob/grep or list it with the shell.`;
|
|
52
|
-
}
|
|
53
51
|
const size = preRead ? preRead.byteLength : meta.value.size;
|
|
54
52
|
if (size > PDF_MAX_EXTRACT_SIZE) {
|
|
55
53
|
return `Error (Read): PDF "${path}" exceeds the maximum size for PDF reading (${size} bytes > ${PDF_MAX_EXTRACT_SIZE}-byte / 100 MB cap).`;
|
|
@@ -7,6 +7,8 @@ import { type ImageDimensions } from "../../core/mcp.js";
|
|
|
7
7
|
import { type PdfModelCapabilities } from "./pdf.js";
|
|
8
8
|
import { type ReadImageDownsamplerOption, type CwdRef } from "./fs-shared.js";
|
|
9
9
|
import { type ReminderDisclosureCounts, type ReminderDisclosureEffects, type ReminderDisclosureVerdict } from "../../core/reminder-disclosure.js";
|
|
10
|
+
import { type DirectoryListing } from "./dir-entries.js";
|
|
11
|
+
import { FileError, type BoundFileObject, type Result } from "../../internal/harness.js";
|
|
10
12
|
/**
|
|
11
13
|
* The Read tool, and the ONE read of a file for the model it is built on, split into three steps so every
|
|
12
14
|
* carrier shares it:
|
|
@@ -42,8 +44,9 @@ import { type ReminderDisclosureCounts, type ReminderDisclosureEffects, type Rem
|
|
|
42
44
|
export declare const READ_OUTCOMES: readonly ["attached", "partial", "unchanged", "not_attached"];
|
|
43
45
|
export type ReadOutcome = (typeof READ_OUTCOMES)[number];
|
|
44
46
|
/** The lane the read took. Absent on a refusal raised before the lane was known. A corrupt notebook served
|
|
45
|
-
* as raw text is `text` (with the `notebook_fallback` note).
|
|
46
|
-
|
|
47
|
+
* as raw text is `text` (with the `notebook_fallback` note). `directory`: the path is a directory — judged in one
|
|
48
|
+
* place, before the lanes; the Read tool refuses it, a carrier that lists directories reads the kind. */
|
|
49
|
+
export type ReadKind = "text" | "notebook" | "image" | "pdf" | "directory";
|
|
47
50
|
/** The engine's statements about one read, as data. The Read carrier's rendering is
|
|
48
51
|
* {@link renderReadNoteForTool}; the frame carrier renders the same members its own way. */
|
|
49
52
|
export type ReadNote = {
|
|
@@ -105,6 +108,12 @@ export type ReadNote = {
|
|
|
105
108
|
| {
|
|
106
109
|
kind: "disclosure";
|
|
107
110
|
verdict: ReminderDisclosureVerdict;
|
|
111
|
+
}
|
|
112
|
+
/** A PDF read as a reference only (a bound read, {@link ReadForModelOptions.bound}): its size and page count, when known. */
|
|
113
|
+
| {
|
|
114
|
+
kind: "pdf_reference";
|
|
115
|
+
bytes?: number;
|
|
116
|
+
pages?: number;
|
|
108
117
|
};
|
|
109
118
|
/** The read-state entry a delivery records, minus the delivery's own facts (when, which transmission). */
|
|
110
119
|
export interface ReadObservation {
|
|
@@ -136,6 +145,17 @@ export interface ReadForModelContext {
|
|
|
136
145
|
taskId?: string;
|
|
137
146
|
principal?: string;
|
|
138
147
|
}
|
|
148
|
+
/** How a carrier other than the Read tool asks for the read. Absent members ⇒ exactly the Read tool's read. */
|
|
149
|
+
export interface ReadForModelOptions {
|
|
150
|
+
/** A BOUND read: the canonical key the carrier resolved and the object it holds open there ({@link ModelFileReader.openBound}),
|
|
151
|
+
* the one it had judged. A path that resolves to another key is refused; the kind, the size and every byte come from the
|
|
152
|
+
* held object, never from the path. A PDF is a reference only: its size from the held object, its page count from its
|
|
153
|
+
* bytes up to the whole-send size (`pdf_reference` note). */
|
|
154
|
+
bound?: {
|
|
155
|
+
key: string;
|
|
156
|
+
object: BoundFileObject;
|
|
157
|
+
};
|
|
158
|
+
}
|
|
139
159
|
export interface ModelFileReaderOptions {
|
|
140
160
|
env: ExecutionEnv;
|
|
141
161
|
state: ReadFileState;
|
|
@@ -159,7 +179,30 @@ export interface ModelFileReaderOptions {
|
|
|
159
179
|
disclosureWindows?: Map<string, number>;
|
|
160
180
|
}
|
|
161
181
|
export interface ModelFileReader {
|
|
162
|
-
readForModel(args: unknown, ctx: ReadForModelContext): Promise<ReadForModelResult>;
|
|
182
|
+
readForModel(args: unknown, ctx: ReadForModelContext, opts?: ReadForModelOptions): Promise<ReadForModelResult>;
|
|
183
|
+
/** The path's resolution alone — the same step `readForModel` opens with (the read-deny table, the roots, the device
|
|
184
|
+
* and UNC refusals): its canonical key, or the Read tool's refusal. */
|
|
185
|
+
resolveTarget(path: string, ctx: ReadForModelContext): Promise<{
|
|
186
|
+
ok: true;
|
|
187
|
+
key: string;
|
|
188
|
+
} | {
|
|
189
|
+
ok: false;
|
|
190
|
+
refusal: ReadRefusal;
|
|
191
|
+
}>;
|
|
192
|
+
/** Open the object at a resolved key and hold it, for a carrier that judges and then reads that same object (the
|
|
193
|
+
* environment's `openBound`; an environment without it cannot bind, and the answer says so). The carrier closes it. */
|
|
194
|
+
openBound(key: string, signal?: AbortSignal): Promise<Result<BoundFileObject, FileError>>;
|
|
195
|
+
/** One level of a held directory, every entry through the walk's per-entry read-deny judge. */
|
|
196
|
+
listDirectory(bound: {
|
|
197
|
+
key: string;
|
|
198
|
+
object: BoundFileObject;
|
|
199
|
+
}, signal?: AbortSignal): Promise<Result<DirectoryListing, FileError>>;
|
|
200
|
+
/** Plan the disclosure over external text this reader did not read (the same pipeline, throttle windows and
|
|
201
|
+
* counters); the effects commit with the result that carries them. */
|
|
202
|
+
planDisclosure(segments: string[], throttleKey: string): {
|
|
203
|
+
note?: ReadNote;
|
|
204
|
+
effects: ReminderDisclosureEffects;
|
|
205
|
+
};
|
|
163
206
|
/** Apply the result's effects: the read-state entry (stamped `lastReadAt` and the transmission that
|
|
164
207
|
* carried it) and the disclosure windows / counters. Once per result: a second commit throws. */
|
|
165
208
|
commit(result: ReadForModelResult, at?: {
|
|
@@ -178,4 +221,4 @@ export declare function createReadFileTool(env: ExecutionEnv, state: ReadFileSta
|
|
|
178
221
|
taskId?: string;
|
|
179
222
|
principal?: string;
|
|
180
223
|
toolCallId?: string;
|
|
181
|
-
}) => boolean, readDeny?: import("./read-deny.js").ReadDenyMatcher, readFace?: import("./containment-face.js").ContainmentFace, reminderMark?: string, reminderDisclosureCounts?: ReminderDisclosureCounts): AgentTool;
|
|
224
|
+
}) => boolean, readDeny?: import("./read-deny.js").ReadDenyMatcher, readFace?: import("./containment-face.js").ContainmentFace, reminderMark?: string, reminderDisclosureCounts?: ReminderDisclosureCounts, sharedReader?: ModelFileReader): AgentTool;
|