@sema-agent/core 5.20.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 +9 -0
- 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/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/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 +107 -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 +292 -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 +608 -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/mcp.d.ts +381 -0
- 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 +33 -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 +12 -11
- package/dist/core/runner/prompt-suggestions.d.ts +7 -0
- package/dist/core/runner/runtask.d.ts +304 -3
- 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-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-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/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 +16 -1
- package/dist/index.js +0 -1
- 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-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/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/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/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/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/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,17 +1,49 @@
|
|
|
1
1
|
import type { Model } from "../../internal/llm.js";
|
|
2
2
|
import { type ModelPricing } from "../pricing.js";
|
|
3
|
+
/** How a provider counts cached tokens in its reported `input`. */
|
|
3
4
|
export type CacheFamily = "input-includes-cached" | "input-excludes-cached";
|
|
5
|
+
/**
|
|
6
|
+
* Resolve the prompt-cache accounting family for a model. **Auto-inferred from `model.api`** by
|
|
7
|
+
* default (Anthropic/Bedrock report `input` EXCLUDING cached tokens; OpenAI/vLLM/Google INCLUDE them),
|
|
8
|
+
* but a deployment can **override** it via `model.params.promptCacheFamily` when `model.api` doesn't
|
|
9
|
+
* match the brain that actually serves the model — e.g. a routing brain that dispatches by `provider`
|
|
10
|
+
* while `api` is left at a default. Accepts the explicit values or the aliases `"anthropic"`/`"openai"`.
|
|
11
|
+
* (design/18: a route-by-provider setup with `api` hardcoded misjudged the family → 1090% hit rate.)
|
|
12
|
+
*/
|
|
4
13
|
export declare function cacheFamilyOf(model: Model): CacheFamily;
|
|
14
|
+
/** Total prompt tokens presented this turn, normalized so `cachedTokens` is always ⊆ the total. */
|
|
5
15
|
export declare function promptTokensOf(family: CacheFamily, u: {
|
|
6
16
|
input: number;
|
|
7
17
|
cacheRead: number;
|
|
8
18
|
cacheWrite: number;
|
|
9
19
|
}): number;
|
|
20
|
+
/**
|
|
21
|
+
* The prompt tokens that were NOT served from (or written to) the cache this turn — i.e. the quantity
|
|
22
|
+
* the Anthropic protocol calls `usage.input_tokens`, normalized across families. Derived from the
|
|
23
|
+
* normalized total so the identity `total = uncached + cacheRead + cacheWrite` holds by construction.
|
|
24
|
+
*
|
|
25
|
+
* RB-457-a: the wire faces named `inputTokens`/`promptTokens` carry THIS, not the total — a consumer
|
|
26
|
+
* computing `cacheRead / (input + cacheRead)` on a same-named protocol field otherwise double-counts
|
|
27
|
+
* the cache subset and reports `h/(1+h)` (a real 98% hit rate surfaces as 49.5%). The BILLING path
|
|
28
|
+
* still consumes the total (`promptTokensOf`) — `computeCostMicroUsd` subtracts the priced subsets
|
|
29
|
+
* itself, so handing it the uncached figure would drop the cache legs from the bill entirely.
|
|
30
|
+
*
|
|
31
|
+
* Clamped at 0: when a provider reports subsets LARGER than its own total the cache family is
|
|
32
|
+
* misdeclared (design/18), which the run loop already reports on its own face; here the identity
|
|
33
|
+
* degrades to `total ≤ uncached + cacheRead + cacheWrite` rather than going negative.
|
|
34
|
+
*/
|
|
10
35
|
export declare function uncachedInputTokensOf(family: CacheFamily, u: {
|
|
11
36
|
input: number;
|
|
12
37
|
cacheRead: number;
|
|
13
38
|
cacheWrite: number;
|
|
14
39
|
}): number;
|
|
40
|
+
/**
|
|
41
|
+
* Normalize one turn's reported usage into its `{ totalInputTokens, uncachedInputTokens, costMicroUsd }`
|
|
42
|
+
* — the authoritative cost re-priced in core from injected pricing (so cached tokens aren't charged at
|
|
43
|
+
* full price). Shared by the run loop's per-turn accounting and post-task memory consolidation
|
|
44
|
+
* (design/41) so a pricing change lives in ONE place. We emit only 5-min-TTL cache writes, so
|
|
45
|
+
* `cacheWriteTokensLong` is 0.
|
|
46
|
+
*/
|
|
15
47
|
export declare function usageCostMicroUsd(family: CacheFamily, u: {
|
|
16
48
|
input?: number;
|
|
17
49
|
output?: number;
|
package/dist/core/runtime.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
import type { AgentCoreRuntimeDeps } from "../internal/harness-types.js";
|
|
2
2
|
import type { Brain } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Build the agent-core runtime dependency object from a Brain.
|
|
5
|
+
* `completeSimple` (used by compaction/summarization) is derived from `stream`
|
|
6
|
+
* when the brain does not provide one explicitly.
|
|
7
|
+
*
|
|
8
|
+
* A supplied `brain.complete` is forwarded BY REFERENCE, never re-wrapped: the summary path's
|
|
9
|
+
* budget-escalation recovery keys on `errorKind`, so anything that rebuilt the message here would
|
|
10
|
+
* disable that recovery for every brain at once (pinned in `brain-complete-contract.test.ts`).
|
|
11
|
+
*/
|
|
3
12
|
export declare function brainToRuntime(brain: Brain): AgentCoreRuntimeDeps;
|
|
@@ -1,17 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RB-463 — host-callback isolation, one primitive.
|
|
3
|
+
*
|
|
4
|
+
* The invariant "a callback the HOST handed us must never take the engine down" was implemented by hand at
|
|
5
|
+
* ~20 sites across 10 modules (observer taps, cascade/verify observability hooks, roster eviction sinks, the
|
|
6
|
+
* retain ledger's eviction reporter, task-registry reap/quiescence/terminal notifiers, compaction observers,
|
|
7
|
+
* the workflow event sink, the tool gate's deny observers). Every one of them was a correct swallow, but the
|
|
8
|
+
* DISCLOSURE grade differed per site: the retain ledger counted its failures and offered them on a dedicated
|
|
9
|
+
* channel, while the cascade and the roster store swallowed in total silence — so a deployment whose observer
|
|
10
|
+
* is broken had no way to find out, and WHICH sites would tell it was a matter of which module it happened to
|
|
11
|
+
* touch.
|
|
12
|
+
*
|
|
13
|
+
* This module is the single implementation those sites now share. Semantics:
|
|
14
|
+
* · SWALLOW — the callback's throw never reaches the engine's control flow (unchanged at every site);
|
|
15
|
+
* · COUNT — every failure is counted per site, readable for diagnostics ({@link SafeNotifier.failuresAt});
|
|
16
|
+
* · BOUNDED DISCLOSURE — the FIRST failure of each site is offered to an optional `onError`, later ones are
|
|
17
|
+
* counted only. A hot path whose sink fails on every call therefore reports once, never floods.
|
|
18
|
+
*
|
|
19
|
+
* WIRING STATUS (RB-473, batches 1/2a/2b landed 2026-08-02): the disclosure channel is now WIRED at the
|
|
20
|
+
* owners a deployment can reach — TaskRegistry offers `notifierFailureCounts()` (read face; it is
|
|
21
|
+
* constructed before any deployment sink exists), the delegation tool routes into `opts.onObserverError`
|
|
22
|
+
* (site attached), auto-compaction / cascade / verify / roster-store take an `onNotifyError` option, the
|
|
23
|
+
* tool gate surfaces failures as `observer.notify_failed` trace events, and the workflow options + the
|
|
24
|
+
* SendMessage resume face take `onNotifyError`. Remaining unwired scopes (retain ledger `failuresAt`
|
|
25
|
+
* read-face only, observer taps, misc subagent internals) disclose via counts.
|
|
26
|
+
*
|
|
27
|
+
* State discipline: no module-level mutable state. Counters live on the notifier instance the owner created
|
|
28
|
+
* (per class instance, or per call for the run-scoped functions), so two runs — and two tests — can never see
|
|
29
|
+
* each other's counts.
|
|
30
|
+
*
|
|
31
|
+
* WHY A THUNK and not `(fn, ...args)`: almost every site reads its callback off a host-owned object
|
|
32
|
+
* (`config.onRung?.(info)`, `opts.onEvicted?.(e)`). `?.()` on a property calls it with THAT OBJECT as the
|
|
33
|
+
* receiver, so a host that passed a method using `this` works today. Handing the extracted function value to
|
|
34
|
+
* a helper would silently re-bind the receiver to `undefined` — an invisible behavior change at ~20 sites.
|
|
35
|
+
* The thunk keeps the call expression (and its `?.`) at the site, byte-for-byte what it was.
|
|
36
|
+
*
|
|
37
|
+
* Scope note (deliberate parity): a callback typed `=> void` that instead returns a REJECTING promise is not
|
|
38
|
+
* contained by {@link SafeNotifier.notify} — it is synchronous and never touches the return value, exactly
|
|
39
|
+
* like the hand-written try/catch it replaced. Sites that genuinely await their callback use
|
|
40
|
+
* {@link SafeNotifier.notifyAsync}.
|
|
41
|
+
*/
|
|
42
|
+
/** One contained failure, as offered to {@link SafeNotifierOptions.onError}. */
|
|
1
43
|
export interface SafeNotifyFailure {
|
|
44
|
+
/** The owner-chosen site name (e.g. `"cascade.onRung"`) — a stable literal, never derived from host input. */
|
|
2
45
|
readonly site: string;
|
|
46
|
+
/** The thrown value, normalized to an `Error`. */
|
|
3
47
|
readonly error: Error;
|
|
48
|
+
/** This site's cumulative failure count including this one (always 1 for a disclosed failure). */
|
|
4
49
|
readonly failures: number;
|
|
5
50
|
}
|
|
6
51
|
export interface SafeNotifierOptions {
|
|
52
|
+
/**
|
|
53
|
+
* Optional disclosure channel: called with the FIRST failure of each site (bounded — later failures of the
|
|
54
|
+
* same site are counted only). A throw from `onError` itself is swallowed: the disclosure channel is host
|
|
55
|
+
* code too, and it must not become a second fault source.
|
|
56
|
+
*/
|
|
7
57
|
readonly onError?: (failure: SafeNotifyFailure) => void;
|
|
8
58
|
}
|
|
9
59
|
export interface SafeNotifier {
|
|
60
|
+
/**
|
|
61
|
+
* Run one host-callback invocation, containing any throw. Returns `true` when it completed, `false` when it
|
|
62
|
+
* threw. The thunk normally holds the original optional call (`() => config.onRung?.(info)`), so an absent
|
|
63
|
+
* callback is a plain no-op that never touches the failure bookkeeping.
|
|
64
|
+
*/
|
|
10
65
|
notify(run: () => void, site: string): boolean;
|
|
66
|
+
/** {@link notify} for a site that AWAITS its callback — contains a rejection as well as a synchronous throw. */
|
|
11
67
|
notifyAsync(run: () => unknown, site: string): Promise<boolean>;
|
|
68
|
+
/** Total contained failures across all sites of this notifier. */
|
|
12
69
|
readonly failures: number;
|
|
70
|
+
/** Contained failures at one site (0 when that site never failed). */
|
|
13
71
|
failuresAt(site: string): number;
|
|
72
|
+
/** The most recent contained error at one site, if any. */
|
|
14
73
|
lastErrorAt(site: string): Error | undefined;
|
|
74
|
+
/** The sites that have failed at least once (diagnostics; empty on the healthy path). */
|
|
15
75
|
failedSites(): readonly string[];
|
|
16
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Create an isolation scope for host callbacks. Cheap: the failure bookkeeping is allocated lazily, so a
|
|
79
|
+
* notifier whose callbacks never throw costs one object and nothing per call beyond the `try`.
|
|
80
|
+
*/
|
|
17
81
|
export declare function createSafeNotifier(opts?: SafeNotifierOptions): SafeNotifier;
|
|
@@ -1,9 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `SAFETY_AXIS_VOCABULARY` — the PUBLISHED safety-axis vocabulary as a zero-logic, zero-runtime-dependency DATA
|
|
3
|
+
* artifact (pure string / number / boolean literal constants).
|
|
4
|
+
*
|
|
5
|
+
* **design/99 center control-plane seam (2026-06-27).** The sema-registry control plane's per-field
|
|
6
|
+
* safety-classification table lives in `@sema-agent/registry-core` and, for every safety-critical config field, cites a
|
|
7
|
+
* core axis VALUE (e.g. `effect: "write"`, `irreversibility: "always"`). That contract package **must not depend on
|
|
8
|
+
* `@sema-agent/core` (the engine) at runtime** — so it dev-imports THIS const (test-only) and runs a conformance test
|
|
9
|
+
* asserting every `coreAxis` string it ships is a legal value here, failing CI if core ever drops / renames one.
|
|
10
|
+
*
|
|
11
|
+
* Anti-drift discipline (mirrors {@link import("./safety-merge-corpus.js").SAFETY_MERGE_CONFORMANCE_CORPUS}, design/87):
|
|
12
|
+
* the arrays are pinned to the engine's safety-axis source unions; `test/safety-axis-vocab.test.ts` regression-tests
|
|
13
|
+
* them in lockstep with the engine version, and the `_AssertEqual` below fails `tsc` if `toolEffect` drifts from the
|
|
14
|
+
* {@link ToolEffect} union (either direction). The const carries NO logic and imports NO runtime value — the emitted
|
|
15
|
+
* JS is pure data, so a consumer can `JSON`-shaped-read it without pulling any engine code.
|
|
16
|
+
*/
|
|
1
17
|
export declare const SAFETY_AXIS_VOCABULARY: {
|
|
18
|
+
/** `ToolSpec.effect` — the data-flow effect class ({@link ToolEffect}, types.ts:74). */
|
|
2
19
|
readonly toolEffect: readonly ["read", "write", "idempotent"];
|
|
20
|
+
/** `ToolSpec.egress` — marks an external write (push / open PR / send a message). */
|
|
3
21
|
readonly egress: readonly [true, false];
|
|
22
|
+
/** `ToolSpec.irreversibility` — reversibility class (types.ts:128; the `toolAxes` record uses the {never,always} subset). */
|
|
4
23
|
readonly irreversibility: readonly ["never", "maybe", "always"];
|
|
24
|
+
/** `SafetyAxis` keys — which axes a gated call trips, for the escalation inbox (checkpoint-store.ts). */
|
|
5
25
|
readonly safetyAxis: readonly ["egress", "irreversible", "shell"];
|
|
26
|
+
/** `RiskDescriptor.severity` — ToolEmu-style tier (5 = most severe), the inbox triage key (checkpoint-store.ts:85). */
|
|
6
27
|
readonly severity: readonly [1, 2, 3, 4, 5];
|
|
28
|
+
/** `TaskSpec.shellGate` — deployment shell-command gate rank, `off` < `classify` < `always` (types.ts:632). */
|
|
7
29
|
readonly shellGate: readonly ["off", "classify", "always"];
|
|
30
|
+
/** `ToolPolicy` decision — per-tool adjudication; `deny` short-circuits the `deny > ask > allow` fold (tool-policy.ts). */
|
|
8
31
|
readonly permissionDecision: readonly ["allow", "ask", "deny"];
|
|
9
32
|
};
|
|
@@ -1,10 +1,47 @@
|
|
|
1
1
|
import type { SessionPermissionRules } from "./session-policy-store.js";
|
|
2
|
+
/**
|
|
3
|
+
* design/99 (sema-registry center control-plane seam, channel review R2): the PUBLISHED golden conformance corpus
|
|
4
|
+
* for the safety-domain MERGE predicate {@link loosenReasons}.
|
|
5
|
+
*
|
|
6
|
+
* THE SEAM. The center control-plane's ConfigBundle merger is a DISPATCHER: for any field it classifies
|
|
7
|
+
* safety-critical (the permissions / tool-policy domain), it MUST delegate the org-published-vs-workspace-override
|
|
8
|
+
* decision to core's {@link loosenReasons} (NOT re-implement "deny>allow" — a forked safety law is the exact
|
|
9
|
+
* "mixed = security incident" failure). Core owns the safety SEMANTICS; center owns the bundle merger that calls it.
|
|
10
|
+
*
|
|
11
|
+
* THIS CORPUS is the anti-drift anchor between the two codebases (the design/87 gold-corpus discipline):
|
|
12
|
+
* - CORE runs it as a regression test (`test/safety-merge-corpus.test.ts`) — every vector's `reasons` MUST equal
|
|
13
|
+
* `loosenReasons(prior, next)`. If core ever changes the loosen law, this test fails and the corpus updates in
|
|
14
|
+
* lockstep with the engine version, so the published contract can never silently drift from the implementation.
|
|
15
|
+
* - The CENTER imports this corpus from `@sema-agent/core` and runs it as a CONTRACT test in its merger CI: for each
|
|
16
|
+
* vector, its merger's accept/reject of a non-operator workspace override on the permissions domain MUST match
|
|
17
|
+
* `loosens` (reject iff `loosens`). That proves center's dispatcher actually routes through core's predicate.
|
|
18
|
+
*
|
|
19
|
+
* Invariant under test: a workspace override that LOOSENS an org-published safety rule (removes a deny, widens an
|
|
20
|
+
* allowlist, removes/widens a path confinement) is a tighten-only violation — `loosens === true`, and a
|
|
21
|
+
* non-operator write of it MUST be rejected. A pure tighten / no-op is `loosens === false`.
|
|
22
|
+
*/
|
|
2
23
|
export interface SafetyMergeVector {
|
|
24
|
+
/** Stable case id (appears in test output + the published contract). */
|
|
3
25
|
name: string;
|
|
26
|
+
/** What this vector proves. */
|
|
4
27
|
intent: string;
|
|
28
|
+
/** The org-published baseline (the lower, authoritative layer). */
|
|
5
29
|
prior: SessionPermissionRules;
|
|
30
|
+
/** The proposed workspace-override (the upper layer being merged down). */
|
|
6
31
|
next: SessionPermissionRules;
|
|
32
|
+
/** Whether `next` LOOSENS `prior` — true ⇒ a non-operator merge of this override MUST be rejected. */
|
|
7
33
|
loosens: boolean;
|
|
34
|
+
/** The EXACT reasons {@link loosenReasons}(prior, next) returns (compared order-insensitively). Empty iff
|
|
35
|
+
* `loosens` is false. Pinned so CORE's regression test catches a change in the loosen SEMANTICS, not just the
|
|
36
|
+
* boolean. ⚠️ CENTER CONTRACT: depend ONLY on `loosens` (reject-iff-loosens) — `reasons` is core's internal
|
|
37
|
+
* message wording, anti-drift for core; a center CI that asserts on `reasons` would break on a core reword. On
|
|
38
|
+
* ACCEPT (`loosens === false`) the resolved safety-domain value is `next` (the tightened override applied). */
|
|
8
39
|
reasons: string[];
|
|
9
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* The published vectors. Covers every loosen path in {@link loosenReasons} (deny removal, allowlist widen, allowlist
|
|
43
|
+
* removal = all-allowed, path-confinement removal, path widen, and a multi-axis loosen) plus the tighten / safe /
|
|
44
|
+
* no-op cases (adding a deny, narrowing an allowlist, narrowing-to-a-subdir, adding confinement from none, identical,
|
|
45
|
+
* empty). Extend it as the safety domain grows — both core and center re-run it.
|
|
46
|
+
*/
|
|
10
47
|
export declare const SAFETY_MERGE_CONFORMANCE_CORPUS: readonly SafetyMergeVector[];
|
package/dist/core/scheduler.d.ts
CHANGED
|
@@ -1,15 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/105 — Scheduler seam(自唤醒/自调度)。「手」腿(`ExecutionEnv`)的**跨-task** 未来意图能力:一个 run 里的模型
|
|
3
|
+
* 把「未来要做的活」(cron 排程 / 延迟唤醒)持久化交给一个**常驻 backend**(TOC = shell daemon),由它在未来重起一个
|
|
4
|
+
* **新** task。
|
|
5
|
+
*
|
|
6
|
+
* 🔴 与 {@link import("./background-shell.js").BackgroundShellCapability} 的根本区别(design/105 §3.1 D1):
|
|
7
|
+
* background-shell 的进程 ⊆ task(在每条退出路径 dispose,不跨 suspend);scheduler 的意图必须 **SURVIVE task 结束**
|
|
8
|
+
* (schedule 的全部意义就是当前 task 结束后 daemon 还能重起)——镜像反转,**绝不 dispose-on-exit**。
|
|
9
|
+
*
|
|
10
|
+
* core 薄壳裁定:core 只出接口 + 工具壳 + `hasScheduler` 门控;**持久化存储 / cron 时钟 / idle 触发 / 起新 task 全在
|
|
11
|
+
* backend(daemon)**——core 是 request-driven 不常驻,绝不假装调度器。NodeExecutionEnv 不自带 daemon(不同于
|
|
12
|
+
* background-shell 自带 spawn),而是**委托一个注入的 backend**(飞轮的 shell daemon 实现本接口)。
|
|
13
|
+
*/
|
|
1
14
|
import type { ExecutionEnv, Result } from "../internal/harness-types.js";
|
|
15
|
+
/** 一个已排未来意图的句柄。**backend-local、durable(daemon 持久化、重启存活)、对调用方不透明** —— 绝不暴露可枚举的 raw id。 */
|
|
2
16
|
export type ScheduledTaskId = string & {
|
|
3
17
|
readonly __brand: "ScheduledTaskId";
|
|
4
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* 类型化错误码(对齐 background-shell 风格)。方法 MUST NOT throw(返回 {@link Result})。
|
|
21
|
+
*/
|
|
5
22
|
export type SchedulerErrorCode = "unsupported" | "not_found" | "limit_exceeded" | "invalid_schedule" | "io";
|
|
23
|
+
/** scheduler 操作的类型化错误。`code` 给程序分类,`message` 给模型自纠。 */
|
|
6
24
|
export declare class SchedulerError extends Error {
|
|
7
25
|
readonly code: SchedulerErrorCode;
|
|
8
26
|
readonly cause?: unknown | undefined;
|
|
9
27
|
constructor(code: SchedulerErrorCode, message: string, cause?: unknown | undefined);
|
|
10
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* 🔴 **模型可控面(不可信)**:纯意图,**无任何身份字段** —— 防模型经自排 prompt 提权(design/62 同款红线:身份是
|
|
31
|
+
* Runner-held,非工具参数)。`prompt` = 未来 task 的不可信 `objective`(daemon 起 task 时经完整 prepare-task gate)。
|
|
32
|
+
*/
|
|
11
33
|
export interface ScheduledIntent {
|
|
34
|
+
/** 未来要跑的 prompt(agent 自排)。daemon 起新 task 时作 `objective`。 */
|
|
12
35
|
prompt: string;
|
|
36
|
+
/** 何时触发。`cron`=重复(受 minCronIntervalSec 约束);`at`=一次性绝对时刻;`delay`=相对延迟(一次性 self re-wake 用)。 */
|
|
13
37
|
when: {
|
|
14
38
|
kind: "cron";
|
|
15
39
|
expr: string;
|
|
@@ -20,41 +44,138 @@ export interface ScheduledIntent {
|
|
|
20
44
|
kind: "delay";
|
|
21
45
|
delaySec: number;
|
|
22
46
|
};
|
|
47
|
+
/** 可选短标签;与 `(scope, when)` 一起做 upsert 去重键(防工具重试产生重复 intent)。 */
|
|
23
48
|
label?: string;
|
|
49
|
+
/**
|
|
50
|
+
* [c209-D2] 生存期维度(durable 分层激活批 2026-07-16;缺省 `"durable"` = 既有行为,零破坏)。
|
|
51
|
+
* - `"durable"`:daemon 持久化、重启存活、跨会话继续触发——本 seam 的历史唯一语义(intent 不带本字段
|
|
52
|
+
* 即此义,老 backend 零迁移)。
|
|
53
|
+
* - `"session"`:会话级易失体(上游同名工具的缺省语义——「会话内过会儿跑一下」,不该活成永生任务)。
|
|
54
|
+
* 🔴 消费契约(daemon 半场,shell 仓实现):session intent MUST 随带 `sessionId` 的
|
|
55
|
+
* {@link SchedulerContext} 排入(工具壳保证);该会话终结(正常收束 / 超时 reap / 显式关闭)时 daemon
|
|
56
|
+
* MUST 一并 reap 本 intent——绝不让它在会话死后继续触发。不支持本维度的 backend 不会收到 session
|
|
57
|
+
* intent:工具壳按 {@link SchedulerCapability} 的 `supportsSessionLifetime` 能力位门控,不支持时对
|
|
58
|
+
* session 语义调用诚实拒绝并引导 `durable: true`——**绝不静默升级为永生任务**(本案的整个意义)。
|
|
59
|
+
*/
|
|
24
60
|
lifetime?: "durable" | "session";
|
|
61
|
+
/**
|
|
62
|
+
* [c209-D2] `when.kind === "cron"` 专用:`false` = 命中一次即删(上游 recurring:false 语义——触发一次后
|
|
63
|
+
* 等价一次性 at);缺省 `true` = 每次 cron 匹配都触发(既有行为,intent 不带本字段即此义)。
|
|
64
|
+
* 🔴 消费契约(daemon 半场,shell 仓实现):recurring:false 的 cron intent 首次触发后 daemon MUST 删除
|
|
65
|
+
* 该 intent,不再排下次。core 侧只把字段进 seam;delay/at kind 与 recurring 同给在工具层 fail-closed 拒
|
|
66
|
+
* (recurring 只属 cron),故 daemon 只会在 cron intent 上见到本字段。
|
|
67
|
+
*/
|
|
25
68
|
recurring?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* 执行形态(CC ScheduleWakeup 对齐批 2026-07-11;缺省 `"task"` = 既有行为,全向后兼容)。
|
|
71
|
+
* - `"task"`:daemon 起一个**无上下文新 task**(`prompt` 作 objective,经完整 prepare-task gate)——CronCreate 语义。
|
|
72
|
+
* - `"session-wakeup"`:daemon **续 `ctx.sessionId` 指定的同一会话**(`prompt` 作该会话下一轮输入;同上下文、
|
|
73
|
+
* 同 prompt cache)——CC ScheduleWakeup 的 /loop dynamic 语义。🔴 契约:`mode:"session-wakeup"` 的 intent
|
|
74
|
+
* MUST 随一个带 `sessionId` 的 {@link SchedulerContext} 排入(工具壳保证);daemon 触发时 MUST resume 该
|
|
75
|
+
* session 而非起新 task,且 principal 原样(不升权)。不支持续会话的 daemon MUST 拒(`invalid_schedule`),
|
|
76
|
+
* 绝不静默降级成新 task(丢上下文=静默换语义)。
|
|
77
|
+
*/
|
|
26
78
|
mode?: "task" | "session-wakeup";
|
|
27
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* 🔴 **Runner-held 可信面**(工具工厂闭包捕获,模型无法触及)。镜像 subagent 经 `ctx.principal` 继承的代码层强制
|
|
82
|
+
* (`agents/subagent.ts`)。`schedule` 的实现 MUST 把 `principal` 钉死进持久化 intent;daemon 触发时原样传
|
|
83
|
+
* `runTask({ principal })` —— **不升权、不省略**。
|
|
84
|
+
*/
|
|
28
85
|
export interface SchedulerContext {
|
|
86
|
+
/**
|
|
87
|
+
* 越权隔离键(cancel/list 只能操作同 scope 排的)。由 Runner 填,且**按被操作 intent 的 lifetime 分叉**
|
|
88
|
+
* (ruled 2026-08-03):`lifetime:"session"` 的意图用会话链(sessionId ?? principal ?? taskId ?? "default");
|
|
89
|
+
* durable 意图用跨会话稳定身份(principal ?? "default")——否则 durable job 会被钉死在排它的那个会话里,
|
|
90
|
+
* 后续会话 cancel/list 一律 `not_found`(任务照常触发却再也删不掉)。backend 侧无需分辨腿别:照旧只按
|
|
91
|
+
* 收到的 `scope` 隔离即可;**同一 daemon 上两类键共存**,一次 `list` 只回本 scope 的行(工具壳自己并两腿)。
|
|
92
|
+
* ⚠️ 部署面:本分叉之前写下的 durable 行仍带旧的会话键,一次性重铸键归 backend 半场,engine 不做迁移。
|
|
93
|
+
*/
|
|
29
94
|
scope: string;
|
|
95
|
+
/** 排程者身份;daemon 触发时原样传给 runTask(防提权)。 */
|
|
30
96
|
principal?: string;
|
|
97
|
+
/** 可选:daemon 触发新 task 时复用的 session(chat-continuity;缺省=fresh-session)。⚠️ 复用需 durable sessionStore(design/105 §3.4)。 */
|
|
31
98
|
sessionId?: string;
|
|
99
|
+
/**
|
|
100
|
+
* 可选 opaque 起-task 配置(model/policy 提示)。v1 daemon 可忽略、用部署默认模板起 task(intent.prompt + 继承的
|
|
101
|
+
* principal 已足);未来精细化时由 daemon 解释。core 不定其 schema(最薄)。**不可由模型提供**(Runner-held)。
|
|
102
|
+
*/
|
|
32
103
|
taskConfig?: unknown;
|
|
33
104
|
}
|
|
105
|
+
/** {@link SchedulerCapability.list} 的条目:足够 self-discovery + 防重复排,不含完整意图。 */
|
|
34
106
|
export interface ScheduledTaskSummary {
|
|
35
107
|
id: ScheduledTaskId;
|
|
108
|
+
/** 渲染用:cron expr / at 时刻 / delay 秒 的人读摘要。 */
|
|
36
109
|
when: string;
|
|
37
110
|
label?: string;
|
|
111
|
+
/** 下次触发的 epoch ms(cron/at 可算;daemon 提供)。 */
|
|
38
112
|
nextRunMs?: number;
|
|
113
|
+
/** 执行形态回显({@link ScheduledIntent.mode})。ScheduleWakeup 的 stop:true 靠它定位要取消的 pending
|
|
114
|
+
* wakeup(cron/task 意图不受 stop 影响——CC 206 D9 语义)。老 backend 不回 = undefined(工具壳以
|
|
115
|
+
* label 兜底过滤)。 */
|
|
39
116
|
mode?: "task" | "session-wakeup";
|
|
117
|
+
/** [c209-D2] codex B4:生命周期层级回显({@link ScheduledIntent.lifetime})——缺了它,任务创建后就再无
|
|
118
|
+
* 公开面能辨认自己是会话级还是持久级(CronCreate 的即时 details 是唯一一瞥)。老 backend 不回 =
|
|
119
|
+
* undefined(层级未知,按既有 durable 直觉读)。 */
|
|
40
120
|
lifetime?: "durable" | "session";
|
|
121
|
+
/** [c209-D2] codex B4:one-shot cron 回显({@link ScheduledIntent.recurring});undefined = 老 backend
|
|
122
|
+
* 或非 cron 意图。 */
|
|
41
123
|
recurring?: boolean;
|
|
42
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* 「手」腿的跨-task 调度能力。一个具体 `ExecutionEnv` 可选附加它(交叉类型),经 {@link hasScheduler} 检测。不支持的
|
|
127
|
+
* env(无注入 daemon backend)= `schedulerCapabilities.supported=false`,四个 scheduler 工具自动不挂(INERT)。
|
|
128
|
+
*/
|
|
43
129
|
export interface SchedulerCapability {
|
|
130
|
+
/** 显式声明能力(像 background-shell 一样不猜)。`supported:false` → 工具不挂(design/105 §3.9 TOB / 无 daemon)。 */
|
|
44
131
|
readonly schedulerCapabilities: {
|
|
45
132
|
readonly supported: boolean;
|
|
133
|
+
/** 单 scope 存量 intent 上限(防自排炸弹;超限 `limit_exceeded`)。 */
|
|
46
134
|
readonly maxScheduledPerScope: number;
|
|
135
|
+
/** delay/at 最小延迟秒(防 busy 自醒)。 */
|
|
47
136
|
readonly minDelaySec: number;
|
|
137
|
+
/** cron 解析后实际触发间隔下限秒(`* * * * *` 占 1 slot 但无限触发 → 须有下限)。 */
|
|
48
138
|
readonly minCronIntervalSec: number;
|
|
139
|
+
/** 最远排程地平线秒(fail-closed 有界,绝不无限未来)。 */
|
|
49
140
|
readonly maxScheduledHorizonSec: number;
|
|
141
|
+
/**
|
|
142
|
+
* [c209-D2] backend 是否支持 {@link ScheduledIntent.lifetime} `"session"`(intent 随排入会话终结被
|
|
143
|
+
* reap)。缺省 undefined/false = 不支持:工具壳收到 session 语义调用(CC 形 `durable` 缺省 false)时
|
|
144
|
+
* 诚实拒绝并引导 `durable: true`——**绝不静默落成永生任务**。声明 `true` 的 backend MUST 实现 session
|
|
145
|
+
* intent 的 reap 消费契约(见 {@link ScheduledIntent.lifetime} 注释)。
|
|
146
|
+
* 🔴 codex B2(TOCTOU 契约条款):本能力位 MUST 在 backend **实例生命周期内不可变**(`readonly` 快照,
|
|
147
|
+
* 不得热翻)——工具壳的门控读与 `schedule()` 是两次操作,中途翻位会让 session intent 落到不会 reap 的
|
|
148
|
+
* backend 上。防线双置:声明面不可变 + `schedule()` 实现 MUST 自行拒绝它无法履行 reap 契约的
|
|
149
|
+
* `lifetime:"session"` intent(fail-closed 兜底,不依赖工具壳的先行探测)。
|
|
150
|
+
*/
|
|
50
151
|
readonly supportsSessionLifetime?: boolean;
|
|
152
|
+
/**
|
|
153
|
+
* TB [991]②b / [997] 裁决 — 宿主是否有会兑现 `mode:"session-wakeup"` intent 的常驻唤醒腿。
|
|
154
|
+
* **opt-out 方向(与 supportsSessionLifetime 的 fail-closed 缺省相反,有意)**:session-wakeup
|
|
155
|
+
* 是既有工作语义(daemon 宿主已在兑现),缺省关断=误伤现网——缺省/undefined=支持;headless 单发
|
|
156
|
+
* 宿主(如 `-p` print 路径:零 daemon,进程终答即退)**显式声明 false** ⇒ 工具壳对 ScheduleWakeup
|
|
157
|
+
* 诚实拒绝(排入即失约=静默尸体,比拒绝更糟)。不可变纪律同 supportsSessionLifetime。
|
|
158
|
+
*/
|
|
51
159
|
readonly supportsSessionWakeup?: boolean;
|
|
52
160
|
};
|
|
161
|
+
/**
|
|
162
|
+
* 持久化一个未来意图。`intent` = 模型可控(无身份);`ctx` = Runner-held 可信上下文(principal/scope/...)。返回不透明
|
|
163
|
+
* 句柄。🔴 实现 MUST 把 `ctx.principal` 钉死进持久化 intent(daemon 触发原样传 runTask,不升权);MUST 用 cron 库
|
|
164
|
+
* 解析 `when.expr` **禁 shell-exec**(RCE 红线);MUST 持久化(durable,daemon 重启存活)。upsert:同
|
|
165
|
+
* `(scope, when, label, lifetime)` 覆盖(幂等)——**lifetime 是身份的一部分**(RB-12/server 1.215 F1 案:
|
|
166
|
+
* session 级与 durable 级、或不同会话的 session 级 job 撞 (when,label) 是正常用法,MUST NOT 互相覆盖;
|
|
167
|
+
* session 级的身份还含 sessionId)。
|
|
168
|
+
*/
|
|
53
169
|
schedule(intent: ScheduledIntent, ctx: SchedulerContext): Promise<Result<{
|
|
54
170
|
id: ScheduledTaskId;
|
|
55
171
|
}, SchedulerError>>;
|
|
172
|
+
/** 取消一个已排意图(幂等:取消不存在的是 ok no-op)。🔴 越权:`id` MUST 属本 scope;非本 scope 一律 `not_found`,不泄露存在性。 */
|
|
56
173
|
cancel(id: ScheduledTaskId, ctx: SchedulerContext): Promise<Result<void, SchedulerError>>;
|
|
174
|
+
/** 列**本 scope** 已排意图(self-discovery + 防重复排)。范围 = `ctx.scope`,非全局。 */
|
|
57
175
|
list(ctx: SchedulerContext): Promise<Result<ScheduledTaskSummary[], SchedulerError>>;
|
|
58
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* 结构 + 语义检测:`env` 是否暴露 scheduler 能力且声明 `supported:true`。挂载门控用此(对齐 `hasBackgroundShell`)。
|
|
179
|
+
*/
|
|
59
180
|
export declare function hasScheduler(env: ExecutionEnv): env is ExecutionEnv & SchedulerCapability;
|
|
60
181
|
export declare function isValidCronExpr(expr: string): boolean;
|
|
@@ -1,12 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical "local-spawn shell secret-env protection" (sema D1) — FIRST-PARTY, vendor-independent.
|
|
3
|
+
*
|
|
4
|
+
* When the engine (or a downstream host/exec adapter) spawns a local shell whose commands the MODEL chooses (no human at the keyboard), the child's
|
|
5
|
+
* inherited env MUST be fail-closed: a model-chosen `printenv DEEPSEEK_API_KEY` via the `bash` tool would
|
|
6
|
+
* otherwise exfiltrate the orchestrator's brain key / git token / DB creds (the gate authorizes WHICH tool runs,
|
|
7
|
+
* NOT isolation). The `scrub` policy drops secret-pattern keys (keeps PATH/build/locale → low breakage).
|
|
8
|
+
*
|
|
9
|
+
* This lives in `src/core/` — NOT `src/vendor/` — on purpose. It is OUR security invariant (D1 is a first-party
|
|
10
|
+
* edit, not openclaw upstream), shared by the (currently-vendored) {@link NodeExecutionEnv} AND a downstream
|
|
11
|
+
* adapter (service host adapter, [265]). Keeping the single source of the secret PATTERN here means:
|
|
12
|
+
* 1. A consumer imports it instead of mirroring a regex that would silently DRIFT when the pattern is extended.
|
|
13
|
+
* 2. The public export points at a STABLE first-party path that SURVIVES the planned de-vendoring refactor —
|
|
14
|
+
* when NodeExecutionEnv is naturalized out of `src/vendor/`, this module does not move and nothing rebinds.
|
|
15
|
+
*
|
|
16
|
+
* The `inheritEnv` THREE-STATE assembly (`"all"` opt-out / `"scrub"` default / `string[]` allowlist) is a
|
|
17
|
+
* per-adapter concern (each exec env owns how it composes its child env); only the secret PATTERN is shared.
|
|
18
|
+
*/
|
|
1
19
|
import type { RedactionConfidence, RedactionSource } from "./arg-summary.js";
|
|
20
|
+
/** Which rule classified a key as secret-shaped — the env arm's `kind` vocabulary. */
|
|
2
21
|
export type SecretEnvFindingKind = "suffix-rule" | "exact-name";
|
|
22
|
+
/** One env entry the `scrub` policy dropped: the key (the VALUE is never carried — this record is meant
|
|
23
|
+
* to be loggable), the rule that classified it, how strong that claim is, and the minting module. */
|
|
3
24
|
export interface SecretEnvFinding {
|
|
4
25
|
key: string;
|
|
5
26
|
kind: SecretEnvFindingKind;
|
|
6
27
|
confidence: RedactionConfidence;
|
|
7
28
|
source: RedactionSource;
|
|
8
29
|
}
|
|
30
|
+
/** What the two exact-name lists say about a name, before any shape rule is consulted. */
|
|
9
31
|
export type ExactEnvNameVerdict = "credential" | "exempt" | "unknown";
|
|
32
|
+
/** The exact-name arm of the classification, taking both lists as arguments. The credential list is read
|
|
33
|
+
* FIRST: an exemption can never take a name away from it, so a name landing on both lists resolves to the
|
|
34
|
+
* credential reading — the fail-closed direction (a wrongly-exempted name leaks; a wrongly-dropped one
|
|
35
|
+
* does not). Module-level export (not part of the package surface): the two real lists are disjoint, so
|
|
36
|
+
* only a controlled collision can tell this precedence from an inverted one. */
|
|
10
37
|
export declare function classifyExactEnvName(key: string, credentialNames: ReadonlySet<string>, exemptNames: ReadonlySet<string>): ExactEnvNameVerdict;
|
|
38
|
+
/** Is `key` a secret-pattern env var (one the fail-closed `scrub` policy drops before spawning a shell)? */
|
|
11
39
|
export declare function isSecretEnvKey(key: string): boolean;
|
|
40
|
+
/** Drop every secret-pattern key (see {@link isSecretEnvKey}) from an env object — the fail-closed `scrub`
|
|
41
|
+
* policy. `findings` is an OPTIONAL caller-owned collector: pass an array to learn which entries were
|
|
42
|
+
* dropped and why, read it back after the call. Omitting it leaves this function byte-for-byte what it
|
|
43
|
+
* was before the channel existed. */
|
|
12
44
|
export declare function scrubSecretEnv(env: NodeJS.ProcessEnv, findings?: SecretEnvFinding[]): NodeJS.ProcessEnv;
|
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import type { Model } from "../internal/llm.js";
|
|
2
|
+
/** Coarse price/capability tier, declared on a model via `model.params.tier`. */
|
|
2
3
|
export type ModelTier = "cheap" | "standard" | "premium";
|
|
4
|
+
/** Declarative "pick a model by capability/price" criteria (design/11 Layer 2). */
|
|
3
5
|
export interface ModelCriteria {
|
|
6
|
+
/** Required capabilities. `vision` = accepts images; `reasoning` = supports extended thinking. */
|
|
4
7
|
needs?: Array<"vision" | "reasoning">;
|
|
8
|
+
/** Minimum usable context window (`contextTokens ?? contextWindow`). */
|
|
5
9
|
minContext?: number;
|
|
10
|
+
/** Require an exact tier — read from `model.params.tier` (`"cheap" | "standard" | "premium"`). */
|
|
6
11
|
tier?: ModelTier;
|
|
12
|
+
/** Tiebreak among the matches by total `cost` ($/Mtok input+output). Default `"cheapest"`. */
|
|
7
13
|
prefer?: "cheapest" | "premium";
|
|
8
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Pick a model from a catalog by capability + price. Filters by `needs`/`minContext`/`tier`, then
|
|
17
|
+
* ranks the survivors by total list cost (`prefer: "cheapest"` default, or `"premium"` = priciest as
|
|
18
|
+
* a capability proxy). Returns `undefined` when nothing matches. The capability/price fields already
|
|
19
|
+
* live on `Model` (`input`, `reasoning`, `contextWindow`, `cost`); `tier` is opt-in via
|
|
20
|
+
* `model.params.tier`. This is the static version of cost-aware routing (RouteLLM is the dynamic,
|
|
21
|
+
* per-query north star — see design/11); compose it into `roles` via a `{ select }` RoleSpec.
|
|
22
|
+
*/
|
|
9
23
|
export declare function selectModel(models: Record<string, Model> | Model[], criteria?: ModelCriteria): Model | undefined;
|
|
24
|
+
/** Throwing variant of {@link selectModel}. */
|
|
10
25
|
export declare function selectModelOrThrow(models: Record<string, Model> | Model[], criteria?: ModelCriteria): Model;
|
|
@@ -1,9 +1,51 @@
|
|
|
1
1
|
import type { ExecutionEnv } from "../internal/harness-types.js";
|
|
2
2
|
import type { ToolPolicy } from "./tool-policy.js";
|
|
3
|
+
/**
|
|
4
|
+
* RECOMMENDED default pattern set for {@link createSensitivePathPolicy} ([871]② — additive export).
|
|
5
|
+
* NO upstream verbatim anchor exists (cc-anchors/2.1.209 carries no sensitive/dangerous file-pattern
|
|
6
|
+
* material), so this is an ENGINEERING-CONSENSUS set — each line states its tradeoff. The factory's
|
|
7
|
+
* default behavior is unchanged (no implicit default list; wiring this set is the caller's opt-in:
|
|
8
|
+
* `createSensitivePathPolicy({ patterns: RECOMMENDED_SENSITIVE_PATTERNS, … })`).
|
|
9
|
+
*
|
|
10
|
+
* Pattern semantics (must match `compilePatterns`/`matchSensitive` below — segment globs, NOT full-path
|
|
11
|
+
* globs): each pattern is a `/`-separated run of path SEGMENTS; `*` matches any run of non-slash chars
|
|
12
|
+
* within one segment and is the ONLY metacharacter (everything else, `?` included, is literal); the run
|
|
13
|
+
* may match ANYWHERE in the canonical path (so `.ssh` covers `~/.ssh/…` and any other `.ssh` directory —
|
|
14
|
+
* home-anchoring like `~/` is NOT part of the syntax, do not prefix it). A pattern that reduces to zero
|
|
15
|
+
* segments is a wiring ERROR (it would guard nothing) and throws rather than being dropped.
|
|
16
|
+
* Remember this policy guards WRITES only; reads are out of scope by design.
|
|
17
|
+
*
|
|
18
|
+
* NOT listed, deliberately (HRD-PRM-10): sema's own data root (`$AGENT_DATA_DIR ?? ~/.ai-agent`). Its
|
|
19
|
+
* `sessions/` subtree is already owned by `createTranscriptIntegrityPolicy`, which is wired ALWAYS-ON by
|
|
20
|
+
* the runner and answers `ask` — the design's deliberate verdict, since «reading transcripts is routine»
|
|
21
|
+
* and a legitimate operator write must remain clearable by judgment. A deny here would outrank that ask
|
|
22
|
+
* under the deny > ask > allow fold and silently convert it into a hard refusal for every deployment
|
|
23
|
+
* that wires this list.
|
|
24
|
+
*/
|
|
3
25
|
export declare const RECOMMENDED_SENSITIVE_PATTERNS: readonly string[];
|
|
26
|
+
/**
|
|
27
|
+
* Build a composable policy that DENIES writes (via the guarded fs tools) whose canonical target
|
|
28
|
+
* lands on a sensitive path. `patterns` are deployment-supplied (no default list is shipped — the
|
|
29
|
+
* set of escalation-vector paths is deployment-specific); an empty list is a no-op allow.
|
|
30
|
+
*
|
|
31
|
+
* `env` is the same ExecutionEnv the hands run against (inject the one you pass to the Runner), so
|
|
32
|
+
* canonicalization sees the task's real filesystem (a remote/E2B task resolves in its container).
|
|
33
|
+
* `rootPath` is the FALLBACK base a relative path resolves against (omit = paths resolve as given).
|
|
34
|
+
* RB-108: when the engine stamps a live cwd onto the request (`ToolCallRequest.cwd` — the tracked
|
|
35
|
+
* directory the shell's `cd` moves and the fs tools resolve with), THAT wins for the call's target, so
|
|
36
|
+
* the guard judges the file the tool will actually write. `rootPath` still serves every deployment that
|
|
37
|
+
* calls this policy outside a Runner.
|
|
38
|
+
*
|
|
39
|
+
* Fail-open by design: a tool with no string `path`, or a path that cannot be canonicalized, returns
|
|
40
|
+
* `allow` here — this guard adds a denial on top of the other gates, it is not the only line of
|
|
41
|
+
* defense, and it must not turn an unrelated tool call into a spurious deny. The verdict it owns is
|
|
42
|
+
* narrow and certain: "the real target IS a guarded path → deny".
|
|
43
|
+
*/
|
|
4
44
|
export declare function createSensitivePathPolicy(opts: {
|
|
5
45
|
env: ExecutionEnv;
|
|
46
|
+
/** `readonly` accepted so {@link RECOMMENDED_SENSITIVE_PATTERNS} can be passed as-is (widening, non-breaking). */
|
|
6
47
|
patterns: readonly string[];
|
|
7
48
|
rootPath?: string;
|
|
49
|
+
/** Override the guarded tool set (default: `Write`, `Edit`, `MultiEdit`-legacy → Edit, `NotebookEdit`). */
|
|
8
50
|
tools?: string[];
|
|
9
51
|
}): ToolPolicy;
|