vaerion 0.1.15__tar.gz

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.
Files changed (127) hide show
  1. vaerion-0.1.15/PKG-INFO +69 -0
  2. vaerion-0.1.15/README.md +48 -0
  3. vaerion-0.1.15/pyproject.toml +40 -0
  4. vaerion-0.1.15/setup.cfg +4 -0
  5. vaerion-0.1.15/vaerion/__init__.py +8 -0
  6. vaerion-0.1.15/vaerion/cli.py +50 -0
  7. vaerion-0.1.15/vaerion/engine/agents/executor.ts +227 -0
  8. vaerion-0.1.15/vaerion/engine/agents/grants.ts +73 -0
  9. vaerion-0.1.15/vaerion/engine/agents/index.ts +61 -0
  10. vaerion-0.1.15/vaerion/engine/agents/metrics.ts +125 -0
  11. vaerion-0.1.15/vaerion/engine/agents/planner.ts +248 -0
  12. vaerion-0.1.15/vaerion/engine/agents/reasoning.ts +146 -0
  13. vaerion-0.1.15/vaerion/engine/agents/research-port.ts +172 -0
  14. vaerion-0.1.15/vaerion/engine/agents/runtime.ts +503 -0
  15. vaerion-0.1.15/vaerion/engine/agents/tools.ts +365 -0
  16. vaerion-0.1.15/vaerion/engine/api/index.ts +12 -0
  17. vaerion-0.1.15/vaerion/engine/api/openapi.ts +170 -0
  18. vaerion-0.1.15/vaerion/engine/api/routes.ts +340 -0
  19. vaerion-0.1.15/vaerion/engine/api/run-registry.ts +1024 -0
  20. vaerion-0.1.15/vaerion/engine/api/server.ts +516 -0
  21. vaerion-0.1.15/vaerion/engine/broker/contracts/audit.ts +145 -0
  22. vaerion-0.1.15/vaerion/engine/broker/contracts/capability.ts +82 -0
  23. vaerion-0.1.15/vaerion/engine/broker/contracts/decision.ts +120 -0
  24. vaerion-0.1.15/vaerion/engine/broker/contracts/events.ts +92 -0
  25. vaerion-0.1.15/vaerion/engine/broker/contracts/gate.ts +52 -0
  26. vaerion-0.1.15/vaerion/engine/broker/contracts/permission-graph.ts +82 -0
  27. vaerion-0.1.15/vaerion/engine/broker/contracts/principal.ts +34 -0
  28. vaerion-0.1.15/vaerion/engine/broker/contracts/review-diff.ts +55 -0
  29. vaerion-0.1.15/vaerion/engine/broker/engine.ts +249 -0
  30. vaerion-0.1.15/vaerion/engine/broker/refusal-log.ts +222 -0
  31. vaerion-0.1.15/vaerion/engine/center/center.ts +190 -0
  32. vaerion-0.1.15/vaerion/engine/cli/account.ts +162 -0
  33. vaerion-0.1.15/vaerion/engine/cli/ai.ts +247 -0
  34. vaerion-0.1.15/vaerion/engine/cli/catalog.ts +59 -0
  35. vaerion-0.1.15/vaerion/engine/cli/commands.ts +3057 -0
  36. vaerion-0.1.15/vaerion/engine/cli/completions.ts +249 -0
  37. vaerion-0.1.15/vaerion/engine/cli/interactive.ts +114 -0
  38. vaerion-0.1.15/vaerion/engine/cli/io.ts +30 -0
  39. vaerion-0.1.15/vaerion/engine/cli/recovery.ts +246 -0
  40. vaerion-0.1.15/vaerion/engine/cli/render.ts +207 -0
  41. vaerion-0.1.15/vaerion/engine/cli/suggest.ts +56 -0
  42. vaerion-0.1.15/vaerion/engine/cli/ui.ts +1654 -0
  43. vaerion-0.1.15/vaerion/engine/cli/vae.ts +885 -0
  44. vaerion-0.1.15/vaerion/engine/cli/workspace.ts +66 -0
  45. vaerion-0.1.15/vaerion/engine/config/config.ts +564 -0
  46. vaerion-0.1.15/vaerion/engine/config/templates.ts +588 -0
  47. vaerion-0.1.15/vaerion/engine/evals/harness.ts +378 -0
  48. vaerion-0.1.15/vaerion/engine/evals/index.ts +14 -0
  49. vaerion-0.1.15/vaerion/engine/extensions/factory.ts +41 -0
  50. vaerion-0.1.15/vaerion/engine/extensions/host.ts +430 -0
  51. vaerion-0.1.15/vaerion/engine/extensions/index.ts +18 -0
  52. vaerion-0.1.15/vaerion/engine/gateway/adapters/anthropic.ts +206 -0
  53. vaerion-0.1.15/vaerion/engine/gateway/adapters/ollama.ts +102 -0
  54. vaerion-0.1.15/vaerion/engine/gateway/adapters/openai.ts +180 -0
  55. vaerion-0.1.15/vaerion/engine/gateway/adapters/sse.ts +145 -0
  56. vaerion-0.1.15/vaerion/engine/gateway/breaker.ts +146 -0
  57. vaerion-0.1.15/vaerion/engine/gateway/cassette.ts +102 -0
  58. vaerion-0.1.15/vaerion/engine/gateway/metering.ts +84 -0
  59. vaerion-0.1.15/vaerion/engine/gateway/mockbrain.ts +187 -0
  60. vaerion-0.1.15/vaerion/engine/gateway/pricing.ts +103 -0
  61. vaerion-0.1.15/vaerion/engine/gateway/secrets.ts +102 -0
  62. vaerion-0.1.15/vaerion/engine/gateway/service.ts +436 -0
  63. vaerion-0.1.15/vaerion/engine/gateway/transport.ts +77 -0
  64. vaerion-0.1.15/vaerion/engine/gateway/types.ts +196 -0
  65. vaerion-0.1.15/vaerion/engine/identity/identity.ts +231 -0
  66. vaerion-0.1.15/vaerion/engine/index.ts +96 -0
  67. vaerion-0.1.15/vaerion/engine/journal/export.ts +137 -0
  68. vaerion-0.1.15/vaerion/engine/journal/hashchain.ts +69 -0
  69. vaerion-0.1.15/vaerion/engine/journal/lock.ts +68 -0
  70. vaerion-0.1.15/vaerion/engine/journal/ls.ts +45 -0
  71. vaerion-0.1.15/vaerion/engine/journal/reader.ts +101 -0
  72. vaerion-0.1.15/vaerion/engine/journal/records.ts +139 -0
  73. vaerion-0.1.15/vaerion/engine/journal/recovery.ts +117 -0
  74. vaerion-0.1.15/vaerion/engine/journal/replay.ts +115 -0
  75. vaerion-0.1.15/vaerion/engine/journal/verify.ts +174 -0
  76. vaerion-0.1.15/vaerion/engine/journal/writer.ts +208 -0
  77. vaerion-0.1.15/vaerion/engine/kernel/canonical.ts +56 -0
  78. vaerion-0.1.15/vaerion/engine/kernel/clock.ts +69 -0
  79. vaerion-0.1.15/vaerion/engine/kernel/errors.ts +229 -0
  80. vaerion-0.1.15/vaerion/engine/kernel/hash.ts +22 -0
  81. vaerion-0.1.15/vaerion/engine/kernel/ids.ts +159 -0
  82. vaerion-0.1.15/vaerion/engine/kernel/redact.ts +64 -0
  83. vaerion-0.1.15/vaerion/engine/kernel/tar.ts +122 -0
  84. vaerion-0.1.15/vaerion/engine/mcp/server.ts +261 -0
  85. vaerion-0.1.15/vaerion/engine/package/build.ts +195 -0
  86. vaerion-0.1.15/vaerion/engine/package/format.ts +358 -0
  87. vaerion-0.1.15/vaerion/engine/package/index.ts +11 -0
  88. vaerion-0.1.15/vaerion/engine/package/lock.ts +121 -0
  89. vaerion-0.1.15/vaerion/engine/package/service.ts +218 -0
  90. vaerion-0.1.15/vaerion/engine/package/verify.ts +231 -0
  91. vaerion-0.1.15/vaerion/engine/perf/perf.ts +345 -0
  92. vaerion-0.1.15/vaerion/engine/receipts/receipt.ts +170 -0
  93. vaerion-0.1.15/vaerion/engine/repo/canonical.ts +110 -0
  94. vaerion-0.1.15/vaerion/engine/repo/ci.ts +417 -0
  95. vaerion-0.1.15/vaerion/engine/repo/constitution.ts +99 -0
  96. vaerion-0.1.15/vaerion/engine/repo/git.ts +371 -0
  97. vaerion-0.1.15/vaerion/engine/repo/index.ts +11 -0
  98. vaerion-0.1.15/vaerion/engine/repo/release.ts +362 -0
  99. vaerion-0.1.15/vaerion/engine/research/capability.ts +131 -0
  100. vaerion-0.1.15/vaerion/engine/research/citation.ts +31 -0
  101. vaerion-0.1.15/vaerion/engine/research/context.ts +202 -0
  102. vaerion-0.1.15/vaerion/engine/research/evidence.ts +121 -0
  103. vaerion-0.1.15/vaerion/engine/research/fencing.ts +135 -0
  104. vaerion-0.1.15/vaerion/engine/research/fingerprint.ts +59 -0
  105. vaerion-0.1.15/vaerion/engine/research/index.ts +20 -0
  106. vaerion-0.1.15/vaerion/engine/research/local-index.ts +243 -0
  107. vaerion-0.1.15/vaerion/engine/research/pipeline.ts +188 -0
  108. vaerion-0.1.15/vaerion/engine/research/principal.ts +53 -0
  109. vaerion-0.1.15/vaerion/engine/research/provenance.ts +85 -0
  110. vaerion-0.1.15/vaerion/engine/research/replay.ts +93 -0
  111. vaerion-0.1.15/vaerion/engine/research/scoring.ts +62 -0
  112. vaerion-0.1.15/vaerion/engine/research/verification.ts +115 -0
  113. vaerion-0.1.15/vaerion/engine/runtime/run.ts +505 -0
  114. vaerion-0.1.15/vaerion/engine/spine/bus.ts +130 -0
  115. vaerion-0.1.15/vaerion/engine/spine/envelope.ts +124 -0
  116. vaerion-0.1.15/vaerion/engine/spine/event-types.ts +82 -0
  117. vaerion-0.1.15/vaerion/engine/spine/persistence.ts +44 -0
  118. vaerion-0.1.15/vaerion/engine/spine/serialization.ts +26 -0
  119. vaerion-0.1.15/vaerion/engine/store/blob-cas.ts +93 -0
  120. vaerion-0.1.15/vaerion/engine/workflow/dag.ts +111 -0
  121. vaerion-0.1.15/vaerion/engine/workflow/engine.ts +322 -0
  122. vaerion-0.1.15/vaerion/engine/workflow/index.ts +9 -0
  123. vaerion-0.1.15/vaerion.egg-info/PKG-INFO +69 -0
  124. vaerion-0.1.15/vaerion.egg-info/SOURCES.txt +125 -0
  125. vaerion-0.1.15/vaerion.egg-info/dependency_links.txt +1 -0
  126. vaerion-0.1.15/vaerion.egg-info/entry_points.txt +2 -0
  127. vaerion-0.1.15/vaerion.egg-info/top_level.txt +1 -0
