@sema-agent/core 7.49.5 → 7.50.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 +157 -0
- package/dist/agents/observer.js +3 -10
- 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 +34 -19
- package/dist/core/gate-lanes.js +15 -13
- 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/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/policy-throw.d.ts +34 -0
- package/dist/core/runner/policy-throw.js +25 -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-ask-lane.d.ts +2 -1
- package/dist/core/runner/prepare-ask-lane.js +14 -16
- 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 +11 -10
- 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 +125 -0
- 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/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 +44 -24
- package/dist/tools/fs/shell-read-device.d.ts +1 -1
- package/dist/tools/fs/shell-read-face.d.ts +15 -0
- package/dist/tools/fs/shell-read-face.js +5 -0
- 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.50.0.json +1699 -0
- package/wire-changes/core@7.50.1.json +65 -0
- package/dist/core/runner/persisted-path-rows.d.ts +0 -88
- package/dist/core/runner/persisted-path-rows.js +0 -108
package/dist/index.js
CHANGED
|
@@ -144,6 +144,7 @@ export { probeParkRoundTrip, durableParkGapOf, durableParkGapFor, PARK_SELFCHECK
|
|
|
144
144
|
export {} from "./core/checkpoint-store.js";
|
|
145
145
|
export {} from "./core/checkpoint-store.js";
|
|
146
146
|
export { projectHumanInput, buildHumanInputEvent, } from "./core/human-input-projection.js";
|
|
147
|
+
export { USER_ATTACHMENT_SEAT, USER_ATTACHMENT_KINDS, USER_ATTACHMENT_SUPPLIES, USER_ATTACHMENT_OUTCOMES, USER_ATTACHMENTS_MAX, USER_ATTACHMENT_LABEL_MAX, } from "./core/user-attachment.js";
|
|
147
148
|
export { TaskRegistry, defaultTaskRegistry, createTaskOutputTool, createTaskStopTool, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccessWorkflowRun, DURABLE_AGENT_HANDLE_RE, } from "./core/task-registry.js";
|
|
148
149
|
export { InMemoryMailboxStore, MailboxStoreError, MAILBOX_TOMBSTONED_RECIPIENT_CODE, MAILBOX_PEER_NOTICE_STATES, MAILBOX_PEER_FROM_MODES, MAILBOX_PEER_RECORD_KINDS, MAILBOX_INVALID_PEER_META_CODE, MAILBOX_CROSS_PROCESS_UNSAFE_CODE, readMailboxPeerMeta, mailboxCrossProcessMountVerdict, } from "./core/mailbox-store.js";
|
|
149
150
|
export { FileMailboxStore } from "./stores/file/mailbox-store.js";
|
|
@@ -199,7 +200,7 @@ export { adoptLocalDataRoot, ackAdoptionConfig, witnessAdoptionConfig, listAdopt
|
|
|
199
200
|
export { formatHookFeedback, runToolGate, createHookEnvCapabilities, createPreToolUseConstraintPolicy, normalizePersistedRuleHit, } from "./core/hooks.js";
|
|
200
201
|
export { HOOK_FAMILIES, HOOKS_INVALID_CODE } from "./core/hook-seats.js";
|
|
201
202
|
export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, MemoryProjectionError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, MEMORY_PROJECT_KEY_ABSENT_REASONS, } from "./core/memory.js";
|
|
202
|
-
export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, buildMemoryInstruction, writableRootOf, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_ORIGIN_CAUSES, committedOriginOf, originEquals, consolidationExposedFrontmatter, ambiguousOriginRepresentation, committedDistilledOf, distilledEquals, CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, deriveShadowedSet, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationIncompleteNotice, memoryConsolidationRefusedNotice, memoryConsolidationWithheldNotice, DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintExposurePartitionedPlan, mintLlmConsolidationPlan, MEMORY_DISTILLER_PURITY_CONTRACT_V1, detectCleanArmVerbatimLeak, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, CONSOLIDATION_DRIVER_PLANS_DIR, CONSOLIDATION_DRIVER_RUNS_FILE, CONSOLIDATION_RUN_STOP_REASONS, archiveDistillerPlan, readConsolidationDriverRun, runMemoryConsolidationDriver, isInstructionEntry, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_CAPTURE_OPTOUT_NOTICE, memoryCaptureOptedOutNotice, memoryCaptureOptOutUnpersistedNotice, SESSION_CAPTURE_OPTOUT_DIR, markSessionCaptureOptOut, readSessionCaptureOptOut, listSessionCaptureOptOut, fileSessionCaptureRecordStore, readV2HeaderHints, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_INDEX_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, MEMORY_EXPOSURE_BANNER, MEMORY_EXPOSURE_HANDLE_TAG, memoryExposureIndexRow, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, erasureSelectHash, computeMemoryBundleHash, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, isOrgScopeKey, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, migrateScope, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, syncMemoryScope, } from "./core/memory-engine/index.js";
|
|
203
|
+
export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, buildMemoryInstruction, writableRootOf, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_ORIGIN_CAUSES, committedOriginOf, originEquals, consolidationExposedFrontmatter, ambiguousOriginRepresentation, committedDistilledOf, distilledEquals, CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, deriveShadowedSet, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationIncompleteNotice, memoryConsolidationRefusedNotice, memoryConsolidationWithheldNotice, DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintExposurePartitionedPlan, mintLlmConsolidationPlan, MEMORY_DISTILLER_PURITY_CONTRACT_V1, detectCleanArmVerbatimLeak, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, CONSOLIDATION_DRIVER_PLANS_DIR, CONSOLIDATION_DRIVER_RUNS_FILE, CONSOLIDATION_RUN_STOP_REASONS, CONSOLIDATION_WRITE_REFUSED_CODE, archiveDistillerPlan, readConsolidationDriverRun, runMemoryConsolidationDriver, isInstructionEntry, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_CAPTURE_OPTOUT_NOTICE, memoryCaptureOptedOutNotice, memoryCaptureOptOutUnpersistedNotice, SESSION_CAPTURE_OPTOUT_DIR, markSessionCaptureOptOut, readSessionCaptureOptOut, listSessionCaptureOptOut, fileSessionCaptureRecordStore, readV2HeaderHints, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_INDEX_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, MEMORY_EXPOSURE_BANNER, MEMORY_EXPOSURE_HANDLE_TAG, memoryExposureIndexRow, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, erasureSelectHash, computeMemoryBundleHash, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, isOrgScopeKey, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, migrateScope, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, syncMemoryScope, } from "./core/memory-engine/index.js";
|
|
203
204
|
export { STORE_FORM_REFUSAL_CODES, TARGET_OUTSIDE_STORE, SCOPE_HOME_NOT_DIRECTORY, SCOPE_HOME_FORMS } from "./core/memory-engine/layout.js";
|
|
204
205
|
export { reanchorMemoryStoreRoot } from "./core/memory-engine/layout.js";
|
|
205
206
|
export { SHARED_MEMORY_READ_CAP_BYTES, SHARED_MEMORY_LIST_PAGE_SIZE, SharedMemoryStoreError, } from "./core/shared-memory/types.js";
|
|
@@ -8,7 +8,7 @@ export type { CompactionPreparation, SummarizationClampDryRun } from "../engine/
|
|
|
8
8
|
export type { InvokedSkillRetention } from "../engine/compaction/utils.js";
|
|
9
9
|
export type { AgentCoreRuntimeDeps } from "../engine/loop/runtime-deps.js";
|
|
10
10
|
export type { AgentMessage, AgentTool, AgentToolResult, AgentToolUpdateCallback, ThinkingLevel, ToolExecutionMode, ToolInputValidationContext, ToolInputVerdict, } from "../engine/loop/types.js";
|
|
11
|
-
export type { AgentHarnessEvent, CompactionSettings, ExecutionEnv, ExecutionErrorCode, FileError, FileKind, FileErrorCode, FileInfo, Result, WriteExpectation, WriteReceipt, SymlinkChain, Session, SessionMetadata, SessionRepo, SessionStorage, SessionTreeEntry, Skill, } from "../engine/harness/types.js";
|
|
11
|
+
export type { AgentHarnessEvent, CompactionSettings, ExecutionEnv, ExecutionErrorCode, FileError, FileKind, FileErrorCode, FileInfo, Result, WriteExpectation, WriteReceipt, SymlinkChain, BoundFileObject, Session, SessionMetadata, SessionRepo, SessionStorage, SessionTreeEntry, Skill, } from "../engine/harness/types.js";
|
|
12
12
|
export type { ExecutionEnvExecOptions, ExecResult } from "../engine/harness/types.js";
|
|
13
13
|
export type { SessionWriteOptions, CompactionEntry } from "../engine/harness/types.js";
|
|
14
14
|
export type { ActiveWorktreeSession, WorkspaceState } from "../engine/harness/types.js";
|
package/dist/internal/llm.d.ts
CHANGED
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* design/118 ①②: the layer is now first-party (`src/engine/llm/`, naturalized out of the vendored
|
|
5
5
|
* llm-core); the facade stays so consumers never notice which side a symbol lives on.
|
|
6
6
|
*/
|
|
7
|
-
export { createAssistantMessageEventStream, ensureToolTurnInvariants, MODEL_OUTPUT_INVALID_CAUSES, snapshotActorAssertion, stampStreamDrops, streamDropsOf, stripEngineMetadata, TOOL_TURN_INCOMPLETE_CAUSES, TOOL_TURN_REPAIR_DROPS } from "../engine/llm/index.js";
|
|
8
|
-
export type { ActorAssertion, AnthropicMessagesCompat, OpenAICompletionsCompat, OpenAIResponsesCompat, AssistantMessage, AssistantMessageDiagnostic, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, Model, ModelOutputInvalid, ModelOutputInvalidCause, OutputLimit, ResilienceOptions, RouteAdjudication, RouteCredential, RouteCredentialSource, RoutePairingConfig, RoutePairingPosture, RouteRefusalCode, RouteRefusalDetail, SimpleStreamOptions, StallTimeouts, StopReason, StreamFn, TextContent, ThinkingContent, Tool, ToolCall, ToolResultMessage, StreamDrop, StreamDropCause, ToolTurnIncompleteCause, ToolTurnRepair, Usage, UserMessage, } from "../engine/llm/index.js";
|
|
7
|
+
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";
|
|
8
|
+
export type { ActorAssertion, UserAttachmentKind, UserAttachmentObservation, UserAttachmentOutcome, UserAttachmentSupply, UserMessageAttachment, AnthropicMessagesCompat, OpenAICompletionsCompat, OpenAIResponsesCompat, AssistantMessage, AssistantMessageDiagnostic, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, Model, ModelOutputInvalid, ModelOutputInvalidCause, OutputLimit, ResilienceOptions, RouteAdjudication, RouteCredential, RouteCredentialSource, RoutePairingConfig, RoutePairingPosture, RouteRefusalCode, RouteRefusalDetail, SimpleStreamOptions, StallTimeouts, StopReason, StreamFn, TextContent, ThinkingContent, Tool, ToolCall, ToolResultMessage, StreamDrop, StreamDropCause, ToolTurnIncompleteCause, ToolTurnRepair, Usage, UserMessage, } from "../engine/llm/index.js";
|
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
|
|
@@ -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;
|
package/dist/tools/fs/fs-read.js
CHANGED
|
@@ -4,17 +4,22 @@ import { sha256, resolveKey, violationText, violationDetails, binaryMagicFormat,
|
|
|
4
4
|
import { decodeTextBytes } from "./encoding.js";
|
|
5
5
|
import { isNotebookPath, parseNotebookCells, renderNotebookCells, stripNotebookImageData, NOTEBOOK_IMAGE_BASE64_BUDGET } from "./notebook.js";
|
|
6
6
|
import { MCP_IMAGE_MAX_BASE64, IMAGE_TARGET_RAW_SIZE } from "../../core/mcp.js";
|
|
7
|
-
import { PDF_MAX_PAGES_PER_READ, pdfMagicMatches } from "./pdf.js";
|
|
7
|
+
import { countPdfPagesFromBytes, PDF_MAX_PAGES_PER_READ, PDF_TARGET_RAW_SIZE, pdfMagicMatches } from "./pdf.js";
|
|
8
8
|
import { MAX_READ_BYTES, SLICED_READ_MAX_BYTES, NO_DOWNSAMPLER_IMAGE_CAP_HINT, resolveAutoDownsampler, MAX_READ_OUTPUT_CHARS, FILE_PATH_PARAMS, countLines, seededFileUnchangedReminder, enoentMessage, } from "./fs-shared.js";
|
|
9
9
|
import { readPdfFile } from "./fs-pdf.js";
|
|
10
|
-
import {
|
|
10
|
+
import { seatForCall, seatReady } from "./read-deny.js";
|
|
11
|
+
import { thrownText } from "../../core/thrown-value.js";
|
|
12
|
+
import { MARKED_BLOCK_AFTER_DATA, openSystemReminder } from "../../core/reminder-mint.js";
|
|
11
13
|
import { planReminderDisclosure, commitReminderDisclosureEffects, renderReminderDisclosureTrailer, } from "../../core/reminder-disclosure.js";
|
|
12
14
|
import { toolFace } from "../../core/tool-catalog-entries.js";
|
|
13
15
|
import { admitImageBytes, imageReadCap } from "./image-admission.js";
|
|
16
|
+
import { createEntryDenyJudge, enumerateDirectory } from "./dir-entries.js";
|
|
17
|
+
import { FileError } from "../../internal/harness.js";
|
|
14
18
|
export const READ_OUTCOMES = Object.freeze(["attached", "partial", "unchanged", "not_attached"]);
|
|
19
|
+
const UNBINDABLE = "this environment cannot bind a read to the file that was checked, so it was not read";
|
|
15
20
|
const NO_EFFECTS = () => ({ disclosure: [] });
|
|
16
21
|
export function createModelFileReader(opts) {
|
|
17
|
-
const { env, state, rootCanonical, cwdRef,
|
|
22
|
+
const { env, state, rootCanonical, cwdRef, imageDownsampler, pdfCapabilities, bgOutputReadExemption, readFace, reminderMark, readDeny: readDenySeat, additionalRoots: rootsSeat } = opts;
|
|
18
23
|
const windows = opts.disclosureWindows ?? new Map();
|
|
19
24
|
const refuse = (envelope, kind) => ({
|
|
20
25
|
outcome: "not_attached",
|
|
@@ -29,7 +34,13 @@ export function createModelFileReader(opts) {
|
|
|
29
34
|
const verdict = plan.verdict;
|
|
30
35
|
return { ...(verdict.reminder !== undefined || verdict.envelopeTags !== undefined ? { note: { kind: "disclosure", verdict } } : {}), effects: plan.effects };
|
|
31
36
|
};
|
|
32
|
-
const
|
|
37
|
+
const resolve = async (path, ctx) => {
|
|
38
|
+
if (ctx.toolCallId === undefined)
|
|
39
|
+
await seatReady(rootsSeat, ctx.signal);
|
|
40
|
+
return resolveKey(env, rootCanonical, path, ctx.signal, cwdRef?.current, seatForCall(rootsSeat, ctx.toolCallId), bgOutputReadExemption === undefined ? undefined : (key) => bgOutputReadExemption(key, ctx), seatForCall(readDenySeat, ctx.toolCallId), readFace);
|
|
41
|
+
};
|
|
42
|
+
const readForModel = async (args, ctx, opts) => {
|
|
43
|
+
const readDeny = seatForCall(readDenySeat, ctx.toolCallId);
|
|
33
44
|
const { offset, limit, pages } = (args ?? {});
|
|
34
45
|
const path = fileArgPath(args);
|
|
35
46
|
if (path === undefined)
|
|
@@ -42,29 +53,35 @@ export function createModelFileReader(opts) {
|
|
|
42
53
|
details: { type: "file_unchanged", reason, file: { filePath: path, startLine, endLine, totalLines } },
|
|
43
54
|
effects: NO_EFFECTS(),
|
|
44
55
|
});
|
|
45
|
-
const r = await
|
|
56
|
+
const r = await resolve(path, ctx);
|
|
46
57
|
if (!r.ok)
|
|
47
58
|
return refuse(errorResult(violationText("Read", r.violation), violationDetails(r.violation)));
|
|
59
|
+
if (opts?.bound !== undefined && r.key !== opts.bound.key) {
|
|
60
|
+
return refuse(errorResult(`Error (Read): "${path.slice(0, 300)}" resolved to a different file while it was being checked, so it was not read.`));
|
|
61
|
+
}
|
|
62
|
+
const bound = opts?.bound;
|
|
63
|
+
const readBytes = (key, laneCap) => bound === undefined ? env.readBinaryFile(key, ctx.signal) : bound.object.readBytes(laneCap, ctx.signal);
|
|
64
|
+
const info = bound === undefined ? await env.fileInfo(r.key, ctx.signal) : await bound.object.size().then((s) => (s.ok ? { ok: true, value: { kind: bound.object.kind, size: s.value } } : s));
|
|
65
|
+
if (info.ok && info.value.kind === "directory") {
|
|
66
|
+
return refuse(errorResult(`Error (Read): "${path}" is a directory, not a file; use glob/grep or list it with the shell.`), "directory");
|
|
67
|
+
}
|
|
48
68
|
const isNb = isNotebookPath(r.key);
|
|
49
69
|
const imageMime = imageMimeForRead(r.key);
|
|
50
70
|
if (imageMime !== undefined) {
|
|
51
|
-
const meta =
|
|
71
|
+
const meta = info;
|
|
52
72
|
if (!meta.ok) {
|
|
53
73
|
const ex = await env.exists(r.key, ctx.signal);
|
|
54
74
|
if (ex.ok && !ex.value)
|
|
55
75
|
return refuse(errorResult(`Error (Read): ${await enoentMessage(env, r.key, cwdRef?.current ?? rootCanonical, ctx.signal, readDeny)}`), "image");
|
|
56
76
|
return refuse(errorResult(`Error (Read): cannot stat image "${path}" to verify its size before reading: ${meta.error.message}`), "image");
|
|
57
77
|
}
|
|
58
|
-
if (meta.value.kind === "directory") {
|
|
59
|
-
return refuse(errorResult(`Error (Read): "${path}" is a directory, not a file; use glob/grep or list it with the shell.`), "image");
|
|
60
|
-
}
|
|
61
78
|
const downsampler = imageDownsampler === false ? undefined : (imageDownsampler ?? (await resolveAutoDownsampler()));
|
|
62
79
|
const readCap = imageReadCap(downsampler);
|
|
63
80
|
const tooLargeToRead = (bytes) => `Error (Read): image "${path}" is too large to read (${bytes} bytes > ${readCap}-byte cap).` +
|
|
64
81
|
(downsampler ? "" : ` ${NO_DOWNSAMPLER_IMAGE_CAP_HINT}`);
|
|
65
82
|
if (meta.value.size > readCap)
|
|
66
83
|
return refuse(errorResult(tooLargeToRead(meta.value.size)), "image");
|
|
67
|
-
const bin = await
|
|
84
|
+
const bin = await readBytes(r.key, readCap);
|
|
68
85
|
if (!bin.ok)
|
|
69
86
|
return refuse(errorResult(`Error (Read): cannot read image "${path}": ${bin.error.message}`), "image");
|
|
70
87
|
const admitted = await admitImageBytes(bin.value, imageMime, downsampler);
|
|
@@ -96,6 +113,25 @@ export function createModelFileReader(opts) {
|
|
|
96
113
|
};
|
|
97
114
|
}
|
|
98
115
|
const pdfOf = async (preRead) => {
|
|
116
|
+
if (bound !== undefined) {
|
|
117
|
+
if (!info.ok)
|
|
118
|
+
return refuse(errorResult(`Error (Read): cannot size PDF "${path.slice(0, 300)}": ${info.error.message.slice(0, 200)}`), "pdf");
|
|
119
|
+
let held = preRead;
|
|
120
|
+
if (held === undefined && info.value.size <= PDF_TARGET_RAW_SIZE) {
|
|
121
|
+
const got = await readBytes(r.key, PDF_TARGET_RAW_SIZE);
|
|
122
|
+
if (!got.ok)
|
|
123
|
+
return refuse(errorResult(`Error (Read): cannot read PDF "${path.slice(0, 300)}": ${got.error.message.slice(0, 200)}`), "pdf");
|
|
124
|
+
held = got.value;
|
|
125
|
+
}
|
|
126
|
+
const pageCount = held !== undefined ? countPdfPagesFromBytes(held) : undefined;
|
|
127
|
+
return {
|
|
128
|
+
outcome: "attached",
|
|
129
|
+
kind: "pdf",
|
|
130
|
+
data: [],
|
|
131
|
+
notes: [{ kind: "pdf_reference", bytes: info.value.size, ...(pageCount !== undefined ? { pages: pageCount } : {}) }],
|
|
132
|
+
effects: NO_EFFECTS(),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
99
135
|
const effects = [];
|
|
100
136
|
const out = await readPdfFile(env, path, r.key, pages, ctx.signal, imageDownsampler, cwdRef?.current ?? rootCanonical, preRead, pdfCapabilities, readDeny, {
|
|
101
137
|
mark: reminderMark,
|
|
@@ -113,11 +149,7 @@ export function createModelFileReader(opts) {
|
|
|
113
149
|
return pdfOf(undefined);
|
|
114
150
|
const binaryExt = hasBinaryExtension(r.key);
|
|
115
151
|
const binaryExtRefusal = () => refuse(errorResult(`Error (Read): "${path}" appears to be a binary file (by extension); this tool reads UTF-8 text only.`), "text");
|
|
116
|
-
const info = await env.fileInfo(r.key, ctx.signal);
|
|
117
152
|
if (info.ok) {
|
|
118
|
-
if (info.value.kind === "directory") {
|
|
119
|
-
return refuse(errorResult(`Error (Read): "${path}" is a directory, not a file; use glob/grep or list it with the shell.`), "text");
|
|
120
|
-
}
|
|
121
153
|
if (info.value.size > SLICED_READ_MAX_BYTES) {
|
|
122
154
|
if (binaryExt)
|
|
123
155
|
return binaryExtRefusal();
|
|
@@ -137,7 +169,7 @@ export function createModelFileReader(opts) {
|
|
|
137
169
|
return refuse(errorResult(`Error (Read): ${await enoentMessage(env, r.key, cwdRef?.current ?? rootCanonical, ctx.signal, readDeny)}`), "text");
|
|
138
170
|
return refuse(errorResult(`Error (Read): cannot determine the type of "${path.slice(0, 300)}" (stat failed: ${info.error.message.slice(0, 200)}); refusing to open it — if it is a FIFO/socket/device, reading it would hang. Retry if this was transient, or inspect it with Bash (e.g. \`file\`, \`ls -l\`).`), "text");
|
|
139
171
|
}
|
|
140
|
-
const readBin = await
|
|
172
|
+
const readBin = await readBytes(r.key, !isNb && limit === undefined ? MAX_READ_BYTES : SLICED_READ_MAX_BYTES);
|
|
141
173
|
if (!readBin.ok)
|
|
142
174
|
return refuse(errorResult(`Error (Read): cannot read "${path}": ${readBin.error.message}`), "text");
|
|
143
175
|
const readSize = readBin.value.byteLength;
|
|
@@ -302,6 +334,16 @@ export function createModelFileReader(opts) {
|
|
|
302
334
|
const committed = new WeakSet();
|
|
303
335
|
return {
|
|
304
336
|
readForModel,
|
|
337
|
+
async resolveTarget(path, ctx) {
|
|
338
|
+
const r = await resolve(path, ctx).catch((err) => ({ ok: false, violation: { code: "invalid", message: thrownText(err) } }));
|
|
339
|
+
return r.ok ? { ok: true, key: r.key } : { ok: false, refusal: errorResult(violationText("Read", r.violation), violationDetails(r.violation)) };
|
|
340
|
+
},
|
|
341
|
+
openBound: (key, signal) => (env.openBound !== undefined ? env.openBound(key, signal) : Promise.resolve({ ok: false, error: new FileError("not_supported", UNBINDABLE, key) })),
|
|
342
|
+
listDirectory: (bound, signal) => enumerateDirectory(env, bound.key, readDenySeat !== undefined ? createEntryDenyJudge(env, readDenySeat, signal) : undefined, signal, () => bound.object.list(signal)),
|
|
343
|
+
planDisclosure(segments, throttleKey) {
|
|
344
|
+
const d = disclosureOf(segments, "read", throttleKey);
|
|
345
|
+
return { ...(d.note !== undefined ? { note: d.note } : {}), effects: d.effects };
|
|
346
|
+
},
|
|
305
347
|
commit(result, at) {
|
|
306
348
|
if (committed.has(result))
|
|
307
349
|
throw new Error("ModelFileReader.commit: this read result was already committed — a delivery commits its read once");
|
|
@@ -348,6 +390,8 @@ export function renderReadNoteForTool(note, mark) {
|
|
|
348
390
|
}
|
|
349
391
|
case "disclosure":
|
|
350
392
|
return renderReminderDisclosureTrailer(note.verdict, mark) ?? "";
|
|
393
|
+
case "pdf_reference":
|
|
394
|
+
return `[PDF not read: ${note.bytes !== undefined ? `${note.bytes} bytes` : "size unknown"}, ${note.pages !== undefined ? `${note.pages} page${note.pages === 1 ? "" : "s"}` : "page count unknown"}. Read it with the pages parameter, at most ${PDF_MAX_PAGES_PER_READ} pages per request.]`;
|
|
351
395
|
}
|
|
352
396
|
}
|
|
353
397
|
export function renderReadToolResult(r, mark) {
|
|
@@ -373,7 +417,7 @@ export function renderReadToolResult(r, mark) {
|
|
|
373
417
|
return {
|
|
374
418
|
content: [
|
|
375
419
|
...(noCells !== undefined ? [{ type: "text", text: renderReadNoteForTool(noCells, mark) }] : r.data),
|
|
376
|
-
...(trailer !== undefined ? [{ type: "text", text: trailer }] : []),
|
|
420
|
+
...(trailer !== undefined ? [{ type: "text", text: `${MARKED_BLOCK_AFTER_DATA}${trailer}` }] : []),
|
|
377
421
|
],
|
|
378
422
|
details: r.details,
|
|
379
423
|
};
|
|
@@ -383,14 +427,14 @@ export function renderReadToolResult(r, mark) {
|
|
|
383
427
|
const header = noteOf("partial_page") ?? noteOf("partial_chars") ?? noteOf("range");
|
|
384
428
|
const body = r.data[0]?.text ?? "";
|
|
385
429
|
return {
|
|
386
|
-
content: `${fallback !== undefined ? renderReadNoteForTool(fallback, mark) : ""}${header !== undefined ? renderReadNoteForTool(header, mark) : ""}${body}${trailer !== undefined ?
|
|
430
|
+
content: `${fallback !== undefined ? renderReadNoteForTool(fallback, mark) : ""}${header !== undefined ? renderReadNoteForTool(header, mark) : ""}${body}${trailer !== undefined ? `${MARKED_BLOCK_AFTER_DATA}${trailer}` : ""}`,
|
|
387
431
|
details: r.details,
|
|
388
432
|
};
|
|
389
433
|
}
|
|
390
434
|
}
|
|
391
435
|
}
|
|
392
|
-
export function createReadFileTool(env, state, rootCanonical, cwdRef, additionalRoots, imageDownsampler, pdfCapabilities, bgOutputReadExemption, readDeny, readFace, reminderMark, reminderDisclosureCounts) {
|
|
393
|
-
const reader = createModelFileReader({
|
|
436
|
+
export function createReadFileTool(env, state, rootCanonical, cwdRef, additionalRoots, imageDownsampler, pdfCapabilities, bgOutputReadExemption, readDeny, readFace, reminderMark, reminderDisclosureCounts, sharedReader) {
|
|
437
|
+
const reader = sharedReader ?? createModelFileReader({
|
|
394
438
|
env,
|
|
395
439
|
state,
|
|
396
440
|
rootCanonical,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentTool, ExecutionEnv } from "../../internal/harness-types.js";
|
|
2
2
|
import { type RootsSeat } from "./safety.js";
|
|
3
|
-
import type
|
|
3
|
+
import { type ReadDenyMatcher } from "./read-deny.js";
|
|
4
4
|
import type { ContainmentFace } from "./containment-face.js";
|
|
5
5
|
import type { CwdRef } from "./fs-shared.js";
|
|
6
6
|
/**
|
|
@@ -12,5 +12,5 @@ import type { CwdRef } from "./fs-shared.js";
|
|
|
12
12
|
* honesty boundary.
|
|
13
13
|
*/
|
|
14
14
|
export declare function grepDetailFields(text: string, mode: "files_with_matches" | "content" | "count", offset?: number, structuredRows?: readonly import("./search.js").GrepRow[]): Record<string, unknown>;
|
|
15
|
-
export declare function createGrepTool(env: ExecutionEnv, rootCanonical: string,
|
|
16
|
-
export declare function createGlobTool(env: ExecutionEnv, rootCanonical: string,
|
|
15
|
+
export declare function createGrepTool(env: ExecutionEnv, rootCanonical: string, rootsSeat?: RootsSeat, denySeat?: ReadDenyMatcher, readFace?: ContainmentFace, cwdRef?: CwdRef, readAdmission?: (toolCallId: string | undefined, canonicalKey: string) => boolean): AgentTool;
|
|
16
|
+
export declare function createGlobTool(env: ExecutionEnv, rootCanonical: string, rootsSeat?: RootsSeat, denySeat?: ReadDenyMatcher, readFace?: ContainmentFace, cwdRef?: CwdRef, readAdmission?: (toolCallId: string | undefined, canonicalKey: string) => boolean): AgentTool;
|
|
@@ -2,6 +2,7 @@ import { Type } from "typebox";
|
|
|
2
2
|
import { defineTool, errorResult } from "../../core/tools.js";
|
|
3
3
|
import { clipSpelling, pathFamilyOf, resolveKey, violationText, violationDetails, WIN32_NAMESPACE_REFUSAL_TEXT } from "./safety.js";
|
|
4
4
|
import { runGrepDetailed, runGlobDetailed, invalidGlobTokens } from "./search.js";
|
|
5
|
+
import { seatForCall } from "./read-deny.js";
|
|
5
6
|
import { toolFace } from "../../core/tool-catalog-entries.js";
|
|
6
7
|
import { pathTargetBaseOf, splitAbsoluteGlobPattern } from "../../core/effective-path-target.js";
|
|
7
8
|
import { pathTargetValue } from "../../core/tool-registry.js";
|
|
@@ -74,7 +75,7 @@ export function grepDetailFields(text, mode, offset, structuredRows) {
|
|
|
74
75
|
}
|
|
75
76
|
return detailFields;
|
|
76
77
|
}
|
|
77
|
-
export function createGrepTool(env, rootCanonical,
|
|
78
|
+
export function createGrepTool(env, rootCanonical, rootsSeat, denySeat, readFace, cwdRef, readAdmission) {
|
|
78
79
|
const declaredTarget = toolFace("grep").pathTarget;
|
|
79
80
|
return defineTool({
|
|
80
81
|
name: "Grep",
|
|
@@ -112,6 +113,8 @@ export function createGrepTool(env, rootCanonical, additionalRoots, readDeny, re
|
|
|
112
113
|
offset: Type.Optional(Type.Number({ description: "Skip the first N output lines (pagination partner of head_limit)." })),
|
|
113
114
|
}),
|
|
114
115
|
execute: async (args, ctx) => {
|
|
116
|
+
const readDeny = seatForCall(denySeat, ctx.toolCallId);
|
|
117
|
+
const additionalRoots = seatForCall(rootsSeat, ctx.toolCallId);
|
|
115
118
|
const retired = args;
|
|
116
119
|
for (const [name, repair] of [
|
|
117
120
|
["regex", "the `pattern` is ALWAYS evaluated as a regular expression (ripgrep semantics) — drop the key; to match text literally, escape the regex metacharacters in `pattern`"],
|
|
@@ -177,7 +180,7 @@ export function createGrepTool(env, rootCanonical, additionalRoots, readDeny, re
|
|
|
177
180
|
},
|
|
178
181
|
});
|
|
179
182
|
}
|
|
180
|
-
export function createGlobTool(env, rootCanonical,
|
|
183
|
+
export function createGlobTool(env, rootCanonical, rootsSeat, denySeat, readFace, cwdRef, readAdmission) {
|
|
181
184
|
const declaredTarget = toolFace("glob").pathTarget;
|
|
182
185
|
return defineTool({
|
|
183
186
|
name: "Glob",
|
|
@@ -201,6 +204,8 @@ export function createGlobTool(env, rootCanonical, additionalRoots, readDeny, re
|
|
|
201
204
|
max_results: Type.Optional(Type.Number({ description: "Cap results (default 500)." })),
|
|
202
205
|
}),
|
|
203
206
|
execute: async (args, ctx) => {
|
|
207
|
+
const readDeny = seatForCall(denySeat, ctx.toolCallId);
|
|
208
|
+
const additionalRoots = seatForCall(rootsSeat, ctx.toolCallId);
|
|
204
209
|
let pattern = args.pattern;
|
|
205
210
|
let path = declaredTarget === undefined ? undefined : pathTargetValue(args, declaredTarget);
|
|
206
211
|
const { max_results } = args;
|
|
@@ -2,7 +2,7 @@ import type { AgentTool, ExecutionEnv } from "../../internal/harness-types.js";
|
|
|
2
2
|
import type { BeforeWriteHook, FileEditedHook, TrackFileEditHook } from "../../core/types.js";
|
|
3
3
|
import { type ReadFileState } from "./safety.js";
|
|
4
4
|
import type { ContainmentFace } from "./containment-face.js";
|
|
5
|
-
import type
|
|
5
|
+
import { type WriteDenyMatcher } from "./read-deny.js";
|
|
6
6
|
import { type CwdRef } from "./fs-shared.js";
|
|
7
7
|
/**
|
|
8
8
|
* The `beforeWrite` CONTENT hook, mounted here rather than in ToolPolicy because only this band sees
|