tinker-agent 2.8.0 → 2.10.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 +79 -1
- package/README.md +81 -11
- package/package.json +5 -3
- package/src/agent/runtime-context-capabilities.ts +19 -0
- package/src/agent/runtime-context-events.ts +127 -0
- package/src/agent/runtime-context-maintenance.ts +780 -0
- package/src/agent/runtime-hosted-session.ts +443 -0
- package/src/agent/runtime-interactions.ts +291 -0
- package/src/agent/runtime-prompt-scheduler.ts +182 -0
- package/src/agent/runtime-session-contracts.ts +317 -0
- package/src/agent/runtime-session.ts +250 -2130
- package/src/agent/runtime-skills.ts +544 -0
- package/src/cli/command-line.ts +26 -2
- package/src/cli/connect-runner.tsx +26 -0
- package/src/cli/main.ts +26 -0
- package/src/cli/output.ts +1 -1
- package/src/cli/public-cli-contract.ts +18 -0
- package/src/cli/public-config-contract.ts +1 -1
- package/src/cli/runner-dependencies.ts +6 -5
- package/src/cli/serve-runner.ts +45 -0
- package/src/cli/serve-runtime.ts +100 -0
- package/src/context/context-automation-policy.ts +12 -118
- package/src/context/context-swap-renderer.ts +14 -0
- package/src/events/types.ts +12 -0
- package/src/memory/memory-get-tool.ts +1 -1
- package/src/observation/observation-builder.ts +128 -48
- package/src/remote/client.ts +350 -0
- package/src/remote/config.ts +95 -0
- package/src/remote/http-server.ts +240 -0
- package/src/remote/protocol.ts +228 -0
- package/src/remote/service-store.ts +175 -0
- package/src/remote/service.ts +219 -0
- package/src/remote/sync-hub.ts +95 -0
- package/src/session/remote-history-reader.ts +143 -0
- package/src/session/resume-projection.ts +47 -21
- package/src/session/session-history-access.ts +238 -0
- package/src/session/session-store-context-readers.ts +183 -0
- package/src/session/session-store-ledger-writer.ts +315 -0
- package/src/session/session-store-record-writer.ts +318 -0
- package/src/session/session-store-recovery.ts +225 -0
- package/src/session/session-store-revisions.ts +1004 -0
- package/src/session/session-store-sql.ts +40 -0
- package/src/session/session-store-validation.ts +657 -0
- package/src/session/session-store.ts +756 -3186
- package/src/tools/bash-task.ts +46 -18
- package/src/tools/bash.ts +44 -2
- package/src/tools/glob.ts +107 -19
- package/src/tools/grep-output.ts +130 -0
- package/src/tools/grep-pagination.ts +73 -0
- package/src/tools/grep-path.ts +11 -0
- package/src/tools/grep-snippets.ts +111 -0
- package/src/tools/grep.ts +139 -154
- package/src/tools/read.ts +0 -9
- package/src/tools/recall.ts +106 -50
- package/src/tools/registry.ts +4 -6
- package/src/tools/ripgrep.ts +19 -26
- package/src/tools/shell-process.ts +30 -4
- package/src/tools/task-output-range.ts +146 -0
- package/src/tools/task-output-tool.ts +35 -5
- package/src/tools/task-output.ts +35 -0
- package/src/tools/task-stop.ts +2 -1
- package/src/tools/task-tool-args.ts +34 -0
- package/src/tools/terminal-screen.ts +11 -2
- package/src/tools/types.ts +39 -2
- package/src/tui/event-store.ts +23 -5
- package/src/tui/remote-app.tsx +210 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,82 @@ All notable user-facing changes to Tinker are documented here. The project follo
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [2.10.0] - 2026-09-06
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Add remote access for paired clients. `tinker serve --config <path>` runs the
|
|
13
|
+
local daemon that paired remote clients connect to, and
|
|
14
|
+
`tinker connect --config <path>` attaches a terminal client to a running
|
|
15
|
+
service; exiting the client detaches without stopping the service. See
|
|
16
|
+
`docs/remote-access.md`. A native iOS client under `client/Tinker` is included
|
|
17
|
+
for acceptance.
|
|
18
|
+
- Add `offset` and `head_limit` pagination to `Glob` results. Long result sets
|
|
19
|
+
now report whether more matches remain instead of being silently capped.
|
|
20
|
+
- Add `cols` and `rows` options to `Bash` for custom initial PTY dimensions when
|
|
21
|
+
`tty=true`, so terminal applications that require a specific size can run in
|
|
22
|
+
an appropriately sized pseudo-terminal.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Run `Grep` directory searches with ripgrep's working directory set to the search
|
|
27
|
+
directory and `.` as the path argument. Directory globs such as `sub/**` now
|
|
28
|
+
match from that directory; globs that relied on absolute search paths may need
|
|
29
|
+
updating. Explicit file searches keep their existing invocation.
|
|
30
|
+
- Increase the default `Bash` foreground wait before a command continues in the
|
|
31
|
+
background, and clarify how `TaskOutput` and `TaskInput` poll PTY sessions.
|
|
32
|
+
- Omit internal file hashes from tool observations; the model sees the same
|
|
33
|
+
content without opaque bookkeeping tokens.
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- Stop `TaskStop` from hanging when a shell's child processes survive after the
|
|
38
|
+
shell itself exits; stopping a task now reliably reports its final state.
|
|
39
|
+
- Preserve `Grep` match context across paginated results, keep long-line matches
|
|
40
|
+
instead of dropping them, and report counts and paginated records
|
|
41
|
+
consistently, including a `count-matches` mode with explicit counting units.
|
|
42
|
+
- Resolve symbolic-link search roots in `Glob` while preserving result paths,
|
|
43
|
+
and exclude directory and broken symbolic links from results.
|
|
44
|
+
- Accept pagination arguments in `Read` when reading empty files instead of
|
|
45
|
+
rejecting the call.
|
|
46
|
+
|
|
47
|
+
## [2.9.0] - 2026-09-05
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- Add optional `sessionId` selection to `RecallSearch` and `RecallGet`, allowing
|
|
52
|
+
the agent to retrieve original history from another session, including a
|
|
53
|
+
Memory result's source session or another workspace under the same Tinker
|
|
54
|
+
home. Results identify their source session and workspace. External history is
|
|
55
|
+
read without resuming, repairing, or migrating the source session. Retrieved
|
|
56
|
+
text is sent to the current model provider and stored in the current session;
|
|
57
|
+
cross-workspace access does not show an additional confirmation dialog.
|
|
58
|
+
- Add `offset` and `limit` to `TaskOutput` for reading consecutive, numbered lines
|
|
59
|
+
from non-PTY task logs. Omitting both preserves the head/tail preview; PTY tasks
|
|
60
|
+
continue to return the current terminal screen.
|
|
61
|
+
|
|
62
|
+
### Changed
|
|
63
|
+
|
|
64
|
+
- Enable automatic context swaps and prefix retirement as product defaults,
|
|
65
|
+
independent of model names, evaluation results, report availability, and tool
|
|
66
|
+
description hashes. Existing Recall capability, protocol, transaction, and
|
|
67
|
+
request-consistency checks remain enforced. Evaluation still measures model
|
|
68
|
+
behavior but no longer enables or disables runtime maintenance; this does not
|
|
69
|
+
guarantee reliable history retrieval by every model.
|
|
70
|
+
- Clarify shell guidance so finite builds, tests, and checks run in the foreground
|
|
71
|
+
when their result is needed next and no independent work remains. Reserve
|
|
72
|
+
background execution for persistent processes or useful concurrent work, and
|
|
73
|
+
describe task tools in terms of their capabilities.
|
|
74
|
+
|
|
75
|
+
### Fixed
|
|
76
|
+
|
|
77
|
+
- Restore sessions containing follow-up messages submitted during an active turn
|
|
78
|
+
instead of rejecting turns with multiple user messages. Resumed timelines keep
|
|
79
|
+
follow-ups in their original order for completed and failed turns.
|
|
80
|
+
- Include available exit codes, termination signals, and errors in `TaskOutput`
|
|
81
|
+
observations. Distinguish PTY screen snapshots from cumulative log statistics,
|
|
82
|
+
and clarify byte-limited log ranges and polling of a still-growing final line.
|
|
83
|
+
|
|
8
84
|
## [2.8.0] - 2026-09-04
|
|
9
85
|
|
|
10
86
|
### Changed
|
|
@@ -361,7 +437,9 @@ All notable user-facing changes to Tinker are documented here. The project follo
|
|
|
361
437
|
- First formal npm release under the `tinker-agent` package name with the `tinker`
|
|
362
438
|
executable.
|
|
363
439
|
|
|
364
|
-
[Unreleased]: https://github.com/ishowshao/tinker/compare/v2.
|
|
440
|
+
[Unreleased]: https://github.com/ishowshao/tinker/compare/v2.10.0...HEAD
|
|
441
|
+
[2.10.0]: https://github.com/ishowshao/tinker/releases/tag/v2.10.0
|
|
442
|
+
[2.9.0]: https://github.com/ishowshao/tinker/releases/tag/v2.9.0
|
|
365
443
|
[2.8.0]: https://github.com/ishowshao/tinker/releases/tag/v2.8.0
|
|
366
444
|
[2.7.0]: https://github.com/ishowshao/tinker/releases/tag/v2.7.0
|
|
367
445
|
[2.6.0]: https://github.com/ishowshao/tinker/releases/tag/v2.6.0
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ This does not pretend that any model has infinite tokens or guarantee that it wi
|
|
|
19
19
|
- `TaskList` / `TaskOutput` / `TaskInput` / `TaskStop` — Inspect, interact with, and stop long-running shell tasks
|
|
20
20
|
- `WebSearch` — Search the web via Exa API
|
|
21
21
|
- `WebFetch` — Fetch and refine web page content (local, browser, or Exa backend)
|
|
22
|
-
- `
|
|
22
|
+
- `RecallSearch` / `RecallGet` — Search or retrieve model-visible history from the current session or an explicitly selected session
|
|
23
23
|
- **Agent Skills**: Discover compatible `SKILL.md` packages at project and user
|
|
24
24
|
scope, disclose their catalog progressively, and keep activated instructions
|
|
25
25
|
durable across context compaction and session resume.
|
|
@@ -29,11 +29,79 @@ This does not pretend that any model has infinite tokens or guarantee that it wi
|
|
|
29
29
|
- **Turn cancellation**: Users can cancel an ongoing turn safely, with protocol-safe synthetic tool messages.
|
|
30
30
|
- **Context metering**: Budget-aware context management with protocol validation before sending requests to the model.
|
|
31
31
|
- **Deterministic context compaction**: Idle sessions can swap eligible historical tool output into Recall-addressable placeholders without calling the model.
|
|
32
|
-
- **Infinite Context architecture**: Immutable canonical history, deterministic context revisions, Recall-addressable cold state, and
|
|
32
|
+
- **Infinite Context architecture**: Immutable canonical history, deterministic context revisions, Recall-addressable cold state, and protocol-safe prefix retirement support sessions designed to continue indefinitely without pretending the model has infinite tokens.
|
|
33
33
|
- **Choice of models**: Uses an OpenAI-compatible Chat Completions transport with
|
|
34
34
|
explicit model and context limits. Actual provider support must be established
|
|
35
35
|
by a qualification matrix; transport compatibility alone is not a guarantee.
|
|
36
36
|
|
|
37
|
+
### PTY screen size
|
|
38
|
+
|
|
39
|
+
`Bash` accepts optional `cols` and `rows` for the initial PTY screen size:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{"command":"python3 -q","tty":true,"cols":160,"rows":48}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Each omitted dimension keeps its default: 80 columns and 24 rows. Columns accept
|
|
46
|
+
integers from 2 to 1000; rows accept integers from 1 to 1000. When `tty` is omitted
|
|
47
|
+
or `false`, dimensions are ignored and execution continues through ordinary pipes.
|
|
48
|
+
`TaskOutput` and `TaskInput` report the actual screen size. Dimensions are set at
|
|
49
|
+
creation; running tasks cannot be resized through these tools.
|
|
50
|
+
|
|
51
|
+
### Reading another session's history
|
|
52
|
+
|
|
53
|
+
Both Recall tools accept an optional `sessionId` (a canonical session UUID).
|
|
54
|
+
Omitting it keeps the current-session behavior. In the TUI or one-shot CLI, the
|
|
55
|
+
agent can use a session ID you supply or a Memory result's `sourceSessionId`:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
RecallSearch({ sessionId: sourceSessionId, query: "distinctive-anchor" })
|
|
59
|
+
RecallGet({ sessionId: sourceSessionId, source: "ctx://message/<message-UUID>" })
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Reuse the same `sessionId` for Get and subsequent pages. Search's
|
|
63
|
+
`snapshot_through_ordinal`, ordinals and turn numbers belong to that session only.
|
|
64
|
+
Results identify their source session and workspace. Missing, ambiguous, unsafe,
|
|
65
|
+
unsupported or corrupt sessions return errors; Recall never silently switches
|
|
66
|
+
back to the current session. Memory is not required.
|
|
67
|
+
|
|
68
|
+
**Data scope:** explicit session selection can read other workspaces under the
|
|
69
|
+
configured Tinker home (`TINKER_HOME` overrides the OS home). Retrieved text is
|
|
70
|
+
sent to the **current model provider** and saved as a tool result in the **current
|
|
71
|
+
session**, including when projects or providers differ. There is no additional
|
|
72
|
+
cross-workspace confirmation dialog.
|
|
73
|
+
|
|
74
|
+
External history uses short read-only SQLite snapshots, without resuming the
|
|
75
|
+
source session, taking its execution lock, repairing indexes or migrating its
|
|
76
|
+
schema. Only the current readable schema is supported. Active writers' committed
|
|
77
|
+
history is readable; an open/interrupted turn may be incomplete. Historical
|
|
78
|
+
instructions, Skills and authorizations are not activated, and content hashes
|
|
79
|
+
prove storage consistency, not truth. Use Read/Grep to verify current facts.
|
|
80
|
+
Original workspaces need not still exist. SQLite WAL reads can coordinate through
|
|
81
|
+
SHM; read-only access does not promise that an active writer's directory remains
|
|
82
|
+
byte-for-byte unchanged. See the
|
|
83
|
+
[history access implementation](src/session/session-history-access.ts).
|
|
84
|
+
|
|
85
|
+
### Automatic context maintenance and evaluation
|
|
86
|
+
|
|
87
|
+
Automatic swap and prefix retirement are product defaults, independent of model
|
|
88
|
+
names, evaluation scores, report availability, and tool-description hashes. Under
|
|
89
|
+
context pressure, the runtime tries swap first and attempts retirement only when
|
|
90
|
+
swap has no eligible candidates or insufficient candidates. Existing scheduling,
|
|
91
|
+
protocol boundaries, cancellation, transaction, and request/surface consistency
|
|
92
|
+
checks remain in force. Required Recall tools and the current retirement contract
|
|
93
|
+
must be available; enabling a product policy does not bypass execution safety.
|
|
94
|
+
There are no new user-facing switches or model allowlists.
|
|
95
|
+
|
|
96
|
+
Evaluation measures model behavior; it does not enable or disable these features.
|
|
97
|
+
New evaluation reports (`active-recall-qualification-v2`) contain metrics, gates,
|
|
98
|
+
and provenance but no automation flags. Historical reports remain unchanged. The
|
|
99
|
+
session-selection evaluation
|
|
100
|
+
retains its measured failure: Search → Get missed the threshold even though all
|
|
101
|
+
Recall-only tasks passed. Its old automation fields are legacy data, not runtime
|
|
102
|
+
policy. The subsequent description cleanup has not been re-evaluated with a live
|
|
103
|
+
model.
|
|
104
|
+
|
|
37
105
|
## Quick Start
|
|
38
106
|
|
|
39
107
|
### Install with your existing agent
|
|
@@ -104,6 +172,8 @@ The installed package exposes this public CLI:
|
|
|
104
172
|
| `tinker run [--profile <profile-name>] [--yolo] --stdin` | Read the prompt from standard input until EOF. |
|
|
105
173
|
| `tinker run [--profile <profile-name>] [--yolo] --file <path>` | Read the prompt from a UTF-8 text file. |
|
|
106
174
|
| `tinker update` | Update the global npm installation from the official npm registry. |
|
|
175
|
+
| `tinker serve --config <path>` | Run the local daemon for paired remote clients. |
|
|
176
|
+
| `tinker connect --config <path>` | Attach a terminal client to a service; exiting detaches only. |
|
|
107
177
|
| `tinker --help` | Show top-level CLI help. |
|
|
108
178
|
| `tinker help run` | Show one-shot command help. |
|
|
109
179
|
| `tinker help update` | Show update command help. |
|
|
@@ -175,7 +245,7 @@ are required. Boolean environment values accept case-insensitive `true/false`,
|
|
|
175
245
|
| `EXA_API_KEY` | Tooling | All modes | No | Non-empty string | — | Yes | Enables WebSearch and the Exa WebFetch backend when set. |
|
|
176
246
|
| `TINKER_MCP_TIMEOUT_MS` | Tooling | All modes | No | Positive integer | `60000` | No | MCP tool-call timeout in milliseconds. |
|
|
177
247
|
| `TINKER_MCP_MAX_OBSERVATION_CHARS` | Tooling | All modes | No | Positive integer | `40000` | No | Maximum model-visible characters in one MCP result. |
|
|
178
|
-
| `TINKER_BASH_DEFAULT_TIMEOUT_MS` | Tooling | All modes | No | Positive integer | `
|
|
248
|
+
| `TINKER_BASH_DEFAULT_TIMEOUT_MS` | Tooling | All modes | No | Positive integer | `60000` | No | Default Bash foreground timeout in milliseconds. |
|
|
179
249
|
| `TINKER_BASH_MAX_TIMEOUT_MS` | Tooling | All modes | No | Positive integer | `600000` | No | Maximum Bash foreground timeout in milliseconds. |
|
|
180
250
|
| `TINKER_YOLO` | Tooling | All modes | No | Boolean | `false` | No | Allow high-confidence destructive Bash commands without confirmation. |
|
|
181
251
|
| `TINKER_GREP_TIMEOUT_MS` | Tooling | All modes | No | Positive integer | `20000` | No | Bundled ripgrep invocation timeout in milliseconds. |
|
|
@@ -398,9 +468,9 @@ pixels in total. Provider requests preserve smaller images and proportionally
|
|
|
398
468
|
downscale larger images to a maximum 2048-pixel long edge. Context planning uses
|
|
399
469
|
fixed local token buckets derived from the materialized dimensions and performs no
|
|
400
470
|
independent token-estimator request. See the
|
|
401
|
-
[
|
|
402
|
-
[
|
|
403
|
-
|
|
471
|
+
[image input policy](src/image/image-input-policy.ts) and
|
|
472
|
+
[image asset store](src/image/image-asset-store.ts) for the policy and storage
|
|
473
|
+
implementations.
|
|
404
474
|
|
|
405
475
|
`ViewImage(file_path)` is registered only when the selected profile declares both
|
|
406
476
|
`inputModalities: ["text", "image"]` and
|
|
@@ -410,8 +480,8 @@ text-only for tool results. Relative paths stay inside the workspace, absolute
|
|
|
410
480
|
paths may explicitly select an external local file, and symbolic links are
|
|
411
481
|
rejected. Canonical history stores content-addressed image references rather than
|
|
412
482
|
Base64, while stdout, TUI, Recall, and logs show deterministic text summaries.
|
|
413
|
-
See the [`ViewImage
|
|
414
|
-
|
|
483
|
+
See the [`ViewImage implementation`](src/tools/view-image.ts) for the tool's
|
|
484
|
+
validation and execution logic.
|
|
415
485
|
|
|
416
486
|
### Built-in Slash Commands
|
|
417
487
|
|
|
@@ -476,9 +546,9 @@ turn. Built-in slash commands appear first in suggestions, followed by project
|
|
|
476
546
|
commands in configuration order. Custom commands accept no arguments and cannot
|
|
477
547
|
override built-ins. The optional configuration is loaded once at TUI startup,
|
|
478
548
|
must be valid when present, and has a 1 MiB size limit. It is not loaded by the
|
|
479
|
-
one-shot `tinker run` command. See
|
|
480
|
-
[
|
|
481
|
-
|
|
549
|
+
one-shot `tinker run` command. See the
|
|
550
|
+
[project command loader](src/tui/project-slash-commands.ts) for configuration
|
|
551
|
+
validation and loading behavior.
|
|
482
552
|
|
|
483
553
|
### Global Runtime Data
|
|
484
554
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tinker-agent",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"description": "A personal coding agent with an interactive TUI and one-shot CLI.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"src/memory",
|
|
24
24
|
"src/model",
|
|
25
25
|
"src/observation",
|
|
26
|
+
"src/remote",
|
|
26
27
|
"src/session",
|
|
27
28
|
"src/skills",
|
|
28
29
|
"src/tools",
|
|
@@ -64,8 +65,9 @@
|
|
|
64
65
|
"docs:generate": "bun scripts/render-public-contract-docs.ts --write",
|
|
65
66
|
"docs:check": "bun scripts/render-public-contract-docs.ts --check",
|
|
66
67
|
"tinker": "bun src/cli/index.ts",
|
|
67
|
-
"check": "bun run typecheck && bun run format:check && bun run lint && bun run docs:check && bun run test && bun run bench:smoke",
|
|
68
|
-
"check:fast": "bun run typecheck && bun run format:check && bun run lint && bun run test:fast",
|
|
68
|
+
"check": "bun run check:source-lines && bun run typecheck && bun run format:check && bun run lint && bun run docs:check && bun run test && bun run bench:smoke",
|
|
69
|
+
"check:fast": "bun run check:source-lines && bun run typecheck && bun run format:check && bun run lint && bun run test:fast",
|
|
70
|
+
"check:source-lines": "bun scripts/check-source-lines.ts",
|
|
69
71
|
"format": "biome format --write .",
|
|
70
72
|
"format:check": "biome format .",
|
|
71
73
|
"lint": "eslint \"bin/**/*.js\" \"src/**/*.{ts,tsx}\" \"scripts/**/*.ts\" \"packages/**/*.ts\" --max-warnings=0",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CURRENT_RECALL_RETIREMENT_CONTRACT_VERSION } from "../context/recall-retirement-contract";
|
|
2
|
+
import type { ToolRegistry } from "../tools/registry";
|
|
3
|
+
|
|
4
|
+
/** Structural runtime prerequisites, not model qualification or description hashes. */
|
|
5
|
+
export function assertContextMaintenanceCapabilities(
|
|
6
|
+
registry: Pick<ToolRegistry, "get">,
|
|
7
|
+
recallContractVersion: string,
|
|
8
|
+
): void {
|
|
9
|
+
for (const name of ["RecallSearch", "RecallGet"]) {
|
|
10
|
+
if (registry.get(name) === undefined) {
|
|
11
|
+
throw new Error(`Context maintenance requires an executable ${name} tool.`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
if (recallContractVersion !== CURRENT_RECALL_RETIREMENT_CONTRACT_VERSION) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
"Context maintenance requires the current Recall retirement contract.",
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ContextCompactionResult,
|
|
3
|
+
type ContextRetirementResult,
|
|
4
|
+
} from "../context/context-manager";
|
|
5
|
+
import { type StoredContextSurfaceV8 } from "../context/context-surface";
|
|
6
|
+
import type { ContextRevisionFinishedData } from "../events/types";
|
|
7
|
+
import { type ModelClient } from "../model/model-client";
|
|
8
|
+
|
|
9
|
+
export function assertPreparedMatchesSurface(
|
|
10
|
+
prepared: ReturnType<ModelClient["prepare"]>,
|
|
11
|
+
surface: StoredContextSurfaceV8,
|
|
12
|
+
): void {
|
|
13
|
+
if (
|
|
14
|
+
prepared.requestConfigHash !== surface.requestConfigSha256 ||
|
|
15
|
+
prepared.toolSchemaHash !== surface.toolSchemaSha256 ||
|
|
16
|
+
prepared.requestMaxOutputTokens !== surface.requestMaxOutputTokens
|
|
17
|
+
) {
|
|
18
|
+
throw new Error("Prepared model request does not match its context surface.");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function elapsedMs(startedAt: number): number {
|
|
23
|
+
return Math.round((performance.now() - startedAt) * 100) / 100;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function boundedContextErrorCode(code: string): string {
|
|
27
|
+
return /^[A-Za-z0-9_]+$/.test(code) && code.length <= 80
|
|
28
|
+
? code
|
|
29
|
+
: "CONTEXT_COMPACTION_FAILED";
|
|
30
|
+
}
|
|
31
|
+
export function contextRevisionFinishedData(
|
|
32
|
+
result: ContextCompactionResult,
|
|
33
|
+
reason: "manual" | "runtime_pressure" | "model_directed" = "manual",
|
|
34
|
+
automationPolicyId?: string,
|
|
35
|
+
): ContextRevisionFinishedData {
|
|
36
|
+
if (result.status === "unchanged") {
|
|
37
|
+
return {
|
|
38
|
+
strategy: "swap",
|
|
39
|
+
reason,
|
|
40
|
+
policyVersion: "swap-only-v1",
|
|
41
|
+
outcome: result.outcome,
|
|
42
|
+
baseRevisionNumber: result.revisionNumber,
|
|
43
|
+
addedOverrideCount: 0,
|
|
44
|
+
activeOverrideCount: result.activeOverrideCount,
|
|
45
|
+
originalObservationBytes: 0,
|
|
46
|
+
projectedObservationBytes: 0,
|
|
47
|
+
rawTokensBefore: result.rawTokensBefore,
|
|
48
|
+
guardedTokensBefore: result.guardedTokensBefore,
|
|
49
|
+
targetTokens: result.targetTokens,
|
|
50
|
+
durationMs: result.durationMs,
|
|
51
|
+
...(automationPolicyId === undefined ? {} : { automationPolicyId }),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
strategy: "swap",
|
|
56
|
+
reason,
|
|
57
|
+
policyVersion: "swap-only-v1",
|
|
58
|
+
outcome: result.outcome,
|
|
59
|
+
baseRevisionNumber: result.previousRevisionNumber,
|
|
60
|
+
revisionNumber: result.revisionNumber,
|
|
61
|
+
addedOverrideCount: result.addedOverrideCount,
|
|
62
|
+
activeOverrideCount: result.activeOverrideCount,
|
|
63
|
+
originalObservationBytes: result.originalObservationBytes,
|
|
64
|
+
projectedObservationBytes: result.projectedObservationBytes,
|
|
65
|
+
rawTokensBefore: result.rawTokensBefore,
|
|
66
|
+
rawTokensAfter: result.rawTokensAfter,
|
|
67
|
+
guardedTokensBefore: result.guardedTokensBefore,
|
|
68
|
+
guardedTokensAfter: result.guardedTokensAfter,
|
|
69
|
+
targetTokens: result.targetTokens,
|
|
70
|
+
planHash: result.planHash,
|
|
71
|
+
durationMs: result.durationMs,
|
|
72
|
+
...(automationPolicyId === undefined ? {} : { automationPolicyId }),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function contextRetirementFinishedData(
|
|
77
|
+
result: ContextRetirementResult,
|
|
78
|
+
reason: "manual" | "runtime_pressure" = "manual",
|
|
79
|
+
automationPolicyId?: string,
|
|
80
|
+
): ContextRevisionFinishedData {
|
|
81
|
+
if (result.status === "unchanged") {
|
|
82
|
+
return {
|
|
83
|
+
strategy: "retire_prefix",
|
|
84
|
+
reason,
|
|
85
|
+
policyVersion: "recall-first-retirement-v1",
|
|
86
|
+
outcome: result.outcome,
|
|
87
|
+
baseRevisionNumber: result.revisionNumber,
|
|
88
|
+
previousKeepFromOrdinal: result.keepFromOrdinal,
|
|
89
|
+
keepFromOrdinal: result.keepFromOrdinal,
|
|
90
|
+
retiredTurnCount: 0,
|
|
91
|
+
retiredFrameCount: 0,
|
|
92
|
+
retiredMessageCount: 0,
|
|
93
|
+
activeOverrideCount: result.activeOverrideCount,
|
|
94
|
+
guardedTokensBefore: result.guardedTokensBefore,
|
|
95
|
+
targetTokens: result.targetTokens,
|
|
96
|
+
planningDurationMs: result.planningDurationMs,
|
|
97
|
+
durationMs: result.durationMs,
|
|
98
|
+
...(automationPolicyId === undefined ? {} : { automationPolicyId }),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
strategy: "retire_prefix",
|
|
103
|
+
reason,
|
|
104
|
+
policyVersion: "recall-first-retirement-v1",
|
|
105
|
+
outcome: result.outcome,
|
|
106
|
+
baseRevisionNumber: result.previousRevisionNumber,
|
|
107
|
+
revisionNumber: result.revisionNumber,
|
|
108
|
+
previousKeepFromOrdinal: result.previousKeepFromOrdinal,
|
|
109
|
+
keepFromOrdinal: result.keepFromOrdinal,
|
|
110
|
+
retiredTurnCount: result.retiredTurnCount,
|
|
111
|
+
retiredFrameCount: result.retiredFrameCount,
|
|
112
|
+
retiredMessageCount: result.retiredMessageCount,
|
|
113
|
+
activeOverrideCount: result.activeOverrideCount,
|
|
114
|
+
rawTokensBefore: result.rawTokensBefore,
|
|
115
|
+
rawTokensAfter: result.rawTokensAfter,
|
|
116
|
+
guardedTokensBefore: result.guardedTokensBefore,
|
|
117
|
+
guardedTokensAfter: result.guardedTokensAfter,
|
|
118
|
+
targetTokens: result.targetTokens,
|
|
119
|
+
planHash: result.planHash,
|
|
120
|
+
planningDurationMs: result.planningDurationMs,
|
|
121
|
+
validationDurationMs: result.validationDurationMs,
|
|
122
|
+
transactionDurationMs: result.transactionDurationMs,
|
|
123
|
+
activationDurationMs: result.activationDurationMs,
|
|
124
|
+
durationMs: result.durationMs,
|
|
125
|
+
...(automationPolicyId === undefined ? {} : { automationPolicyId }),
|
|
126
|
+
};
|
|
127
|
+
}
|