Repository navigation
feat(ai-persistence, ai-harness): identity and access, with tenants, shared sessions, and a run context - #1812
AlemTuzlak wants to merge 13 commits into
Conversation
…th owner, members, and required compare-and-set
…t as the user who started the run
… revoke, and handlers that fail closed
…and the run context
…and the CLI act as a principal
…he owner, host.hasAccess, and events wait for a new thread
|
| Name | Type |
|---|---|
| @tanstack/ai-harness-cli | Minor |
| @tanstack/ai-harness | Minor |
| @tanstack/ai-mcp | Minor |
| @tanstack/ai-acp | Minor |
| @tanstack/ai-persistence | Minor |
| @tanstack/ai-code-mode | Patch |
| @tanstack/ai-sandbox | Patch |
| @tanstack/ai-skills | Patch |
| @tanstack/ai-grok-build | Patch |
Click here to learn what changesets are, and how to add one.
Click here if you're a maintainer who wants to add a changeset to this PR
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
View your CI Pipeline Execution ↗ for commit cfa1721
☁️ Nx Cloud last updated this comment at |
@tanstack/ai
@tanstack/ai-acp
@tanstack/ai-angular
@tanstack/ai-anthropic
@tanstack/ai-bedrock
@tanstack/ai-byteplus
@tanstack/ai-claude-code
@tanstack/ai-client
@tanstack/ai-cloudflare
@tanstack/ai-code-mode
@tanstack/ai-code-mode-snippets
@tanstack/ai-codex
@tanstack/ai-cohere
@tanstack/ai-compaction
@tanstack/ai-devtools-core
@tanstack/ai-durable-stream
@tanstack/ai-elevenlabs
@tanstack/ai-event-client
@tanstack/ai-fal
@tanstack/ai-gemini
@tanstack/ai-grok
@tanstack/ai-grok-build
@tanstack/ai-groq
@tanstack/ai-harness
@tanstack/ai-harness-cli
@tanstack/ai-isolate-cloudflare
@tanstack/ai-isolate-daytona
@tanstack/ai-isolate-e2b
@tanstack/ai-isolate-node
@tanstack/ai-isolate-quickjs
@tanstack/ai-isolate-quickjs-bun
@tanstack/ai-llmgateway
@tanstack/ai-lovable
@tanstack/ai-mcp
@tanstack/ai-memory
@tanstack/ai-mistral
@tanstack/ai-octane
@tanstack/ai-ollama
@tanstack/ai-ollaya
@tanstack/ai-openai
@tanstack/ai-opencode
@tanstack/ai-openrouter
@tanstack/ai-perplexity
@tanstack/ai-persistence
@tanstack/ai-preact
@tanstack/ai-react
@tanstack/ai-react-ui
@tanstack/ai-reactor
@tanstack/ai-remix
@tanstack/ai-sandbox
@tanstack/ai-sandbox-blaxel
@tanstack/ai-sandbox-boxd
@tanstack/ai-sandbox-cloudflare
@tanstack/ai-sandbox-daytona
@tanstack/ai-sandbox-docker
@tanstack/ai-sandbox-e2b
@tanstack/ai-sandbox-local-process
@tanstack/ai-sandbox-railway
@tanstack/ai-sandbox-sprites
@tanstack/ai-sandbox-upstash-box
@tanstack/ai-sandbox-vercel
@tanstack/ai-skills
@tanstack/ai-solid
@tanstack/ai-solid-ui
@tanstack/ai-svelte
@tanstack/ai-typesafe
@tanstack/ai-utils
@tanstack/ai-vercel-gateway
@tanstack/ai-vertex
@tanstack/ai-vue
@tanstack/ai-vue-ui
@tanstack/ai-worldlabs
@tanstack/openai-base
@tanstack/preact-ai-devtools
@tanstack/react-ai-devtools
@tanstack/solid-ai-devtools
@tanstack/svelte-ai-devtools
commit: |
Coverage✅ Coverage held across 70 compared package(s). Each package is measured twice in this job — on this PR and on its merge-base with
|
Every harness session now belongs to one tenant, and only allowed users reach it. Add
access: { identify, authorize }to the host, or use the readymembersOnly()rule to share a session between users with roles. Each run acts as the user who started it, so a tool never gets another user's token. This is PR 3 of the harness redesign stack for #1755. It targets #1809 (feat/harness-api-shape).🎯 Changes
createHarnessHost({ access: { identify, authorize } }). The principal type is inferred fromidentify, soauthorizeand every host call are typed by it with no annotation.authorize.host.open(harness, { threadId, principal })returns a handle bound to that principal. A refused action throwsAccessDeniedError.access, there is one default tenant and no checks.membersOnly({ fork: { members: 'self' | 'all' } })has the roles owner, member, and viewer.host.sessions.share,unshare, andfork({ members })change the members.unsharecancels the removed user's work and closes their streams.host.revoke({ threadId, principal })is for apps with their own access tables.host.identify({ request })andhost.hasAccessare for your own routes.@tanstack/ai-persistenceis keyed by(tenantId, threadId), withownerIdandmembers.getVersionedandupsertIfare required,listreads one tenant, anddeleteis a hard delete.logIdOf({ tenantId, logId })), and so do metadata, inbox, work claims, runs, interrupts, messages, and media keys.host.openrefuses child threads.host.sessions.deletealso deletes the transcript.ctx.context.runin tools and middleware: tenant, user, log, thread, run, signal, credentials, and keys.ctx.credentialsandctx.keysthrow, because they have no user. This fixes D1: a background agent's tool got the token of whoever sent the latest turn.access.envKeys: true.createHarnessHandler,handleHarnessSocket, andcreateHarnessMcpServerread the user from the host'sidentify. Without host access they throw at the start, unless they setopenAccess: true | { principal }.principal(E7).Docs: a new
docs/harness/access.md, a rewrittenshared-threads.md, and 18 changed pages, includingstore-reference.md. Changesets: the unreleased harness, persistence, MCP, ACP, and CLI changesets are edited in place.Decisions made while building (the plan lists all of them):
ctx.context.run), so core does not change.events()keeps trying on 404, so a view of a new chat works.tenantStoresis a small internal view that writes messages, runs, and interrupts under the tenant key. PR 5 deletes it when those stores leave the harness.askon the calling run (D9) to PR 7, the ownershipepochin the run to PR 5, and a full purge of media and plugin data to PR 4.✅ Checklist
pnpm run test:pr, or these tests do not apply to this pull request.docs/for this change, or this change is not user-facing.pnpm changeset), or this PR does not change a published package.🚀 Release Impact
Testing
Commands run:
ai-persistence,ai-harness,ai-mcp,ai-acp, andai-harness-cli.test:typesandtest:oxlintfor those 5 packages: pass (old warnings only).test:build(publint) forai-persistenceandai-harness: pass.--maxWorkers=2: 54 harness test files in 8 batches (about 915 tests), and the touched tests ofai-persistence,ai-mcp,ai-acp, andai-harness-cli. All pass.oxfmt --checkon every changed file,pnpm test:docs, andkiira checkon the 21 changed docs pages (67 of 67 snippets).Not run locally:
pnpm test:pr, E2E (including the newharness-access.spec.ts), thetesting/e2etype check, and the full suites. CI runs them.Manual test:
pnpm --dir packages/ai-harness exec vitest run tests/access.test.ts tests/http-access.test.ts tests/tenant-keys.test.ts tests/run-context.test.ts.tests/run-context.test.ts, the first case: user A's background agent keeps A's token while user B's turn runs.tests/tenant-keys.test.ts: two tenants open the same thread id and share nothing, on a durable host and on a message-store host.How this PR makes testing easy:
tests/access.test.tsandtests/members-only.test.tspin the roles, sharing, revoke, and the inferred principal type (tests/types.test-d.ts).tests/http-access.test.tspins the handlers that fail closed, signed URLs afterunshare, and streams that close on revoke.testing/e2e/tests/harness-access.spec.tsruns a shared thread with two members, a refused third user, and a user of another tenant.Risk / rollback
Medium. Every network handler changes its options, and a read of a missing thread is now 404. The harness and its integrations are not released yet, and all callers in this repo are moved. To undo, revert this PR.
Public API change
Before
After