@sema-agent/core 5.19.0 → 5.21.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 +102 -4
- package/dist/agents/agent-definition.d.ts +7 -0
- package/dist/agents/agent-transcript-tool.d.ts +30 -0
- package/dist/agents/builtin-agents.d.ts +60 -0
- package/dist/agents/cascade.d.ts +107 -0
- package/dist/agents/cumulative-stats.d.ts +56 -0
- package/dist/agents/observer.d.ts +162 -0
- package/dist/agents/peer-admission.d.ts +95 -0
- package/dist/agents/repair-loop.d.ts +226 -0
- package/dist/agents/retain-ledger.d.ts +141 -0
- package/dist/agents/roster-store.d.ts +105 -0
- package/dist/agents/roster-store.js +3 -0
- package/dist/agents/send-message-tool.d.ts +92 -0
- package/dist/agents/session-util.d.ts +5 -0
- package/dist/agents/subagent-steps.d.ts +66 -0
- package/dist/agents/subagent.d.ts +600 -0
- package/dist/agents/suspend-guard.d.ts +29 -0
- package/dist/agents/teacher.d.ts +75 -0
- package/dist/agents/team.d.ts +120 -1
- package/dist/agents/tool-filter.d.ts +34 -0
- package/dist/agents/verify.d.ts +198 -0
- package/dist/bench/metrics.d.ts +455 -0
- package/dist/brain/anthropic.d.ts +30 -0
- package/dist/brain/circuit-breaker.d.ts +33 -0
- package/dist/brain/circuit-breaker.js +14 -3
- package/dist/brain/context-overflow.d.ts +60 -3
- package/dist/brain/degrading.d.ts +67 -0
- package/dist/brain/errors.d.ts +42 -0
- package/dist/brain/failover.d.ts +15 -0
- package/dist/brain/media-degrade.d.ts +39 -0
- package/dist/brain/model-presets.d.ts +31 -0
- package/dist/brain/open-responses.d.ts +19 -0
- package/dist/brain/openai.d.ts +46 -0
- package/dist/brain/reasoning.d.ts +106 -1
- package/dist/brain/repetition.d.ts +83 -0
- package/dist/brain/request-params.d.ts +56 -0
- package/dist/brain/retry.d.ts +46 -0
- package/dist/brain/routing.d.ts +12 -0
- package/dist/brain/status-sink.d.ts +30 -1
- package/dist/brain/stream-engine.d.ts +147 -0
- package/dist/brain/stream-shared.d.ts +34 -0
- package/dist/brain/terminal-cause.d.ts +31 -0
- package/dist/brain/timeout.d.ts +108 -0
- package/dist/brain/timeout.js +11 -0
- package/dist/brain/tool-call-id.d.ts +20 -0
- package/dist/brain/tool-call-repair.d.ts +13 -0
- package/dist/config/catalog.d.ts +47 -0
- package/dist/config/defaults.d.ts +33 -0
- package/dist/core/a2a-task-state.d.ts +53 -0
- package/dist/core/a2a.d.ts +51 -0
- package/dist/core/arg-summary.d.ts +62 -0
- package/dist/core/ask-question.d.ts +272 -2
- package/dist/core/auto-compaction.d.ts +467 -0
- package/dist/core/auto-compaction.js +20 -6
- package/dist/core/auto-mode-prompt-assets.d.ts +8 -0
- package/dist/core/auto-mode-prompt.d.ts +27 -0
- package/dist/core/auto-mode.d.ts +54 -3
- package/dist/core/auto-promote.d.ts +100 -0
- package/dist/core/background-agent-store.d.ts +293 -0
- package/dist/core/background-agent-store.js +5 -0
- package/dist/core/background-shell.d.ts +110 -0
- package/dist/core/cache-break-detector.d.ts +34 -0
- package/dist/core/canonical-json.d.ts +57 -0
- package/dist/core/checkpoint-store.d.ts +1574 -16
- package/dist/core/compliance.d.ts +30 -0
- package/dist/core/consolidate-scope.d.ts +75 -0
- package/dist/core/context-edit.d.ts +99 -0
- package/dist/core/context-guard.d.ts +46 -0
- package/dist/core/exec-gate.d.ts +44 -0
- package/dist/core/exec-output-tail.d.ts +61 -0
- package/dist/core/file-snapshot-store.d.ts +104 -0
- package/dist/core/fs-write-gate-policy.d.ts +36 -0
- package/dist/core/git-worktree-env.d.ts +31 -0
- package/dist/core/governance-codes.d.ts +19 -0
- package/dist/core/hooks.d.ts +609 -1
- package/dist/core/human-input-projection.d.ts +37 -0
- package/dist/core/human-input-projection.js +13 -0
- package/dist/core/image-downsample.d.ts +74 -0
- package/dist/core/locked-config.d.ts +37 -0
- package/dist/core/lsp-diagnostics.d.ts +77 -0
- package/dist/core/lsp-protocol.d.ts +29 -0
- package/dist/core/lsp-session.d.ts +60 -1
- package/dist/core/lsp.d.ts +150 -1
- package/dist/core/mailbox-store.d.ts +57 -0
- package/dist/core/mailbox-store.js +2 -0
- package/dist/core/mcp.d.ts +385 -0
- package/dist/core/mcp.js +58 -11
- package/dist/core/media-byte-cap.d.ts +21 -0
- package/dist/core/memory-admission.d.ts +71 -0
- package/dist/core/memory-engine/content-origin.d.ts +64 -0
- package/dist/core/memory-engine/data-plane.d.ts +43 -0
- package/dist/core/memory-engine/dual-root.d.ts +24 -0
- package/dist/core/memory-engine/engine.d.ts +230 -0
- package/dist/core/memory-engine/engine.js +103 -35
- package/dist/core/memory-engine/file-backend.d.ts +155 -0
- package/dist/core/memory-engine/frontmatter.d.ts +16 -0
- package/dist/core/memory-engine/layout.d.ts +217 -0
- package/dist/core/memory-engine/memory-backend-contract.d.ts +12 -0
- package/dist/core/memory-engine/migrate.d.ts +9 -0
- package/dist/core/memory-engine/scan.d.ts +12 -0
- package/dist/core/memory-engine/scope-contract.d.ts +61 -1
- package/dist/core/memory-engine/sync-client.d.ts +87 -0
- package/dist/core/memory-engine/sync.d.ts +60 -0
- package/dist/core/memory-engine/tools.d.ts +41 -0
- package/dist/core/memory-engine/types.d.ts +188 -0
- package/dist/core/memory-recall.d.ts +141 -0
- package/dist/core/memory-vector.d.ts +20 -0
- package/dist/core/memory.d.ts +458 -0
- package/dist/core/message-utils.d.ts +6 -0
- package/dist/core/oracle-isolation.d.ts +69 -0
- package/dist/core/permission-rule-consent.d.ts +138 -0
- package/dist/core/permission-rule-model.d.ts +122 -0
- package/dist/core/permission-rule-store.d.ts +119 -3
- package/dist/core/permission-rules.d.ts +87 -1
- package/dist/core/present-plan-tool.d.ts +20 -0
- package/dist/core/pricing.d.ts +26 -0
- package/dist/core/property-harness.d.ts +86 -0
- package/dist/core/protocol-naming.d.ts +38 -0
- package/dist/core/protocol-table.d.ts +61 -0
- package/dist/core/push-queue.d.ts +1 -0
- package/dist/core/remote-env.d.ts +383 -1
- package/dist/core/retention-policy.d.ts +40 -0
- package/dist/core/retention-policy.js +21 -0
- package/dist/core/retention.d.ts +51 -0
- package/dist/core/roles.d.ts +59 -0
- package/dist/core/runner/active-skill-scope.d.ts +34 -0
- package/dist/core/runner/assemble-result.d.ts +134 -0
- package/dist/core/runner/compaction-call-options.d.ts +97 -1
- package/dist/core/runner/grounding-signal.d.ts +10 -0
- package/dist/core/runner/image.d.ts +17 -0
- package/dist/core/runner/image.js +29 -15
- package/dist/core/runner/memory-consolidation.d.ts +60 -0
- package/dist/core/runner/prepare-memory.d.ts +59 -0
- package/dist/core/runner/prepare-task.d.ts +1011 -2
- package/dist/core/runner/prepare-task.js +51 -14
- package/dist/core/runner/prompt-suggestions.d.ts +7 -0
- package/dist/core/runner/runtask.d.ts +304 -3
- package/dist/core/runner/runtask.js +17 -2
- package/dist/core/runner/session-file-state-replay.d.ts +49 -0
- package/dist/core/runner/session-rule-policy.d.ts +58 -0
- package/dist/core/runner/strict-output-schema.d.ts +18 -3
- package/dist/core/runner/synthetic-tools.d.ts +113 -0
- package/dist/core/runner/teardown-bounded.d.ts +34 -0
- package/dist/core/runner/tool-disclosure.d.ts +227 -0
- package/dist/core/runner/tool-output-projection.d.ts +6 -0
- package/dist/core/runner/turn-attachments.d.ts +634 -0
- package/dist/core/runner/usage-accounting.d.ts +32 -0
- package/dist/core/runtime.d.ts +9 -0
- package/dist/core/safe-notify.d.ts +64 -0
- package/dist/core/safety-axis-vocab.d.ts +23 -0
- package/dist/core/safety-merge-corpus.d.ts +37 -0
- package/dist/core/scheduler.d.ts +121 -0
- package/dist/core/secret-env.d.ts +32 -0
- package/dist/core/select-model.d.ts +15 -0
- package/dist/core/sensitive-path-policy.d.ts +42 -0
- package/dist/core/session-policy-store.d.ts +94 -0
- package/dist/core/session-reconcile.d.ts +80 -0
- package/dist/core/session-store.d.ts +85 -0
- package/dist/core/session.d.ts +153 -0
- package/dist/core/shared-memory/contract.d.ts +22 -0
- package/dist/core/shared-memory/normalize.d.ts +123 -2
- package/dist/core/shared-memory/tools.d.ts +14 -0
- package/dist/core/shared-memory/types.d.ts +105 -0
- package/dist/core/shutdown-debug.d.ts +6 -0
- package/dist/core/side-query.d.ts +38 -0
- package/dist/core/side-query.js +6 -1
- package/dist/core/skill-tool-specifier.d.ts +72 -0
- package/dist/core/skills-directory.d.ts +100 -1
- package/dist/core/spec-contract.d.ts +89 -0
- package/dist/core/store-contracts/background-agent-store-contract.d.ts +31 -0
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +26 -0
- package/dist/core/store-contracts/contract-harness.d.ts +20 -0
- package/dist/core/store-contracts/contract-kit-version.d.ts +27 -0
- package/dist/core/store-contracts/file-snapshot-store-contract.d.ts +8 -0
- package/dist/core/store-contracts/mailbox-store-contract.d.ts +42 -0
- package/dist/core/store-contracts/tool-result-store-contract.d.ts +13 -0
- package/dist/core/strategy-store.d.ts +37 -0
- package/dist/core/stub-env.d.ts +7 -0
- package/dist/core/surrogate-safe-slice.d.ts +35 -0
- package/dist/core/task-notification.d.ts +202 -0
- package/dist/core/task-outcome.d.ts +53 -0
- package/dist/core/task-registry-agent.d.ts +337 -1
- package/dist/core/task-registry-agent.js +2 -0
- package/dist/core/task-registry-monitor.d.ts +12 -0
- package/dist/core/task-registry-shared.d.ts +540 -0
- package/dist/core/task-registry.d.ts +343 -0
- package/dist/core/task-registry.js +13 -2
- package/dist/core/task-tool-shape.d.ts +44 -0
- package/dist/core/tighten-task-spec.d.ts +21 -0
- package/dist/core/tool-detach.d.ts +21 -0
- package/dist/core/tool-errors.d.ts +131 -0
- package/dist/core/tool-errors.js +4 -0
- package/dist/core/tool-name-aliases.d.ts +27 -0
- package/dist/core/tool-policy.d.ts +555 -0
- package/dist/core/tool-policy.js +3 -0
- package/dist/core/tool-result-budget.d.ts +32 -0
- package/dist/core/tool-result-store.d.ts +174 -1
- package/dist/core/tools.d.ts +45 -0
- package/dist/core/trace.d.ts +323 -0
- package/dist/core/types.d.ts +3859 -2
- package/dist/core/untrusted-egress.d.ts +8 -0
- package/dist/core/untrusted-text.d.ts +156 -0
- package/dist/core/usage-window-store.d.ts +95 -0
- package/dist/core/version.d.ts +1 -0
- package/dist/core/warm-resume.d.ts +17 -0
- package/dist/core/wiring-manifest.d.ts +169 -0
- package/dist/core/with-retry.d.ts +24 -0
- package/dist/core/workflow-journal-store.d.ts +160 -0
- package/dist/core/workflow-run-store-contract.d.ts +25 -0
- package/dist/core/workflow-run-store.d.ts +119 -0
- package/dist/core/workflow-run-store.js +2 -0
- package/dist/engine/compaction/compaction.d.ts +256 -1
- package/dist/engine/compaction/utils.d.ts +94 -0
- package/dist/engine/execution-env/kill-tree.d.ts +29 -0
- package/dist/engine/execution-env/node-execution-env.d.ts +94 -0
- package/dist/engine/harness/agent-harness.d.ts +116 -0
- package/dist/engine/harness/agent-harness.js +3 -14
- package/dist/engine/harness/messages.d.ts +15 -0
- package/dist/engine/harness/types.d.ts +464 -2
- package/dist/engine/llm/diagnostics.d.ts +4 -0
- package/dist/engine/llm/event-stream.d.ts +3 -0
- package/dist/engine/llm/index.d.ts +7 -0
- package/dist/engine/llm/types.d.ts +500 -3
- package/dist/engine/llm/validation.d.ts +3 -0
- package/dist/engine/loop/agent-loop.d.ts +87 -2
- package/dist/engine/loop/runtime-deps.d.ts +7 -0
- package/dist/engine/loop/types.d.ts +424 -0
- package/dist/engine/lsp/frame-decoder.d.ts +13 -0
- package/dist/engine/lsp/node-lsp-manager.d.ts +107 -0
- package/dist/engine/lsp/stdio-lsp-transport.d.ts +7 -0
- package/dist/engine/session/import-validate.d.ts +27 -0
- package/dist/engine/session/log-digest.d.ts +93 -0
- package/dist/engine/session/memory-repo.d.ts +6 -0
- package/dist/engine/session/memory-storage.d.ts +2 -0
- package/dist/engine/session/session.d.ts +75 -0
- package/dist/engine/session/storage-base.d.ts +8 -0
- package/dist/fixtures/index.d.ts +36 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +1 -2
- package/dist/internal/harness-types.d.ts +6 -0
- package/dist/internal/harness.d.ts +11 -0
- package/dist/internal/llm.d.ts +6 -0
- package/dist/orchestration/builtin-workflows.d.ts +53 -0
- package/dist/orchestration/dev-vm-script-runner.d.ts +19 -0
- package/dist/orchestration/goal.d.ts +57 -0
- package/dist/orchestration/goal.js +3 -0
- package/dist/orchestration/run-spec.d.ts +42 -0
- package/dist/orchestration/run-spec.js +4 -0
- package/dist/orchestration/run-workflow-tool.d.ts +169 -0
- package/dist/orchestration/workflow-governance.d.ts +61 -0
- package/dist/orchestration/workflow-meta.d.ts +28 -0
- package/dist/orchestration/workflow-observe.d.ts +60 -0
- package/dist/orchestration/workflow-primitives.d.ts +23 -1
- package/dist/orchestration/workflow-sandbox-conformance.d.ts +38 -0
- package/dist/orchestration/workflow-script-runner.d.ts +88 -0
- package/dist/orchestration/workflow-script-store.d.ts +98 -0
- package/dist/orchestration/workflow-size-guideline.d.ts +67 -0
- package/dist/orchestration/workflow-types.d.ts +169 -2
- package/dist/orchestration/workflow.d.ts +358 -0
- package/dist/orchestration/workflow.js +13 -2
- package/dist/prompt-assembly/artifact-store.d.ts +33 -0
- package/dist/prompt-assembly/artifact.d.ts +25 -0
- package/dist/prompt-assembly/assemble.d.ts +20 -0
- package/dist/prompt-assembly/composer.d.ts +29 -0
- package/dist/prompt-assembly/epoch.d.ts +55 -1
- package/dist/prompt-assembly/event-registry.d.ts +35 -0
- package/dist/prompt-assembly/explain.d.ts +12 -0
- package/dist/prompt-assembly/tool-catalog.d.ts +38 -0
- package/dist/prompt-assembly/turn-snapshot.d.ts +40 -0
- package/dist/prompt-assembly/types.d.ts +115 -0
- package/dist/prompts/coordinator.d.ts +27 -0
- package/dist/prompts/default.d.ts +539 -0
- package/dist/prompts/simple-sections.d.ts +45 -0
- package/dist/prompts/supervisor.d.ts +66 -0
- package/dist/scenarios/env.d.ts +28 -0
- package/dist/scenarios/full-body.d.ts +50 -0
- package/dist/scenarios/scenario-registry.d.ts +60 -0
- package/dist/scenarios/teacher-quickstart.d.ts +27 -0
- package/dist/server/http.d.ts +17 -0
- package/dist/stores/cc/lockfile.d.ts +6 -0
- package/dist/stores/cc/mailbox-store.d.ts +8 -0
- package/dist/stores/cc/roster-adapter.d.ts +4 -0
- package/dist/stores/cc/sidecar-transcript.d.ts +66 -0
- package/dist/stores/file/background-agent-store.d.ts +24 -0
- package/dist/stores/file/background-agent-store.js +2 -1
- package/dist/stores/file/checkpoint-store.d.ts +38 -0
- package/dist/stores/file/file-snapshot-store.d.ts +25 -0
- package/dist/stores/file/fs-atomic.d.ts +155 -0
- package/dist/stores/file/index.d.ts +89 -0
- package/dist/stores/file/mailbox-store.d.ts +36 -0
- package/dist/stores/file/mailbox-store.js +2 -0
- package/dist/stores/file/memory-store.d.ts +82 -0
- package/dist/stores/file/permission-rule-store.d.ts +79 -0
- package/dist/stores/file/session-policy-store.d.ts +28 -0
- package/dist/stores/file/session-store.d.ts +40 -0
- package/dist/stores/file/shared-ledger.d.ts +83 -0
- package/dist/stores/file/tool-result-store.d.ts +11 -0
- package/dist/stores/file/usage-window-store.d.ts +18 -0
- package/dist/stores/file/workflow-journal-store.d.ts +100 -0
- package/dist/stores/file/workflow-run-store.d.ts +11 -0
- package/dist/stores/file/workflow-run-store.js +2 -0
- package/dist/tools/fs/bash-readonly-classifier.d.ts +282 -0
- package/dist/tools/fs/encoding.d.ts +60 -0
- package/dist/tools/fs/fs-bash.d.ts +133 -0
- package/dist/tools/fs/fs-pdf.d.ts +28 -0
- package/dist/tools/fs/fs-search-tools.d.ts +5 -0
- package/dist/tools/fs/fs-shared.d.ts +360 -0
- package/dist/tools/fs/fs-write.d.ts +16 -0
- package/dist/tools/fs/gh-rate-limit.d.ts +22 -0
- package/dist/tools/fs/index.d.ts +79 -0
- package/dist/tools/fs/notebook.d.ts +56 -0
- package/dist/tools/fs/pdf.d.ts +70 -0
- package/dist/tools/fs/pdf.js +8 -2
- package/dist/tools/fs/repo-map.d.ts +10 -0
- package/dist/tools/fs/safety.d.ts +376 -0
- package/dist/tools/fs/search.d.ts +131 -0
- package/dist/tools/loop-tick.d.ts +24 -0
- package/dist/tools/monitor.d.ts +55 -0
- package/dist/tools/scheduler-tools.d.ts +51 -0
- package/dist/tools/sql-adapters.d.ts +18 -0
- package/dist/tools/sql.d.ts +25 -0
- package/dist/tools/task-list.d.ts +77 -0
- package/dist/tools/todo.d.ts +8 -0
- package/dist/tools/web.d.ts +184 -0
- package/dist/tools/web.js +32 -5
- package/dist/tools/worktree.d.ts +81 -0
- package/package.json +2 -2
- package/dist/tools/gitea-issue.d.ts +0 -13
- package/dist/tools/gitea-issue.js +0 -75
|
@@ -1,26 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/179 §8 — the persisted allow-rule store seam, its core-private write face, and the removal entry.
|
|
3
|
+
*
|
|
4
|
+
* ## Two faces, deliberately unequal
|
|
5
|
+
*
|
|
6
|
+
* A deployment sees a READ face: `list()`, scoped to one verified principal by a factory. There is no
|
|
7
|
+
* exported write API at all — the only way a rule enters the store through the engine is the core-private
|
|
8
|
+
* redemption path (`permission-rule-consent.ts`), which requires an approved durable approval record.
|
|
9
|
+
* `expectedRev` is concurrency control, not authorization, so "hold a put API and skip the ticket" is not
|
|
10
|
+
* a shape that exists here rather than a rule someone must remember.
|
|
11
|
+
*
|
|
12
|
+
* That claim is scoped to the API. A standard in-process deployment shares filesystem credentials with the
|
|
13
|
+
* user, so it can edit a file backend's file directly — the same trust model the settings file it mirrors
|
|
14
|
+
* has. The checksum detects corruption, not an editor who recomputes it. This is stated, not defended
|
|
15
|
+
* against, in v1: the file backend's trust is host = user, no more and no less.
|
|
16
|
+
*
|
|
17
|
+
* ## Principal scoping is a factory boundary, not a parameter
|
|
18
|
+
*
|
|
19
|
+
* `forPrincipal` returns a store already anchored to one identity, so `list()` has no cross-tenant
|
|
20
|
+
* argument to pass wrong. An unauthenticated task (`principal === undefined`) resolves to ZERO rules
|
|
21
|
+
* rather than to a shared bucket — fail-closed on a loosening face means fewer allows, never a shared one.
|
|
22
|
+
*
|
|
23
|
+
* ## Delete is a tombstone, and the tombstone IS the operation's identity
|
|
24
|
+
*
|
|
25
|
+
* Removal takes the observed-remove form: the tombstone carries every add dot the deleting replica could
|
|
26
|
+
* see at delete time, and that observation is FIXED when the call constructs it. An OCC retry inside that
|
|
27
|
+
* one live call re-submits the SAME tombstone — re-snapshotting would suck a concurrently landed add into
|
|
28
|
+
* `removedDots` and swallow a legitimate re-add. The fixing is scoped to one live call on purpose: there
|
|
29
|
+
* is no cross-process or cross-restart continuation of a delete in v1, so calling the entry again after a
|
|
30
|
+
* restart is a NEW delete intent (a new observation, a new tombstone) — which is the correct reading of a
|
|
31
|
+
* person pressing delete a second time.
|
|
32
|
+
*/
|
|
1
33
|
import type { PersistedAllowRule, RuleAdd, RuleDot, RuleScope, RuleTombstone } from "./permission-rule-model.js";
|
|
2
34
|
import type { StoreDurability, StoreFidelity } from "./checkpoint-store.js";
|
|
35
|
+
/** One store read: the rules as persisted, their tombstones, and the revision they were read at. */
|
|
3
36
|
export interface StoredAllowRules {
|
|
37
|
+
/** Rules with their FULL add sets — tombstoned dots already removed by the backend on read. */
|
|
4
38
|
rules: PersistedAllowRule[];
|
|
5
39
|
tombstones: RuleTombstone[];
|
|
40
|
+
/** Monotonic revision of this store, for optimistic concurrency on every write. */
|
|
6
41
|
rev: number;
|
|
42
|
+
/** Integrity fingerprint the backend computed, when it has one. Corruption detection only. */
|
|
7
43
|
checksum?: string;
|
|
8
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* The host-visible store face: read-only, already anchored to a single principal.
|
|
47
|
+
*
|
|
48
|
+
* A backend that fails to read must not silently report an empty set as if it were an empty store — it
|
|
49
|
+
* throws, and the lane's caller turns that into zero rules PLUS a loud disclosure. Both outcomes deny
|
|
50
|
+
* more than they allow; only one of them is honest about why.
|
|
51
|
+
*/
|
|
9
52
|
export interface PermissionRuleStore {
|
|
10
53
|
list(): Promise<StoredAllowRules>;
|
|
54
|
+
/** Declared durability; an undeclared backend reads fail-closed as `"process-local"`. */
|
|
11
55
|
readonly durability?: StoreDurability;
|
|
56
|
+
/** Declared serialization fidelity, same doctrine as the other store families. */
|
|
12
57
|
readonly fidelity?: StoreFidelity;
|
|
13
58
|
}
|
|
59
|
+
/** Resolves a store for one verified principal. `undefined` ⇒ a store that reports zero rules. */
|
|
14
60
|
export interface PermissionRuleStoreProvider {
|
|
15
61
|
forPrincipal(principal: string | undefined): PermissionRuleStore;
|
|
16
62
|
}
|
|
63
|
+
/** The outcome of one accepted write. */
|
|
17
64
|
export interface PutResult {
|
|
18
65
|
rev: number;
|
|
19
66
|
}
|
|
67
|
+
/** Authorization accompanying an add: the redemption that produced it. Carrying the record id makes the
|
|
68
|
+
* add's logical operation identity checkable at the backend, not just at the caller. */
|
|
20
69
|
export interface RedemptionAuthorization {
|
|
21
70
|
recordId: string;
|
|
22
71
|
principal: string;
|
|
23
72
|
}
|
|
73
|
+
/** The add half of the write union: one redeemed approval becoming one dot on one (rule, scope). */
|
|
24
74
|
export interface RuleAddDelta {
|
|
25
75
|
kind: "redemption-add";
|
|
26
76
|
rule: string;
|
|
@@ -31,12 +81,25 @@ export interface RuleAddDelta {
|
|
|
31
81
|
add: RuleAdd;
|
|
32
82
|
redemption: RedemptionAuthorization;
|
|
33
83
|
}
|
|
84
|
+
/** The delete half: appending one tombstone, and nothing else. */
|
|
34
85
|
export interface RuleDeleteDelta {
|
|
35
86
|
kind: "tighten-delete";
|
|
36
87
|
tombstone: RuleTombstone;
|
|
37
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* What a write may say. Authorization discriminates on the DELTA SHAPE, not on a full snapshot: only the
|
|
91
|
+
* add arm can introduce a dot, and the delete arm carries a tombstone and no adds. A backend additionally
|
|
92
|
+
* REFUSES at runtime any delete that would introduce a new add dot — structure and runtime check together,
|
|
93
|
+
* so "pick the delete arm and smuggle an add" is neither expressible nor accepted.
|
|
94
|
+
*/
|
|
38
95
|
export type RuleWriteDelta = RuleAddDelta | RuleDeleteDelta;
|
|
96
|
+
/**
|
|
97
|
+
* The core-private write face. Deliberately absent from the package's public exports: a host cannot hold
|
|
98
|
+
* one, so no API-level path to the store bypasses the consent protocol.
|
|
99
|
+
*/
|
|
39
100
|
export interface PermissionRuleWriter {
|
|
101
|
+
/** Mint the next dot for this replica. Counters need only be unique and monotonic, so a dot minted for
|
|
102
|
+
* an operation that then fails is simply never used. */
|
|
40
103
|
nextDot(): Promise<RuleDot>;
|
|
41
104
|
apply(delta: RuleWriteDelta, opts: {
|
|
42
105
|
expectedRev: number;
|
|
@@ -45,28 +108,75 @@ export interface PermissionRuleWriter {
|
|
|
45
108
|
rev: number;
|
|
46
109
|
}>;
|
|
47
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* The internal handle a writable backend hangs its write face on. Not exported from the package index —
|
|
113
|
+
* that omission IS the boundary described in the module doc.
|
|
114
|
+
*/
|
|
48
115
|
export declare const PERMISSION_RULE_WRITER = "__semaPermissionRuleWriter";
|
|
116
|
+
/** A store that also carries the core-private write face. */
|
|
49
117
|
export interface WritablePermissionRuleStore extends PermissionRuleStore {
|
|
50
118
|
readonly [PERMISSION_RULE_WRITER]: PermissionRuleWriter;
|
|
51
119
|
}
|
|
120
|
+
/** The writer of a store, or `undefined` when the backend is read-only from the engine's side. */
|
|
52
121
|
export declare function writerOf(store: PermissionRuleStore): PermissionRuleWriter | undefined;
|
|
122
|
+
/** Do two scopes name the same place? */
|
|
53
123
|
export declare function sameScope(a: RuleScope, b: RuleScope): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Apply tombstones to a raw persisted set: an add survives iff its dot appears in no tombstone for the
|
|
126
|
+
* same (rule, scope). The criterion is dot IDENTITY — single dots across replicas carry no order to
|
|
127
|
+
* compare — and an add the deleting replica never observed survives (add-wins), because behind every add
|
|
128
|
+
* there is one real human approval.
|
|
129
|
+
*/
|
|
54
130
|
export declare function applyTombstones(rules: readonly PersistedAllowRule[], tombstones: readonly RuleTombstone[]): PersistedAllowRule[];
|
|
131
|
+
/** Fold one delta into a raw rule set, returning the new set. Pure — the backends share it so the file and
|
|
132
|
+
* in-memory forms cannot drift in what a delta MEANS. */
|
|
55
133
|
export declare function foldDelta(rules: readonly PersistedAllowRule[], delta: RuleAddDelta): PersistedAllowRule[];
|
|
134
|
+
/** Every add dot present in a rule set. */
|
|
56
135
|
export declare function addDotsOf(rules: readonly PersistedAllowRule[]): RuleDot[];
|
|
136
|
+
/**
|
|
137
|
+
* The runtime half of the delete-arm authorization, shared by every backend so the two cannot drift on
|
|
138
|
+
* what a delta MEANS.
|
|
139
|
+
*
|
|
140
|
+
* The union already makes "pick the delete arm and also add something" unspellable in TypeScript, and a
|
|
141
|
+
* union does not constrain a JavaScript caller's payload — so the check is executed, not merely intended.
|
|
142
|
+
* Every backend calls this before appending a tombstone.
|
|
143
|
+
*/
|
|
57
144
|
export declare function assertDeleteDeltaCarriesNoAdd(delta: RuleDeleteDelta): void;
|
|
145
|
+
/** Integrity fingerprint over a store's own facts. Corruption detection, not tamper-proofing. */
|
|
58
146
|
export declare function ruleStoreChecksum(payload: unknown): Promise<string>;
|
|
59
|
-
|
|
147
|
+
/**
|
|
148
|
+
* The result of a removal.
|
|
149
|
+
*
|
|
150
|
+
* `conflict` is not a member: an OCC conflict is retried internally to a terminal state, so a caller never
|
|
151
|
+
* has to write the retry loop that must not re-snapshot.
|
|
152
|
+
*/
|
|
153
|
+
export type RemoveResult =
|
|
154
|
+
/** The tombstone landed and none of the observed dots survive. `stillLive` reports whether an approval
|
|
155
|
+
* that landed DURING this call keeps the rule alive anyway (add-wins) — a real outcome with a name,
|
|
156
|
+
* not an anomaly. */
|
|
157
|
+
{
|
|
60
158
|
status: "removed";
|
|
61
159
|
rev: number;
|
|
62
160
|
stillLive: boolean;
|
|
63
|
-
}
|
|
161
|
+
}
|
|
162
|
+
/** Nothing to remove — including a repeated delete. No empty tombstone is minted. */
|
|
163
|
+
| {
|
|
64
164
|
status: "no-op";
|
|
65
165
|
rev: number;
|
|
66
|
-
}
|
|
166
|
+
}
|
|
167
|
+
/** Terminal failure, confirmed by read-back to have written NOTHING. When the read-back itself failed,
|
|
168
|
+
* `error` says so and the caller reconciles with `list()`. */
|
|
169
|
+
| {
|
|
67
170
|
status: "failed";
|
|
68
171
|
error: string;
|
|
69
172
|
};
|
|
173
|
+
/**
|
|
174
|
+
* Remove a persisted rule.
|
|
175
|
+
*
|
|
176
|
+
* Removal is the TIGHTENING direction, so it needs no approval-record ceremony: a host may narrow on a
|
|
177
|
+
* user's behalf, it may not widen. The asymmetry is the point — minting takes a human's click, revoking
|
|
178
|
+
* does not.
|
|
179
|
+
*/
|
|
70
180
|
export declare function removePersistedRule(opts: {
|
|
71
181
|
rule: string;
|
|
72
182
|
scope: RuleScope;
|
|
@@ -74,7 +184,13 @@ export declare function removePersistedRule(opts: {
|
|
|
74
184
|
provider: PermissionRuleStoreProvider;
|
|
75
185
|
}): Promise<RemoveResult>;
|
|
76
186
|
export declare function errText(err: unknown): string;
|
|
187
|
+
/** A store that always reports zero rules — what an unauthenticated principal resolves to, and the shape a
|
|
188
|
+
* failed read degrades to at the consumption site. */
|
|
77
189
|
export declare const EMPTY_RULE_STORE: PermissionRuleStore;
|
|
190
|
+
/**
|
|
191
|
+
* In-memory backend — the reference implementation of the delta semantics, and the one the tests drive.
|
|
192
|
+
* `process-local` by declaration: it makes no durability promise it cannot keep.
|
|
193
|
+
*/
|
|
78
194
|
export declare class InMemoryPermissionRuleStore implements WritablePermissionRuleStore {
|
|
79
195
|
private readonly actor;
|
|
80
196
|
readonly durability: StoreDurability;
|
|
@@ -1,17 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/127 — **参数级权限规则 DSL**(CC 2.1.201 追平批 γ)。声明式规则字符串 → {@link ToolPolicy}
|
|
3
|
+
* 编译器:`"Tool"`(裸)/ `"Tool(param:pattern)"`(参数级,`*` 通配全串锚定)。CC ground truth
|
|
4
|
+
* 行号级:解析 `Lh` :55214 · 通配 `ZMr` :55196 · 参数级 matcher `gnn` :595123 · 评估序 `G1e` :595272。
|
|
5
|
+
*
|
|
6
|
+
* 架构边界(design/127 §0,重判过的「core 不长 rule interpreter」):这是纯函数式、opt-in、零
|
|
7
|
+
* run-loop 介入的「声明式数据→ToolPolicy」工厂(`createCoarseCommandNamePolicy` 同形态先例)。
|
|
8
|
+
* core 不读设置文件、不管 source 层级合并 —— Settings-loader 把各层合并成**单一规则表**后编译
|
|
9
|
+
* **一个** policy(不要按层各编译再组合:combinePolicies 的 fold 里 ask 胜 allow,跨 policy 的
|
|
10
|
+
* 显式 allow 规则会被另一 policy 的 ask 吞掉 —— codex 127 审 B3)。
|
|
11
|
+
*
|
|
12
|
+
* 🔴 与 CC 的三处有意差(design/127 r2):
|
|
13
|
+
* - CC 参数级 generic 道无 allow lane(gnn 只有 deny/ask)—— 我们同样:`allow` + 参数级 content =
|
|
14
|
+
* 无效规则;auto-allow 只来自裸工具规则。
|
|
15
|
+
* - CC 对尾缀垃圾静默降级为裸名(Lh `n !== len-1`)—— `parsePermissionRule` 保持 CC parity,但
|
|
16
|
+
* **工厂 validator strict**:降级即 invalid(fail-fast 世界观,写错的规则不能静默变宽)。
|
|
17
|
+
* - 已知主字段参数规则(如 `Bash(command:…)`)默认 **reject**:通配是 trim 后**整串 lexical**
|
|
18
|
+
* 匹配,不是 shell AST / 前缀 lane —— `Bash(command:git push*)` 匹配不了 `cd /x && git push`,
|
|
19
|
+
* 「以为挡住了」比没挡更危险(codex 127 审 M2)。`primaryFieldGeneric:"allow-lexical"` 显式解锁。
|
|
20
|
+
*/
|
|
1
21
|
import type { NamedToolPolicy } from "./tool-policy.js";
|
|
22
|
+
/** [K-PLATFORM-SWEEP] MINOR#11: Bash's REAL non-primary arg names, accepted as generic param rules
|
|
23
|
+
* (`Bash(timeout:...)`). Exported SOLELY so a lockstep test can assert it against the live Bash tool
|
|
24
|
+
* schema — a schema param added without updating this set would compile to silently-never-matching
|
|
25
|
+
* rules (the exact drift class the Opus 复审 m note warned about). */
|
|
2
26
|
export declare const BASH_GENERIC_PARAMS: ReadonlySet<string>;
|
|
3
27
|
export interface PermissionRule {
|
|
28
|
+
/** CC 语法:`"Tool"` 或 `"Tool(param:pattern)"`。`Tool()`/`Tool(*)` 归一为裸规则;括号可 `\(`/`\)` 转义。 */
|
|
4
29
|
rule: string;
|
|
5
30
|
behavior: "deny" | "ask" | "allow";
|
|
31
|
+
/** Provenance(codex 127 审 M7):进 deny/ask 的 message 供审计(e.g. `"policySettings"`)。层级
|
|
32
|
+
* 优先级/tighten-only 语义在 Settings-loader,不在这里。 */
|
|
6
33
|
source?: string;
|
|
7
34
|
}
|
|
35
|
+
/** Parse result — CC `Lh` parity (INCLUDING the silent bare-name downgrade on malformed parens; the
|
|
36
|
+
* factory validator is strict on top of this, see module doc). */
|
|
8
37
|
export interface ParsedPermissionRule {
|
|
9
38
|
toolName: string;
|
|
10
39
|
ruleContent?: string;
|
|
11
40
|
}
|
|
12
41
|
export interface PermissionRuleIssue {
|
|
13
42
|
rule: string;
|
|
14
|
-
|
|
43
|
+
/** `invalid.*` = 语法/语义错;`unsupported.*` = CC 合法但 v1 不支持的 lane(codex 127 审 B5:独立
|
|
44
|
+
* 分类,绝不静默 no-op —— `Bash(npm run:*)` 被当 generic 参数规则接受后永不匹配是最危险的失败形态)。 */
|
|
45
|
+
code: "invalid.empty_tool" | "invalid.paren" | "invalid.param_split" | "invalid.allow_param_rule" | "invalid.primary_field" | "invalid.cap_exceeded" | "unsupported.bash_prefix"
|
|
46
|
+
/** design/179 D7: a Bash prefix rule under `bashPrefixLane:"rules-store"` — reported so a migration
|
|
47
|
+
* report can tell "route this through the rule store" apart from "this is a mistake". */
|
|
48
|
+
| "unsupported.bash_prefix_rules_store" | "unsupported.file_glob" | "unsupported.mcp_paren"
|
|
49
|
+
/** HRD-PRM-7: a param-level rule naming a parameter the target tool does not carry. Additive member —
|
|
50
|
+
* the lane that used to compile silently and never match (see {@link FILE_TOOL_PARAMS}). */
|
|
51
|
+
| "unsupported.unknown_param";
|
|
15
52
|
message: string;
|
|
16
53
|
}
|
|
17
54
|
export interface PermissionRuleCaps {
|
|
@@ -19,18 +56,67 @@ export interface PermissionRuleCaps {
|
|
|
19
56
|
maxRuleLength: number;
|
|
20
57
|
maxPatternLength: number;
|
|
21
58
|
maxStars: number;
|
|
59
|
+
/** Scalar arg values longer than this are NOT matched textually — the rule **fail-closes** to its
|
|
60
|
+
* lane (a deny rule targeting an oversized value denies; an ask rule asks). 租户规则 × 模型巨串
|
|
61
|
+
* 的热路径成本上界(codex 127 审 M6)。 */
|
|
22
62
|
maxScalarValueChars: number;
|
|
23
63
|
}
|
|
24
64
|
export interface PermissionRulePolicyOptions {
|
|
65
|
+
/** Invalid/unsupported rules: `"throw"`(default — 部署作者写错要立刻知道)aggregates ALL issues
|
|
66
|
+
* into one error; `"skip"` drops them (pair with {@link validatePermissionRules} for a report, and/or
|
|
67
|
+
* supply {@link onIssue}). Exception(codex 实现审 M3):`invalid.cap_exceeded` on the WHOLE rule set
|
|
68
|
+
* (maxRules) throws EVEN under `"skip"` — skipping it would compile an EMPTY table and fail-open. */
|
|
25
69
|
onInvalidRule?: "throw" | "skip";
|
|
70
|
+
/** Called once per dropped rule under `"skip"` (audit surface — silent drops are how a deployment
|
|
71
|
+
* discovers, months later, that its deny never existed). Default: one aggregated `console.warn`. */
|
|
26
72
|
onIssue?: (issue: PermissionRuleIssue) => void;
|
|
73
|
+
/** What the policy returns when NO rule matches. Default `"allow"` = 本 policy 无意见(组合语义)。
|
|
74
|
+
* default-closed 部署用 `"ask"`/`"deny"` —— 必须在这 INSIDE the policy(codex 127 审 B3:链尾
|
|
75
|
+
* ask policy 会在 fold 里吞掉本 policy 的显式 allow)。 */
|
|
27
76
|
defaultAction?: "allow" | "ask" | "deny";
|
|
77
|
+
/** 已知主字段参数规则(`Bash(command:…)` 等)的处置。默认 `"reject"`(整串 lexical ≠ 前缀/AST,
|
|
78
|
+
* 假安全感);`"allow-lexical"` 显式接受并按 generic 语义匹配。 */
|
|
28
79
|
primaryFieldGeneric?: "reject" | "allow-lexical";
|
|
80
|
+
/**
|
|
81
|
+
* design/179 D7 — where a Bash PREFIX rule (`Bash(npm run:*)`) belongs.
|
|
82
|
+
*
|
|
83
|
+
* This DSL is a pure function with no access to a deployment's wiring, so it cannot discover on its own
|
|
84
|
+
* that a persisted-rule store exists; the choice has to be said out loud. `"reject"` is the default and
|
|
85
|
+
* keeps this file's behavior byte-identical to what it was: a prefix rule is an `unsupported.bash_prefix`
|
|
86
|
+
* issue, because a generic parameter matcher would compile it into a rule that never matches anything.
|
|
87
|
+
* `"rules-store"` says the deployment routes that form through the persisted allow-rule lane instead —
|
|
88
|
+
* the issue is then re-coded to {@link PermissionRuleIssue.code} `unsupported.bash_prefix_rules_store`,
|
|
89
|
+
* which reads as "handled elsewhere" rather than "you wrote something wrong". Either way the rule does
|
|
90
|
+
* NOT enter this policy: the two lanes stay separate, and only the report changes.
|
|
91
|
+
*/
|
|
29
92
|
bashPrefixLane?: "reject" | "rules-store";
|
|
30
93
|
caps?: Partial<PermissionRuleCaps>;
|
|
31
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Parse one rule string — CC `Lh` :55214 parity, including its lenient downgrades (malformed parens /
|
|
97
|
+
* trailing garbage ⇒ the WHOLE string becomes the bare tool name). The strict complement lives in
|
|
98
|
+
* {@link validatePermissionRules} — use that (or the factory) to refuse the downgrades.
|
|
99
|
+
*/
|
|
32
100
|
export declare function parsePermissionRule(rule: string): ParsedPermissionRule;
|
|
101
|
+
/**
|
|
102
|
+
* Linear-time `*` glob match (design/127 M6: NOT a RegExp — patterns may come from tenant-supplied
|
|
103
|
+
* Settings layers; the classic two-pointer walk has zero ReDoS surface and the same semantics as CC's
|
|
104
|
+
* anchored `^…$`+dotAll construction: every non-`*` char is literal, `*` spans anything incl. newlines).
|
|
105
|
+
*/
|
|
33
106
|
export declare function wildcardMatch(pattern: string, value: string): boolean;
|
|
107
|
+
/** Exported for the lockstep guard only (see {@link FILE_TOOL_PARAMS}) — not part of the rule DSL. */
|
|
34
108
|
export declare const fileToolParamVocabulary: (canonicalTool: string) => ReadonlySet<string> | undefined;
|
|
109
|
+
/** Dry-run 校验/迁移报告(codex 127 审 B5):不 throw,返回全部 issues(含 `unsupported.*` 分类,
|
|
110
|
+
* 供从 CC settings 迁移的部署逐条对照)。 */
|
|
35
111
|
export declare function validatePermissionRules(rules: PermissionRule[], opts?: Pick<PermissionRulePolicyOptions, "primaryFieldGeneric" | "caps" | "bashPrefixLane">): PermissionRuleIssue[];
|
|
112
|
+
/**
|
|
113
|
+
* Compile declarative permission rules into ONE {@link ToolPolicy} (design/127). Evaluation order
|
|
114
|
+
* inside the policy (CC `G1e` :595272 isomorph): bare deny → param deny → bare ask → param ask →
|
|
115
|
+
* bare allow → `defaultAction`. `check()` is idempotent and side-effect-free (combinePolicies 契约);
|
|
116
|
+
* all parsing/validation happens HERE, the hot path never re-parses.
|
|
117
|
+
*
|
|
118
|
+
* ⚠️ Composition note (codex 127 审 B3): an `allow` from this policy is "no objection", NOT a
|
|
119
|
+
* cross-policy override — another policy's ask/deny still outranks it in the combinePolicies fold.
|
|
120
|
+
* Express default-closed via `defaultAction`, never via a trailing always-ask policy.
|
|
121
|
+
*/
|
|
36
122
|
export declare function createPermissionRulePolicy(rules: PermissionRule[], opts?: PermissionRulePolicyOptions): NamedToolPolicy;
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
import type { ToolSpec } from "./types.js";
|
|
2
|
+
/** The first-party plan-review tool's name (design/80 D-B; CC `ExitPlanMode` parity). Reserved when
|
|
3
|
+
* `TaskSpec.enablePlanMode` is set. */
|
|
2
4
|
export declare const PRESENT_PLAN_TOOL_NAME = "ExitPlanMode";
|
|
5
|
+
/** design/108 — the first-party "enter plan mode" tool's name (CC `EnterPlanMode` parity). Mounted (alongside
|
|
6
|
+
* `present_plan`) when `TaskSpec.enablePlanMode` is set, so the model can self-impose read-only plan mode. */
|
|
3
7
|
export declare const ENTER_PLAN_MODE_TOOL_NAME = "EnterPlanMode";
|
|
8
|
+
/**
|
|
9
|
+
* design/108 — the first-party `enter_plan_mode` tool (CC `EnterPlanMode` parity). A THIN composition over the
|
|
10
|
+
* general `ctx.enterPlanMode()` primitive: the model calls it to self-impose read-only plan mode for the rest of
|
|
11
|
+
* THIS run. `effect:"read"` (it grants nothing — it RESTRICTS). `executionMode:"sequential"` so that in a batch
|
|
12
|
+
* like `[enter_plan_mode, edit_file]` the whole batch runs sequentially (agent-loop `hasSequentialToolCall`),
|
|
13
|
+
* making enter execute (set the flag) BEFORE the sibling edit is prepared+gated — closing the same-batch window.
|
|
14
|
+
* Exit is via `present_plan` (→ plan_review → human approve-resume), not by this tool.
|
|
15
|
+
*/
|
|
4
16
|
export declare function createEnterPlanModeTool(enterPlanMode: () => void): ToolSpec;
|
|
17
|
+
/**
|
|
18
|
+
* design/80 D-B — the first-party `present_plan` tool (CC `ExitPlanMode` parity). A THIN composition over the
|
|
19
|
+
* general `ctx.requestReview()` primitive: the model calls it with a plan; the tool returns the plan as its
|
|
20
|
+
* content (so it reaches the reviewer via the transcript — the plan is NOT stored on the gate, design/76 §9),
|
|
21
|
+
* and signals the engine to pause with a `plan_review` checkpoint at the next safe turn boundary. The tool has
|
|
22
|
+
* NO side effect (`effect:"read"`); the actual pause/mint is the engine's, gated on a wired `checkpointStore`.
|
|
23
|
+
* `requestReview` is the prepare-task closure (the same primitive `ctx.requestReview` exposes to caller tools).
|
|
24
|
+
*/
|
|
5
25
|
export declare function createPresentPlanTool(requestReview: (opts?: {
|
|
6
26
|
reason?: string;
|
|
7
27
|
}) => void): ToolSpec;
|
package/dist/core/pricing.d.ts
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost computation (1.37). core never hardcodes provider pricing — a deployment injects it via
|
|
3
|
+
* `RunnerDeps.pricing` or each `Model.cost`. All prices are **absolute per-1M-token USD**, not
|
|
4
|
+
* multipliers: each provider's adapter precomputes its discount into an absolute value
|
|
5
|
+
* (OpenAI/DeepSeek: the cache-hit price; Anthropic: base×0.1 read / ×1.25 5min-write / ×2.0 1h-write).
|
|
6
|
+
*/
|
|
7
|
+
/** Per-1M-token absolute prices (USD) for a model. */
|
|
1
8
|
export interface ModelPricing {
|
|
2
9
|
inputPer1M: number;
|
|
3
10
|
outputPer1M: number;
|
|
11
|
+
/** Cache-read (hit) absolute price per 1M. Default 0 (treated as full-price input if absent). */
|
|
4
12
|
cacheReadPer1M?: number;
|
|
13
|
+
/** Cache-write 5-min-TTL absolute price per 1M (Anthropic ~1.25× base). 0 elsewhere. */
|
|
5
14
|
cacheWritePer1M?: number;
|
|
15
|
+
/** Cache-write 1-hour-TTL absolute price per 1M (Anthropic ~2.0× base). 0 elsewhere. */
|
|
6
16
|
cacheWriteLongPer1M?: number;
|
|
7
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Unified token counts for one task/turn, **already normalized** so `totalInputTokens` INCLUDES all
|
|
20
|
+
* cache tokens (matching OTel `gen_ai.usage.input_tokens`). `cacheReadTokens`/`cacheWriteTokens`/
|
|
21
|
+
* `cacheWriteTokensLong` are mutually exclusive subsets of `totalInputTokens`.
|
|
22
|
+
*/
|
|
8
23
|
export interface TokenCounts {
|
|
9
24
|
totalInputTokens: number;
|
|
10
25
|
cacheReadTokens: number;
|
|
@@ -12,7 +27,18 @@ export interface TokenCounts {
|
|
|
12
27
|
cacheWriteTokensLong: number;
|
|
13
28
|
outputTokens: number;
|
|
14
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Cost in **integer micro-USD** (1e-6 USD) — integer to avoid float-accumulation error in billing
|
|
32
|
+
* reconcile (Stripe/AWS-style). Convergent across providers: full-price input = `totalInputTokens`
|
|
33
|
+
* minus all cache tokens; cache read/write priced at their own absolute rates; output at its rate.
|
|
34
|
+
*
|
|
35
|
+
* DeepSeek (hit price as `cacheReadPer1M`, no cache-write) and OpenAI (no 1h write) fall out by their
|
|
36
|
+
* zero token counts; Anthropic uses all fields. This fixes P2 (cached charged at full price) by
|
|
37
|
+
* pricing the cache subset separately instead of trusting the brain's possibly-overstated cost total.
|
|
38
|
+
*/
|
|
15
39
|
export declare function computeCostMicroUsd(counts: TokenCounts, pricing: ModelPricing): number;
|
|
40
|
+
/** Map a vendor `Model.cost` (already per-1M absolute) to `ModelPricing`. We don't emit 1h cache
|
|
41
|
+
* writes, so `cacheWriteLongPer1M` defaults to the 5-min write price (irrelevant while that count is 0). */
|
|
16
42
|
export declare function modelCostToPricing(cost: {
|
|
17
43
|
input?: number;
|
|
18
44
|
output?: number;
|
|
@@ -1,39 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Property-harness (design/57 §9 / design/58) — the **oracle-free** half of the trusted-oracle problem.
|
|
3
|
+
*
|
|
4
|
+
* From a **trusted contract** (supplied by the spec / leader — NEVER the worker, so it dodges BUG8: a worker
|
|
5
|
+
* can't write `assert(true)` here) this derives executable **invariants** that hold for ANY correct
|
|
6
|
+
* implementation, with **no expected values** (no oracle — dodging the "expected is LLM-computed" trap of a
|
|
7
|
+
* generated test) and **no LLM** (pure deterministic — design/56's "execute > analyze"). Run against an
|
|
8
|
+
* implementation over many generated inputs, they catch the **structural-contract** bug class deterministically
|
|
9
|
+
* at **0 false positives** (probe-13: structural 16/16 caught, FP 0/12).
|
|
10
|
+
*
|
|
11
|
+
* It is a thin **complement** to the mechanical exit gate ({@link runExecGate}), not a replacement: it provably
|
|
12
|
+
* **cannot** catch value-semantic bugs — wrong output that is still structurally valid (`abs → square`,
|
|
13
|
+
* titlecase `don't → Don'T`). Those still need a real test suite (MECH) or the L3 judge. The value is the
|
|
14
|
+
* **sound invariant library + the contract→invariant derivation** centralized here (a profile re-deriving it
|
|
15
|
+
* risks unsound invariants = false positives = the thing that makes a gate harmful).
|
|
16
|
+
*
|
|
17
|
+
* Honest limits (two independent probes converged — core probe-13 + search [52], both FP=0):
|
|
18
|
+
* - **The only false-positive risk is an UNFAITHFUL contract.** Each invariant is sound by construction, so a
|
|
19
|
+
* *correct* impl can't violate one — UNLESS the contract misdescribes the intended behavior (declaring a
|
|
20
|
+
* property the correct impl doesn't have). The contract must faithfully describe intent (it is trusted input).
|
|
21
|
+
* - **Order/positional blindness.** `permutation`/`subset`/multiset-based invariants are order-agnostic, so a
|
|
22
|
+
* wrong-order-but-same-elements result (concat `b+a`, a mis-ordered flatten) passes. That is the value-semantic
|
|
23
|
+
* class — catch it with a positional contract entry, a real test (MECH), or the judge.
|
|
24
|
+
* - **No contract ⇒ no signal.** A function with no declared contract derives zero invariants (zero coverage);
|
|
25
|
+
* the catch comes from the *contract* you declare, not from the type alone — this is not magic from signatures.
|
|
26
|
+
*
|
|
27
|
+
* Scope (design/58 §2): no type→input generation (caller supplies `genInput`), no multi-language rendering
|
|
28
|
+
* (this is the JS/TS reference; other languages render their own from {@link FunctionContract}), no
|
|
29
|
+
* non-termination detection (a sync infinite loop blocks {@link checkInvariants} — gate it with the
|
|
30
|
+
* env/exec timeout via `runExecGate`; `totalNoThrow` only catches throws).
|
|
31
|
+
*/
|
|
32
|
+
/** Sound, oracle-free invariant kinds (design/58 §1.3). Each holds for ANY correct implementation. */
|
|
1
33
|
export type InvariantKind = "permutation" | "lengthPreserving" | "subset" | "distinctOutput" | "idempotent" | "involution" | "outputPredicate" | "rangeBound" | "nonNegative" | "nonEmptyPreserving" | "concatPreserving" | "chunkMaxLen" | "lengthEq" | "roundtrip" | "totalNoThrow";
|
|
34
|
+
/**
|
|
35
|
+
* The TRUSTED contract a function is expected to satisfy — from the spec / leader, **never the worker** (BUG8).
|
|
36
|
+
* The predicate/bound fields carry trusted JS supplied by the spec author (not worker output), so the
|
|
37
|
+
* in-process model is safe for them.
|
|
38
|
+
*/
|
|
2
39
|
export interface FunctionContract {
|
|
40
|
+
/** Output is a permutation (same multiset) of the input collection — sort / shuffle / reverse / rotate. */
|
|
3
41
|
permutation?: boolean;
|
|
42
|
+
/** `|output| === |input collection|`. */
|
|
4
43
|
lengthPreserving?: boolean;
|
|
44
|
+
/** Output is a sub-multiset of the input collection — filter / take. */
|
|
5
45
|
subset?: boolean;
|
|
46
|
+
/** Output has no duplicate elements — dedupe / unique. */
|
|
6
47
|
distinctOutput?: boolean;
|
|
48
|
+
/** `f(f(x))` deep-equals `f(x)` — normalize / sort / dedupe. (Output type must equal input type.) */
|
|
7
49
|
idempotent?: boolean;
|
|
50
|
+
/** `f(f(x))` deep-equals `x` — reverse / negate. (Output type must equal input type.) */
|
|
8
51
|
involution?: boolean;
|
|
52
|
+
/** Numeric output is `>= 0` — abs / length / count. */
|
|
9
53
|
nonNegative?: boolean;
|
|
54
|
+
/** A non-empty input collection implies a non-empty output — titlecase / dedupe. */
|
|
10
55
|
nonEmptyPreserving?: boolean;
|
|
56
|
+
/** Concatenating the output groups in order deep-equals the input collection — chunk / split. */
|
|
11
57
|
concatPreserving?: boolean;
|
|
58
|
+
/** The function is an `{ encode, decode }` pair and `decode(encode(x))` deep-equals `x` — serde / base62. */
|
|
12
59
|
roundtrip?: boolean;
|
|
60
|
+
/** The function must not throw on any valid-typed input. (Non-termination is NOT covered — see file header.) */
|
|
13
61
|
totalNoThrow?: boolean;
|
|
62
|
+
/** Every output element satisfies this trusted predicate — filter-by-P. */
|
|
14
63
|
outputPredicate?: (el: any) => boolean;
|
|
64
|
+
/** Numeric output lies within `[lo, hi]` computed from the input by this trusted fn — clamp. */
|
|
15
65
|
rangeBound?: (input: any) => readonly [number, number];
|
|
66
|
+
/** Every output group has length in `(0, n]` where `n` is this trusted fn of the input — chunk. */
|
|
16
67
|
chunkMaxLen?: (input: any) => number;
|
|
68
|
+
/** `|output| === ` this trusted fn of the input — e.g. `countdown(n)` has length `n + 1`. */
|
|
17
69
|
lengthEq?: (input: any) => number;
|
|
70
|
+
/**
|
|
71
|
+
* Extract the input collection when the input WRAPS it — e.g. `(x) => x.a` for `{ a, k }`. Default: the input
|
|
72
|
+
* IS the collection. 🔴 Required for the collection invariants when the input is a wrapper object, else they
|
|
73
|
+
* compare the output against the wrapper instead of the collection (probe-13 soundness fix).
|
|
74
|
+
*/
|
|
18
75
|
inputCollection?: (input: any) => unknown[];
|
|
19
76
|
}
|
|
77
|
+
/** One derived, runnable invariant. `check(fn, input)` returns `true` iff the invariant HOLDS. */
|
|
20
78
|
export interface Invariant {
|
|
21
79
|
kind: InvariantKind;
|
|
80
|
+
/** Human-readable description (surfaced in a violation). */
|
|
22
81
|
description: string;
|
|
82
|
+
/** For `roundtrip`, `fn` is the `{ encode, decode }` pair; otherwise a unary function. A throw propagates to the runner. */
|
|
23
83
|
check: (fn: any, input: any) => boolean;
|
|
24
84
|
}
|
|
85
|
+
/** A concrete invariant violation found by {@link checkInvariants}. */
|
|
25
86
|
export interface InvariantViolation {
|
|
26
87
|
kind: InvariantKind;
|
|
27
88
|
description: string;
|
|
89
|
+
/** The input that triggered it (the first one observed). */
|
|
28
90
|
input: unknown;
|
|
91
|
+
/** A-5 fold: the violation was detected via the check THROWING on a structurally wrong return value
|
|
92
|
+
* (e.g. `.length` of undefined) rather than returning false — the impl's output doesn't even have
|
|
93
|
+
* the shape the contract implies. fn itself did NOT throw (that is `totalNoThrow`'s domain). */
|
|
29
94
|
evaluationThrew?: true;
|
|
30
95
|
}
|
|
96
|
+
/** The outcome of running invariants over generated inputs. */
|
|
31
97
|
export interface CheckResult {
|
|
98
|
+
/** True iff no invariant was violated across all trials. */
|
|
32
99
|
ok: boolean;
|
|
100
|
+
/** One entry per violated invariant (first triggering input). */
|
|
33
101
|
violations: InvariantViolation[];
|
|
102
|
+
/** How many inputs were tried. */
|
|
34
103
|
trials: number;
|
|
35
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Derive the sound, oracle-free invariants implied by a trusted {@link FunctionContract}. Pure and
|
|
107
|
+
* deterministic. The collection invariants honor `contract.inputCollection` (default: the input is the
|
|
108
|
+
* collection) so a wrapper-object input (`{ a, k }`) is handled correctly.
|
|
109
|
+
*/
|
|
36
110
|
export declare function deriveInvariants(contract: FunctionContract): Invariant[];
|
|
111
|
+
/**
|
|
112
|
+
* Run derived `invariants` against `fn` over `opts.trials` generated inputs (default 200). Returns the
|
|
113
|
+
* violated invariants (first triggering input each).
|
|
114
|
+
*
|
|
115
|
+
* 🔴 Runs `fn` **in the caller's process** (design/58 §1.2). Pass only a TRUSTED `fn`, or invoke this INSIDE
|
|
116
|
+
* the worker's sandbox (a generated test the leader drops into the env and runs via `runExecGate`, gating on
|
|
117
|
+
* exit code). **Non-termination is NOT caught here** — a sync infinite loop blocks the call; bound it with the
|
|
118
|
+
* env/exec timeout. An impl throw is detected by the self-contained `totalNoThrow` invariant (recorded ONLY
|
|
119
|
+
* when totality was contracted — soundness over recall); the runner's `catch` is just a safety net so one
|
|
120
|
+
* pathological input can't crash the whole run. Note: `fn` is invoked once per invariant per trial (twice for
|
|
121
|
+
* `idempotent`/`involution`) — pass a PURE function (the intended use); a side-effecting `fn` is amplified.
|
|
122
|
+
*/
|
|
37
123
|
export declare function checkInvariants(fn: unknown, genInput: (i: number) => unknown, invariants: Invariant[], opts?: {
|
|
38
124
|
trials?: number;
|
|
39
125
|
}): CheckResult;
|
|
@@ -1,7 +1,45 @@
|
|
|
1
1
|
import type { ProtocolNamespace } from "./protocol-table.js";
|
|
2
|
+
/** The provider's tool-name pattern is `^[a-zA-Z0-9_-]{1,64}$` — the limit applies to the ASSEMBLED name,
|
|
3
|
+
* not to its segments (design/116 W5-5, CC 2.1.187 parity `buildMcpToolName`). */
|
|
2
4
|
export declare const TOOL_NAME_MAX_CHARS = 64;
|
|
5
|
+
/** Reserved for the tool segment when budgeting the peer segment: a peer kept at the full name budget
|
|
6
|
+
* overflows the assembled name on its own (prefix + 64 + separator = 71 > 64), which is how the tool
|
|
7
|
+
* segment used to be handed a NEGATIVE budget. A tool name shorter than this is not recognizable. */
|
|
3
8
|
export declare const MINTED_TOOL_SEGMENT_MIN_CHARS = 16;
|
|
9
|
+
/**
|
|
10
|
+
* design/116 W5-5 (CC 2.1.187 parity) — normalize a peer/tool segment to the API tool-name charset by
|
|
11
|
+
* replacing every other character with `_`. CC does exactly this on BOTH segments when composing
|
|
12
|
+
* `mcp__<server>__<tool>` (services/mcp/normalization.ts `normalizeNameForMCP` + mcpStringUtils.ts
|
|
13
|
+
* `buildMcpToolName`), so a peer advertising a dotted/spaced/unicode name can't mint a name the provider
|
|
14
|
+
* rejects. NOTE: only the MODEL-FACING namespaced name is normalized — the raw remote name still goes on
|
|
15
|
+
* the wire and still keys the caller-facing maps (`allowTools`/`toolAxes`). Same known collision property
|
|
16
|
+
* as CC: two remote names that normalize to the same string collide (rare; CC accepts this).
|
|
17
|
+
*
|
|
18
|
+
* RB-83 (2026-07-25, red probe): the pattern this enforces is `{1,64}`, and only the charset half was
|
|
19
|
+
* enforced. Both other halves matter for the same reason the charset does — an over-long or empty segment
|
|
20
|
+
* produces a name the provider rejects, which 400s the WHOLE model request, the exact failure the intake
|
|
21
|
+
* gate exists to contain ("a single misconfigured server never bricks the whole task").
|
|
22
|
+
*/
|
|
4
23
|
export declare function normalizeNameSegment(name: string): string;
|
|
24
|
+
/** RB-83: force a normalized segment into `{1,max}`, keeping long names distinct via a stable digest. */
|
|
5
25
|
export declare function clampNameSegment(seg: string, max?: number): string;
|
|
26
|
+
/**
|
|
27
|
+
* The registered-name prefix for `peer` in `ns` — i.e. the set `name.startsWith(prefix)` that a consumer
|
|
28
|
+
* uses as its splice domain when swapping one peer's tools wholesale.
|
|
29
|
+
*
|
|
30
|
+
* The peer segment is kept as long as the assembled name allows (it is how an operator recognizes which
|
|
31
|
+
* peer a tool came from) and absorbs the clamp, digest-suffixed, when it does not fit.
|
|
32
|
+
*
|
|
33
|
+
* NOT `ns.makeName`: that leg REFUSES a peer carrying the separator, while this pipeline SANITIZES its
|
|
34
|
+
* inputs (the peer name is deployment/remote data, not a caller-authored identifier) and must not turn a
|
|
35
|
+
* long or exotic peer name into a materialization failure. SANITIZE, however, means the sanitized result
|
|
36
|
+
* must be sound: {@link settlePeerSegment} owes the same round-trip guarantee `makeName` gets by refusing
|
|
37
|
+
* (ticket #10), and the property test holds the two legs to the identical law.
|
|
38
|
+
*/
|
|
6
39
|
export declare function mintNamespacePrefix(ns: ProtocolNamespace, peer: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* The full registered name for `(peer, tool)` in `ns`. Always starts with {@link mintNamespacePrefix}'s
|
|
42
|
+
* answer for the same peer (the invariant ticket #9's pins hold), and never exceeds
|
|
43
|
+
* {@link TOOL_NAME_MAX_CHARS}: whatever the peer segment leaves over is the tool segment's budget.
|
|
44
|
+
*/
|
|
7
45
|
export declare function mintNamespacedToolName(ns: ProtocolNamespace, peer: string, tool: string): string;
|