ai-runtime-engine 1.2.0 → 2.7.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 +602 -0
- package/dist/agents/admit.d.ts +69 -0
- package/dist/agents/admit.js +129 -0
- package/dist/agents/definition.d.ts +36 -0
- package/dist/agents/definition.js +9 -0
- package/dist/agents/envelope.d.ts +53 -0
- package/dist/agents/envelope.js +68 -0
- package/dist/agents/finding.d.ts +79 -0
- package/dist/agents/finding.js +80 -0
- package/dist/agents/task.d.ts +60 -0
- package/dist/agents/task.js +32 -0
- package/dist/agents/worker.d.ts +68 -0
- package/dist/agents/worker.js +256 -0
- package/dist/capabilities/capability.d.ts +117 -0
- package/dist/capabilities/capability.js +66 -0
- package/dist/capabilities/registry.d.ts +139 -0
- package/dist/capabilities/registry.js +413 -0
- package/dist/capabilities/vocabulary.d.ts +32 -0
- package/dist/capabilities/vocabulary.js +34 -0
- package/dist/cli/cli.js +56 -4
- package/dist/cli/commands/cleanup.js +29 -27
- package/dist/cli/commands/doctor.d.ts +14 -0
- package/dist/cli/commands/doctor.js +38 -8
- package/dist/cli/commands/executions.js +34 -25
- package/dist/cli/commands/info.d.ts +1 -0
- package/dist/cli/commands/info.js +11 -9
- package/dist/cli/commands/init.js +19 -0
- package/dist/cli/commands/inspect.d.ts +40 -1
- package/dist/cli/commands/inspect.js +157 -2
- package/dist/cli/commands/mcp.d.ts +45 -0
- package/dist/cli/commands/mcp.js +148 -0
- package/dist/cli/commands/route.js +21 -0
- package/dist/cli/commands/run.d.ts +2 -0
- package/dist/cli/commands/run.js +36 -4
- package/dist/cli/commands/skills.d.ts +2 -0
- package/dist/cli/commands/skills.js +29 -7
- package/dist/cli/interactive/ansi.d.ts +41 -0
- package/dist/cli/interactive/ansi.js +43 -0
- package/dist/cli/interactive/complete.d.ts +10 -0
- package/dist/cli/interactive/complete.js +19 -0
- package/dist/cli/interactive/repl.d.ts +3 -0
- package/dist/cli/interactive/repl.js +105 -16
- package/dist/cli/interactive/session.d.ts +12 -1
- package/dist/cli/interactive/session.js +83 -5
- package/dist/cli/render.d.ts +13 -0
- package/dist/cli/render.js +18 -0
- package/dist/cli/runtimeSession.d.ts +11 -0
- package/dist/cli/runtimeSession.js +17 -0
- package/dist/config/defaults.d.ts +3 -1
- package/dist/config/defaults.js +2 -0
- package/dist/config/schema.d.ts +1 -0
- package/dist/config/schema.js +2 -2
- package/dist/context/lossVerifier.d.ts +24 -0
- package/dist/context/lossVerifier.js +45 -0
- package/dist/context/summarize.d.ts +19 -0
- package/dist/context/summarize.js +53 -0
- package/dist/core/fallback/fallback.d.ts +8 -0
- package/dist/core/fallback/fallback.js +3 -1
- package/dist/core/router/executor.d.ts +6 -1
- package/dist/core/router/executor.js +9 -2
- package/dist/core/router/normalize.d.ts +2 -0
- package/dist/core/router/request.js +2 -0
- package/dist/core/router/router.d.ts +3 -0
- package/dist/core/router/router.js +7 -0
- package/dist/executions/execution.d.ts +13 -2
- package/dist/generation/generateAdapter.d.ts +14 -0
- package/dist/generation/generateAdapter.js +38 -0
- package/dist/generation/generateSkill.d.ts +26 -0
- package/dist/generation/generateSkill.js +51 -0
- package/dist/index.d.ts +44 -5
- package/dist/index.js +26 -2
- package/dist/mcp/client.d.ts +70 -0
- package/dist/mcp/client.js +221 -0
- package/dist/mcp/manager.d.ts +151 -0
- package/dist/mcp/manager.js +493 -0
- package/dist/mcp/protocol.d.ts +216 -0
- package/dist/mcp/protocol.js +149 -0
- package/dist/mcp/toolAdapter.d.ts +44 -0
- package/dist/mcp/toolAdapter.js +94 -0
- package/dist/mcp/transport.d.ts +109 -0
- package/dist/mcp/transport.js +383 -0
- package/dist/memory/embedders/hash.d.ts +12 -0
- package/dist/memory/embedders/hash.js +31 -0
- package/dist/memory/embedders/http.d.ts +25 -0
- package/dist/memory/embedders/http.js +48 -0
- package/dist/memory/memory.d.ts +19 -2
- package/dist/memory/memory.js +75 -11
- package/dist/memory/semantic.d.ts +17 -0
- package/dist/memory/semantic.js +29 -0
- package/dist/orchestration/budget.d.ts +30 -0
- package/dist/orchestration/budget.js +40 -0
- package/dist/orchestration/executor.d.ts +39 -1
- package/dist/orchestration/executor.js +64 -4
- package/dist/orchestration/orchestrator.d.ts +29 -1
- package/dist/orchestration/orchestrator.js +89 -8
- package/dist/orchestration/plan.d.ts +15 -1
- package/dist/orchestration/plan.js +23 -4
- package/dist/orchestration/planner.d.ts +19 -1
- package/dist/orchestration/planner.js +25 -5
- package/dist/plugin/ai.d.ts +4 -0
- package/dist/plugin/ai.js +9 -0
- package/dist/providers/httpClient.d.ts +25 -1
- package/dist/providers/httpClient.js +93 -0
- package/dist/providers/httpProvider.d.ts +1 -0
- package/dist/providers/httpProvider.js +67 -1
- package/dist/providers/mock/mockProvider.d.ts +3 -0
- package/dist/providers/mock/mockProvider.js +54 -0
- package/dist/providers/mock/scenarios.d.ts +7 -0
- package/dist/providers/provider.d.ts +6 -0
- package/dist/providers/wire/anthropicWire.js +34 -0
- package/dist/providers/wire/openaiWire.js +30 -0
- package/dist/providers/wire/types.d.ts +16 -0
- package/dist/runtime/config.js +50 -6
- package/dist/runtime/intent/aiClassifier.d.ts +19 -0
- package/dist/runtime/intent/aiClassifier.js +74 -0
- package/dist/runtime/models/modelProfile.d.ts +61 -0
- package/dist/runtime/models/modelProfile.js +139 -0
- package/dist/runtime/planning/deriveCapabilities.d.ts +95 -0
- package/dist/runtime/planning/deriveCapabilities.js +146 -0
- package/dist/runtime/policy.d.ts +10 -0
- package/dist/runtime/policy.js +9 -2
- package/dist/runtime/runtime.d.ts +173 -0
- package/dist/runtime/runtime.js +723 -50
- package/dist/runtime/types.d.ts +94 -2
- package/dist/skills/manifest.d.ts +3 -0
- package/dist/skills/manifest.js +24 -0
- package/dist/skills/registry.d.ts +16 -1
- package/dist/skills/registry.js +21 -1
- package/dist/skills/skill.d.ts +6 -1
- package/dist/store/area.d.ts +15 -1
- package/dist/store/area.js +19 -8
- package/dist/store/crypto.d.ts +21 -0
- package/dist/store/crypto.js +49 -0
- package/dist/store/paths.d.ts +5 -1
- package/dist/store/paths.js +6 -0
- package/dist/store/store.d.ts +15 -3
- package/dist/store/store.js +28 -7
- package/dist/telemetry/sinks/otlp.d.ts +31 -0
- package/dist/telemetry/sinks/otlp.js +76 -0
- package/dist/tools/builtins/filesystem.js +1 -0
- package/dist/tools/builtins/git.js +1 -0
- package/dist/tools/builtins/shell.js +1 -0
- package/dist/tools/permissions.d.ts +28 -0
- package/dist/tools/permissions.js +72 -0
- package/dist/tools/registry.d.ts +18 -2
- package/dist/tools/registry.js +22 -2
- package/dist/tools/tool.d.ts +4 -0
- package/dist/types.d.ts +11 -1
- package/dist/util/flatten.d.ts +11 -0
- package/dist/util/flatten.js +18 -0
- package/dist/util/semaphore.d.ts +19 -0
- package/dist/util/semaphore.js +60 -0
- package/package.json +24 -9
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,590 @@ All notable changes to `ai-runtime` are documented here. The format follows
|
|
|
5
5
|
Versioning](https://semver.org/). Development history and rationale live in
|
|
6
6
|
[docs/DECISIONS.md](docs/DECISIONS.md) and [docs/PROGRESS.md](docs/PROGRESS.md).
|
|
7
7
|
|
|
8
|
+
## [2.7.0] — 2026-09-04
|
|
9
|
+
|
|
10
|
+
Multi-agent core. A plan step can now **delegate to an agent** — a bounded sub-task with its own plan,
|
|
11
|
+
its own narrowed catalog and permissions, its own budget, and a structured report of what it found.
|
|
12
|
+
Additive: with `runtime.agents` absent every prompt, key, observation, and rendered line is
|
|
13
|
+
byte-identical to 2.6.0.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **Agent execution as a THIRD step kind** (`skill` | `tool` | `agent`), reusing the orchestrator that
|
|
18
|
+
already exists: waves, skip-on-failed-dependency, the concurrency semaphore, and the budget gate are
|
|
19
|
+
all kind-agnostic. There is no second orchestration engine.
|
|
20
|
+
- **`runtime.agents`** — `enabled`, per-task defaults (`maxToolCalls` 25, `maxDurationMs` 120s,
|
|
21
|
+
`maxInnerCalls` 3), and operator-authored `definitions`. A definition is a **ceiling**: it can remove
|
|
22
|
+
a tool but never add one, lower a cap but never raise it, drop a permission but never grant one, and
|
|
23
|
+
add a routing exclusion but never re-admit an excluded provider. `Runtime.registerAgent` does the same
|
|
24
|
+
for a library host.
|
|
25
|
+
- **Findings** — an agent reports `{ type, claim, subject?, verdict? }` with two numbers that are never
|
|
26
|
+
conflated: `executionCoverage` (deterministic — how much of its plan ran) and `confidence`
|
|
27
|
+
(evidence-based belief). Conflict resolution weighs only `confidence`; coverage filters and breaks
|
|
28
|
+
ties. Evidence entries carry the validation checks that back them.
|
|
29
|
+
- **Budget reservations** — an agent step reserves model calls in the pre-flight estimate and in the
|
|
30
|
+
executor's wave gate, through one shared per-step cost rule. A plan whose agents cannot fit refuses to
|
|
31
|
+
start with a truthful estimate instead of overrunning mid-run.
|
|
32
|
+
- **Envelope disclosure at the approval gate** — an agent step's plan line now shows what it may spend,
|
|
33
|
+
what it may touch, and what it is allowed to do, because approving a delegation blind is approving a
|
|
34
|
+
blank cheque.
|
|
35
|
+
- **Lifecycle events** `agent.task.started` / `agent.task.completed`, carrying ids and counts only.
|
|
36
|
+
|
|
37
|
+
### Guarantees
|
|
38
|
+
|
|
39
|
+
- **One router.** The worker never constructs an `AI`. Inner model calls go through a
|
|
40
|
+
prototype-delegating metered facade over the parent's — which is also what lets it be handed to a
|
|
41
|
+
skill as `SkillContext.ai`, so it counts the calls a skill makes on its own that the parent budget
|
|
42
|
+
cannot see today. An agent's routing may only narrow the parent's.
|
|
43
|
+
- **Bounded, at depth 1, structurally.** The inner plan is generated with an empty agent list, so a
|
|
44
|
+
nested agent step is a validation error rather than a runtime check a refactor can bypass.
|
|
45
|
+
- **One enforcement point.** `narrowEnvelope` derives the inner catalog, the permission clamp, the caps,
|
|
46
|
+
and the reservation, and it has exactly one caller. A skill whose declared tools escape the envelope is
|
|
47
|
+
excluded there, because a skill's own `callTool` resolves off the Runtime registry with no allowlist.
|
|
48
|
+
- **Arbitrary agent output never becomes a Finding.** Candidates pass extract → output-contract validate
|
|
49
|
+
→ Finding validate → persist, each with one rejection reason; a rejected candidate is an auditable
|
|
50
|
+
diagnostic and is never threaded into a prompt, an observation, or a result. A finding with no
|
|
51
|
+
evidence cannot claim belief, even with a skill-authored override.
|
|
52
|
+
- **Both prompt boundaries are fenced.** A model-authored step input reaches the inner planner inside an
|
|
53
|
+
untrusted-data fence; every definition- and source-controlled string is flattened and clamped.
|
|
54
|
+
- **No new status anywhere.** Every agent-task state projects onto the existing step and execution
|
|
55
|
+
vocabularies, and the table is encoded in code so it cannot drift from the docs. An interruption is
|
|
56
|
+
metadata on the record, not a state. There is no inner approval wait: a headless denial becomes a
|
|
57
|
+
first-class finding plus a fail-branch.
|
|
58
|
+
- **A cancelled branch is distinguishable from a skipped one**, and `pauseExecution`/`cancelExecution`
|
|
59
|
+
now abort agent work that is actually in flight rather than only flipping a stored status.
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- The resume-continue path built its own step runners with no agent runner, so a persisted plan
|
|
64
|
+
containing an agent step would have failed every one of those steps. There is now one runner source.
|
|
65
|
+
- `execStatus` is exhaustive: an unrecognized orchestration status was silently persisted as
|
|
66
|
+
`waiting_for_clarification` — resumable, answerable with a text answer, and wrong.
|
|
67
|
+
- The three copies of "a model call is a skill step" (estimate, wave gate, resume recomputation) are one
|
|
68
|
+
primitive. A third step kind with a non-unit cost made three copies untenable.
|
|
69
|
+
|
|
70
|
+
### Notes
|
|
71
|
+
|
|
72
|
+
- 796 tests pass (was 742); the runtime dependency count is unchanged (4).
|
|
73
|
+
- Persistence, resume, and cancellation of agent tasks are Phase 3.5. 3.4's shapes are chosen so that
|
|
74
|
+
phase needs no breaking change: the task record is already self-identifying and JSON-serializable, and
|
|
75
|
+
the waiting/paused projections are declared but unreachable.
|
|
76
|
+
|
|
77
|
+
## [2.6.0] — 2026-09-03
|
|
78
|
+
|
|
79
|
+
Capability-first planning and the MCP UX. The runtime can now answer **"what does this goal need, and
|
|
80
|
+
what is missing?"** before it plans — offline, for free — and tell you exactly what to grant. Additive:
|
|
81
|
+
with `runtime.capabilities.planning` off (the default) the planner prompt and every result field are
|
|
82
|
+
byte-identical to 2.5.1.
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
|
|
86
|
+
- **`runtime.capabilities.planning`** (default off) — derives the capabilities a goal needs BEFORE
|
|
87
|
+
planning, resolves them against that run's permissions, and reports the gaps. Two rungs: an **offline
|
|
88
|
+
BM25 pass over the live registry** runs first (free, deterministic, and the common path), and a single
|
|
89
|
+
model call sits under it, consulted only when the offline pass finds nothing. The model's reply is
|
|
90
|
+
filtered against the closed candidate set, so no model-authored string can reach resolution, a prompt,
|
|
91
|
+
or your terminal.
|
|
92
|
+
- **A post-plan capability check** — maps each plan step's real provider to what it actually does and
|
|
93
|
+
resolves that. Zero model calls, and the only path that surfaces a genuine `permission` gap with a
|
|
94
|
+
concrete config key to grant.
|
|
95
|
+
- **The gap UX.** `RuntimeResult.capabilityGaps` has been populated since 2.4.0 but was rendered
|
|
96
|
+
nowhere. `ai-runtime run`, the REPL, and both `capabilities` surfaces now print one shared block:
|
|
97
|
+
```
|
|
98
|
+
Capabilities this goal needs:
|
|
99
|
+
✗ commit_changes permission the runtime is not allowed to do this
|
|
100
|
+
✓ read_file available tool:filesystem
|
|
101
|
+
To fix:
|
|
102
|
+
• grant permissions.gitCommit in .ai-runtime/config.yaml
|
|
103
|
+
```
|
|
104
|
+
- **`ai-runtime capabilities --actions "<goal>"`** and **`/capabilities <goal>`** — a free, offline
|
|
105
|
+
"can you do this?" pre-flight. No model call and no provider needed: it answers correctly with
|
|
106
|
+
`providers: []` and no network.
|
|
107
|
+
- **REPL `/mcp` and `/mcp/<id>`** — the MCP surface inside the interactive session, reusing the exact
|
|
108
|
+
formatters the `mcp` command prints (and never opening a second Runtime).
|
|
109
|
+
- **A `doctor` MCP section** — servers, state, tool counts, and grants, with any ungranted server named
|
|
110
|
+
explicitly. Read-only: `doctor` never connects, so states are as last recorded.
|
|
111
|
+
|
|
112
|
+
### Guarantees
|
|
113
|
+
|
|
114
|
+
- **Advisory, never authorization.** Capability planning never blocks a run, adds no orchestration
|
|
115
|
+
status, and grants nothing — the tool's own permission check remains the authority. A gap is metadata
|
|
116
|
+
plus a line in the planner prompt telling the model not to plan around it.
|
|
117
|
+
- **No budget can be exceeded to answer a question about capabilities.** The model rung is skipped
|
|
118
|
+
entirely whenever a call budget is set, and on a dry run; `maxCalls` counts plan steps and cannot
|
|
119
|
+
express a pre-plan call, so declining is the fail-closed reading. Nothing rewrites a resolved policy.
|
|
120
|
+
- **One router.** The model rung goes through the same `AI.run` facade as everything else, on the
|
|
121
|
+
existing `chat` task — the task registry is identical whether the flag is on or off.
|
|
122
|
+
- **The goal is fenced as untrusted** in the derive prompt, and every candidate label is flattened and
|
|
123
|
+
clamped — so an MCP server's description cannot forge a row in it.
|
|
124
|
+
- **Resolution and execution read the same permissions.** A run's gaps are resolved against that run's
|
|
125
|
+
merged permissions (config + per-run override, with `mcp` merged by per-server minimum), through one
|
|
126
|
+
extracted helper, so what gets reported and what the executor will allow can never disagree.
|
|
127
|
+
- `MissingCapabilityReport` now has exactly **one** builder, shared by the public reporter and the run
|
|
128
|
+
path, so the two can no longer drift.
|
|
129
|
+
|
|
130
|
+
### Review outcomes
|
|
131
|
+
|
|
132
|
+
The phase's adversarial review pass produced 24 findings. Two were refuted by measurement (a claimed
|
|
133
|
+
IDF collapse — a 306-capability registry still derives correctly, because the slate is relevance-ranked
|
|
134
|
+
first; and a claimed flag-off report difference — the divergence needs duplicate suggestions, which plan
|
|
135
|
+
validation cannot produce). The rest are fixed:
|
|
136
|
+
|
|
137
|
+
- **No over-grant advice.** A plan step's provider can do more than the step will (`tool:filesystem`
|
|
138
|
+
provides both `read_file` and `write_file`), and lexical derivation can match a sibling. A
|
|
139
|
+
`permission` gap now survives only when the goal actually derived that capability — telling an
|
|
140
|
+
operator to grant write access for a read is worse than saying nothing. Other gap reasons (unknown /
|
|
141
|
+
unavailable / disabled) are always reported, because those block the step whatever it intends.
|
|
142
|
+
- **The relevance cut is tuned by measurement against the real registry** (0.45 → 0.6): zero false
|
|
143
|
+
positives and zero misses across the goal suite, where 0.45 derived `write_file` for "read a
|
|
144
|
+
workspace file" and 0.65 lost `commit_changes` for "commit the fix and run the tests".
|
|
145
|
+
- **Every budget declines the model rung**, not just a call ceiling: a cost ceiling counts, and so does a
|
|
146
|
+
ceiling set in the config file (which deliberately does not flow into `policy.maxCalls`, because
|
|
147
|
+
threading it there would newly gate orchestration for every existing config).
|
|
148
|
+
- **An idempotent retry pays nothing.** Derivation now happens after the `requestId` dedup, so a retry
|
|
149
|
+
that returns the existing execution no longer spends a model call whose result is discarded.
|
|
150
|
+
- A capability id from an operator `aliases` key is clamped before it reaches the derive prompt (it is
|
|
151
|
+
the one id with no charset or length guarantee); `capabilitiesOf` refuses a sanitization-colliding raw
|
|
152
|
+
id rather than answering with the incumbent provider's capabilities; the MCP grant lookup is
|
|
153
|
+
own-property checked everywhere (a server legally named `constructor` could otherwise inherit a
|
|
154
|
+
grant); `capabilities --actions --json` stays JSON on every path; a goal passed without `--actions` is
|
|
155
|
+
honored rather than discarded; `/mcp <id>` and `/capabilities <goal>` accept both the slash and space
|
|
156
|
+
forms; and `doctor` reports whether servers are live instead of a hardcoded `false`.
|
|
157
|
+
|
|
158
|
+
### Notes
|
|
159
|
+
|
|
160
|
+
- 741 tests pass (was 692); the runtime dependency count is unchanged (4).
|
|
161
|
+
- A latent test-double defect is fixed: the MCP `hang` fixture settled only via the caller's abort
|
|
162
|
+
signal, and `AbortSignal.timeout` is unref'd — so a process whose only pending work was that promise
|
|
163
|
+
could exit with an awaiting test unresolved, cancelling it and every test after it in the file. Seen
|
|
164
|
+
once on a CI runner, nine milliseconds after the previous test passed; the mechanism is reproducible in
|
|
165
|
+
four lines of Node. The hang path now carries a ref'd backstop and the behavior is pinned.
|
|
166
|
+
|
|
167
|
+
## [2.5.1] — 2026-09-03
|
|
168
|
+
|
|
169
|
+
Fixes a leak that could hang a test run or a CLI invocation, found by Windows CI. No API changes.
|
|
170
|
+
|
|
171
|
+
### Fixed
|
|
172
|
+
|
|
173
|
+
- **A stdio child is released even when the code that owns it fails.** An MCP stdio child holds the event
|
|
174
|
+
loop open, so a manager that was not closed — because an assertion or an error unwound past the close —
|
|
175
|
+
left the process unable to exit. This is what stalled Windows CI: a platform-specific assertion failed,
|
|
176
|
+
its manager was never closed, and the run reported nothing until it was cancelled. Every spawn-owning
|
|
177
|
+
path now releases in a `finally`.
|
|
178
|
+
- **A dying child's pipes can no longer raise an uncaught exception.** `stdin`/`stdout`/`stderr` each get
|
|
179
|
+
an error handler, because an EPIPE while writing into a process that just exited (or an ECONNRESET on a
|
|
180
|
+
Windows named pipe) is expected during teardown — unhandled, a stream `error` takes down the host.
|
|
181
|
+
- **Pipe handles are destroyed after the child exits**, so no lingering handle can keep the event loop
|
|
182
|
+
alive on a platform where a terminated process's stdio outlives it.
|
|
183
|
+
- **A flaky crypto test is deterministic** (present since 1.10.0, ~1.75% failure rate): it inspected
|
|
184
|
+
`body[10]` but substituted `body[0]`, so whenever that character already held the replacement it
|
|
185
|
+
tampered nothing and AES-GCM correctly did not throw. It now substitutes at the index it inspects,
|
|
186
|
+
asserts the ciphertext actually changed, and a companion test sweeps **every** position in the
|
|
187
|
+
envelope body.
|
|
188
|
+
|
|
189
|
+
### Changed
|
|
190
|
+
|
|
191
|
+
- `npm test` (and each battery) now passes `--test-timeout=120000`, and the CI job carries
|
|
192
|
+
`timeout-minutes: 15`. A future hang fails fast with the offending test's name instead of consuming a
|
|
193
|
+
runner's whole time budget.
|
|
194
|
+
- The MCP stdio tests that inspect the process table now **skip on platforms that cannot be probed**
|
|
195
|
+
(the same shape as the existing symlink skip) — they assert POSIX process semantics that
|
|
196
|
+
`StdioTransport` deliberately does not use on Windows. Windows keeps three real spawn tests plus the
|
|
197
|
+
entire protocol, client, HTTP-transport, permission, and fencing suite.
|
|
198
|
+
`AI_RUNTIME_TEST_NO_PROCESS_PROBE=1` exercises the skipping path on a POSIX host.
|
|
199
|
+
|
|
200
|
+
## [2.5.0] — 2026-09-03
|
|
201
|
+
|
|
202
|
+
MCP connectivity — tools from external **MCP servers** become ordinary Runtime tools. There is no second
|
|
203
|
+
execution path: a discovered MCP tool goes through the same `runTool` permission, approval, cancellation,
|
|
204
|
+
and redaction machinery as `filesystem` or `shell`. Additive: with no `mcp:` config the subsystem is
|
|
205
|
+
entirely inert.
|
|
206
|
+
|
|
207
|
+
### Added
|
|
208
|
+
|
|
209
|
+
- **Zero-dependency MCP client** (`src/mcp/`) — JSON-RPC 2.0 over **stdio** (newline-framed, own process
|
|
210
|
+
group) or **streamable HTTP** (JSON or SSE bodies, `Mcp-Session-Id` carried, 404 ⇒ re-initialize), with
|
|
211
|
+
version negotiation, per-call timeouts, cooperative cancellation, and concurrent request multiplexing.
|
|
212
|
+
The runtime dependency count is unchanged (4).
|
|
213
|
+
- **`mcp:` config** — declare servers by transport with `command`/`args` or `url`, an optional
|
|
214
|
+
`tokenEnv` (an env-var **NAME**; a key-like value is rejected by the same guard `apiKeyEnv` uses), and
|
|
215
|
+
per-server `timeoutMs`.
|
|
216
|
+
- **`permissions.mcp.servers.<id>`** — `off` | `read` | `full` (`true` ≡ full, `false` ≡ off).
|
|
217
|
+
Deny-by-default: adding or connecting a server grants **nothing**. `read` admits only tools the server
|
|
218
|
+
declares read-only; anything else needs `full`.
|
|
219
|
+
- **`ai-runtime mcp`** — list servers with state, tool count, and grant; `mcp <id>` for detail and
|
|
220
|
+
redacted diagnostics; `mcp add|remove|enable|disable|test`. `mcp add` persists to the local **store**,
|
|
221
|
+
never to your config file.
|
|
222
|
+
- **Action capabilities for MCP tools** — each discovered tool provides `mcp:<server>.<tool>`, with
|
|
223
|
+
availability driven by the server's lifecycle (connected ⇒ available, cache-only ⇒ unknown,
|
|
224
|
+
unreachable ⇒ unavailable, disabled ⇒ disabled).
|
|
225
|
+
- **`Runtime.close()`** — releases MCP child processes. Wired into the one-shot CLI, `run`, and REPL exit,
|
|
226
|
+
with a synchronous process-exit net so a crash cannot orphan a server.
|
|
227
|
+
|
|
228
|
+
### Guarantees
|
|
229
|
+
|
|
230
|
+
- **MCP metadata is untrusted at every rendering point, not just call output.** Tool names, descriptions,
|
|
231
|
+
and error text pass a discovery-time normalization gate (name charset validated, control characters
|
|
232
|
+
stripped, length clamped) — a server cannot forge a catalog row or smuggle instructions. An unsafe
|
|
233
|
+
declaration is rejected and never registered; call output is `wrapUntrusted`-fenced and redacted; a
|
|
234
|
+
tool error yields a fixed taxonomy with the server's text only as a fenced diagnostic.
|
|
235
|
+
- **Effects come from the live handshake, never a cache.** A cached `readOnlyHint` cannot lower the
|
|
236
|
+
permission gate; a cache-seeded tool is write-like until a live handshake re-registers it.
|
|
237
|
+
- **Permissions only narrow.** `mcp` is the first nested permission dimension: it merges by per-server
|
|
238
|
+
minimum, so a per-run override can revoke a grant but never widen one.
|
|
239
|
+
- **A `destructiveHint` tool always confirms**, even when its server is granted `full`.
|
|
240
|
+
- **An MCP tool never shadows an existing tool** — the collision is skipped and reported.
|
|
241
|
+
- Credentials are named, never valued: no token, URL, or spawn command reaches an error message, status,
|
|
242
|
+
diagnostic, warning, or the persisted store. Status reports the env-var **name** and whether it resolves.
|
|
243
|
+
- All persisted MCP state (servers, enable-state, tool caches) is schema-validated on read; invalid ⇒
|
|
244
|
+
discarded and reported, never trusted.
|
|
245
|
+
- Bounded by construction: 20 `tools/list` pages, 500 tools per server, a 30s default per-call timeout,
|
|
246
|
+
and a capped reconnect backoff. One server failing never affects another.
|
|
247
|
+
- A failed handshake releases its connection, so a stdio child whose `initialize` times out is closed
|
|
248
|
+
rather than left running; and removing one server never strips a sibling whose id shares its prefix.
|
|
249
|
+
- **A server's JSON Schema is prompt text too**, so it is deep-sanitized: every string inside it is
|
|
250
|
+
flattened and clamped, and its depth, node count, and key count are bounded — an unbounded schema
|
|
251
|
+
would otherwise inflate every planning call that declares the tool.
|
|
252
|
+
- **Deny-by-default holds for every key, not just configured ones.** The grant map is prototype-free, so
|
|
253
|
+
a lookup of `constructor` (or any unconfigured server) can only answer "no grant", and a value that is
|
|
254
|
+
not exactly `off`/`read`/`full` collapses to `off`.
|
|
255
|
+
- **A cached annotation can never relax a gate in either direction.** A stale `readOnlyHint` cannot lower
|
|
256
|
+
the permission gate and a stale `destructiveHint: false` cannot remove the confirmation; with no live
|
|
257
|
+
connection both gates fail closed. The adapter reads live annotations at call time, not a snapshot.
|
|
258
|
+
- **Capability resolution honors the MCP grant**, so an ungranted server's tools are a `permission` gap
|
|
259
|
+
instead of being planned against and then refused by the executor.
|
|
260
|
+
- The model-facing declaration path (`AI.run({ mcp: true })`) honors the same read/full split, emits
|
|
261
|
+
already-namespaced names, and is revoked when a server is disabled or removed.
|
|
262
|
+
- A live discovery is authoritative: a tool the server no longer offers is unregistered rather than
|
|
263
|
+
lingering as available. Re-enabling a server restores its tools.
|
|
264
|
+
- Correlation is response-only, so a server-initiated request can no longer resolve a pending call; an
|
|
265
|
+
already-aborted call never reaches the wire; abort listeners are released on completion.
|
|
266
|
+
- A dynamic server id is validated exactly like a config one, `--token-env` refuses a token value, and
|
|
267
|
+
the persisted `servers` file is validated against the same schema as the config file.
|
|
268
|
+
- Every Runtime-based CLI command releases its Runtime on every path (`withRuntime`), so no command can
|
|
269
|
+
leave a live child holding the process open. A missing stdio command fails immediately instead of
|
|
270
|
+
waiting out the request timeout.
|
|
271
|
+
|
|
272
|
+
### Notes
|
|
273
|
+
|
|
274
|
+
- MCP connects **lazily**: a one-shot CLI command that cannot execute tools pays nothing. The REPL
|
|
275
|
+
connects eagerly, once, at session start.
|
|
276
|
+
- `mcp:` is a Runtime-config key. `AI.load()` (the plain router loader) still rejects it.
|
|
277
|
+
- Public surface: the config/status types, `mcpToolId`, `MCP_PROTOCOL_VERSION`, and
|
|
278
|
+
`clampMcpPermissions`. The client, transports, and manager internals stay private so the wire
|
|
279
|
+
implementation can change without a breaking release.
|
|
280
|
+
|
|
281
|
+
## [2.4.0] — 2026-09-03
|
|
282
|
+
|
|
283
|
+
Action capabilities — the Runtime now reasons about **what it can do** (`read_file`, `run_tests`,
|
|
284
|
+
`read_repository`), independent of which tool or skill provides it. Additive: with no `capabilities`
|
|
285
|
+
config, planning and every existing surface behave exactly as 2.3.0.
|
|
286
|
+
|
|
287
|
+
### Added
|
|
288
|
+
|
|
289
|
+
- **Action-capability layer** (`src/capabilities/`) — a first-class capability model distinct from the
|
|
290
|
+
router's model-capability system: a shipped curated vocabulary, per-provider availability + evidence,
|
|
291
|
+
and a fully deterministic 8-step resolution (availability → operator pin → evidence → source → id).
|
|
292
|
+
- **Declarations** — tools, skills, and skill manifests may declare `provides: [{ id, effects }]`;
|
|
293
|
+
anything undeclared still surfaces under its own namespace, so nothing is ever invisible.
|
|
294
|
+
- **`runtime.capabilities`** config — `catalog` (enrich the planner prompt with capabilities and an
|
|
295
|
+
explicit "unavailable, do not use" section), `aliases` (an operator claims a curated id for a
|
|
296
|
+
provider), and `pins` (an operator selects among eligible providers).
|
|
297
|
+
- **Structured capability gaps** — an unknown plan reference now also produces a machine-readable gap
|
|
298
|
+
(`RuntimeResult.capabilityGaps`) with actionable suggestions, instead of only a raw error string.
|
|
299
|
+
- **`ai-runtime capabilities --actions`** and the REPL **`/capabilities`** — see every action capability,
|
|
300
|
+
its providers, effects, availability, and evidence.
|
|
301
|
+
|
|
302
|
+
### Guarantees
|
|
303
|
+
|
|
304
|
+
- **`effects` is advisory metadata, never authorization.** Actual operation permission is always enforced
|
|
305
|
+
by the selected Tool/Skill execution path.
|
|
306
|
+
- **Capability resolution never grants permission**, and a bare curated id can be claimed only by an
|
|
307
|
+
in-tree builtin or an operator config alias — third-party code is always namespaced to its own source.
|
|
308
|
+
- Source-controlled text is clamped before it reaches a model prompt.
|
|
309
|
+
|
|
310
|
+
## [2.3.0] — 2026-09-01
|
|
311
|
+
|
|
312
|
+
Release automation — push a tag, and CI publishes. Repo tooling only; nothing in the published package
|
|
313
|
+
changes.
|
|
314
|
+
|
|
315
|
+
### Added
|
|
316
|
+
|
|
317
|
+
- **`.github/workflows/release.yml`** — push `v<version>` to publish `ai-runtime-engine`, or `pack-v<version>`
|
|
318
|
+
to publish `ai-runtime-developer-skills`. Each release runs typecheck + tests + build and a **version-sync
|
|
319
|
+
guard** (the tag must equal `package.json`, `cli.ts`, and the CHANGELOG — it fails fast otherwise) before
|
|
320
|
+
`npm publish`. A `409 "previously staged"` is treated as done, not a failure. A manual `workflow_dispatch`
|
|
321
|
+
run performs a `--dry-run` to prove the pipeline without releasing.
|
|
322
|
+
|
|
323
|
+
### Notes
|
|
324
|
+
|
|
325
|
+
- **One-time setup:** add an npm granular access token (publish permission, 2FA-bypass) as the repo secret
|
|
326
|
+
`NPM_TOKEN`. The manual publish flow documented in `docs/handbook/09-npm.md` remains a supported fallback.
|
|
327
|
+
|
|
328
|
+
## [2.2.0] — 2026-09-01
|
|
329
|
+
|
|
330
|
+
A richer interactive terminal — color, tab-completion, history, and a live spinner. Zero new dependencies,
|
|
331
|
+
and all of it is gated on an interactive TTY, so piped/CI output is unchanged.
|
|
332
|
+
|
|
333
|
+
### Added
|
|
334
|
+
|
|
335
|
+
- **Colored** banner and prompt (disabled automatically when not a TTY, when `NO_COLOR` is set, or on a
|
|
336
|
+
`dumb` terminal).
|
|
337
|
+
- **Slash-command tab-completion** — press Tab after `/` to complete a command (only bare commands, never
|
|
338
|
+
your natural-language input or command arguments).
|
|
339
|
+
- **Persistent command history** across REPL sessions (best-effort, stored under the project cache dir).
|
|
340
|
+
- An in-place **spinner** while a request is in flight.
|
|
341
|
+
|
|
342
|
+
### Unchanged
|
|
343
|
+
|
|
344
|
+
- The REPL command surface (`ReplSession`) and all output redaction are exactly as before; nothing about
|
|
345
|
+
scripted/piped usage changes.
|
|
346
|
+
|
|
347
|
+
## [2.1.0] — 2026-09-01
|
|
348
|
+
|
|
349
|
+
Generative seams — draft a skill from a goal, and let a model fill gaps in a provider adapter. Additive:
|
|
350
|
+
both emit **validated config/manifests, never code**, and the scaffolder **writes nothing without your
|
|
351
|
+
confirmation**.
|
|
352
|
+
|
|
353
|
+
### Added
|
|
354
|
+
|
|
355
|
+
- **`ai-runtime skills --scaffold "<goal>"`** — a model drafts a `*.skill.yaml` manifest that composes your
|
|
356
|
+
registered tools. It is refused unless it passes shape validation, names only real tools, has a safe
|
|
357
|
+
kebab-case id, and compiles — then it is printed and **saved only after you confirm** (`--yes` to skip the
|
|
358
|
+
prompt) into `.ai-runtime/skills/`. API: `Runtime.scaffoldSkill(goal)` + `saveScaffoldedSkill(manifest)`,
|
|
359
|
+
and `generateSkillManifest`.
|
|
360
|
+
- **`suggestProviderConfig(analysis, ai)`** — an opt-in AI rung over `generateProviderConfig` that proposes a
|
|
361
|
+
model list when an OpenAPI spec doesn't enumerate one. The output is always the deterministic, **validated**
|
|
362
|
+
`ProviderConfig` — a bad suggestion can only propose model-id strings, never an unvalidated config.
|
|
363
|
+
|
|
364
|
+
### Guarantees
|
|
365
|
+
|
|
366
|
+
- Nothing generated is executed as code — manifests are data parsed by `parseManifest`; adapter output is a
|
|
367
|
+
validated `ProviderConfig`. Goals and specs are fenced as untrusted input.
|
|
368
|
+
- The scaffolder never writes without confirmation, and a scaffolded id can never escape the skills directory.
|
|
369
|
+
|
|
370
|
+
## [2.0.0] — 2026-09-01
|
|
371
|
+
|
|
372
|
+
**The ecosystem milestone.** A first-party developer skill pack ships alongside the engine. This is **not a
|
|
373
|
+
breaking change** — no engine code changed, the public API is fully backward compatible, and every 1.x
|
|
374
|
+
config keeps working. 2.0 marks the start of the pack ecosystem.
|
|
375
|
+
|
|
376
|
+
### Added
|
|
377
|
+
|
|
378
|
+
- **`ai-runtime-developer-skills`** (published separately, `v1.0.0`) — a dependency-free developer skill pack
|
|
379
|
+
loaded via the existing `skills: { packages: [...] }` mechanism. Five skills, each fencing untrusted input
|
|
380
|
+
and **validating by evidence**:
|
|
381
|
+
- **`code-review`** — structured findings for a file or files (evidence: bytes read + ≥1 parsed finding).
|
|
382
|
+
- **`refactor`** — proposes a refactor toward a goal and **never writes** (returns `data.proposal`).
|
|
383
|
+
- **`migration-planner`** — an ordered migration plan for a manifest.
|
|
384
|
+
- **`dependency-analyzer`** — enumerates dependencies, cross-checked against the real manifest count.
|
|
385
|
+
- **`debugger`** — hypotheses + concrete next checks for an error.
|
|
386
|
+
|
|
387
|
+
### Unchanged
|
|
388
|
+
|
|
389
|
+
- The `ai-runtime-engine` public API, config schema, and CLI are all backward compatible with 1.x. The pack
|
|
390
|
+
is **not** bundled into the engine; install it separately.
|
|
391
|
+
|
|
392
|
+
## [1.11.0] — 2026-09-01
|
|
393
|
+
|
|
394
|
+
Scale & ops — per-tool/skill/provider concurrency caps and an OTLP telemetry exporter. Fully additive and
|
|
395
|
+
opt-in: with no `concurrency` config and no `otlp` sink, behavior is byte-identical to 1.10.
|
|
396
|
+
|
|
397
|
+
### Added
|
|
398
|
+
|
|
399
|
+
- **`runtime.concurrency`** — cap how much runs at once: `maxParallelSteps` (orchestrator batch bound, a
|
|
400
|
+
config rung under the per-run override), `perTool` / `perSkill` (cap concurrent uses of a given tool/skill
|
|
401
|
+
within a wave), and `perProvider` (cap concurrent calls to a given provider across the router, under
|
|
402
|
+
fan-out). Backed by a small zero-dep `KeyedSemaphore`.
|
|
403
|
+
- **`telemetry.sink: 'otlp'`** (+ `endpoint`, optional `headersEnv`) — an OpenTelemetry-shaped exporter that
|
|
404
|
+
batches the routing/health metadata events and POSTs them to an OTLP/HTTP endpoint. Metadata only, redacted,
|
|
405
|
+
and **all IO is swallowed** so telemetry never fails a run. The auth header value is read from the env var
|
|
406
|
+
**named** by `headersEnv` (never a value in config).
|
|
407
|
+
- New public exports: `KeyedSemaphore` (`util/semaphore.ts`), `OtlpSink`, `FileSink`.
|
|
408
|
+
|
|
409
|
+
### Guarantees
|
|
410
|
+
|
|
411
|
+
- No `concurrency` config ⇒ scheduling is unchanged; no `otlp` sink ⇒ the sink chain is unchanged.
|
|
412
|
+
- A capped tool/skill/provider still completes every step/call — the cap serializes, it never drops work.
|
|
413
|
+
|
|
414
|
+
## [1.10.0] — 2026-09-01
|
|
415
|
+
|
|
416
|
+
Encryption at rest — transparently encrypt the local store with a key you control. Fully additive and
|
|
417
|
+
opt-in: with no `storage` config, the store stays plaintext exactly as before.
|
|
418
|
+
|
|
419
|
+
### Added
|
|
420
|
+
|
|
421
|
+
- **`runtime.storage: { encrypt: true, keyEnv: "<ENV>" }`** — transparently **AES-256-GCM**-encrypts every
|
|
422
|
+
store file (memory, conversations, executions, artifacts, …). The key is read from the env var **named**
|
|
423
|
+
by `keyEnv` (never a value); a missing key with `encrypt:true` is a hard config error at load. Zero new
|
|
424
|
+
dependencies (`node:crypto`).
|
|
425
|
+
- New public exports: `makeCodec`, `deriveKey`, `encryptString`, `decryptString`, `ENVELOPE_PREFIX`,
|
|
426
|
+
`ContentCodec` (`store/crypto.ts`).
|
|
427
|
+
|
|
428
|
+
### Guarantees
|
|
429
|
+
|
|
430
|
+
- **Mixed store** — records written before encryption still read after you enable it; new writes are
|
|
431
|
+
encrypted. A wrong key surfaces as store corruption (reported by the integrity check), never wrong data.
|
|
432
|
+
- **`meta.json` stays plaintext** so version/migration always works; stateless mode is unaffected.
|
|
433
|
+
- The key lives only in memory — never written to disk, logged, put in telemetry, or included in an error.
|
|
434
|
+
- Not configured ⇒ byte-identical to 1.9.
|
|
435
|
+
|
|
436
|
+
## [1.9.0] — 2026-09-01
|
|
437
|
+
|
|
438
|
+
Organization memory scope — a shared memory store above user/project/repository, for facts that belong to
|
|
439
|
+
a whole team. Fully additive: with no `organization` configured, memory behaves exactly as 1.8.
|
|
440
|
+
|
|
441
|
+
### Added
|
|
442
|
+
|
|
443
|
+
- **`runtime.organization: "<name>"`** — enables the new **`organization`** memory scope, a store *above*
|
|
444
|
+
user/project/repository. Its id is **name-derived**, so every project and repo that configures the same
|
|
445
|
+
organization name shares one org store; different names never share, and project/repo isolation is
|
|
446
|
+
unchanged. `remember({ scope: 'organization' })`, search, delete-cascade, conflict-supersession, temporal
|
|
447
|
+
purge, and the integrity check all span the org area **when configured**.
|
|
448
|
+
- New public export **`organizationId`** (`store/paths.ts`); `info` / `doctor` show the org store path when
|
|
449
|
+
configured.
|
|
450
|
+
|
|
451
|
+
### Guarantees
|
|
452
|
+
|
|
453
|
+
- **Not configured ⇒ nothing changes** — the org area is never traversed, and behavior is byte-identical to 1.8.
|
|
454
|
+
- `remember({ scope: 'organization' })` with **no org configured throws a clear error** rather than silently
|
|
455
|
+
writing the fact to the project store.
|
|
456
|
+
|
|
457
|
+
## [1.8.0] — 2026-09-01
|
|
458
|
+
|
|
459
|
+
Smarter context compiler — optional model-verified loss checking and abstractive summarization. Fully
|
|
460
|
+
additive and opt-in: with both flags unset, context compilation is byte-identical to 1.7.
|
|
461
|
+
|
|
462
|
+
### Added
|
|
463
|
+
|
|
464
|
+
- **`runtime.context.verifyLoss: true`** — after the deterministic compile, a model checks whether anything
|
|
465
|
+
task-critical was dropped and **appends** a `model-loss-verify` check to the context validation. It
|
|
466
|
+
**never blocks**: any budget / parse / model failure records an `inconclusive` (ok) check and leaves the
|
|
467
|
+
deterministic validation result untouched. New public export **`verifyContextLoss`**.
|
|
468
|
+
- **`runtime.context.summarize: true`** — before compiling, over-budget **non-critical** blocks are
|
|
469
|
+
abstractively shortened by one model call each. `critical` blocks are never summarized, originals are
|
|
470
|
+
never mutated, a summary is used only if it actually shrinks the block, and any failure falls back to the
|
|
471
|
+
original (deterministic truncation then applies). New public export **`summarizeOverBudget`**.
|
|
472
|
+
|
|
473
|
+
### Guarantees
|
|
474
|
+
|
|
475
|
+
- Neither feature runs on a **dry run** (a dry run still makes zero model calls).
|
|
476
|
+
- Both `wrapUntrusted`-fence the block/context text before it enters a prompt.
|
|
477
|
+
- The loss verifier compares against the **true pre-summary originals**, so it catches loss from
|
|
478
|
+
summarization as well as from compilation.
|
|
479
|
+
|
|
480
|
+
## [1.7.0] — 2026-09-01
|
|
481
|
+
|
|
482
|
+
AI-assisted intent classification — a model picks the mode when the offline heuristic is unsure. Fully
|
|
483
|
+
additive and opt-in: with `intent.aiFallback` unset, mode detection is byte-identical to 1.6.
|
|
484
|
+
|
|
485
|
+
### Added
|
|
486
|
+
|
|
487
|
+
- **`runtime.intent.aiFallback: true`** — when the deterministic heuristic classifier is *ambiguous*, the
|
|
488
|
+
Runtime consults **one** model call to choose the mode. A **confident** heuristic result pays **zero**
|
|
489
|
+
model cost (it is returned verbatim). Any model failure, unparseable output, or out-of-range mode degrades
|
|
490
|
+
back to the heuristic — the enhancement never breaks a run.
|
|
491
|
+
- New public export **`AIIntentClassifier`** (`runtime/intent/aiClassifier.ts`) — implements the existing
|
|
492
|
+
`IntentClassifier` seam; usable directly via `RuntimeOptions.classifier` too.
|
|
493
|
+
|
|
494
|
+
### Guarantees
|
|
495
|
+
|
|
496
|
+
- **Precedence intact** — an explicit / config / env mode never reaches the classifier.
|
|
497
|
+
- **Security** — the user's request is `wrapUntrusted`-fenced before it enters the classifier prompt (a
|
|
498
|
+
request is data to classify, never instructions), and the chosen mode is validated against the known modes.
|
|
499
|
+
|
|
500
|
+
## [1.6.0] — 2026-09-01
|
|
501
|
+
|
|
502
|
+
Semantic memory retrieval — rank durable facts by meaning, not just keywords. Fully additive: with no
|
|
503
|
+
`embedding` config, memory retrieval is byte-identical to 1.5 (BM25 keyword ranking).
|
|
504
|
+
|
|
505
|
+
### Added
|
|
506
|
+
|
|
507
|
+
- **`runtime.embedding`** config — opt in to semantic retrieval: `{ provider: 'local' }` uses the zero-dep,
|
|
508
|
+
deterministic **`HashEmbedder`** (offline, no key); `{ provider: 'openai-compatible', baseUrl, apiKeyEnv,
|
|
509
|
+
model? }` calls a `POST {baseUrl}/embeddings` endpoint via **`HttpEmbedder`** (key by **env NAME** only,
|
|
510
|
+
never a value; the request URL is kept out of every error). Absent → BM25 exactly as before.
|
|
511
|
+
- **`MemoryStore.searchSemantic(query, opts)`** — the async vector path: the *same* filter stage as
|
|
512
|
+
`search()` (scope / confidence / temporal / supersession / domain), then **cosine-similarity** ranking
|
|
513
|
+
over embeddings. `Runtime` chat retrieval and the REPL **`/memory search`** use it automatically when an
|
|
514
|
+
embedder is configured. Candidate vectors are cached per fact text (per instance).
|
|
515
|
+
- New public exports: `cosineSimilarity`, `semanticRank` (`memory/semantic.ts`), `HashEmbedder`,
|
|
516
|
+
`HttpEmbedder`.
|
|
517
|
+
|
|
518
|
+
### Guarantees
|
|
519
|
+
|
|
520
|
+
- **`search()` is unchanged** — still synchronous BM25, the frozen public API since 1.0.
|
|
521
|
+
- **Retrieval never breaks a run.** Any embedder problem — network failure, malformed response, an empty or
|
|
522
|
+
non-finite vector — **degrades to BM25**, never an error and never a silently-empty result.
|
|
523
|
+
|
|
524
|
+
## [1.5.0] — 2026-09-01
|
|
525
|
+
|
|
526
|
+
Model routing profiles — route your own way with a `models.md` file. Additive: with no file, routing is
|
|
527
|
+
identical to 1.4.
|
|
528
|
+
|
|
529
|
+
### Added
|
|
530
|
+
|
|
531
|
+
- **`models.md`** (workspace root or `.ai-runtime/models.md`) — a friendly per-mode / per-task mapping of
|
|
532
|
+
which model to use, resolved through the router's existing controls (no second router). Sections
|
|
533
|
+
`## By mode` and `## By task`; each entry is a **soft prefer** (default), a **hard pin** (`=provider:model`
|
|
534
|
+
or `pin:`), or a **strategy** keyword (`best`/`fastest`/`cheapest`/`highest-quality`/`local-only`/… or
|
|
535
|
+
`free` → cheapest). Example: *chat → free, plan → a strong model, execute → model X, a task → a specific
|
|
536
|
+
model.* Precedence: **explicit per-run > `models.md` > config > defaults**; a `## By task` entry wins over
|
|
537
|
+
`## By mode`; a prefer never re-admits an excluded model.
|
|
538
|
+
- **`ai-runtime models --profile`** prints the resolved profile; **`init`** scaffolds a commented
|
|
539
|
+
`models.md`; `runtime.modelProfile()` exposes it. `## By mode` steers Runtime modes; `## By task` steers
|
|
540
|
+
router tasks via `ai-runtime route <task>` (and any `AI.run({ task })` caller).
|
|
541
|
+
|
|
542
|
+
**Scope:** in chat mode and for route tasks, all three directive kinds apply; orchestration modes
|
|
543
|
+
(plan/execute/orchestrate/agent/debug) honor the **soft prefer** (a per-mode hard pin/strategy is not
|
|
544
|
+
applied there — the planner and skills pick their own models).
|
|
545
|
+
|
|
546
|
+
## [1.4.0] — 2026-09-01
|
|
547
|
+
|
|
548
|
+
Budget-aware phased execution. When a task would need more model calls than your budget allows, it no
|
|
549
|
+
longer fails partway — it tells you, and lets you run it in phases. Additive: with no call budget set,
|
|
550
|
+
behavior is identical to 1.3.
|
|
551
|
+
|
|
552
|
+
### Added
|
|
553
|
+
|
|
554
|
+
- **Budget-aware orchestration** — set a call budget with `AI_MAX_CALLS` (or per-run `maxCalls`). When a
|
|
555
|
+
plan's estimated model calls exceed it, the run **notifies instead of failing**: it reports the estimate
|
|
556
|
+
and waits, executing nothing, so you can either raise the budget and re-run, or run what fits with
|
|
557
|
+
`--partial`. A `--partial` run executes the phases that fit the budget, checkpoints, and **pauses
|
|
558
|
+
resumably** (`waiting_for_budget`, a first-class non-failure) — raise `AI_MAX_CALLS` and
|
|
559
|
+
`resume-execution <id>` to continue from where it stopped. A phase is a plan wave; a skill step counts as
|
|
560
|
+
one model call, tool steps are free.
|
|
561
|
+
- **`run --partial`**, the REPL **`/budget`** command (shows `AI_MAX_CALLS` / `AI_MAX_COST_USD`), and an
|
|
562
|
+
over-budget resume hint.
|
|
563
|
+
|
|
564
|
+
### Fixed
|
|
565
|
+
|
|
566
|
+
- An **approval-gated** over-budget plan now respects the call budget on resume (it previously ran to
|
|
567
|
+
completion, ignoring the budget, because the approval gate was reached before the budget check).
|
|
568
|
+
|
|
569
|
+
## [1.3.0] — 2026-09-01
|
|
570
|
+
|
|
571
|
+
Token-by-token streaming. Additive and backward compatible — every new field is optional and, with
|
|
572
|
+
streaming unconfigured, behavior is identical to 1.2.0.
|
|
573
|
+
|
|
574
|
+
### Added
|
|
575
|
+
|
|
576
|
+
- **Streaming responses end-to-end (`response.delta`)** — the reserved streaming event is now emitted for
|
|
577
|
+
real. Opt in with `stream: true` + `onDelta` on `AI.run()`/`RunRequest`, or `runtime.run({ stream: true })`
|
|
578
|
+
in chat mode. Text output only (a JSON/structured request never streams). Implemented through the one
|
|
579
|
+
router: optional `AIProvider.executeStream`, optional wire `buildStreamRequest`/`readDelta` for the
|
|
580
|
+
OpenAI-compatible and Anthropic shapes, and an SSE reader (`callHttpStream`) that buffers across network
|
|
581
|
+
boundaries. `AIResponse` is unchanged and remains the full aggregate — deltas ride the event channel.
|
|
582
|
+
- **Live rendering in the terminal** — the interactive REPL renders answers token-by-token (toggle with
|
|
583
|
+
`/stream`), and one-shot `ai-runtime run --stream` does the same. Streamed text is redacted like every
|
|
584
|
+
egress and is never reprinted after it streams.
|
|
585
|
+
|
|
586
|
+
### Reliability
|
|
587
|
+
|
|
588
|
+
- A provider whose gateway doesn't support SSE **degrades gracefully to a buffered call** before the first
|
|
589
|
+
token, so enabling streaming never breaks a non-streaming endpoint. A mid-stream drop is categorized and
|
|
590
|
+
sanitized (never leaks the request URL) and falls back to the next candidate.
|
|
591
|
+
|
|
8
592
|
## [1.2.0] — 2026-08-31
|
|
9
593
|
|
|
10
594
|
Closes the known gaps between what the CLI/REPL exposed and what the Runtime supported. Additive and
|
|
@@ -107,6 +691,24 @@ Initial release: the provider-agnostic AI **router** — capability-based routin
|
|
|
107
691
|
scoring, evidence validation, fallback, health tracking, learning-based scoring, multi-model verification,
|
|
108
692
|
budgets, MCP tools, OpenAPI-based adapter generation, and the `AI` class + CLI.
|
|
109
693
|
|
|
694
|
+
[2.7.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v2.7.0
|
|
695
|
+
[2.6.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v2.6.0
|
|
696
|
+
[2.5.1]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v2.5.1
|
|
697
|
+
[2.5.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v2.5.0
|
|
698
|
+
[2.4.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v2.4.0
|
|
699
|
+
[2.3.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v2.3.0
|
|
700
|
+
[2.2.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v2.2.0
|
|
701
|
+
[2.1.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v2.1.0
|
|
702
|
+
[2.0.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v2.0.0
|
|
703
|
+
[1.11.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v1.11.0
|
|
704
|
+
[1.10.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v1.10.0
|
|
705
|
+
[1.9.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v1.9.0
|
|
706
|
+
[1.8.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v1.8.0
|
|
707
|
+
[1.7.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v1.7.0
|
|
708
|
+
[1.6.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v1.6.0
|
|
709
|
+
[1.5.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v1.5.0
|
|
710
|
+
[1.4.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v1.4.0
|
|
711
|
+
[1.3.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v1.3.0
|
|
110
712
|
[1.2.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v1.2.0
|
|
111
713
|
[1.1.1]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v1.1.1
|
|
112
714
|
[1.1.0]: https://github.com/pavankhandelwal21/ai-runtime/releases/tag/v1.1.0
|