Skip to content

feat(transaction): app-defined verbs, server composition, and clientTransaction - #942

Closed
jherr wants to merge 12 commits into
feat/define-use-assistantfrom
feat/transaction-client-stub
Closed

feat(transaction): app-defined verbs, server composition, and clientTransaction#942
jherr wants to merge 12 commits into
feat/define-use-assistantfrom
feat/transaction-client-stub

Conversation

@jherr

@jherr jherr commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Stacked on #930 (feat/define-use-assistant). Replaces the assistant-style capability model with app-defined transaction verbs and adds clientTransaction so the browser binds typed clients without mirroring inert verb callbacks.

  • defineTransaction / useTransaction: chatVerb + verb registry behind one handler; one-shot verbs compose siblings via ctx.call with live sub-run streaming
  • clientTransaction: type-only client stub from a verb-name → kind map, checked against the server definition
  • Blog studio example: consolidated into lib/blog-studio.ts (blogTransaction + blogTxnDef)
  • Docs + skill: transaction guides updated for the new client binding pattern

Test plan

Made with Cursor

jherr and others added 7 commits July 14, 2026 18:33
Reshape the assistant feature into a transaction system, layered on top of
feat/define-use-assistant for merge back into #930:

- defineTransaction({ ... }) replaces defineAssistant: verb names are
  app-defined (banner, narration, blogPost, ...) instead of the fixed
  capability set. Two verb kinds: chatVerb(cb) for conversational surfaces
  (several per endpoint now supported) and verb({ input, execute }) for
  one-shots with Standard-Schema-validated inputs (400 + issues on failure).
- Transactions: a verb's execute receives ctx; ctx.call(siblingVerb, input)
  runs sub-work inside the same request, streamed live to the client as
  tagged transaction:sub-run:* events (parentRunId-scoped), including chat
  verbs run to completion ({ text, structured }). One request, one abort
  scope: stop()/disconnect trips req.signal/ctx.signal server-side.
- Client: TransactionClient composes one ChatClient per chat verb and one
  GenerationClient per one-shot verb, demuxing sub-run events into live
  per-verb subRuns state. TransactionSystem infers every surface from the
  server definition ('~verbs' phantom): chat tools/outputSchema per verb,
  run(input)/result typed from each verb's schema and execute return.
- Hooks: useTransaction (react/solid/vue) and createTransaction (svelte)
  replace useAssistant/createAssistant; per-verb options nest under
  options.verbs to avoid name collisions.
- E2E: transaction routes/spec/fixtures replace the assistant ones and add
  ctx.call sub-run coverage; blog-studio example reworked around a one-click
  blogPost transaction with live sub-run steps plus user-driven regenerate
  verbs; docs rewritten (overview/transactions/scenarios), ai-core skill and
  changeset updated.

pnpm test:pr green across all 66 projects; transaction e2e spec passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tials

The blog-studio drafting step blocked until completion instead of streaming.
When orchestration moved server-side into a transaction, the drafting chat
became a sub-run whose demux accumulated raw text but never parsed the
structured-output JSON — so the client only had partial JSON (unrenderable)
and the final result, nothing in between. Regression vs. the original, where
drafting went through ChatClient and got live partial parsing.

- TransactionClient demux now runs parsePartialJSON on each streamed chat
  sub-run chunk, exposing a live `partial` on TransactionSubRun and snapping
  it to the validated object on structured-output.complete. Prose yields
  undefined, so plain chat verbs are unaffected. New `partial?: unknown` field.