@@ -0,0 +1,69 @@
1
+ Metadata-Version: 2.4
2
+ Name: vaerion
3
+ Version: 0.1.15
4
+ Summary: Vaerion — the AI-native development engine: deterministic runtime, broker-governed autonomy, hash-chained journals, receipts, and permanent provenance. Evidence, not branding.
5
+ Author-email: Auren <auren@vaerion.dev>
6
+ License: Apache-2.0
7
+ Project-URL: Repository, https://github.com/VaerionLab/vaerion
8
+ Project-URL: Issues, https://github.com/VaerionLab/vaerion/issues
9
+ Project-URL: Changelog, https://github.com/VaerionLab/vaerion/blob/main/CHANGELOG.md
10
+ Keywords: ai,agents,determinism,audit,provenance,journal,local-first,cli
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Topic :: Software Development :: Build Tools
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+
22
+ # vaerion — PyPI distribution
23
+
24
+
25
+ ## PyPI naming strategy (decision of record, 2026-10-03)
26
+
27
+ Two Python distributions exist in this repository and they must not
28
+ collide on PyPI:
29
+
30
+ | Distribution | PyPI name | Provides | Source |
31
+ |---|---|---|---|
32
+ | CLI launcher wheel | `vaerion` | the `vae` console command | `packaging/python/` |
33
+ | SDK | `vaerion-sdk` | the `vaerion` import (Agent / VaeDaemonClient) | `sdks/python/` |
34
+
35
+ This mirrors the npm/JVM rows of record: npm `vaerion` (CLI) vs
36
+ `@vaerion/sdk`; Maven `dev.vaerion:vaerion-sdk`. The SDK import name
37
+ remains `vaerion` in both layouts. PyPI `vaerion` is **published** —
38
+ `0.1.15` (sdist + wheel), measured live on pypi.org 2026-10-17; the
39
+ `vaerion-sdk` distribution remains Founder-gated.
40
+
41
+ `pip install vaerion` installs the `vae` console launcher plus the packaged
42
+ engine source. Python is the delivery channel, not the substrate: the
43
+ launcher resolves the Bun runtime (ADR-0018) and `exec`s the engine's own
44
+ `main()` — identical exit codes and streaming behavior to every other
45
+ channel. A missing Bun runtime produces a taught error (E1600, exit 2)
46
+ with the exact install command for the detected OS, never a traceback.
47
+
48
+ ```sh
49
+ pip install vaerion
50
+ vae --help
51
+ ```
52
+
53
+ ## Build the publishable wheel
54
+
55
+ ```sh
56
+ sh packaging/python/make-package.sh
57
+ # -> dist/python/vaerion-<version>-py3-none-any.whl (+ sdist)
58
+ ```
59
+
60
+ The wheel build is the input to the publication flow. PyPI `vaerion` is
61
+ **published** (0.1.15, live); rebuilding locally reproduces the same
62
+ package for offline verification.
63
+ Offline verification without any registry:
64
+
65
+ ```sh
66
+ python3 -m venv /tmp/vaerion-venv
67
+ /tmp/vaerion-venv/bin/pip install --no-deps dist/python/vaerion-<version>-py3-none-any.whl
68
+ /tmp/vaerion-venv/bin/vae --version
69
+ ```
@@ -0,0 +1,48 @@
1
+ # vaerion — PyPI distribution
2
+
3
+
4
+ ## PyPI naming strategy (decision of record, 2026-10-03)
5
+
6
+ Two Python distributions exist in this repository and they must not
7
+ collide on PyPI:
8
+
9
+ | Distribution | PyPI name | Provides | Source |
10
+ |---|---|---|---|
11
+ | CLI launcher wheel | `vaerion` | the `vae` console command | `packaging/python/` |
12
+ | SDK | `vaerion-sdk` | the `vaerion` import (Agent / VaeDaemonClient) | `sdks/python/` |
13
+
14
+ This mirrors the npm/JVM rows of record: npm `vaerion` (CLI) vs
15
+ `@vaerion/sdk`; Maven `dev.vaerion:vaerion-sdk`. The SDK import name
16
+ remains `vaerion` in both layouts. PyPI `vaerion` is **published** —
17
+ `0.1.15` (sdist + wheel), measured live on pypi.org 2026-10-17; the
18
+ `vaerion-sdk` distribution remains Founder-gated.
19
+
20
+ `pip install vaerion` installs the `vae` console launcher plus the packaged
21
+ engine source. Python is the delivery channel, not the substrate: the
22
+ launcher resolves the Bun runtime (ADR-0018) and `exec`s the engine's own
23
+ `main()` — identical exit codes and streaming behavior to every other
24
+ channel. A missing Bun runtime produces a taught error (E1600, exit 2)
25
+ with the exact install command for the detected OS, never a traceback.
26
+
27
+ ```sh
28
+ pip install vaerion
29
+ vae --help
30
+ ```
31
+
32
+ ## Build the publishable wheel
33
+
34
+ ```sh
35
+ sh packaging/python/make-package.sh
36
+ # -> dist/python/vaerion-<version>-py3-none-any.whl (+ sdist)
37
+ ```
38
+
39
+ The wheel build is the input to the publication flow. PyPI `vaerion` is
40
+ **published** (0.1.15, live); rebuilding locally reproduces the same
41
+ package for offline verification.
42
+ Offline verification without any registry:
43
+
44
+ ```sh
45
+ python3 -m venv /tmp/vaerion-venv
46
+ /tmp/vaerion-venv/bin/pip install --no-deps dist/python/vaerion-<version>-py3-none-any.whl
47
+ /tmp/vaerion-venv/bin/vae --version
48
+ ```
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "vaerion"
7
+ version = "0.1.15"
8
+ description = "Vaerion — the AI-native development engine: deterministic runtime, broker-governed autonomy, hash-chained journals, receipts, and permanent provenance. Evidence, not branding."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "Apache-2.0" }
12
+ authors = [{ name = "Auren", email = "auren@vaerion.dev" }]
13
+ keywords = ["ai", "agents", "determinism", "audit", "provenance", "journal", "local-first", "cli"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Environment :: Console",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: Apache Software License",
19
+ "Operating System :: MacOS",
20
+ "Operating System :: POSIX :: Linux",
21
+ "Programming Language :: Python :: 3",
22
+ "Topic :: Software Development :: Build Tools",
23
+ ]
24
+
25
+ [project.urls]
26
+ # Identity of record: LEGAL.md §1. The repository is public; the remaining
27
+ # URLs land with the Founder's publication step (risk-ledger F-5).
28
+ Repository = "https://github.com/VaerionLab/vaerion"
29
+ Issues = "https://github.com/VaerionLab/vaerion/issues"
30
+ Changelog = "https://github.com/VaerionLab/vaerion/blob/main/CHANGELOG.md"
31
+
32
+ [project.scripts]
33
+ vae = "vaerion.cli:main"
34
+
35
+ [tool.setuptools]
36
+ packages = ["vaerion"]
37
+ include-package-data = true
38
+
39
+ [tool.setuptools.package-data]
40
+ vaerion = ["engine/**/*.ts", "engine/**/*.json", "engine/**/*.md"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,8 @@
1
+ """Vaerion — the AI-native development engine (PyPI delivery channel).
2
+
3
+ Python is the delivery channel, not the substrate: the engine is
4
+ TypeScript executed by the Bun runtime (ADR-0018). This package installs
5
+ the `vae` console launcher and the packaged engine source.
6
+ """
7
+
8
+ __version__ = "0.1.15"
@@ -0,0 +1,50 @@
1
+ """`vae` console launcher — resolves Bun, then hands argv to the engine.
2
+
3
+ Design laws:
4
+ - One entrypoint: the packaged engine's own main() (same exit codes as
5
+ every other distribution channel).
6
+ - Educated errors: a missing Bun runtime is a taught error (exit 2),
7
+ never a traceback.
8
+ - exec, not wrap: os.exec* replaces this process, so streaming, signals,
9
+ and exit codes pass through unchanged.
10
+ """
11
+
12
+ import os
13
+ import shutil
14
+ import sys
15
+ from pathlib import Path
16
+
17
+ _BUN_INSTALL = {
18
+ "darwin": "brew install oven-sh/bun/bun (or: curl -fsSL https://bun.sh/install | sh)",
19
+ "linux": "curl -fsSL https://bun.sh/install | sh",
20
+ "default": "see https://bun.sh (docs/INSTALL.md lists every method)",
21
+ }
22
+
23
+
24
+ def _bun_hint() -> str:
25
+ if sys.platform == "darwin":
26
+ return _BUN_INSTALL["darwin"]
27
+ if sys.platform.startswith("linux"):
28
+ return _BUN_INSTALL["linux"]
29
+ return _BUN_INSTALL["default"]
30
+
31
+
32
+ def main() -> int:
33
+ bun = shutil.which("bun")
34
+ if bun is None:
35
+ print("E1600 vae requires the Bun runtime (>= 1.2) to execute the engine.", file=sys.stderr)
36
+ print(f"Fix: install Bun -> {_bun_hint()}", file=sys.stderr)
37
+ print("Docs: docs/INSTALL.md (all installation methods)", file=sys.stderr)
38
+ return 2
39
+
40
+ cli = Path(__file__).resolve().parent / "engine" / "cli" / "vae.ts"
41
+ if not cli.exists():
42
+ print("E1900 packaged engine source is missing — the vaerion install is incomplete.", file=sys.stderr)
43
+ print("Fix: reinstall -> pip install --force-reinstall vaerion", file=sys.stderr)
44
+ return 1
45
+
46
+ os.execvp(bun, [bun, "run", str(cli), *sys.argv[1:]])
47
+
48
+
49
+ if __name__ == "__main__": # pragma: no cover
50
+ raise SystemExit(main())
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Vaerion — the agent step executor (MS-4).
3
+ *
4
+ * One responsibility: run a single PlanStep through its constitutional path
5
+ * and return an honest outcome.
6
+ *
7
+ * model step → GatewayService (the single gate: decide → journal → act →
8
+ * meter); citation enforcement applies when the step asks
9
+ * for it and the run has prepared research context.
10
+ * tool step → ToolInvocationService (broker → journal → execute →
11
+ * receipts → replay).
12
+ * note step → ReasoningSession (persistent scratchpad, journaled).
13
+ * context step → the ResearchPort (One Context Path: declared capability →
14
+ * deterministic retrieval → evidence → citations → pack).
15
+ *
16
+ * The executor is stateless with respect to authority: gate prompts
17
+ * (GatewayGatePrompt / ToolGatePrompt) propagate — the supervisor owns the
18
+ * pause-and-resume law. Failures are RETURNED as outcomes (never swallowed),
19
+ * so the supervisor can retry or replan with the failure in the history.
20
+ */
21
+
22
+ import { VaerionError } from "../kernel/errors.ts";
23
+ import type { Clock } from "../kernel/clock.ts";
24
+ import type { Actor } from "../spine/envelope.ts";
25
+ import type { Principal } from "../broker/contracts/principal.ts";
26
+ import type { PolicyContract } from "../broker/contracts/decision.ts";
27
+ import type { InvocationResult } from "../gateway/types.ts";
28
+ import { GatewayGatePrompt } from "../gateway/service.ts";
29
+ import type { GatewayService, BudgetGuard, GatewayHost } from "../gateway/service.ts";
30
+ import { ToolGatePrompt } from "./tools.ts";
31
+ import type { ToolInvocationService, ToolHost } from "./tools.ts";
32
+ import type { ReasoningSession } from "./reasoning.ts";
33
+ import type { PlanStep, PlannerHistoryItem } from "./planner.ts";
34
+ import type { Citation } from "../research/citation.ts";
35
+
36
+ /** The research port: the One Context Path behind `context` steps. */
37
+ export interface ResearchPort {
38
+ prepare(query: string, capability: string): Promise<{ pack_fingerprint: string; citation_ids: string[]; evidence_count: number; blocks: number; dropped: number; tokens_estimated: number }>;
39
+ }
40
+
41
+ export type StepOutcome =
42
+ | {
43
+ ok: true;
44
+ kind: PlanStep["kind"];
45
+ summary: string;
46
+ /** Model-backed step accounting (present for kind === "model"). */
47
+ model?: { model: string; inputTokens: number; outputTokens: number; costMicroUsd: number; latencyMs: number; attempts: number; textHash: string | null; text: string };
48
+ /** Tool-backed step accounting (present for kind === "tool"). */
49
+ tool?: { tool: string; resultHash: string; blobRef: string | null };
50
+ /** Citations referenced by the step's output when citation-checked. */
51
+ citations?: string[];
52
+ }
53
+ | { ok: false; kind: PlanStep["kind"]; error_code: string; message: string };
54
+
55
+ export interface StepExecutorOptions {
56
+ clock: Clock;
57
+ actor: Actor;
58
+ gateway: GatewayService | null;
59
+ /** The run host for gateway invocations (RunHarness satisfies it). */
60
+ gatewayHost: GatewayHost | null;
61
+ tools: ToolInvocationService | null;
62
+ /** The run host for tool pipelines (RunHarness satisfies it). */
63
+ toolHost: ToolHost | null;
64
+ reasoning: ReasoningSession;
65
+ research: ResearchPort | null;
66
+ }
67
+
68
+ const CITATION_RE = /cit_\d{4}/g;
69
+
70
+ /** Gate prompts are NOT failures: they propagate for the supervisor's pause law. */
71
+ function isGatePrompt(err: unknown): err is GatewayGatePrompt | ToolGatePrompt {
72
+ return err instanceof GatewayGatePrompt || err instanceof ToolGatePrompt;
73
+ }
74
+
75
+ export class StepExecutor {
76
+ private readonly opts: StepExecutorOptions;
77
+ private readonly gatewayHostField: GatewayHost | null;
78
+ private readonly toolHostField: ToolHost | null;
79
+ /** Citation ids minted by context steps in THIS run (citation enforcement). */
80
+ private readonly availableCitations: string[] = [];
81
+
82
+ constructor(opts: StepExecutorOptions) {
83
+ this.opts = opts;
84
+ this.gatewayHostField = opts.gatewayHost;
85
+ this.toolHostField = opts.toolHost;
86
+ }
87
+
88
+ /** Citation enforcement input: the run's prepared citation ids. */
89
+ availableCitationIds(): readonly string[] {
90
+ return this.availableCitations;
91
+ }
92
+
93
+ async execute(
94
+ step: PlanStep,
95
+ ctx: { principal: Principal; policy: PolicyContract; goal: string; requestId: () => string; budget: () => BudgetGuard },
96
+ ): Promise<StepOutcome> {
97
+ switch (step.kind) {
98
+ case "model":
99
+ return this.executeModel(step, ctx);
100
+ case "tool":
101
+ return this.executeTool(step, ctx);
102
+ case "note":
103
+ return this.executeNote(step);
104
+ case "context":
105
+ return this.executeContext(step, ctx);
106
+ }
107
+ }
108
+
109
+ private async executeModel(
110
+ step: Extract<PlanStep, { kind: "model" }>,
111
+ ctx: { principal: Principal; policy: PolicyContract; goal: string; requestId: () => string; budget: () => BudgetGuard },
112
+ ): Promise<StepOutcome> {
113
+ if (this.opts.gateway === null) {
114
+ return { ok: false, kind: "model", error_code: "E1600", message: "no gateway bound in this process — model steps are unavailable" };
115
+ }
116
+ let result: InvocationResult;
117
+ try {
118
+ result = await this.opts.gateway.invoke(this.gatewayHostField as GatewayHost, {
119
+ request: { op: "chat", model: step.model, messages: step.messages, seed: step.seed, maxOutputTokens: step.maxOutputTokens },
120
+ principal: ctx.principal,
121
+ policy: ctx.policy,
122
+ requestId: ctx.requestId(),
123
+ intent: `agent model step for goal: ${ctx.goal}`,
124
+ budget: ctx.budget(),
125
+ });
126
+ } catch (err) {
127
+ if (isGatePrompt(err)) throw err; // human authority is not a failure
128
+ return { ok: false, kind: "model", error_code: err instanceof VaerionError ? err.code : "E1900", message: (err as Error).message };
129
+ }
130
+ // Citation enforcement (E1806): an answer step over prepared research
131
+ // content must reference at least one prepared citation id.
132
+ let citations: string[] | undefined;
133
+ if (step.requiresCitations === true) {
134
+ if (this.availableCitations.length === 0) {
135
+ return { ok: false, kind: "model", error_code: "E1806", message: "answer step requires citations but the run prepared no research context" };
136
+ }
137
+ const cited = new Set(result.text.match(CITATION_RE) ?? []);
138
+ const used = this.availableCitations.filter((c) => cited.has(c));
139
+ if (used.length === 0) {
140
+ return {
141
+ ok: false,
142
+ kind: "model",
143
+ error_code: "E1806",
144
+ message: `answer does not reference any prepared citation (${this.availableCitations.slice(0, 4).join(", ")}${this.availableCitations.length > 4 ? "…" : ""})`,
145
+ };
146
+ }
147
+ citations = used;
148
+ }
149
+ return {
150
+ ok: true,
151
+ kind: "model",
152
+ summary: result.text.slice(0, 120),
153
+ model: {
154
+ model: result.model,
155
+ inputTokens: result.usage?.inputTokens ?? 0,
156
+ outputTokens: result.usage?.outputTokens ?? 0,
157
+ costMicroUsd: result.cost?.totalMicroUsd ?? 0,
158
+ latencyMs: result.latencyMs,
159
+ attempts: result.attempts,
160
+ textHash: result.textHash,
161
+ text: result.text,
162
+ },
163
+ ...(citations !== undefined ? { citations } : {}),
164
+ };
165
+ }
166
+
167
+ private async executeTool(
168
+ step: Extract<PlanStep, { kind: "tool" }>,
169
+ ctx: { principal: Principal; policy: PolicyContract; goal: string; requestId: () => string; budget: () => BudgetGuard },
170
+ ): Promise<StepOutcome> {
171
+ if (this.opts.tools === null) {
172
+ return { ok: false, kind: "tool", error_code: "E1600", message: "no tool pipeline bound in this process — tool steps are unavailable" };
173
+ }
174
+ try {
175
+ const result = await this.opts.tools.invoke(this.toolHostField as ToolHost, {
176
+ tool: step.tool,
177
+ args: step.args,
178
+ principal: ctx.principal,
179
+ policy: ctx.policy,
180
+ requestId: ctx.requestId(),
181
+ intent: `agent tool step for goal: ${ctx.goal}`,
182
+ });
183
+ return {
184
+ ok: true,
185
+ kind: "tool",
186
+ summary: `tool ${result.tool} completed (${result.resultHash.slice(0, 12)}…)`,
187
+ tool: { tool: result.tool, resultHash: result.resultHash, blobRef: result.blobRef?.hash ?? null },
188
+ };
189
+ } catch (err) {
190
+ if (isGatePrompt(err)) throw err; // human authority is not a failure
191
+ return { ok: false, kind: "tool", error_code: err instanceof VaerionError ? err.code : "E1900", message: (err as Error).message };
192
+ }
193
+ }
194
+
195
+ private async executeNote(step: Extract<PlanStep, { kind: "note" }>): Promise<StepOutcome> {
196
+ const note = await this.opts.reasoning.note(step.text);
197
+ return { ok: true, kind: "note", summary: `note #${note.index}: ${note.text.slice(0, 80)}` };
198
+ }
199
+
200
+ private async executeContext(
201
+ step: Extract<PlanStep, { kind: "context" }>,
202
+ ctx: { principal: Principal; policy: PolicyContract; goal: string; requestId: () => string; budget: () => BudgetGuard },
203
+ ): Promise<StepOutcome> {
204
+ if (this.opts.research === null) {
205
+ return { ok: false, kind: "context", error_code: "E1600", message: "no research port bound in this process — context steps are unavailable" };
206
+ }
207
+ try {
208
+ const prepared = await this.opts.research.prepare(step.query, step.capability);
209
+ this.availableCitations.push(...prepared.citation_ids);
210
+ return {
211
+ ok: true,
212
+ kind: "context",
213
+ summary: `context ${prepared.pack_fingerprint.slice(0, 12)}… (${prepared.blocks} blocks, ${prepared.evidence_count} evidence, ${prepared.citation_ids.length} citations)`,
214
+ };
215
+ } catch (err) {
216
+ if (isGatePrompt(err)) throw err; // human authority is not a failure
217
+ return { ok: false, kind: "context", error_code: err instanceof VaerionError ? err.code : "E1900", message: (err as Error).message };
218
+ }
219
+ }
220
+ }
221
+
222
+ /** Convert an outcome into a planner history item (newest-last fold input). */
223
+ export function historyItemOf(round: number, index: number, outcome: StepOutcome): PlannerHistoryItem {
224
+ return outcome.ok
225
+ ? { round, index, kind: outcome.kind, ok: true, summary: outcome.summary }
226
+ : { round, index, kind: outcome.kind, ok: false, summary: outcome.message.slice(0, 160), error_code: outcome.error_code };
227
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Vaerion — agent permission grants (MS-4 wiring).
3
+ *
4
+ * The agent principal acts inside the permission-graph ceiling like every
5
+ * other principal. Its grants are DERIVED from human declarations only:
6
+ *
7
+ * - tool.call: one grant over every DECLARED tool scope (config.tools) —
8
+ * declaring a tool in vaerion.yaml is the human's statement that this
9
+ * tool exists; the broker policy still decides allow/deny/prompt.
10
+ * - model.invoke: the DECLARED model scopes (enabled gateway providers'
11
+ * concrete `provider/model` ceilings) that a declared policy rule admits
12
+ * for agents — the human typed both the models and the rules; nothing
13
+ * is invented here.
14
+ *
15
+ * Fail-closed: declare nothing, grant nothing. Derived grants are concrete
16
+ * scope strings that sit INSIDE the standing ceilings (graphFromConfig
17
+ * enforces coverage), so grants only ever narrow.
18
+ */
19
+
20
+ import type { VaerionConfig } from "../config/config.ts";
21
+ import type { PolicyContract } from "../broker/contracts/decision.ts";
22
+ import type { ConfigGrantInput } from "../broker/engine.ts";
23
+ import type { Principal } from "../broker/contracts/principal.ts";
24
+ import { scopeMatches } from "../broker/contracts/capability.ts";
25
+
26
+ /** Does any declared rule admit `agentKind` for `domain` over `scope`? */
27
+ function policyAdmits(policy: PolicyContract, domain: string, scope: string, agentKind: Principal["kind"]): boolean {
28
+ return policy.rules.some((rule) => {
29
+ if (rule.domain !== domain && rule.domain !== "*") return false;
30
+ if (rule.effect === "deny") return false;
31
+ if (rule.principalKinds !== "all" && !rule.principalKinds.some((k) => k === agentKind)) return false;
32
+ return scopeMatches(rule.scope, scope);
33
+ });
34
+ }
35
+
36
+ /** Derive the agent's ceiling-internal grants from config + policy. */
37
+ export function agentGrants(config: VaerionConfig, policy: PolicyContract, agent: Principal): ConfigGrantInput[] {
38
+ const grants: ConfigGrantInput[] = [];
39
+ // Tool ceilings: declared tools + declared extensions only (declared-before-used
40
+ // law; an extension is reachable as a tool, so its name is its scope).
41
+ const toolScopes = [
42
+ ...(config.tools ?? []).map((t) => t.scope ?? t.name),
43
+ ...(config.extensions ?? []).map((e) => e.name),
44
+ ];
45
+ if (toolScopes.length > 0) grants.push({ principalId: agent.id, domain: "tool.call", scopes: toolScopes });
46
+ // Model ceilings: concrete declared models admitted by declared policy.
47
+ const modelScopes: string[] = [];
48
+ for (const [provider, p] of Object.entries(config.gateway?.providers ?? {})) {
49
+ if (!p.enabled) continue;
50
+ for (const model of p.models ?? []) {
51
+ const scope = `${provider}/${model}`;
52
+ if (policyAdmits(policy, "model.invoke", scope, agent.kind)) modelScopes.push(scope);
53
+ }
54
+ }
55
+ if (modelScopes.length > 0) grants.push({ principalId: agent.id, domain: "model.invoke", scopes: modelScopes });
56
+ return grants;
57
+ }
58
+
59
+ /** The builtin scopes the R-2 host bridge exposes to extensions. */
60
+ export const BRIDGEABLE_BUILTIN_SCOPES: ReadonlyArray<string> = ["echo", "clock.read"];
61
+
62
+ /**
63
+ * Derive the EXTENSION principal's ceiling-internal grants (MS-5, ADR-0009):
64
+ * an extension may bridge only to the declared builtins, and only where a
65
+ * declared policy rule admits `extension` for that scope. Declaring an
66
+ * extension grants nothing by itself — this mirrors agentGrants.
67
+ */
68
+ export function extensionGrants(config: VaerionConfig, policy: PolicyContract): ConfigGrantInput[] {
69
+ if ((config.extensions ?? []).length === 0) return [];
70
+ const scopes = BRIDGEABLE_BUILTIN_SCOPES.filter((scope) => policyAdmits(policy, "tool.call", scope, "extension"));
71
+ if (scopes.length === 0) return [];
72
+ return (config.extensions ?? []).map((ext) => ({ principalId: `extension:${ext.name}`, domain: "tool.call", scopes: [...scopes] }));
73
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Vaerion — agents subsystem barrel (MS-4).
3
+ *
4
+ * Agent runtime (supervisor over journaled decisions), tool invocation
5
+ * pipeline, planners, reasoning sessions, metrics, and the local research
6
+ * port. Everything here is L2: it may import L0/L1/L2, never L4.
7
+ */
8
+
9
+ export type {
10
+ ToolHost,
11
+ ToolDeclaration,
12
+ ToolArgsSchema,
13
+ ToolExecutor,
14
+ ToolContext,
15
+ ToolInvokeInput,
16
+ ToolInvokeResult,
17
+ SearchHit,
18
+ SearchableIndex,
19
+ } from "./tools.ts";
20
+ export {
21
+ ToolRegistry,
22
+ ToolInvocationService,
23
+ ToolGatePrompt,
24
+ echoTool,
25
+ clockReadTool,
26
+ researchSearchTool,
27
+ } from "./tools.ts";
28
+
29
+ export type { PlanStep, Plan, Planner, PlannerInput, PlannerHistoryItem } from "./planner.ts";
30
+ export {
31
+ InlinePlanner,
32
+ ModelPlanner,
33
+ parsePlanText,
34
+ assertPlan,
35
+ type GatewayHostLike,
36
+ type ModelPlannerOptions,
37
+ type InlinePlannerOptions,
38
+ } from "./planner.ts";
39
+
40
+ export type { ReasoningNote, ReasoningFold, ReasoningState, ReasoningHost } from "./reasoning.ts";
41
+ export {
42
+ ReasoningSession,
43
+ initialReasoningState,
44
+ reasoningStateReducer,
45
+ unfoldedNotes,
46
+ foldSummary,
47
+ } from "./reasoning.ts";
48
+
49
+ export type { StepOutcome, ResearchPort } from "./executor.ts";
50
+ export { StepExecutor, historyItemOf } from "./executor.ts";
51
+
52
+ export type { AgentOutcome, AgentRunState, AgentRuntimeOptions, AgentRunInput, AgentRunResult } from "./runtime.ts";
53
+ export { AgentRuntime, initialAgentRunState, agentRunStateReducer, agentStateFromRecords } from "./runtime.ts";
54
+
55
+ export type { AgentMetrics } from "./metrics.ts";
56
+ export { agentMetricsFromRecords } from "./metrics.ts";
57
+
58
+ export type { LocalResearchPortOptions } from "./research-port.ts";
59
+ export { LocalResearchPort } from "./research-port.ts";
60
+
61
+ export { agentGrants } from "./grants.ts";