tinker-agent 1.9.0 → 1.11.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 +36 -1
- package/README.md +64 -6
- package/package.json +1 -1
- package/src/agent/loop.ts +17 -0
- package/src/agent/runtime-session.ts +341 -1
- package/src/agent/session-ledger.ts +100 -3
- package/src/cli/config.ts +11 -2
- package/src/cli/model-profiles.ts +58 -0
- package/src/cli/public-config-contract.ts +73 -7
- package/src/cli/run-runner.ts +4 -1
- package/src/cli/runner-dependencies.ts +28 -4
- package/src/cli/tui-memory.ts +4 -0
- package/src/cli/tui-runner.tsx +8 -1
- package/src/context/context-automation-policy.ts +22 -21
- package/src/context/context-manager.ts +91 -15
- package/src/context/context-policy.ts +0 -2
- package/src/context/context-swap-renderer.ts +1 -1
- package/src/context/prefix-retirement-planner.ts +58 -8
- package/src/context/recall-retirement-contract.ts +5 -4
- package/src/context/swap-planner.ts +33 -27
- package/src/events/observation-text-log.ts +4 -0
- package/src/events/stdout-event-printer.ts +5 -0
- package/src/events/types.ts +5 -1
- package/src/model/fake-model-client.ts +55 -16
- package/src/model/model-api.ts +12 -0
- package/src/model/model-client.ts +9 -1
- package/src/model/moonshot-input-token-estimator.ts +5 -1
- package/src/model/openai-chat-mapping.ts +2 -24
- package/src/model/openai-chat-model-client.ts +18 -294
- package/src/model/openai-image-mapping.ts +20 -0
- package/src/model/openai-model-utils.ts +304 -0
- package/src/model/openai-responses-mapping.ts +532 -0
- package/src/model/openai-responses-model-client.ts +295 -0
- package/src/model/openai-responses-stream.ts +96 -0
- package/src/model/openai-responses-token-estimator.ts +155 -0
- package/src/model/reasoning-effort.ts +60 -0
- package/src/session/session-catalog.ts +2 -2
- package/src/session/session-history-reader.ts +6 -1
- package/src/session/session-schema.ts +268 -4
- package/src/session/session-store.ts +134 -26
- package/src/skills/skill-context.ts +2 -2
- package/src/tools/bounded-output-preview.ts +276 -0
- package/src/tools/recall.ts +67 -36
- package/src/tools/registry.ts +7 -2
- package/src/tools/task-output-snapshot.ts +6 -22
- package/src/tools/task-output.ts +23 -27
- package/src/tui/app.tsx +153 -11
- package/src/tui/components/footer.tsx +6 -1
- package/src/tui/components/prompt-input.tsx +9 -1
- package/src/tui/event-store.ts +15 -0
- package/src/tui/slash-commands.ts +20 -0
- package/src/tui/tui-session-controller.ts +14 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,39 @@ All notable user-facing changes to Tinker are documented here. The project follo
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [1.11.0] - 2026-08-15
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Allow text follow-up prompts to be queued while a turn is running. Follow-ups
|
|
13
|
+
are applied safely after a complete tool batch or handed off to a new turn
|
|
14
|
+
after a final response, while preserving canonical session history and TUI
|
|
15
|
+
continuity.
|
|
16
|
+
|
|
17
|
+
## [1.10.1] - 2026-08-15
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Add an OpenAI Responses API adapter selectable per model profile, including
|
|
22
|
+
stateless request mapping, streaming, reasoning output, tool calls, image
|
|
23
|
+
input, token estimation, and compatible encrypted reasoning items.
|
|
24
|
+
- Add per-profile reasoning effort configuration and a session-runtime
|
|
25
|
+
`/reasoning` control. The TUI displays the active effort, and `Ctrl+R` cycles
|
|
26
|
+
through supported efforts in profile order without changing configuration or
|
|
27
|
+
canonical history.
|
|
28
|
+
- Add a model provider configuration guide with ready-to-adapt examples for
|
|
29
|
+
OpenAI, Kimi K3, and Zhipu GLM-5.2.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- Split historical session retrieval into `RecallSearch` and `RecallGet`, so the
|
|
34
|
+
agent can locate relevant history before retrieving exact bounded content.
|
|
35
|
+
- Track active-turn tool-output consumption when maintaining context, allowing
|
|
36
|
+
already-consumed observations to be compacted safely during long-running
|
|
37
|
+
turns.
|
|
38
|
+
- Bound Bash and background-task output previews while preserving complete
|
|
39
|
+
output in log files for paginated inspection.
|
|
40
|
+
|
|
8
41
|
## [1.9.0] - 2026-08-04
|
|
9
42
|
|
|
10
43
|
### Added
|
|
@@ -175,7 +208,9 @@ All notable user-facing changes to Tinker are documented here. The project follo
|
|
|
175
208
|
- First formal npm release under the `tinker-agent` package name with the `tinker`
|
|
176
209
|
executable.
|
|
177
210
|
|
|
178
|
-
[Unreleased]: https://github.com/ishowshao/tinker/compare/v1.
|
|
211
|
+
[Unreleased]: https://github.com/ishowshao/tinker/compare/v1.11.0...HEAD
|
|
212
|
+
[1.11.0]: https://github.com/ishowshao/tinker/releases/tag/v1.11.0
|
|
213
|
+
[1.10.1]: https://github.com/ishowshao/tinker/releases/tag/v1.10.1
|
|
179
214
|
[1.9.0]: https://github.com/ishowshao/tinker/releases/tag/v1.9.0
|
|
180
215
|
[1.8.0]: https://github.com/ishowshao/tinker/releases/tag/v1.8.0
|
|
181
216
|
[1.7.0]: https://github.com/ishowshao/tinker/releases/tag/v1.7.0
|
package/README.md
CHANGED
|
@@ -140,12 +140,13 @@ are required. Boolean environment values accept case-insensitive `true/false`,
|
|
|
140
140
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
141
141
|
| `TINKER_MODELS` | Model | All modes | No | Non-empty string | — | No | Optional model profiles JSON path. Relative paths resolve from the process cwd. |
|
|
142
142
|
| `TINKER_MODEL` | Model | Env mode | Env mode | Non-empty string | — | No | Model name used when model profiles are not configured. |
|
|
143
|
-
| `
|
|
143
|
+
| `TINKER_API` | Model | Env mode | No | Non-empty string | `"chat-completions"` | No | Model API adapter: "chat-completions" or "responses". |
|
|
144
|
+
| `TINKER_BASE_URL` | Model | Env mode | Env mode | Non-empty string | — | No | OpenAI-compatible API root URL; do not append /chat/completions or /responses. |
|
|
144
145
|
| `TINKER_API_KEY` | Model | Env mode | Env mode | Non-empty string | — | Yes | API credential for the configured model endpoint. |
|
|
145
146
|
| `TINKER_CONTEXT_WINDOW_TOKENS` | Model | Env mode | Env mode | Positive integer | — | No | Model context-window size in tokens. |
|
|
146
147
|
| `TINKER_MAX_SUPPORTED_OUTPUT_TOKENS` | Model | Env mode | Env mode | Positive integer | — | No | Maximum output-token count supported by the model; must not exceed the context window. |
|
|
147
|
-
| `TINKER_INCLUDE_REASONING_CONTENT` | Model | Env mode | No | Boolean | `false` | No |
|
|
148
|
-
| `TINKER_STREAM` | Model | Env mode | No | Boolean | `true` | No | Use streaming
|
|
148
|
+
| `TINKER_INCLUDE_REASONING_CONTENT` | Model | Env mode | No | Boolean | `false` | No | Replay provider reasoning_content in Chat Completions history; ignored by Responses. |
|
|
149
|
+
| `TINKER_STREAM` | Model | Env mode | No | Boolean | `true` | No | Use streaming transport for the selected model API. |
|
|
149
150
|
| `TINKER_WEBFETCH_REFINE_MODEL` | Model | Env mode | No | Non-empty string | — | No | Optional WebFetch refiner model; currently must match TINKER_MODEL. |
|
|
150
151
|
| `TINKER_WORKSPACE` | Workspace | All modes | No | Non-empty string | Process cwd | No | Workspace path. Relative paths resolve from the process cwd. |
|
|
151
152
|
| `TINKER_MAX_ITERATIONS` | Workspace | All modes | No | Positive integer | `512` | No | Maximum agent-loop iterations per turn. |
|
|
@@ -174,21 +175,36 @@ switch to another profile. If `TINKER_MODELS` is not set, Tinker falls back to
|
|
|
174
175
|
the individual `TINKER_*` environment variables. A configured profiles file must
|
|
175
176
|
exist and be valid; Tinker does not silently fall back when it cannot be loaded.
|
|
176
177
|
|
|
178
|
+
For provider-specific examples and guidance on API adapters, model capabilities,
|
|
179
|
+
reasoning efforts, and context limits, see the
|
|
180
|
+
[`.tinker/models.json` provider configuration guide](docs/models-json-provider-guide.md).
|
|
181
|
+
|
|
177
182
|
<!-- BEGIN GENERATED: MODEL PROFILE FIELDS -->
|
|
178
183
|
Profile fields:
|
|
179
184
|
|
|
180
185
|
| Field | Required | Type / constraint | Default | Secret | Description |
|
|
181
186
|
| --- | --- | --- | --- | --- | --- |
|
|
182
187
|
| `model` | Yes | Non-empty string | — | No | Provider model name. |
|
|
183
|
-
| `
|
|
188
|
+
| `api` | No | Non-empty string | `"chat-completions"` | No | Model API adapter: "chat-completions" or "responses". |
|
|
189
|
+
| `apiBase` | Yes | Non-empty string | — | No | OpenAI-compatible API root URL; do not append /chat/completions or /responses. |
|
|
184
190
|
| `apiKey` | Yes | Non-empty string | — | Yes | API credential for this profile. |
|
|
185
191
|
| `contextWindowTokens` | Yes | Positive integer | — | No | Model context-window size in tokens. |
|
|
186
192
|
| `maxSupportedOutputTokens` | Yes | Positive integer | — | No | Maximum output-token count supported by the model; must not exceed contextWindowTokens. |
|
|
187
|
-
| `
|
|
188
|
-
| `
|
|
193
|
+
| `reasoning` | No | Object | — | No | Provider-specific reasoning efforts and the default for each new session runtime. |
|
|
194
|
+
| `includeReasoningContent` | No | JSON boolean | `false` | No | Replay provider reasoning_content in Chat Completions history; ignored by Responses. |
|
|
195
|
+
| `stream` | No | JSON boolean | `true` | No | Use streaming transport for the selected model API. |
|
|
189
196
|
| `inputModalities` | No | Normalized modality array | `["text"]` | No | Accepted model input modalities; normalizes to ["text"] or ["text", "image"]. |
|
|
190
197
|
| `tokenEstimator` | With image | Object | — | Yes | Independent token estimator required for image profiles. |
|
|
191
198
|
|
|
199
|
+
`reasoning` fields:
|
|
200
|
+
|
|
201
|
+
| Field | Type / constraint | Description |
|
|
202
|
+
| --- | --- | --- |
|
|
203
|
+
| `supportedEfforts` | Non-empty unique string array | Provider-supported effort values exposed by the /reasoning command. |
|
|
204
|
+
| `defaultEffort` | Non-empty string listed above | Effort used whenever a session runtime is created or reopened. |
|
|
205
|
+
|
|
206
|
+
The optional `reasoning` object declares provider-specific effort values. Efforts must be unique non-whitespace strings, `reset` is reserved by the TUI command, and `defaultEffort` must appear in `supportedEfforts`. Omitting `reasoning` sends no effort parameter and disables `/reasoning` for that profile.
|
|
207
|
+
|
|
192
208
|
`tokenEstimator` fields:
|
|
193
209
|
|
|
194
210
|
| Field | Type / constraint | Secret | Description |
|
|
@@ -212,6 +228,14 @@ Text-only profile example:
|
|
|
212
228
|
"apiKey": "your-model-api-key",
|
|
213
229
|
"contextWindowTokens": 128000,
|
|
214
230
|
"maxSupportedOutputTokens": 8192,
|
|
231
|
+
"reasoning": {
|
|
232
|
+
"supportedEfforts": [
|
|
233
|
+
"low",
|
|
234
|
+
"medium",
|
|
235
|
+
"high"
|
|
236
|
+
],
|
|
237
|
+
"defaultEffort": "medium"
|
|
238
|
+
},
|
|
215
239
|
"includeReasoningContent": false,
|
|
216
240
|
"stream": true,
|
|
217
241
|
"inputModalities": [
|
|
@@ -234,6 +258,14 @@ Image-capable profile example:
|
|
|
234
258
|
"apiKey": "your-model-api-key",
|
|
235
259
|
"contextWindowTokens": 128000,
|
|
236
260
|
"maxSupportedOutputTokens": 8192,
|
|
261
|
+
"reasoning": {
|
|
262
|
+
"supportedEfforts": [
|
|
263
|
+
"low",
|
|
264
|
+
"medium",
|
|
265
|
+
"high"
|
|
266
|
+
],
|
|
267
|
+
"defaultEffort": "medium"
|
|
268
|
+
},
|
|
237
269
|
"includeReasoningContent": false,
|
|
238
270
|
"stream": true,
|
|
239
271
|
"inputModalities": [
|
|
@@ -285,6 +317,14 @@ Atomic-memory profile example:
|
|
|
285
317
|
"apiKey": "your-model-api-key",
|
|
286
318
|
"contextWindowTokens": 128000,
|
|
287
319
|
"maxSupportedOutputTokens": 8192,
|
|
320
|
+
"reasoning": {
|
|
321
|
+
"supportedEfforts": [
|
|
322
|
+
"low",
|
|
323
|
+
"medium",
|
|
324
|
+
"high"
|
|
325
|
+
],
|
|
326
|
+
"defaultEffort": "medium"
|
|
327
|
+
},
|
|
288
328
|
"includeReasoningContent": false,
|
|
289
329
|
"stream": true,
|
|
290
330
|
"inputModalities": [
|
|
@@ -307,6 +347,12 @@ Atomic-memory profile example:
|
|
|
307
347
|
```
|
|
308
348
|
<!-- END GENERATED: MODEL PROFILE FIELDS -->
|
|
309
349
|
|
|
350
|
+
Set `api` to `"responses"` to use the standard Responses API. Keep `apiBase`
|
|
351
|
+
at the API root—such as `https://api.openai.com/v1`—because Tinker appends the
|
|
352
|
+
`/responses` route. Responses requests use the stateless common subset
|
|
353
|
+
(`store: false` with complete input history), so the same adapter works with
|
|
354
|
+
OpenAI and compatible providers that do not implement stored response chaining.
|
|
355
|
+
|
|
310
356
|
You can also select profiles explicitly for the TUI or one-shot command:
|
|
311
357
|
|
|
312
358
|
```bash
|
|
@@ -353,6 +399,7 @@ complete fixed policy and persistence contract.
|
|
|
353
399
|
| `/view <path>` | View a local UTF-8 text file |
|
|
354
400
|
| `/copy` | Copy the last response as Markdown |
|
|
355
401
|
| `/model [profile-name]` | Switch model profile (new session) |
|
|
402
|
+
| `/reasoning [effort\|reset]` | Show or change reasoning effort for this session runtime |
|
|
356
403
|
| `/resume [session-id]` | Choose or resume a session |
|
|
357
404
|
| `/session delete <session-id> --confirm` | Manage stored sessions |
|
|
358
405
|
| `/quit` | Exit the TUI |
|
|
@@ -364,6 +411,17 @@ swaps eligible historical tool output, while `/compact retire` retires a complet
|
|
|
364
411
|
cold prefix whose original history remains available through `Recall`. `/copy`
|
|
365
412
|
copies the last completed assistant response as raw Markdown.
|
|
366
413
|
|
|
414
|
+
Profiles that declare `reasoning` expose `/reasoning` as a session-runtime
|
|
415
|
+
control. `/reasoning <effort>` temporarily selects one of the profile's
|
|
416
|
+
`supportedEfforts`, and `/reasoning reset` restores `defaultEffort`. The
|
|
417
|
+
selection is not written to configuration or canonical history: `/clear`,
|
|
418
|
+
`/fork`, `/model`, `/resume`, and a TUI restart create a new runtime from the
|
|
419
|
+
profile default. Responses requests send `reasoning.effort`; Chat Completions
|
|
420
|
+
requests send `reasoning_effort`. Press `Ctrl+R` while the prompt is idle to cycle
|
|
421
|
+
through `supportedEfforts` in profile order, wrapping from the last effort to the
|
|
422
|
+
first. When configured, the TUI information line shows the live effort immediately
|
|
423
|
+
after the model name, for example `gpt-5.6-sol max`.
|
|
424
|
+
|
|
367
425
|
### Project Custom Slash Commands
|
|
368
426
|
|
|
369
427
|
The TUI loads optional project-scoped prompt aliases from `.tinker.json` in the
|
package/package.json
CHANGED
package/src/agent/loop.ts
CHANGED
|
@@ -93,6 +93,7 @@ const MODEL_REQUEST_MAX_ATTEMPTS =
|
|
|
93
93
|
|
|
94
94
|
export async function runAgent(input: RunAgentInput): Promise<RunAgentResult> {
|
|
95
95
|
let lastIteration: IterationIdentity | undefined;
|
|
96
|
+
let consumedThroughOrdinal = 1;
|
|
96
97
|
const committedPrefixAuditor =
|
|
97
98
|
input.committedPrefixAuditor ?? new CommittedPrefixAuditor();
|
|
98
99
|
|
|
@@ -154,6 +155,7 @@ export async function runAgent(input: RunAgentInput): Promise<RunAgentResult> {
|
|
|
154
155
|
built,
|
|
155
156
|
prepared,
|
|
156
157
|
preflight,
|
|
158
|
+
consumedThroughOrdinal,
|
|
157
159
|
});
|
|
158
160
|
try {
|
|
159
161
|
input.contextMeter.assertWithinBudget(preflight);
|
|
@@ -365,6 +367,7 @@ export async function runAgent(input: RunAgentInput): Promise<RunAgentResult> {
|
|
|
365
367
|
},
|
|
366
368
|
});
|
|
367
369
|
const measured = input.contextMeter.recordProviderUsage(request, modelOutput);
|
|
370
|
+
consumedThroughOrdinal = built.canonical.messages.length;
|
|
368
371
|
await input.runtimeSession.append({
|
|
369
372
|
type: "context.usage.updated",
|
|
370
373
|
...iteration,
|
|
@@ -495,12 +498,21 @@ export async function runAgent(input: RunAgentInput): Promise<RunAgentResult> {
|
|
|
495
498
|
}
|
|
496
499
|
}
|
|
497
500
|
|
|
501
|
+
await input.runtimeSession.applyQueuedSteering?.({
|
|
502
|
+
turn: input.turn,
|
|
503
|
+
ledger: input.ledger,
|
|
504
|
+
});
|
|
498
505
|
await input.runtimeSession.append({
|
|
499
506
|
type: "agent.iteration.finished",
|
|
500
507
|
...iteration,
|
|
501
508
|
data: { outcome: "continue", toolCallCount: toolCalls.length },
|
|
502
509
|
});
|
|
503
510
|
input.runtimeSession.finishIterationForContinuation(iteration);
|
|
511
|
+
await input.runtimeSession.maintainContextAfterIteration?.({
|
|
512
|
+
turn: input.turn,
|
|
513
|
+
consumedThroughOrdinal,
|
|
514
|
+
ledger: input.ledger,
|
|
515
|
+
});
|
|
504
516
|
}
|
|
505
517
|
|
|
506
518
|
if (lastIteration === undefined) {
|
|
@@ -520,6 +532,7 @@ async function runShadowPlanning(input: {
|
|
|
520
532
|
built: BuiltContextRequest;
|
|
521
533
|
prepared: PreparedModelRequest;
|
|
522
534
|
preflight: ReturnType<ContextMeter["measure"]>;
|
|
535
|
+
consumedThroughOrdinal: number;
|
|
523
536
|
}): Promise<void> {
|
|
524
537
|
const shadowPlanning = input.input.shadowPlanning;
|
|
525
538
|
if (shadowPlanning === undefined) {
|
|
@@ -547,6 +560,10 @@ async function runShadowPlanning(input: {
|
|
|
547
560
|
tools: input.input.tools.definitions(),
|
|
548
561
|
policy: swapOnlyPolicyV1,
|
|
549
562
|
trigger: decision.trigger,
|
|
563
|
+
activeTurn: {
|
|
564
|
+
turnId: input.input.turn.turnId,
|
|
565
|
+
consumedThroughOrdinal: input.consumedThroughOrdinal,
|
|
566
|
+
},
|
|
550
567
|
...(decision.forcedTargetTokens === undefined
|
|
551
568
|
? {}
|
|
552
569
|
: { forcedTargetTokens: decision.forcedTargetTokens }),
|