- Coalesce the reactive notify for streamed text deltas to one per 12 chunks
  (mirroring the core StreamProcessor's structured-output batch size), so
  consumers rendering live Markdown re-render at a bounded rate instead of
  once per token. Internal sub-run state still updates every chunk, so
  getSubRuns() stays exact; status changes and completion flush immediately.
- blog-studio renders the drafting body as live-building Markdown again
  (matching the original), sourced from the sub-run's parsed `partial`.
- Add demux unit tests: structured sub-run → live parsed partial + terminal
  snap; prose sub-run leaves partial unset.

Verified live: the article body streams in as formatted Markdown (headings
and paragraphs growing mid-stream, no raw ##, no main-thread stall) while the
hero image and voice-over finish in parallel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rb mirrors

clientTransaction binds useTransaction to a server defineTransaction via
import type, so the browser only declares verb names/kinds instead of
duplicating inert callbacks. Consolidates the blog-studio example into a
shared lib module and updates docs, skill, and e2e coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>
Update overview, transactions, scenarios, and the transaction skill to
document blogTxnDef exported from lib/blog-studio.ts instead of inert
client mirrors or import-type-from-api-route snippets.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ction

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4a4e928e-daa5-487b-b639-60fb94eaa433

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/transaction-client-stub

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Changeset Version Preview

19 package(s) bumped directly, 26 bumped as dependents.

🟥 Major bumps

Package Version Reason
@tanstack/ai-angular 0.2.3 → 1.0.0 Changeset
@tanstack/ai-anthropic 0.16.1 → 1.0.0 Changeset
@tanstack/ai-bedrock 0.1.2 → 1.0.0 Changeset
@tanstack/ai-fal 0.9.10 → 1.0.0 Changeset
@tanstack/ai-gemini 0.19.1 → 1.0.0 Changeset
@tanstack/ai-grok 0.14.7 → 1.0.0 Changeset
@tanstack/ai-groq 0.5.1 → 1.0.0 Changeset
@tanstack/ai-mistral 0.2.1 → 1.0.0 Changeset
@tanstack/ai-ollama 0.8.14 → 1.0.0 Changeset
@tanstack/ai-openai 0.16.0 → 1.0.0 Changeset
@tanstack/ai-openrouter 0.15.8 → 1.0.0 Changeset
@tanstack/ai-preact 0.10.3 → 1.0.0 Changeset
@tanstack/ai-react 0.16.4 → 1.0.0 Changeset
@tanstack/ai-sandbox 0.2.2 → 1.0.0 Changeset
@tanstack/ai-solid 0.14.3 → 1.0.0 Changeset
@tanstack/ai-svelte 0.14.3 → 1.0.0 Changeset
@tanstack/ai-vue 0.14.3 → 1.0.0 Changeset
@tanstack/ai-acp 0.2.1 → 1.0.0 Dependent
@tanstack/ai-claude-code 0.2.1 → 1.0.0 Dependent
@tanstack/ai-code-mode 0.3.6 → 1.0.0 Dependent
@tanstack/ai-code-mode-skills 0.3.9 → 1.0.0 Dependent
@tanstack/ai-codex 0.2.1 → 1.0.0 Dependent
@tanstack/ai-elevenlabs 0.2.32 → 1.0.0 Dependent
@tanstack/ai-grok-build 0.2.1 → 1.0.0 Dependent
@tanstack/ai-isolate-node 0.1.45 → 1.0.0 Dependent
@tanstack/ai-isolate-quickjs 0.1.45 → 1.0.0 Dependent
@tanstack/ai-opencode 0.2.1 → 1.0.0 Dependent
@tanstack/ai-react-ui 0.8.13 → 1.0.0 Dependent
@tanstack/ai-sandbox-cloudflare 0.2.2 → 1.0.0 Dependent
@tanstack/ai-sandbox-daytona 0.2.0 → 1.0.0 Dependent
@tanstack/ai-sandbox-docker 0.2.0 → 1.0.0 Dependent
@tanstack/ai-sandbox-local-process 0.2.0 → 1.0.0 Dependent
@tanstack/ai-sandbox-sprites 0.2.1 → 1.0.0 Dependent
@tanstack/ai-sandbox-vercel 0.2.0 → 1.0.0 Dependent
@tanstack/ai-solid-ui 0.7.12 → 1.0.0 Dependent
@tanstack/openai-base 0.9.7 → 1.0.0 Dependent

🟨 Minor bumps

Package Version Reason
@tanstack/ai 0.40.0 → 0.41.0 Changeset
@tanstack/ai-client 0.20.0 → 0.21.0 Changeset

🟩 Patch bumps

Package Version Reason
@tanstack/ai-devtools-core 0.4.22 → 0.4.23 Dependent
@tanstack/ai-isolate-cloudflare 0.2.36 → 0.2.37 Dependent
@tanstack/ai-mcp 0.2.3 → 0.2.4 Dependent
@tanstack/ai-vue-ui 0.2.31 → 0.2.32 Dependent
@tanstack/preact-ai-devtools 0.1.65 → 0.1.66 Dependent
@tanstack/react-ai-devtools 0.2.65 → 0.2.66 Dependent
@tanstack/solid-ai-devtools 0.2.65 → 0.2.66 Dependent

@nx-cloud

nx-cloud Bot commented Jul 15, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 9ff1fcf

Command Status Duration Result
nx run-many --targets=build --exclude=examples/... ✅ Succeeded 2s View ↗

☁️ Nx Cloud last updated this comment at 2026-07-15 23:53:25 UTC

@pkg-pr-new

pkg-pr-new Bot commented Jul 15, 2026

Copy link
Copy Markdown

Open in StackBlitz

@tanstack/ai

npm i https://pkg.pr.new/@tanstack/ai@942

@tanstack/ai-acp

npm i https://pkg.pr.new/@tanstack/ai-acp@942

@tanstack/ai-angular

npm i https://pkg.pr.new/@tanstack/ai-angular@942

@tanstack/ai-anthropic

npm i https://pkg.pr.new/@tanstack/ai-anthropic@942

@tanstack/ai-bedrock

npm i https://pkg.pr.new/@tanstack/ai-bedrock@942

@tanstack/ai-claude-code

npm i https://pkg.pr.new/@tanstack/ai-claude-code@942

@tanstack/ai-client

npm i https://pkg.pr.new/@tanstack/ai-client@942

@tanstack/ai-code-mode

npm i https://pkg.pr.new/@tanstack/ai-code-mode@942

@tanstack/ai-code-mode-skills

npm i https://pkg.pr.new/@tanstack/ai-code-mode-skills@942

@tanstack/ai-codex

npm i https://pkg.pr.new/@tanstack/ai-codex@942

@tanstack/ai-devtools-core

npm i https://pkg.pr.new/@tanstack/ai-devtools-core@942

@tanstack/ai-elevenlabs

npm i https://pkg.pr.new/@tanstack/ai-elevenlabs@942

@tanstack/ai-event-client

npm i https://pkg.pr.new/@tanstack/ai-event-client@942

@tanstack/ai-fal

npm i https://pkg.pr.new/@tanstack/ai-fal@942

@tanstack/ai-gemini

npm i https://pkg.pr.new/@tanstack/ai-gemini@942

@tanstack/ai-grok

npm i https://pkg.pr.new/@tanstack/ai-grok@942

@tanstack/ai-grok-build

npm i https://pkg.pr.new/@tanstack/ai-grok-build@942

@tanstack/ai-groq

npm i https://pkg.pr.new/@tanstack/ai-groq@942

@tanstack/ai-isolate-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-isolate-cloudflare@942

@tanstack/ai-isolate-node

npm i https://pkg.pr.new/@tanstack/ai-isolate-node@942

@tanstack/ai-isolate-quickjs

npm i https://pkg.pr.new/@tanstack/ai-isolate-quickjs@942

@tanstack/ai-mcp

npm i https://pkg.pr.new/@tanstack/ai-mcp@942

@tanstack/ai-mistral

npm i https://pkg.pr.new/@tanstack/ai-mistral@942

@tanstack/ai-ollama

npm i https://pkg.pr.new/@tanstack/ai-ollama@942

@tanstack/ai-openai

npm i https://pkg.pr.new/@tanstack/ai-openai@942

@tanstack/ai-opencode

npm i https://pkg.pr.new/@tanstack/ai-opencode@942

@tanstack/ai-openrouter

npm i https://pkg.pr.new/@tanstack/ai-openrouter@942

@tanstack/ai-preact

npm i https://pkg.pr.new/@tanstack/ai-preact@942

@tanstack/ai-react

npm i https://pkg.pr.new/@tanstack/ai-react@942

@tanstack/ai-react-ui

npm i https://pkg.pr.new/@tanstack/ai-react-ui@942

@tanstack/ai-sandbox

npm i https://pkg.pr.new/@tanstack/ai-sandbox@942

@tanstack/ai-sandbox-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-sandbox-cloudflare@942

@tanstack/ai-sandbox-daytona

npm i https://pkg.pr.new/@tanstack/ai-sandbox-daytona@942

@tanstack/ai-sandbox-docker

npm i https://pkg.pr.new/@tanstack/ai-sandbox-docker@942

@tanstack/ai-sandbox-local-process

npm i https://pkg.pr.new/@tanstack/ai-sandbox-local-process@942

@tanstack/ai-sandbox-sprites

npm i https://pkg.pr.new/@tanstack/ai-sandbox-sprites@942

@tanstack/ai-sandbox-vercel

npm i https://pkg.pr.new/@tanstack/ai-sandbox-vercel@942

@tanstack/ai-solid

npm i https://pkg.pr.new/@tanstack/ai-solid@942

@tanstack/ai-solid-ui

npm i https://pkg.pr.new/@tanstack/ai-solid-ui@942

@tanstack/ai-svelte

npm i https://pkg.pr.new/@tanstack/ai-svelte@942

@tanstack/ai-utils

npm i https://pkg.pr.new/@tanstack/ai-utils@942

@tanstack/ai-vue

npm i https://pkg.pr.new/@tanstack/ai-vue@942

@tanstack/ai-vue-ui

npm i https://pkg.pr.new/@tanstack/ai-vue-ui@942

@tanstack/openai-base

npm i https://pkg.pr.new/@tanstack/openai-base@942

@tanstack/preact-ai-devtools

npm i https://pkg.pr.new/@tanstack/preact-ai-devtools@942

@tanstack/react-ai-devtools

npm i https://pkg.pr.new/@tanstack/react-ai-devtools@942

@tanstack/solid-ai-devtools

npm i https://pkg.pr.new/@tanstack/solid-ai-devtools@942

commit: 0709ffa

jherr and others added 2 commits July 14, 2026 21:04
…ction cast

Add kiira group tags and explicit snippet types in transaction docs, and
document the phantom-only double cast in clientTransaction with an eslint
opt-out matching the chat activity pattern.

Co-authored-by: Cursor <cursoragent@cursor.com>
… example

The emitted .d.ts picked up `./api.blog-studio` from the @example block
and failed scan-dangling-dts in CI.

Co-authored-by: Cursor <cursoragent@cursor.com>

@tombeckenham tombeckenham left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review Summary — #942

PR: feat(transaction): app-defined verbs, server composition, and clientTransaction
Base: feat/define-use-assistant (#930) · Head: feat/transaction-client-stub
Scope: ~6.4k / ~4.7k lines across core, client, 4 framework packages, docs, skill, e2e, blog-studio example


Freshness & merge readiness

Signal Status
Behind base 0 commits — fully current with feat/define-use-assistant
Ahead of base 9 commits
Mergeable MERGEABLE
Merge state UNSTABLE (CI may still be settling)
Base PR #930 OPEN, MERGEABLE
Stale / conflicts No

Verdict: Fresh and still applicable. This is a deliberate stack rewrite of the #930 assistant model (not a stale fork of an old design). No rebase onto the base branch is required right now.

Before merge into main: land #930 first (as the PR body already says), then rebase this branch onto main. Do not merge #942 alone — it replaces the assistant surface that only exists on the stack.


Critical Issues (must fix before merge)

1. Chat sub-runs treat stream RUN_ERROR as success

Where: packages/ai/src/activities/transaction/index.tscollectChatSubRun

chat() streams usually yield RUN_ERROR and end; they don’t throw. The same class of bug was already fixed in summarize (packages/ai/src/activities/summarize/chat-stream-summarize.ts):

// Surface failures: the underlying chatStream emits RUN_ERROR instead
// of throwing, so without this branch summarize() would return an
// empty summary and pretend a failed run succeeded.
if (chunk.type === 'RUN_ERROR') {  }

collectChatSubRun only accumulates text / structured-output, then ctx.call emits SUB_RUN_RESULT (success). Client demux drops nested non-text chunks, so UI can show status: 'success' on a failed draft. Blog-studio may fail later via safeParse(draft.structured) with a misleading error; any composing verb that trusts draft.text / optional structured output can finish the whole transaction successfully after a failed chat.

Suggested fix:

if (chunk.type === EventType.RUN_ERROR) {
  const message =
    (typeof chunk.message === 'string' && chunk.message) ||
    chunk.error?.message ||
    'Chat sub-run failed'
  throw new Error(message)
}

Also demux inner RUN_ERRORsubRuns[].status = 'error'. Add a unit test that a chat sub-stream ending in RUN_ERROR produces SUB_RUN_ERROR + parent RUN_ERROR.


2. Streaming one-shot sub-runs: RUN_ERROR / missing result → success with null

Where: packages/ai/src/activities/transaction/index.tsforwardAndExtractResult

Only looks for generation:result. A nested stream: true path that ends in RUN_ERROR (or without a result) still resolves with null and SUB_RUN_RESULT. Parent can treat a failed image/speech step as a successful empty step. Contrasts with GenerationClient.processStream, which throws on RUN_ERROR.

Suggested fix: On RUN_ERROR, throw with message/code. Prefer fail-closed if the stream ends without generation:result.


Important Issues (should fix)

3. Parallel Promise.all(ctx.call…) leaves sibling sub-runs stuck running

Where: createChunkChannel push-after-close + execution.finally(() => channel.close()) in runVerbStream

Blog-studio and unit tests use:

await Promise.all([ctx.call(heroImage, ), ctx.call(narration, )])

If A fails → channel closes → B’s later push is a silent no-op → client keeps B as running forever while parent shows error. Also risks an unhandled rejection from B after Promise.all already rejected.

Suggested fix (pick one or combine):

  • Refcount in-flight calls; close the channel only after all settle
  • On parent failure, emit synthetic SUB_RUN_ERROR (cancelled / sibling failure) for non-terminal sub-runs before close
  • Client: on parent RUN_ERROR / abort, flip remaining runningerror/cancelled

Add regression test: Promise.all with one fast fail + one delayed success; assert both terminal sub-run events and no stuck running.


4. async chat verb callbacks that return a stream fail at runtime

Where: handler + collectChatSubRun

chatVerb(async (req) => {
  await authorize(req.request)
  return chat({})  // Promise, not AsyncIterable
})

Types allow Promise<object> via ChatVerbReturn; runtime returns 400 / throws. Auth/logging wrappers around chat() are the common case; examples/tests only use sync callbacks or async function*.

Suggested fix: Await thenable results before isAsyncIterable check (same for collectChatSubRun). Prefer stream-only types on ChatVerbReturn.


5. Abort / stop() half-wired vs “one abort scope” claim

  • SSE response not clearly linked to an abort controller for verb work
  • forwardAndExtractResult never checks request.signal
  • Client stop() clears loading but does not finalize subRuns (left running forever)
  • Image/speech have no abort API; docs overclaim “nothing keeps burning tokens”

Suggested fix: Wire cancel properly; mark open sub-runs cancelled/error on stop; soften docs for non-chat activities. Fix VerbRequest JSDoc: chat takes abortController, not abortSignal.


6. Docs / JSDoc inaccuracies

Issue Location
chat({ abortSignal }) — chat takes abortController types.ts VerbRequest JSDoc
Stale createTransaction as server factory (defineTransaction is correct; createTransaction is Svelte client) docs/transaction/overview.md, transaction SKILL
subRuns.partial missing from public docs (used in blog-studio) transactions.md, SKILL
onResult: null does not mean “keep raw” (keeps previous) transaction-types.ts
Skill import @tanstack/ai-openai/adapters is not a package export SKILL.md
Abort/provider-cancel claims overstated for image/speech transactions docs + skill

7. clientTransaction without type arg loses all safety

With clientTransaction<typeof server>(…) kinds are exhaustive (missing/extra/wrong-kind rejected — good, tested). Without the generic, safety collapses to any-ish kinds and untyped surfaces.

Suggested fix: Prefer default never or a curried form so forgetting TDef is a hard error.


8. High-value test gaps

Happy path is solid (server composition, demux, e2e chat/one-shot/sub-runs). Missing:

  • Abort / stop() mid-run
  • Chat / stream sub-run RUN_ERROR → parent failure
  • Non-stream chat → 400
  • AsyncIterable execute (root + sub)
  • Multi sub-run demux interleaving + notify batching assertions (changes array is built but never asserted)
  • Hook error / React dispose depth

E2E meets the mandatory bar for the feature shape; not enough for failure/abort UX.


Suggestions (nice to have)

  • Promise-wrapped AsyncIterable from async execute is treated as a plain result (serializes poorly) — detect after await or document the escape hatch
  • Discriminated TransactionSubRun status unions
  • Thread structured type into ctx.call chat overload (CollectedChatResult.structured is always unknown)
  • Root chat callback sync throw → structured error rather than bare 500
  • Demux: upsert on ERROR/RESULT without prior STARTED
  • Document that composed chat sub-runs get tools: []
  • txn.<verb>.run() never rejects (GenerationClient swallows) — same as generation, but document clearly
  • Document the raw AsyncIterable execute escape hatch (channel closed; ctx.call unused)

Strengths

  1. Clear product model — app-named verbs, single handler, clientTransaction kinds map with compile-time exhaustiveness
  2. Composition protocolTRANSACTION_EVENTS + tagged live sub-runs; parallel composition unit-tested on happy path
  3. Type pipeline — tools / outputSchema / onResultTransactionSystem is ambitious and type-tested
  4. Client demux — live partial via parsePartialJSON, 12-chunk notify batching, RESULT/ERROR flush
  5. Security hygiene — verb routing on own keys only; prototype key (toString) tested
  6. E2E baseline — dedicated /transaction page + chat / one-shot / composition
  7. blog-studio — strong end-to-end narrative, re-validates structured draft after ctx.call
  8. clientTransaction.handler fails loud if mounted in the browser

Recommended action

  1. Block merge until Critical #1 and #2 are fixed (stream failures must not look like successful sub-runs).
  2. Fix Important #3 (parallel ctx.call channel lifecycle) — blog-studio uses this pattern.
  3. Fix #4 (await chat Promise returns) and #5 (abort/sub-run finalization + docs honesty).
  4. Patch docs/JSDoc (#6) and harden clientTransaction typing (#7).
  5. Add regression tests for #1#3 and abort.
  6. Wait for pending Test + E2E CI green; then re-review.
  7. Stack order: merge #930 → rebase #942 onto main → land. No base rebase needed today (0 behind).

Suggested fix order

  1. collectChatSubRun + forwardAndExtractResult: treat RUN_ERROR as failure
  2. Channel lifecycle under concurrent ctx.call (no stuck running)
  3. Await Promise-returning chat callbacks
  4. Abort wiring + client sub-run finalization
  5. Docs/JSDoc accuracy + clientTransaction never-default
  6. Targeted tests + re-run CI

Verdict

Not ready to merge as-is for composition failure modes. Architecture, typing, happy-path protocol, and e2e wiring look strong, and the PR is fresh on its stack base. But streamed failures that don’t throw can be recorded as successful sub-runs, and parallel composition can leave the client permanently mid-flight — those break core claims of the feature (ctx.call, live sub-runs, one abort scope).

Demonstrate the same draft → (hero ∥ narration) pipeline without
defineTransaction — one createServerFn composes the activities and
returns the finished artifact for comparison with /blog-studio.
tombeckenham and others added 2 commits July 16, 2026 09:50
Restore server-side draft → (hero ∥ narration) composition with
pipeline:step events, live structured-output deltas, and a final
pipeline:result so the plain path matches the transaction UX without
defineTransaction.
@tombeckenham tombeckenham added the waiting-on: author Waiting for the author to respond or update label Jul 23, 2026
@AlemTuzlak AlemTuzlak closed this Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-on: author Waiting for the author to respond or update

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants