Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
314 commits
Select commit Hold shift + click to select a range
ce40b61
Merge remote-tracking branch 'origin/feat/harness-p9-coding-agents' i…
AlemTuzlak Sep 28, 2026
d3a80ca
fix(ai-harness): the goal plugin drops its queued turn when the goal …
AlemTuzlak Sep 28, 2026
154e0ac
test(ai-isolate-daytona): cover each timeout branch with a controlled…
AlemTuzlak Sep 28, 2026
8b46a04
feat(ai-harness): session.transcript(), session.describe(), and plugi…
AlemTuzlak Sep 28, 2026
7364ac5
feat(ai-harness): remote transcript and describe reads, client answer…
AlemTuzlak Sep 28, 2026
7779044
feat(ai-harness): session view state and its pure reducer
AlemTuzlak Sep 28, 2026
3bf4c0c
feat(ai-harness): createSessionView, a live TanStack Store view of a …
AlemTuzlak Sep 28, 2026
c902163
feat(ai-harness): selectGoal reads the goal from a session view
AlemTuzlak Sep 28, 2026
4f87a94
docs(ai-harness): build your own UI with createSessionView
AlemTuzlak Sep 28, 2026
3a53aa2
feat(ai-harness-cli)!: no UI library in the CLI; runCli({ ui }) runs …
AlemTuzlak Sep 28, 2026
9d7d383
refactor(ai-harness-cli): line mode prints from the session view; rem…
AlemTuzlak Sep 28, 2026
fb1f97e
test(ai-harness): cover the session view paths
AlemTuzlak Sep 28, 2026
7a2dd08
docs(ai-harness-cli): your own screen with runCli({ ui }), and an Ink…
AlemTuzlak Sep 28, 2026
1e1f1e9
Merge remote-tracking branch 'origin/feat/harness-p11-session-view' i…
AlemTuzlak Sep 28, 2026
281d37b
chore(examples): ts-solid-chat uses the latest @tanstack/solid-store
AlemTuzlak Sep 28, 2026
83825af
feat(ai, ai-harness): agentMiddleware runs plugin middleware in every…
AlemTuzlak Sep 28, 2026
6d97231
docs(ai-harness): middleware in every agent
AlemTuzlak Sep 28, 2026
ac2c148
Merge remote-tracking branch 'origin/feat/harness-p12-cli' into feat/…
AlemTuzlak Sep 28, 2026
47ee22f
feat(ai-harness): usage() counts the model calls of every agent
AlemTuzlak Sep 28, 2026
54cc422
Merge remote-tracking branch 'origin/main' into feat/harness-p0-groun…
AlemTuzlak Sep 28, 2026
474f1a3
Merge branch 'feat/harness-p0-groundwork' into feat/harness-p1-core
AlemTuzlak Sep 28, 2026
c2d3534
Merge branch 'feat/harness-p1-core' into feat/harness-p2-protocols
AlemTuzlak Sep 28, 2026
07f0df9
Merge branch 'feat/harness-p2-protocols' into feat/harness-p3-plugins
AlemTuzlak Sep 28, 2026
88d3d09
Merge branch 'feat/harness-p3-plugins' into feat/harness-p4-subagents
AlemTuzlak Sep 28, 2026
59aae84
Merge branch 'feat/harness-p4-subagents' into feat/harness-p5-build
AlemTuzlak Sep 28, 2026
b08b64a
Merge branch 'feat/harness-p5-build' into feat/harness-p6-dashboard
AlemTuzlak Sep 28, 2026
1f24e28
Merge branch 'feat/harness-p6-dashboard' into feat/harness-p7-connect…
AlemTuzlak Sep 28, 2026
17f92ef
Merge branch 'feat/harness-p7-connectors-media' into feat/harness-p8-…
AlemTuzlak Sep 28, 2026
c782dc2
Merge branch 'feat/harness-p8-code-mode' into feat/harness-p9-coding-…
AlemTuzlak Sep 28, 2026
fa9d2ca
Merge branch 'feat/harness-p9-coding-agents' into feat/harness-p10-goal
AlemTuzlak Sep 28, 2026
556d68a
Merge branch 'feat/harness-p10-goal' into feat/harness-p11-session-view
AlemTuzlak Sep 28, 2026
7790e06
Merge branch 'feat/harness-p11-session-view' into feat/harness-p12-cli
AlemTuzlak Sep 28, 2026
a3b364b
Merge branch 'feat/harness-p12-cli' into feat/harness-p13-agent-middl…
AlemTuzlak Sep 28, 2026
ff6844a
feat(ai-mcp): serve a harness as an MCP server
AlemTuzlak Sep 28, 2026
c341668
feat(ai-harness-cli): add --mcp and --yes, and serve MCP at /mcp
AlemTuzlak Sep 28, 2026
d66990e
docs(harness): use a harness from any MCP client
AlemTuzlak Sep 28, 2026
e6f3fa2
test(ai-mcp): cover the connector branches after the v2 client move
AlemTuzlak Sep 28, 2026
d28914b
fix(ai-mcp): concrete .d.ts import path, and cover the harness MCP se…
AlemTuzlak Sep 28, 2026
5945199
fix(ai-mcp): answer each interrupt kind the right way in the harness …
AlemTuzlak Sep 28, 2026
905d9f7
Merge the P7 connector tests into the combined branch
AlemTuzlak Sep 28, 2026
c480fc3
fix(ai-mcp): connector sign-in replaces old tokens, clear auth errors…
AlemTuzlak Sep 28, 2026
4db4610
feat(ai, ai-harness): runtime inputModalities on text adapters, and h…
AlemTuzlak Sep 29, 2026
9ed41b5
feat: provider inputModalities, harness media store, view media parts…
AlemTuzlak Sep 29, 2026
2026619
feat(ai-harness): keep agent media, send stored files to the model, a…
AlemTuzlak Sep 29, 2026
9f68d1e
feat(ai-harness, ai-acp): HTTP media routes with signed URLs, media t…
AlemTuzlak Sep 29, 2026
116f1de
feat(ai-mcp): harness MCP media (attachments, media in results, media…
AlemTuzlak Sep 29, 2026
f10e6f5
feat(ai-harness-cli): attach files with @path, save media to a folder…
AlemTuzlak Sep 29, 2026
44dfbe8
docs(harness): send and show media; example keeps agent media
AlemTuzlak Sep 29, 2026
fc24c4c
chore: changeset for harness media
AlemTuzlak Sep 29, 2026
10f008d
feat(examples/harness-cli): voice input, every media kind, a model pi…
AlemTuzlak Sep 29, 2026
3f1fc01
ci: apply automated fixes
autofix-ci[bot] Sep 29, 2026
6882cd7
feat(examples/harness-cli): a nicer screen, hold-to-talk voice, and t…
AlemTuzlak Sep 29, 2026
6a90d92
feat(ai, ai-harness, ai-openrouter): users connect their own model pr…
AlemTuzlak Sep 29, 2026
4b61d2b
feat(examples/harness-cli): command history, / suggestions, pickers, …
AlemTuzlak Sep 30, 2026
278c5ec
docs: refresh updatedAt for the provider keys and coding agent pages
AlemTuzlak Sep 30, 2026
fd49987
fix(ai-harness, ai-mcp): Linear sign-in; feat(examples/harness-cli): …
AlemTuzlak Sep 30, 2026
9030d69
Merge origin/main into feat/harness-p14-mcp-server
AlemTuzlak Sep 30, 2026
432817b
feat(ai-persistence): add the LogStore contract, a memory log store, …
AlemTuzlak Sep 30, 2026
f3d6ab1
feat(ai-harness): input ids, settlement and receipt types, durability…
AlemTuzlak Sep 30, 2026
e62ee9f
feat(ai-harness): configurable lease, tool error on the crash note, a…
AlemTuzlak Sep 30, 2026
0db128c
test(ai-harness): guard harness core against Node-only imports
AlemTuzlak Sep 30, 2026
4a52a6a
chore: changeset for the harness durable session log
AlemTuzlak Sep 30, 2026
8bbd84b
feat(ai-harness): durableTool with step.do and staged append
AlemTuzlak Sep 30, 2026
6b7b997
feat(ai-harness): session log writer, fold, checkpoints, and logMessa…
AlemTuzlak Sep 30, 2026
892aac4
docs(persistence): the LogStore contract for backend authors
AlemTuzlak Sep 30, 2026
6d593fa
feat(ai-harness): durable mode with a session log (events, transcript…
AlemTuzlak Sep 30, 2026
615b21c
feat(ai-harness): input ids, receipts, settlement, attempt budget, ti…
AlemTuzlak Sep 30, 2026
e571a53
feat(ai-harness): durable ordered joins, and late steers answered in …
AlemTuzlak Sep 30, 2026
c98ae3d
test(e2e): a duplicate inputId over the harness protocol runs once
AlemTuzlak Sep 30, 2026
58d4c2b
feat(ai-harness): durable tool steps, kept tool results, and staged r…
AlemTuzlak Sep 30, 2026
740e3ae
docs(harness): durable sessions, inputs, durable tools, and the sessi…
AlemTuzlak Sep 30, 2026
dc92d10
feat(ai, ai-models): chat({ reasoning }) and the @tanstack/ai-models …
AlemTuzlak Sep 30, 2026
ba8cc2b
feat(ai-openai, openai-base)!: chat({ reasoning }) and openaiCompatib…
AlemTuzlak Sep 30, 2026
7788856
feat(ai-anthropic)!: map chat({ reasoning }) to Claude thinking
AlemTuzlak Sep 30, 2026
dcf6f7e
feat(ai-gemini)!: map chat({ reasoning }) to Gemini thinking
AlemTuzlak Sep 30, 2026
253888d
feat(openai-base): send chat({ reasoning }) from a modelReasoning hook
AlemTuzlak Sep 30, 2026
4fcfaf6
feat(ai-bedrock)!: map chat({ reasoning }) on all three Bedrock APIs
AlemTuzlak Sep 30, 2026
428bbad
feat(ai-mistral): map chat({ reasoning }) to Mistral reasoning fields
AlemTuzlak Sep 30, 2026
49d15df
feat(ai-grok)!: map chat({ reasoning }) to xAI reasoning.effort
AlemTuzlak Sep 30, 2026
3123368
feat(ai-openrouter)!: map chat({ reasoning }) to OpenRouter reasoning
AlemTuzlak Sep 30, 2026
e437a7b
feat(gateways)!: map chat({ reasoning }) on the gateway adapters
AlemTuzlak Sep 30, 2026
1a973d9
feat(adapters)!: map chat({ reasoning }) on Groq, Ollama, BytePlus, C…
AlemTuzlak Sep 30, 2026
7c60206
fix(ai-anthropic): use budget thinking on Claude before 4.6
AlemTuzlak Sep 30, 2026
1bc4177
chore(examples): set reasoning with chat({ reasoning })
AlemTuzlak Sep 30, 2026
5d87fa1
docs: chat({ reasoning }), the reasoning migration, and the model cat…
AlemTuzlak Sep 30, 2026
15aa370
chore: changesets for chat({ reasoning }) and @tanstack/ai-models
AlemTuzlak Sep 30, 2026
f00762c
Merge origin/feat/harness-p14-mcp-server into feat/ai-models-reasoning
AlemTuzlak Sep 30, 2026
7b61267
fix(ai): run the server tools of one model turn at the same time
AlemTuzlak Sep 30, 2026
bbe7796
fix(ai, ai-anthropic): send redacted thinking and tool errors back to…
AlemTuzlak Sep 30, 2026
d4f41e8
feat(ai): isContextOverflow finds context-window overflows across pro…
AlemTuzlak Sep 30, 2026
1b0a5d2
feat(ai): fakeText scripted adapter at @tanstack/ai/testing
AlemTuzlak Sep 30, 2026
ca2a9df
feat(ai-cloudflare): cloudflareBindingFetch for anthropic/ and openai…
AlemTuzlak Sep 30, 2026
4b5e166
docs: stop the agent loop from a tool, and the new testing page in th…
AlemTuzlak Sep 30, 2026
ff20513
Merge branch 'fix/parallel-server-tools' into feat/loop-gaps
AlemTuzlak Sep 30, 2026
0cd4a56
Merge branch 'fix/anthropic-thinking-replay' into feat/loop-gaps
AlemTuzlak Sep 30, 2026
8a461de
fix(ai-cloudflare): show cloudflareBindingFetch with createAnthropicC…
AlemTuzlak Sep 30, 2026
eabb0c1
Merge origin/feat/harness-p14-mcp-server into feat/ai-models-reasoning
AlemTuzlak Oct 1, 2026
71c19da
Revert the draft parallel-tools and redacted-thinking commits
AlemTuzlak Oct 1, 2026
247a921
Merge origin/main into feat/ai-models-reasoning
AlemTuzlak Oct 1, 2026
97954de
test(ai-sandbox): call at most 3 coding agents in one step in the pla…
AlemTuzlak Oct 1, 2026
d996347
feat(examples): harness-cli model catalog, saved sessions, and a full…
AlemTuzlak Oct 1, 2026
988185f
feat(examples): harness-cli voice input fills the input line
AlemTuzlak Oct 1, 2026
6f1c28a
feat(examples): harness-cli suggests files and folders after @
AlemTuzlak Oct 1, 2026
55e5c93
feat(examples): harness-cli boot splash
AlemTuzlak Oct 1, 2026
d1a819b
fix(examples): harness-cli start without the .env message, cursor in …
AlemTuzlak Oct 1, 2026
eb13f8f
feat(ai-harness): a replay option on durableTool
AlemTuzlak Oct 1, 2026
4a73456
feat(ai-harness, ai-code-mode): live plugin commands and lazy code-mo…
AlemTuzlak Oct 1, 2026
0ef1028
test(ai-sandbox): call the plan-mode delegates in two model steps
AlemTuzlak Oct 1, 2026
a22ceac
fix(ai-harness): bind durable tools that a middleware returns
AlemTuzlak Oct 1, 2026
b0a8a73
feat(ai-skills): skills() harness plugin with live slash commands
AlemTuzlak Oct 1, 2026
a47f4f9
refactor(ai-harness): one log writer per log, with one fold per session
AlemTuzlak Oct 1, 2026
4a7e44d
feat(ai-harness): workspaceTools asks before a path outside the works…
AlemTuzlak Oct 1, 2026
95893b0
fix(ai-harness): close, failure, and checkpoint rules of a shared log
AlemTuzlak Oct 1, 2026
5ecb7f6
fix(ai-harness): give the log view back when a session fails to open
AlemTuzlak Oct 1, 2026
ae1d023
feat(ai-harness): sessions that share one log
AlemTuzlak Oct 1, 2026
2bff4d3
feat(ai-persistence): a LeaseStore type and the stores.leases key
AlemTuzlak Oct 1, 2026
96d33e9
fix(ai-harness): a host with reduce fits every HarnessHost parameter
AlemTuzlak Oct 1, 2026
36e4c0d
refactor(ai-harness): repairTranscript takes the pending tool calls
AlemTuzlak Oct 1, 2026
fc035aa
feat(ai-harness): turn leases from a host lease store
AlemTuzlak Oct 1, 2026
627776c
fix(ai-harness): release the turn lease before the turn ends
AlemTuzlak Oct 1, 2026
562f88a
feat(examples): harness CLI on Cloudflare
AlemTuzlak Oct 1, 2026
7770101
feat(ai-harness): keep started tool calls in the log
AlemTuzlak Oct 1, 2026
a7f2388
feat(ai-harness): types for the turn hooks
AlemTuzlak Oct 1, 2026
ce14a53
feat(ai-harness): a recover hook for durable inputs
AlemTuzlak Oct 1, 2026
efc4e59
feat(ai-harness): retryTransientErrors and isTransientModelError
AlemTuzlak Oct 1, 2026
467e77a
feat(ai-harness): retry a failed model call in the same turn
AlemTuzlak Oct 1, 2026
7b64428
fix(ai-harness): retry keeps the resume, the steer, and the earlier text
AlemTuzlak Oct 1, 2026
ab68c7b
feat(ai-harness): a beforeFinish hook that keeps the turn going
AlemTuzlak Oct 1, 2026
f049329
fix(ai-harness): a cancelled turn adds nothing from beforeFinish
AlemTuzlak Oct 1, 2026
2d49b76
docs(harness): turn control, shared logs, leases, recover, and the re…
AlemTuzlak Oct 1, 2026
9dfe29d
feat(ai-harness): stop a join at an aborted or refused steer
AlemTuzlak Oct 1, 2026
9b60dba
test(e2e): a retried 503 and a beforeFinish turn over the harness pro…
AlemTuzlak Oct 1, 2026
5d3b406
feat(ai-harness): an onJoin hook for joined inputs
AlemTuzlak Oct 1, 2026
e6cb8af
fix(ai-harness): recovery settles a cancelled input that never ran
AlemTuzlak Oct 1, 2026
8c9e2d3
chore: changeset for the generic harness host features
AlemTuzlak Oct 1, 2026
7b15764
fix(ai-harness): a join claims its steers, and a late cancel is refused
AlemTuzlak Oct 1, 2026
8e3c4d9
test(ai-harness): a join stops at a steer cancelled while canJoin runs
AlemTuzlak Oct 1, 2026
a89b522
Merge origin/feat/harness-p14-mcp-server into feat/harness-host-generic
AlemTuzlak Oct 1, 2026
40bce96
fix(ai-harness): fail a background agent that a stopped host left run…
AlemTuzlak Oct 2, 2026
ce2c04c
fix(ai-claude-code): count cache tokens in promptTokens
AlemTuzlak Oct 2, 2026
2e4184a
fix(ai-bedrock): count cache tokens in promptTokens
AlemTuzlak Oct 2, 2026
583d78c
fix(ai-anthropic): count cache tokens in promptTokens
AlemTuzlak Oct 2, 2026
52ea90b
fix(ai-openrouter): report cache-read tokens on the Responses adapter
AlemTuzlak Oct 2, 2026
24f899c
feat(ai): add the promptCache option to chat()
AlemTuzlak Oct 2, 2026
121ae82
feat(ai-bedrock): add automatic cache points for Claude models
AlemTuzlak Oct 2, 2026
c548cb4
feat(ai-openai): send prompt cache fields on Responses and Chat Compl…
AlemTuzlak Oct 2, 2026
608636c
feat(ai-mistral): send the prompt cache key and report cache reads
AlemTuzlak Oct 2, 2026
988d887
feat(ai-harness): cache prompts in every session by default
AlemTuzlak Oct 2, 2026
d4c8a3e
feat(ai-openrouter): add automatic cache markers for Claude models
AlemTuzlak Oct 2, 2026
574daab
feat(ai-anthropic): add automatic prompt cache markers
AlemTuzlak Oct 2, 2026
d067f6c
test(ai-cloudflare): prove the binding passes prompt cache fields thr…
AlemTuzlak Oct 2, 2026
819d221
feat(ai-openai): apply prompt cache rules to openaiCompatible
AlemTuzlak Oct 2, 2026
cc0db80
docs: add the prompt caching guide
AlemTuzlak Oct 2, 2026
efd2a18
test(e2e): check the prompt cache fields on the wire
AlemTuzlak Oct 2, 2026
41e8abb
chore: add the prompt caching changeset
AlemTuzlak Oct 2, 2026
b6a7500
Merge remote-tracking branch 'origin/feat/harness-p14-mcp-server' int…
AlemTuzlak Oct 2, 2026
79a8b37
Merge origin/main into feat/harness-p14-mcp-server
AlemTuzlak Oct 2, 2026
a501c7b
feat(ai, ai-harness): route a harness turn to root agents
AlemTuzlak Oct 2, 2026
5001eca
feat(ai): add the ModelMessage block order map and its helpers
AlemTuzlak Oct 2, 2026
6ef4847
fix(ai): text after a thinking block starts a new text part
AlemTuzlak Oct 2, 2026
1241689
fix(ai-anthropic): end each thinking block in the stream
AlemTuzlak Oct 2, 2026
c5beabf
test(ai-skills): cover the skill source and the failure paths of the …
AlemTuzlak Oct 2, 2026
5ca1582
Merge remote-tracking branch 'origin/feat/harness-p14-mcp-server' int…
AlemTuzlak Oct 2, 2026
0bd0739
feat(ai): chat() writes blockOrder on assistant messages
AlemTuzlak Oct 2, 2026
5cc000e
fix(ai-harness): run turn hooks in a handoff, and resume a subagents.…
AlemTuzlak Oct 2, 2026
6528940
feat(ai): keep the block order between UIMessage and ModelMessage
AlemTuzlak Oct 2, 2026
6c27489
feat(ai): add mid-conversation change types and helpers
AlemTuzlak Oct 2, 2026
d3f5790
fix(ai-harness): continue an interrupted turn after a restart
AlemTuzlak Oct 2, 2026
193ec94
test(ai-skills): cover load_skill, a removed skill, and a failed watcher
AlemTuzlak Oct 2, 2026
5c4f92a
feat(ai): add the mid-conversation planner and prompt hash
AlemTuzlak Oct 2, 2026
216faf4
feat(ai-anthropic): replay assistant blocks in their block order
AlemTuzlak Oct 2, 2026
d67e2f0
feat(openai-base): send mid-conversation changes in Responses requests
AlemTuzlak Oct 2, 2026
ddc0b2c
feat(ai): send and save mid-conversation changes in chat()
AlemTuzlak Oct 2, 2026
2ae57b5
test(ai-harness): keep the block order through the log and a rebuild
AlemTuzlak Oct 2, 2026
5f39276
test(ai-harness): keep the start tools across turns, a rebuild, and a…
AlemTuzlak Oct 2, 2026
7301f2f
fix(ai-persistence): keep the stored mid-conversation record when a c…
AlemTuzlak Oct 2, 2026
d8c0165
feat(ai): send assistant wire rows in block order and join them on th…
AlemTuzlak Oct 2, 2026
723e2a5
feat(ai-openai): use mid-conversation channels on the GPT models that…
AlemTuzlak Oct 2, 2026
017ac06
feat(ai-anthropic): use mid-conversation channels on the Claude model…
AlemTuzlak Oct 2, 2026
2558e7e
chore: add changesets for block order and mid-conversation changes
AlemTuzlak Oct 2, 2026
4851601
docs(ai): explain mid-conversation changes and the kept block order
AlemTuzlak Oct 2, 2026
3eb401f
test(ai-e2e): keep the order of a client tool answer with thinking
AlemTuzlak Oct 2, 2026
589b143
test(e2e): check mid-conversation tool changes on the wire
AlemTuzlak Oct 2, 2026
87b67bc
docs(ai): say when the mid-conversation record and the Claude beta apply
AlemTuzlak Oct 2, 2026
71f2591
Merge remote-tracking branch 'origin/feat/harness-p14-mcp-server' int…
AlemTuzlak Oct 2, 2026
81f4d9e
feat(ai): let a middleware set the prompt cache of a model call
AlemTuzlak Oct 2, 2026
b28bb79
fix(openai-base): send the function call namespace back to the Respon…
AlemTuzlak Oct 2, 2026
577ef1c
feat(ai-harness): add per-turn overrides to prompt() and followUp()
AlemTuzlak Oct 2, 2026
598bada
test(e2e): check per-turn overrides on the wire
AlemTuzlak Oct 2, 2026
328ee92
fix(ai-harness): take the same reasoning option as chat()
AlemTuzlak Oct 2, 2026
ceea3a4
docs: per-turn overrides, harness reasoning, and the cache in onConfig
AlemTuzlak Oct 2, 2026
a8b8d2d
chore: add the turn overrides changeset
AlemTuzlak Oct 2, 2026
75c87cd
feat(ai-mcp): fill missing schema fields and freeze tool annotations
AlemTuzlak Oct 3, 2026
347f692
feat(ai-mcp): add toolName to set the MCP tool names the model sees
AlemTuzlak Oct 3, 2026
eac67f2
feat(ai, ai-harness): add LogRecordsCapability and provide it on a du…
AlemTuzlak Oct 3, 2026
e9a713a
feat(ai-mcp): add requestOptions for MCP request timeouts
AlemTuzlak Oct 3, 2026
a5c8616
feat(ai-mcp): accept a strict list of tool names in toolFilter
AlemTuzlak Oct 3, 2026
f80e249
feat(ai-compaction): count tokens with the reported usage
AlemTuzlak Oct 3, 2026
1e89faf
test(ai-harness): check compaction-style records from a middleware
AlemTuzlak Oct 3, 2026
ccdef92
docs(ai-mcp): document toolName, requestOptions, and the toolFilter list
AlemTuzlak Oct 3, 2026
29694fc
test(e2e): check the MCP tool options on the wire
AlemTuzlak Oct 3, 2026
9f90723
feat(ai-compaction): add compactNext and the auto option
AlemTuzlak Oct 3, 2026
18314ec
feat(ai-compaction): report the reason, usage, and errors of a compac…
AlemTuzlak Oct 3, 2026
bca797c
feat(ai-compaction): durable compaction records and the after-turn check
AlemTuzlak Oct 3, 2026
2443f0c
feat(ai-compaction): turn cut, summary merge, and conversationSummarizer
AlemTuzlak Oct 4, 2026
2e7b5dd
fix(ai-harness): commit the engine list with log records from a middl…
AlemTuzlak Oct 4, 2026
eb034cb
test(e2e): check durable compaction in a harness session
AlemTuzlak Oct 4, 2026
a05e8c4
docs(ai-compaction): document usage counts, compactNext, durable comp…
AlemTuzlak Oct 4, 2026
6735e83
fix(ai): fakeText modalities, parentRunId, and unique tool call ids
AlemTuzlak Oct 5, 2026
0dd064b
feat(ai): let a tool that asks for input set the interrupt reason
AlemTuzlak Oct 5, 2026
5d6ba16
feat(ai-harness): per-input sender and context, useChat on POST run, …
AlemTuzlak Oct 5, 2026
6636a8f
fix(ai-mcp): keep the connector sign-in per sender
AlemTuzlak Oct 5, 2026
802377e
feat(ai-harness-cli): runCli takes a host and a principal
AlemTuzlak Oct 5, 2026
79e523a
test(e2e): check the harness run route, inputs, and a reloaded ChatCl…
AlemTuzlak Oct 5, 2026
3061750
docs(ai-harness): shared threads, useChat on POST run, client tools, …
AlemTuzlak Oct 5, 2026
c9f8e5f
chore: add changesets for the harness report fixes
AlemTuzlak Oct 5, 2026
fdb6d75
fix(ai): preserve replay and adapter behavior across saved turns
AlemTuzlak Oct 5, 2026
fdaeabe
Merge branch 'main' into feat/harness-p14-mcp-server
AlemTuzlak Oct 5, 2026
4c12b1e
fix(ai-harness): pass the parent run of a queued resume turn
AlemTuzlak Oct 5, 2026
01a42c2
ci: apply automated fixes
autofix-ci[bot] Oct 5, 2026
af7274d
fix(ai-compaction): fail the compaction when the summary is empty
AlemTuzlak Oct 5, 2026
581efd8
fix(ai-harness): keep a host record from the last model call of a turn
AlemTuzlak Oct 5, 2026
71d5e93
test(ai-mcp): count both tools/list walks in the sender isolation test
AlemTuzlak Oct 5, 2026
e677b75
fix(ai-harness): do not offer an interrupt again after its tool ran
AlemTuzlak Oct 5, 2026
343c8fb
feat(ai): add a durable step to the agent run context
AlemTuzlak Oct 5, 2026
bce32d6
feat(ai-harness): usage totals, resumable agents, thread settings, fo…
AlemTuzlak Oct 5, 2026
7e591a7
test(e2e): check usage, settings, reset, fork, and a resumable agent
AlemTuzlak Oct 5, 2026
20b7a86
docs(ai-harness): usage, fork and reset, thread settings, and resumab…
AlemTuzlak Oct 5, 2026
6f3ea4a
chore: add changesets for usage, settings, fork, reset, and resumable…
AlemTuzlak Oct 5, 2026
bf329d5
fix(ai): run a tool with no input or null arguments as {} again
AlemTuzlak Oct 5, 2026
c1e9fda
fix(ai): record no execute_tool span for a client tool
AlemTuzlak Oct 5, 2026
f02f0dd
test(e2e): keep two scenarios true under the final tool input check
AlemTuzlak Oct 5, 2026
f07b75e
test(e2e): count only this turn's tool results in the tools-test adapter
AlemTuzlak Oct 5, 2026
8092599
test: expect no input and null tool arguments to run as {} in adapter…
AlemTuzlak Oct 5, 2026
15868e6
test(ai-compaction): cover part text in the summary prompt and after-…
AlemTuzlak Oct 5, 2026
661c193
Merge branch 'main' into feat/harness-p14-mcp-server
AlemTuzlak Oct 6, 2026
6767029
feat: take a model's reasoning data from the adapter config
AlemTuzlak Oct 6, 2026
b24c0b6
feat(ai-models): price tiers and 1-hour cache writes, no Claude on go…
AlemTuzlak Oct 6, 2026
f317047
Merge branch 'main' into feat/harness-p14-mcp-server
AlemTuzlak Oct 6, 2026
d26ce8f
feat(openai-base): replay Responses answer items with their id and phase
AlemTuzlak Oct 6, 2026
c0d7bfe
docs: reasoning from the adapter config, catalog adapters, and cost r…
AlemTuzlak Oct 6, 2026
280263d
test(e2e): expect the failed-message mark on a chunk before RUN_ERROR
AlemTuzlak Oct 6, 2026
1d6c666
feat(examples): add Batman-themed harness CLI
AlemTuzlak Oct 6, 2026
bf5db16
ci: apply automated fixes
autofix-ci[bot] Oct 6, 2026
53fab01
fix(examples): resolve harness-cli-batman like harness-cli in the loc…
AlemTuzlak Oct 6, 2026
ef76ab6
Merge branch 'main' into feat/harness-p14-mcp-server
AlemTuzlak Oct 6, 2026
a0eb579
feat: send the Anthropic thinking shape that the model record gives
AlemTuzlak Oct 6, 2026
57ea69f
docs, e2e: the Anthropic thinking shape from the record
AlemTuzlak Oct 6, 2026
6656c1d
fix(ai-vercel-gateway): Gemma 4 31B reasons, as in the catalog
AlemTuzlak Oct 6, 2026
618d711
test(ai-isolate-e2b): cover stderr without an out-of-memory report
AlemTuzlak Oct 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
20 changes: 20 additions & 0 deletions .changeset/adapter-reasoning-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
'@tanstack/ai': minor
'@tanstack/ai-anthropic': minor
'@tanstack/ai-openai': minor
'@tanstack/ai-gemini': minor
'@tanstack/ai-bedrock': minor
'@tanstack/ai-mistral': minor
'@tanstack/ai-cloudflare': minor
'@tanstack/ai-models': minor
---

Give an adapter the model's reasoning data in its config. A model id that is not in the adapter's own list (a gateway id, a new model, or a catalog id) got no reasoning field before. Now `reasoning?: ModelReasoning` in the config wins over the adapter's table, for the request fields and for the levels that `chat({ reasoning })` takes. `false` sends no reasoning field. Without it, nothing changes.

The factories take any model id string: `anthropicText`, `createAnthropicChat`, `anthropicVertexText`, `openaiText`, `createOpenaiChat`, `azureOpenaiText`, `geminiText`, `createGeminiChat`, `createBedrockConverse`, `mistralText`, `createMistralText`, `cloudflareText`, and `createCloudflareText`. A misspelled id is no longer a type error.

`@tanstack/ai-models` adds `modelReasoning(record)`, which turns a catalog record into the config value:

```ts
createAnthropicChat(record.id, apiKey, { reasoning: modelReasoning(record) })
```
5 changes: 5 additions & 0 deletions .changeset/ai-models-catalog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai-models': minor
---

New package: a runtime catalog of 1,932 models across 38 providers, generated from models.dev and the OpenRouter and Vercel AI Gateway model lists. `getProviders`, `getModels`, and `getModel` return each model's id, input modalities, context window, output limit, prices, reasoning levels, and request quirks (`compat`). `supportedReasoningLevels`, `clampReasoningLevel`, and `modelCost` work on a record, and `generatedAt` is the time of the data. Each provider also has its own subpath, for example `@tanstack/ai-models/deepseek`.
5 changes: 5 additions & 0 deletions .changeset/ai-models-no-vertex-claude.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai-models': patch
---

Leave the Claude models out of the `google-vertex` catalog. They had the Gemini wire (`api: 'google-vertex'`), which the Gemini adapter cannot call. Use `anthropicVertexText` from `@tanstack/ai-anthropic/vertex` for Claude on Vertex.
5 changes: 5 additions & 0 deletions .changeset/ai-null-tool-input.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai': patch
---

Run a tool again when the model sends no input or a literal `null` for a tool with no required fields (an empty tool_use block, issue #265). The final tool input check rejected these, so the tool did not run. Now no input is `{}`, and a `null` that the schema rejects is checked as `{}`. Other values must still fit the schema.
16 changes: 16 additions & 0 deletions .changeset/anthropic-thinking-shape.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
'@tanstack/ai': minor
'@tanstack/ai-anthropic': minor
'@tanstack/ai-models': minor
'@tanstack/ai-vercel-gateway': patch
---

Send the Anthropic thinking shape that the model record gives.

- `ModelReasoning.adaptive`: `true` sends adaptive thinking with the effort, `false` sends budget thinking. Without it, the adapter picks from the model id, as before. Adaptive thinking without a level map now sends pi's default effort (`minimal` and `low` give `low`, `medium` gives `medium`, the rest give `high`).
- `ModelReasoning.midConversationEffort`: the level goes into the messages as an effort `system` message, with `block_binding`, a fixed `output_config.effort: 'high'`, and the `mid-conversation-output-config-2026-07-01` and `thinking-binding-controls-2026-08-01` betas. Each answer keeps its level in `metadata.tanstack.reasoningEffort`, so a level change keeps the cached start.
- `midConversationChannels` takes `{ tools?: boolean; systemPrompts?: boolean }` to turn on one channel only.

`modelReasoning(record)` sets `adaptive` from `compat.forceAdaptiveThinking` and `midConversationEffort` from the new `compat.supportsMidConvoEffort` for `anthropic-messages` records. The catalog flags now equal pi's: Claude 4.6 and later think adaptively on every provider (also with dot ids such as `anthropic/claude-opus-4.7`), and the other Vercel AI Gateway models think with a budget.

Vercel `google/gemma-4-31b-it` reasons, in the catalog and in `@tanstack/ai-vercel-gateway`. Vercel's own model list tags it `reasoning`. Seven Fireworks records take Fireworks' own effort levels.
12 changes: 12 additions & 0 deletions .changeset/block-order.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@tanstack/ai': minor
'@tanstack/ai-anthropic': minor
---

Keep the order of Claude's thinking, text, and tool calls in one answer.

- Claude can answer with thinking, a tool call, more thinking, and another tool call. The stream, the stored messages, the client wire, and the next request to Claude keep that order.
- `ModelMessage` has a new optional `blockOrder` field. The library writes it only when the order is not the default (thinking, then text, then tool calls), so a message in the default order does not change. `orderedAssistantBlocks(message)` gives adapter authors the blocks in order.
- Each Claude thinking block ends with its own `REASONING_MESSAGE_END` and `REASONING_END`.
- Text after a second thinking block starts a new text part.
- On the client wire, an answer in another order goes out as ordered rows. A row that exists only for the order has `metadata.tanstack.continues`, and the server joins it back into one message. A `UIMessage` that holds two model calls with a tool result between them reaches the server as assistant, tool, assistant, for every adapter.
9 changes: 9 additions & 0 deletions .changeset/cloudflare-binding-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@tanstack/ai-cloudflare': minor
---

Add `cloudflareBindingFetch({ binding, vendor, gateway })`. It sends the requests of the Anthropic and OpenAI text adapters (`createAnthropicChat`, `createOpenaiChat`) through the Workers AI binding (`env.AI.run`) to the AI Gateway `anthropic/...` and `openai/...` models, so a Worker can use Claude and GPT with no provider key.

- `vendor: 'anthropic'` carries Anthropic Messages requests, and `vendor: 'openai'` carries OpenAI Responses requests.
- The request body goes to `env.AI.run('<vendor>/<model>', body)`. Headers such as `anthropic-beta` go along as `extraHeaders`, and the SDK's auth and transport headers are dropped.
- A Cloudflare error body is rewrapped so the SDK reports its message.
5 changes: 5 additions & 0 deletions .changeset/compaction-empty-summary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai-compaction': patch
---

Fail a compaction when the summarizer returns an empty or whitespace-only summary. Before, `summarizeOldest` replaced the history with an empty summary, so the history was lost. Now the compaction fails like any failed strategy: the history stays, `compaction:ended` (or `onCompact` after the turn) carries the error, and no durable record is written. With `continueOnError`, the run sends the history as it is.
12 changes: 12 additions & 0 deletions .changeset/compaction-usage-and-durable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@tanstack/ai-compaction': minor
---

Count with real usage, compact on demand, and keep compaction in a harness log.

- `countTokens: 'usage'` counts with the usage the provider reported for the last call, plus an estimate of the newer messages.
- `compactNext(threadId)` compacts at the next model call, for example after a context overflow. `auto: false` turns off compaction at `maxTokens` and keeps `compactNext` and the overflow check.
- With `countTokens: 'usage'` and `durable: true`, a harness turn checks once more after its last model call. When the usage passed `maxTokens` or `contextWindow`, compaction runs right away. `contextWindow` also counts with `auto: false`.
- `durable: true` writes a `tanstack.compaction` record into a harness session log. Set `project: { version, record: projectCompaction }` on the host.
- `compaction:ended` and `onCompact` report `reason`, the summary `usage`, and an `error`. `continueOnError` sends the full messages when the strategy fails.
- `summarizeOldest({ cut: 'turn' })` gives the start of a cut turn its own summary. `conversationSummarizer` writes a structured summary, updates the older summary, and takes a `details` hook.
8 changes: 8 additions & 0 deletions .changeset/context-overflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@tanstack/ai': minor
---

Add `isContextOverflow({ error, usage, finishReason, contextWindow, provider })`. It tells you that a model call failed, or ended early, because the input did not fit in the model's context window, so you can compact the history and retry.

- It knows the overflow error messages of about 25 providers (Anthropic, OpenAI, Gemini, Bedrock, Mistral, xAI, Groq, OpenRouter, Ollama, and more), and it ignores rate-limit and throttle errors.
- With `contextWindow`, it also finds a silent overflow (the input is bigger than the window) and a length stop with no output and a full window.
5 changes: 5 additions & 0 deletions .changeset/core-provider-keys.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai': minor
---

`keyedAdapter(provider, create)` wraps an adapter factory that needs a provider key, and `isKeyedAdapter` tells it apart from a plain adapter. Agents get `ctx.keys` (`get`, `require`, and `adapter`) from the new `SubagentBinding.keys`, or else from each provider's `env` names.
9 changes: 9 additions & 0 deletions .changeset/fake-text-adapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@tanstack/ai': minor
---

Add `fakeText()` at the new `@tanstack/ai/testing` subpath: a text adapter that answers from a script, for tests of `chat()`, tools, and middleware with no network and no API key.

- Queue answers with `setResponses` and `appendResponses`. An answer is `{ text?, thinking?, toolCalls?, finishReason?, error? }`, or a function that gets `{ request, state }`. An empty queue fails with "No more fake responses queued".
- Token usage is estimated as `ceil(characters / 4)`. With `cache: true`, the part of a request that matches the thread's previous request counts as cached tokens.
- Options: `model`, `input` (the adapter's input modalities), `contextWindow`, and `tokensPerSecond` for stream pacing. The stream stops when the request aborts.
9 changes: 9 additions & 0 deletions .changeset/fake-text-fixes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@tanstack/ai': patch
---

Fix three problems in `fakeText` from `@tanstack/ai/testing`.

- `fakeText()` type-checks as a text adapter with `exactOptionalPropertyTypes: true`. `inputModalities` is now an optional property.
- `RUN_STARTED` carries `parentRunId` when the call has one, as real adapters do.
- Tool call ids are unique across `fakeText()` instances. The default id is now `fake-call-<fake>-<call>-<index>`.
7 changes: 7 additions & 0 deletions .changeset/harness-agent-restart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@tanstack/ai-harness': patch
---

A background agent run no longer stays `running` after its host stops. The agent run now holds a lease, like a chat turn. When the lease expires, the next host ends the run `failed` and adds a note to the transcript. On a durable host, it also settles the input and, for `start(input, { wake: true })`, starts a new turn. The run does not run again, because it has no checkpoints.

A background agent that fails now also writes a note, and with `wake: true` it starts a new turn, the same as an agent that finishes.
11 changes: 11 additions & 0 deletions .changeset/harness-auth-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@tanstack/ai': patch
'@tanstack/ai-harness': minor
---

A turn can wait for a sign-in and then go on.

- `ctx.credentials.require(id, { wait: true })`, and `token({ wait: true })` in an `oauthConnector`, stop the running chat turn with an interrupt whose `reason` is `'auth_required'`. Its payload has the connector id.
- When the credential is saved (the `connect:<id>` command, `/connect`, or `ctx.credentials.set`), the same turn goes on and the tool runs again. No new prompt is needed. On a durable host this also works after a restart.
- A resolve with `status: 'cancelled'` gives up: the tool fails as it does without `wait`.
- In `@tanstack/ai`, a tool that throws the MCP input-required shape can set the interrupt `reason`. MCP interrupts still use `'mcp_input'`.
9 changes: 9 additions & 0 deletions .changeset/harness-cli-host-principal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@tanstack/ai-harness-cli': minor
---

`runCli(harness, { host, principal })` can use your own host and user.

- `host`: the CLI uses this host and does not close it. Without it, the CLI makes its own host and closes it at the end.
- `principal`: every session the CLI opens runs as this principal, and `--serve` gives it to each request with the token. The default is still `{ id: 'cli' }`.
- `host` and `persistence` together fail with "Give runCli a host or persistence, not both."
8 changes: 8 additions & 0 deletions .changeset/harness-connect-iss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@tanstack/ai-harness': patch
'@tanstack/ai-mcp': patch
---

`/connect` now works with MCP servers that send `iss` on the sign-in callback (RFC 9207), such as Linear. `startLoopbackReceiver().waitForCode()` resolves `{ code, iss }`, and `mcpConnector` passes `iss` on to the MCP SDK. A sign-in error names the service, for example `Notion: Sign-in timed out.`

The session view clears the pending sign-in of a connector when its `connect:<id>` command ends.
5 changes: 5 additions & 0 deletions .changeset/harness-consume-ran-resume.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai-harness': patch
---

Do not offer an approval or a client-tool interrupt again after its tool ran. When a resumed turn failed, stopped, or hit its time limit after the tool ran, the interrupt came back, and answering it again ran the tool a second time. Now the harness marks it answered in the interrupt store, and a durable host without an interrupt store skips it when it rebuilds from the log. A resume that stops before its tool runs stays open for a retry.
23 changes: 23 additions & 0 deletions .changeset/harness-durable-log.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
'@tanstack/ai-persistence': minor
'@tanstack/ai-harness': minor
---

Add a durable session log. A harness session can now keep its events, transcript, inputs, and tool steps in one append-only log, so a turn survives a crash, a retry does not run an input twice, and a tool does not repeat a finished side effect.

`@tanstack/ai-persistence` adds the `LogStore` contract: `append` writes a batch at a position, all or nothing, and rejects with `LogConflictError` when another writer took that position. `read` and `subscribe` complete it. Put your store in `stores.log`. `defineLogStore` types an adapter, `memoryLogStore()` is the reference store, and `runPersistenceConformance` runs the log cases when `stores.log` is present.

`@tanstack/ai-harness` turns on durable mode when the host gets `stores.log` and `stores.runs`:

- `prompt`, `steer`, `followUp`, and `resolve` take an optional `inputId`, and so do `prompt`, `steer`, and `followUp` of `createHarnessClient`. The same id with the same payload does not run again. `Operation.receipt` resolves when the input is stored, and `session.settled(inputId)` gives how an input ended, also after a restart.
- `defineHarness({ durability: { maxAttempts, timeoutMs } })` limits each input. The default is 10 attempts and no timeout.
- `durableTool(definition, execute)` gives a tool `step.do(name, fn)`. After a crash, a finished step returns its stored value and does not run again. The tool's `append(records)` adds host records to the same append as the tool batch.
- `session.append(records)` adds host records to the log. The host option `project: { record, version }` folds host records into the model context. `logMessageStore` reads the transcript of a log outside a session.
- Host options `coalesceMs` (default 100 ms in durable mode) and `lease: { ttlMs, renewMs }`. Clients get a `harness.input.settled` event when an input ends.
- A `busy: 'steer'` prompt joins the running turn in the order it arrived, and it settles with that turn.

Breaking changes in the harness:

- `HarnessPersistence` is now a union of the current stores and the log stores.
- After a crash, the note for a tool that may have run now sets `error`, so the model sees a tool error.
- A steer that a turn did not reach is now answered in the same turn, not in a new turn.
13 changes: 13 additions & 0 deletions .changeset/harness-host-generic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@tanstack/ai-harness': minor
'@tanstack/ai-persistence': minor
---

Harness host features for frameworks that build on the harness:

- `host.open(harness, { threadId, logId })`: sessions that share one log. A record can name another session with `thread`, and `createHarnessHost({ reduce })` folds every host record of a log (`host.logState(logId)`).
- `durableTool(definition, execute, { replay: 'never' })`.
- `defineHarness({ turn: { onModelError, beforeFinish, maxFinishCycles, canJoin, onJoin } })`, `durability.recover`, `retryTransientErrors()`, and `isTransientModelError()`.
- `stores.leases` (`LeaseStore`): turn leases from your own system, in place of `stores.runs`.
- Durable tools that a middleware returns from `onConfig` get `step` and `append`.
- A waiting steer stops the join when it has an abort request, and `cancel` on it settles it `aborted`.
20 changes: 20 additions & 0 deletions .changeset/harness-input-sender-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
'@tanstack/ai-harness': minor
'@tanstack/ai-persistence': patch
'@tanstack/ai-mcp': patch
---

Each harness input carries its sender and its context.

- `prompt`, `steer`, `followUp` and `resolve` take `principal`. Without it, the input belongs to the principal that opened the session. `createHarnessHandler` and `handleHarnessSocket` run each input, and each command, as the principal that `authorize` returned for its request.
- The log keeps the sender of each input. The turn's tools, `ctx.session.principal`, `ctx.credentials` and `ctx.keys` use the turn's sender. A turn that waits for a sign-in continues only when its sender signs in.
- `turn.canJoin` gets the `principal` of each waiting input and the `turnPrincipal` of the running turn, so it can keep one person's message out of another person's turn. The `routing.router` context gets `principal` and `context`.
- Without `turn.canJoin`, a waiting message joins the running turn only when the same person sent both. A message from another person waits and runs as its own turn, as its sender.
- A command acts for the person who runs it: its `session.principal` is that person, and `session.prompt` from a command runs as that person. The wake turn after a background agent runs as the person who started the agent.
- `Principal.tenantId` goes into the credential scope, so two organizations' credentials for one user stay apart.
- A credential read finds the user's own credential first, then the tenant's (saved without a `userId`), so one key can serve a whole organization. Saves and deletes change the user's own credential only.
- `prompt`, `steer` and `followUp` take `context`: JSON data from the client, stored with the input and kept after a restart. `POST run` fills it from AG-UI `forwardedProps`. Tools get it merged with `HarnessConfig.context`, and the harness value wins for a key in both.
- A plugin `adapter(turn)` gets `TurnInfo`: the turn's `message`, `context`, `principal`, `inputId` and `overrides`. A plugin with `lifetime: 'turn'` gets the same as `ctx.turn` in `setup`.
- `CommandContext` has `principal` and `credentials` of the principal that ran the command.
- In `@tanstack/ai-persistence`, a stored input's `principal` can carry `tenantId`.
- `mcpConnector` keeps its sign-in state, client and tools per sender, so one person's MCP sign-in is not used for another person's turn.
5 changes: 5 additions & 0 deletions .changeset/harness-interrupt-restart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai-harness': patch
---

A resolve after a restart now continues the turn that stopped for an interrupt. Before, the waiting interrupts lived only in memory, so the next host refused the resolve with `no_pending_interrupts`. The session now keeps them in `stores.metadata`, with the agent cards of a routed turn, and the next host that opens the thread reads them back. A resolve removes the stored copy. Without a metadata store, the interrupts stay in memory, as before.
5 changes: 5 additions & 0 deletions .changeset/harness-keep-host-records.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai-harness': patch
---

Keep a host record that lands during the last model call of a turn. At the end of a turn, `withPersistence` tags older messages with the run, so the engine save rewrites them, and the log rebase then kept only the engine list. A host message that a record had folded in after the engine's last save was lost. Now the engine list still wins for the older messages, and the host messages that came after stay after it.
Loading
Loading