Skip to content

feat(admin): converge experience-editor AI chat to single Mastra+OpenRouter channel#977

Open
up-tandem wants to merge 32 commits into
mainfrom
feat/admin-chat-multi-channel-providers
Open

feat(admin): converge experience-editor AI chat to single Mastra+OpenRouter channel#977
up-tandem wants to merge 32 commits into
mainfrom
feat/admin-chat-multi-channel-providers

Conversation

@up-tandem
Copy link
Copy Markdown
Contributor

Summary

Converges the experience-editor AI chat surface from five exploratory channels (mastra, openrouter, ollama, codex, claude-code) to a single Mastra-orchestrated channel running OpenRouter free models. Mastra runtime ships in this PR alongside the convergence cleanup.

Net change

~5,000 lines of legacy multi-channel scaffolding deleted; Mastra runtime + agents + memory landed. Single chat path with no provider chooser, error fall-through, or CLI binaries in production.

What's in this PR

Baseline (4 commits)

  • Gitignore Mastra build output, test artifacts, tarballs
  • Mastra runtime foundation: singleton + 5 agents + 1 workflow + 3 tools + Postgres memory
  • Wire Mastra as 5th channel (intermediate state — replaced by U1–U7)
  • Brainstorm + plan documents

Convergence (7 units)

Unit Change
U1 Mastra memory isolated in dedicated mastra Postgres schema (migration 0016_mastra_schema). @mastra/pg PostgresStore configured with schemaName: "mastra" — its 32 tables land cleanly out of Prisma's migration history
U2 Channel dropdown removed from chat composer; provider field dropped from the stream client
U3 provider field stripped from the stream route's Zod body schema
U4 streamChatTurn collapsed to single Mastra path; dead brief-flow + mutation_proposal / brief_update event types deleted; chat service test rewritten as 12 focused tests
U5 9 legacy modules deleted: experience-ai-{codex,claude-code,ollama,openrouter-free,cli-gates,chat-provider,quality-draft,chat-brief,content-kit}.ts and their tests
U6 Chat-only env vars pruned: EXPERIENCE_AI_ALLOW_{CODEX,CLAUDE_CODE}, EXPERIENCE_AI_{CODEX,CLAUDE_CODE}_MODEL, OLLAMA_CHAT_MODEL
U7 apps/admin/CLAUDE.md "Experience AI Chat providers" section rewritten for Mastra-only

Verification (1 commit)

  • Mastra chat smoke script (pnpm tsx src/scripts/smoke-mastra-chat.ts). Verified locally: Mastra singleton → experience-default-chat agent → OpenRouter → response in ~1.9 s; memory persists to mastra schema (32 tables).

Key technical decisions

  • Mastra-only, no provider fallback. A second provider channel would reintroduce the multi-channel branching this PR deletes. If OpenRouter is down, the editor sees a clear error envelope.
  • Postgres over LibSQL for Mastra memory. Railway containers are ephemeral. @mastra/pg reuses admin's existing Postgres connection.
  • Dedicated mastra schema. Future reset is DROP SCHEMA mastra CASCADE — no table-by-table cleanup, no interference with Prisma's _prisma_migrations.

What's NOT in this PR (deferred follow-ups)

  • The legacy experience-ai.service.ts draft-generation flow + generate-draft-action.ts are dead at the call boundary (no UI callers) but compile. They still reference EXPERIENCE_AI_ALLOW_CODEX_FALLBACK — that env var is therefore kept until those modules are also deleted.
  • Dead chat-panel UI machinery (StagedDraftPreview, QualityReviewCard, stagedDraft state) — only existed for the removed mutation_proposal event. Compiles; behaviorally unreachable.
  • Agent picker UI to route turns to add-section / rewrite-copy / draft-experience. Agents are registered; routing not wired.
  • multi-step-draft workflow has placeholder step bodies. Structure shipped; agent calls inside steps deferred.

Verification done

  • pnpm --filter @forge/admin typecheck — clean
  • pnpm --filter @forge/admin test — 214/214 admin tests pass across 22 files
  • prisma migrate deploy applies 0016_mastra_schema cleanly; \dn shows mastra schema owned by forge
  • End-to-end smoke (real OpenRouter call): Mastra singleton + experience-default-chat agent + OpenRouter response + memory written to mastra.* tables — all green

Test plan (for reviewer)

  • Pull the branch, run pnpm install, run pnpm --filter @forge/admin db:migrate:deploy0016_mastra_schema migration applies cleanly
  • Run pnpm --filter @forge/admin test — all green
  • Run the smoke: cd apps/admin && pnpm exec tsx --env-file=.env src/scripts/smoke-mastra-chat.ts — should print [smoke] PASS
  • Open the experience editor in dev (pnpm --filter @forge/admin dev), open an experience, send a chat message — should respond from Mastra+OpenRouter, no channel dropdown visible
  • Inspect mastra.* tables in Postgres — mastra_threads and mastra_messages populated after the chat exchange

🤖 Generated with Claude Code

sevenuphome and others added 30 commits May 11, 2026 01:55
Expand the admin data plane, manager trigger surface, web admin-GraphQL cutover, and shared GraphQL parity tooling in one branch snapshot.

Also add experience AI/editor foundations and switch generated embeddings to the 2048-dim OpenRouter NVIDIA free model.
…on WIP

Bundled WIP from feat-125 (AI chat quality-first generation: editorial brief,
OpenRouter free-tier provider loop, quality draft schemas, content creator kit)
and feat-126 scaffolding (experience watch revalidation). Snapshot before
branching off to the Ollama provider channel work (plan 002).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Centralized discriminator that the chat composer, SSE route, and chat
service all consume so literal drift can't sneak in between layers.
Lands the planning artifact for the Ollama provider channel alongside.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds generateOllamaStructuredOutput (quality-draft single-shot) and
runOllamaChat (NDJSON streamed chat-turn) against the local Ollama HTTP
API. Errors map onto the shared ChatErrorCode union, which moves to its
own module so adapters can import it without depending on the chat
service (would otherwise be circular).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…U1, U2)

Promotes ChatProvider to a 4-value closed union (openrouter/ollama/codex/
claude-code) and lands the brainstorm + plan that drive the broader work.
Per-channel env gates (EXPERIENCE_AI_ALLOW_CODEX + EXPERIENCE_AI_ALLOW_
CLAUDE_CODE) gate the CLI providers, with a one-shot deprecation log on
the legacy EXPERIENCE_AI_ALLOW_CODEX_FALLBACK name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extracts the chat-turn Codex spawn out of experience-ai-chat.service.ts into
its own peer of the Ollama adapter and adds generateCodexStructuredOutput
for the quality-draft path. The chat-turn runCodexChat preserves the legacy
error codes (codex_unavailable / codex_timeout / codex_idle_timeout) so R8
holds. Quality-draft uses 'codex exec --output-schema <tmp> -o <out>' for
robust JSON capture.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Spawns 'claude --print --output-format stream-json --verbose --json-schema
<inline>' for both flows. Quality-draft captures the terminal result frame;
chat-turn additionally forwards each assistant message via onToken so the
panel sees progress. Error mapping uses the provider_* code family (not the
codex_* one) since Claude Code is a new channel without legacy callers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…CodexChat (U5)

ChatMutationEnvelopeSchema / ChatMutationsSchema move into experience-ai-
chat-envelope.ts so the CLI adapters can JSON-schema-serialize them without
re-importing the chat service. The in-service runCodexChat block (200 lines)
deletes; chat service imports the adapter version. The legacy
EXPERIENCE_AI_ALLOW_CODEX_FALLBACK !== true gate is replaced by the adapter's
isCodexAllowed() check, which reads the new EXPERIENCE_AI_ALLOW_CODEX var
first and falls back to the legacy name with a one-shot deprecation log.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
generateQualityExperienceDraft now accepts a provider arg and branches to
the right adapter (OpenRouter / Ollama / Codex / Claude Code), stamping
provider.kind to match. Per-channel error mapper preserves the existing
QualityExperienceDraftErrorCode union. Default-on-omit is openrouter so
existing tests pass without modification (R8 invariant).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
streamChatTurn now reads provider from input, normalizes via
normalizeChatProvider, and routes the chat-turn branch to the right
adapter: ollama → runOllamaChat, claude-code → runClaudeCodeChat,
codex / openrouter → runCodexChat (Codex is the legacy default for
the openrouter pick — R8 invariant). Quality-draft branch passes
provider through and stamps the corresponding providerKind. Adapter
errors surface verbatim — no cross-channel auto-fallback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extend the SSE chat route's body schema with the closed 4-value
provider enum and forward it into streamChatTurn alongside existing fields.
Adds optional `provider?: ChatProvider` to `StreamChatRequestBody` so
callers can opt into a non-default channel; wire format is identity
when `provider` is omitted (R8 invariant).

Test expectation: none -- type-only addition exercised by U10 panel.
Add a native <select> next to the cross-locale toggle in the experience
chat composer. Four options stamped with cost posture (free/paid, local/
cloud) and disabled while a turn is streaming. Selection flows into the
SSE request body as `provider`, defaulted to `openrouter` so existing
behavior is unchanged.
document the four chat channels, env gates, model overrides,
and the production CLI caveat in apps/admin/CLAUDE.md.
…ow-up)

The error presentation map hard-coded 'OpenRouter is not configured' /
'free AI model' strings from when OpenRouter was the only quality-draft
provider. With four channels in the dropdown, picking Ollama / Codex /
Claude Code surfaced misleading copy. Switches to provider-agnostic
phrasing that nudges editors to try a different channel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hema

Codex forwards --output-schema to OpenAI's response_format json_schema
strict:true path, which requires additionalProperties:false at EVERY
object node. Our hand-coded schemas only set it at the top level (and
OpenRouter / Claude Code don't enforce it). Verified live: with this
walker, codex exec accepts the schema and emits valid JSON.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
OpenAI's responses-format json_schema strict:true rejects schemas with
`oneOf`, missing `additionalProperties:false` at every node, and other
patterns the editor's quality-draft package uses freely (16-variant
discriminated union on blocks). Strictifying half the schema is
whack-a-mole. The plan's stance is "CLI schema enforcement is a hint";
we rely on the prompt's outputContract for model guidance and Zod
post-hoc validation as the runtime guarantee.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…stic)

Editors hitting the Ollama channel surface 'AI not configured' / 'Draft
rejected' alerts without server-side detail today. Add a one-line
structured warn at the failure site so the dev server log shows model,
error, and a 1KB rawSample of the parsed payload. Useful for tuning
gemma4 + future local-model prompts; expected to stay as a debugging
aid for the local Ollama deployment path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ef flow

After an AI mutation introduces new videoIds, the editor's videoLibrary
(server-loaded with includeVideoIds derived from saved blocks) had no
way to learn about them until a save+reload. New video blocks rendered
without titles/images, so editors thought sections were missing.

experience-editor-with-chat now manages videoLibrary as client state,
walks blocks passed through applyDiff/revertDiff/initial publish, and
calls a new loadVideosByIdsAction server action for any unknown id.
Titles/images appear immediately without a save.

The brief-flow chat path is fully disabled — single-prompt generation
produces a full inline draft instead of routing through the Q&A brief
workflow. Tests for the brief path are skipped with a [brief-flow
disabled] marker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cloudflare Images URLs from admin lacked the /public variant suffix and
returned 400. Added normalizeImageUrl() to inject /public when missing,
and applied it at the content-loader seam (lib/content.ts, lib/enrichment.ts)
so block image URLs are valid before they hit the renderer. Added a
DEFAULT_BLOCK_IMAGE_URL fallback so cards still render when no imageUrl
is set on the block.

VideoHero was using position: fixed for a parallax effect that overlapped
the next section on /watch/03/en. Switched to position: absolute with
h-full so the hero stays contained within its section bounds. Loses
parallax; gains correct stacking.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- **/.mastra/  - Mastra CLI build output (regenerated per dev/build)
- test-results/ - Playwright/vitest per-run artifacts
- *.tgz       - local pnpm pack tarballs

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…orkflow)

Lands the Mastra runtime that backs the upcoming convergence to a
single-channel chat surface:

- Mastra singleton with lazy construction at src/mastra/index.ts
- PostgresStore memory via @mastra/pg with MASTRA_STORAGE_URL fallback to DATABASE_URL
- Agents: experience-default-chat, draft-experience, add-section, rewrite-copy, auto-enrich
- Workflow: multi-step-draft (plan -> draft -> critique -> revise)
- Tools: lookupBibleVerse, fetchVideoImage, searchVideos
- Streaming bridge + budgets + chat-stream-event primitives
- mastra-playground entry for 'mastra dev' (eager export, local-only)
- MASTRA_STORAGE_URL + MASTRA_DEFAULT_PROVIDER env vars (both optional)
- Mastra deps: @mastra/core, @mastra/ai-sdk, @mastra/memory, @mastra/pg,
  @mastra/libsql, ai, @ai-sdk/openai, ollama-ai-provider-v2, jsonrepair
- mastra:dev script wired to playground

89 tests passing across src/mastra/**.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds mastra to the ChatProvider literal union (now 5 values:
mastra, openrouter, ollama, codex, claude-code) and defaults the
composer pick to mastra. Both quality-draft and chat-turn paths
route through the mastra channel via the runtime singleton landed
in the previous commit.

- ChatProvider widened; DEFAULT_CHAT_PROVIDER flips to 'mastra'
- normalizeChatProvider tolerates underscore/hyphen mixed wire formats
- Stream route accepts 'mastra' in the Body Zod enum
- Composer dropdown gains a 'mastra' option
- Chat service streamChatTurn dispatches to Mastra runtime for
  the mastra channel; legacy channels untouched
- generateQualityExperienceDraft adds a mastra branch
- apps/admin/CLAUDE.md table now lists 5 channels

This is the final state of the multi-channel exploration. The
convergence work (delete 4 legacy channels, single mastra path)
follows in the next series of commits per
docs/plans/2026-05-18-001-feat-admin-mastra-only-chat-channel-plan.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures the product decision to converge from 5 chat channels to 1
(mastra over OpenRouter free models) and the implementation plan to
execute it. The brainstorm + plan land here so future work-loop
references resolve from git rather than session memory.

- Requirements doc: WHAT to build (single Mastra channel, dedicated
  mastra Postgres schema, no provider fallback)
- Plan doc: HOW, broken into 7 U-IDs (U1 schema isolation,
  U2 dropdown removal, U3 route field strip, U4 service collapse,
  U5 adapter delete, U6 env prune, U7 docs rewrite)

The plan body is the source of truth for the follow-up commits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mastra/pg PostgresStore now creates its tables under the 'mastra'
schema instead of the default 'public' schema. A future reset is
DROP SCHEMA mastra CASCADE — no table-by-table cleanup, no
interference with Prisma's migration history.

- Add 0016_mastra_schema migration: CREATE SCHEMA IF NOT EXISTS mastra
- Wire schemaName: 'mastra' into the PostgresStore constructor in
  apps/admin/src/mastra/memory.ts
- Test assertion: buildMastraMemory passes schemaName='mastra' to
  PostgresStore (mocked spy on the constructor)

Verified locally: prisma migrate deploy applies cleanly, psql \\dn
shows mastra schema owned by forge.

Per docs/plans/2026-05-18-001-feat-admin-mastra-only-chat-channel-plan.md U1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mastra is the only chat channel — editors no longer have a provider
chooser. The composer shows only the message input and the
'apply across locales' toggle.

- Remove the provider <select> element from experience-chat-panel.tsx
- Drop provider/setProvider state, ChatProvider/DEFAULT_CHAT_PROVIDER
  imports, and provider from the streamFactory call + useCallback
  deps
- Drop the optional 'provider' field from StreamChatRequestBody in
  experience-chat-stream-client.ts (and its ChatProvider import)
- Replace the 3 provider-dropdown panel tests with:
  - 'renders the composer with no provider dropdown'
  - 'calls openChatStream with no provider field on send'

16 panel tests passing. AE1 + AE2 covered.

Per docs/plans/2026-05-18-001-feat-admin-mastra-only-chat-channel-plan.md U2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
POST /api/experience-chat/stream no longer accepts or forwards a
'provider' field. Mastra is the only channel — there is no
selection to make.

- Remove provider from the Body Zod schema in stream/route.ts
- Remove provider from the streamChatTurn input argument
- Replace 4 per-provider routing tests with 2:
  - 'does not forward a provider field to streamChatTurn'
  - 'ignores a legacy provider field in the request body'
    (Zod's default non-strict behavior strips unknown keys, so a
    stale browser tab from before the deploy window won't 400)

10 route tests passing.

Per docs/plans/2026-05-18-001-feat-admin-mastra-only-chat-channel-plan.md U3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
streamChatTurn no longer accepts or branches on a provider field.
Mastra is the only chat-turn channel. The dead brief-flow code (the
brief flow has been permanently disabled since 8dbbe61) is also
removed since it was the only consumer of mutation_proposal /
brief_update events and the legacy quality-draft route.

experience-ai-chat.service.ts:
- Drop imports of normalizeChatProvider, ChatProvider, runOllamaChat,
  runClaudeCodeChat, runCodexChat, generateQualityExperienceDraft,
  QualityExperienceDraftError, EditorialBrief, EditorialBriefField,
  QualityDraftReview, and the brief-flow helpers
- Drop StreamChatTurnInput.provider field
- Delete runChatTurnForProvider switch, providerKindForChatTurn,
  providerErrorEvent, isEmptyCanvas
- Delete the dead 'if (inBriefMode)' branch
- Drop mutation_proposal and brief_update from ChatStreamEvent
- Wire runMastraChat as the only chat-turn call site
- providerKind on persisted assistant message hardcoded to 'mastra'

experience-chat-panel.tsx:
- Drop the unreachable mutation_proposal + brief_update event handlers
- Delete BriefConfirmationPreview type + BriefConfirmationCard
  component + briefConfirmation state + handleConfirmBrief +
  BRIEF_FIELD_LABELS + EditorialBrief/Field imports

Tests:
- Rewrite experience-ai-chat.service.test.ts as a focused 12-test
  suite covering happy path (token_delta + mutation_applied + done,
  providerKind='mastra' stamp), error paths (thread_not_found,
  forbidden, slug_change_rejected, schema_violation,
  cross_locale_unconfirmed + confirmed bypass, mastra throws,
  ProviderNotConfigured), and Mastra integration (agent id,
  abortSignal forwarding). Replaces 30+ codex-spawn-centric tests
  that exercised the legacy multi-channel routing.
- Delete two panel tests that exercised mutation_proposal /
  brief_update flows.

Verified: typecheck passes, 12/12 chat service tests pass.

Per docs/plans/2026-05-18-001-feat-admin-mastra-only-chat-channel-plan.md U4.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
With Mastra as the only chat channel (U4), the codex / claude-code /
ollama / openrouter-free adapters, the shared CLI-gates helper, and
the ChatProvider literal-union module are dead code. The quality-draft
+ chat-brief + content-kit modules are also deleted since their only
consumer was the brief-flow code path removed in U4.

Files deleted (all under apps/admin/src/services/experience-ai/):
- experience-ai-claude-code.ts + .test.ts
- experience-ai-codex.ts + .test.ts
- experience-ai-ollama.ts + .test.ts
- experience-ai-openrouter-free.ts + .test.ts
- experience-ai-cli-gates.ts + .test.ts
- experience-ai-chat-provider.ts + .test.ts
- experience-ai-quality-draft.ts + .test.ts
- experience-ai-chat-brief.ts + .test.ts
- experience-ai-content-kit.ts

Kept (still live):
- experience-ai-quality-draft.schemas.ts — pure Zod schemas; the
  QualityDraftReview type is still referenced by the (now-dead)
  staged-draft preview UI in the panel
- experience-ai.service.ts / .schemas.ts — video candidate loading
- experience-ai-prompts.ts, experience-ai-normalize.ts — consumed
  by experience-ai.service.ts
- experience-ai-chat-envelope.ts, experience-ai-chat-prompts.ts,
  experience-ai-chat-error-codes.ts — consumed by chat.service.ts
- experience-chat-diff.ts — consumed by panel + chat service

Also: clean up a stale 'experience-ai-openrouter-free.ts' comment
reference in src/mastra/agents/default-chat-agent.ts.

Verified: zero grep matches for deleted modules across apps/admin/src;
typecheck passes; 95/95 experience-ai tests pass.

Per docs/plans/2026-05-18-001-feat-admin-mastra-only-chat-channel-plan.md U5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes env vars that were exclusively consumed by the legacy
multi-channel chat adapters deleted in U5. Embedding-pipeline vars
(OLLAMA_BASE_URL, OLLAMA_EMBEDDING_MODEL, OLLAMA_EMBEDDING_DIMENSIONS)
are kept — they belong to the embedding services, not chat.

Removed:
- EXPERIENCE_AI_ALLOW_CODEX (chat-gate)
- EXPERIENCE_AI_ALLOW_CLAUDE_CODE (chat-gate)
- EXPERIENCE_AI_CODEX_MODEL (chat-model)
- EXPERIENCE_AI_CLAUDE_CODE_MODEL (chat-model)
- OLLAMA_CHAT_MODEL (chat-model)

Kept:
- EXPERIENCE_AI_ALLOW_CODEX_FALLBACK — still referenced by the
  legacy experience-ai.service.ts draft-generation flow (dead at
  call boundary; consumed only by generate-draft-action.ts which
  has no UI callers). Removal is a follow-up cleanup once that
  legacy surface is also deleted.
- OLLAMA_BASE_URL / OLLAMA_EMBEDDING_* — embedding pipeline.
- MASTRA_STORAGE_URL / MASTRA_DEFAULT_PROVIDER — Mastra runtime.

.env.example: replace the 'Experience AI Chat CLI channels' block
with a short Mastra-runtime section pointing at MASTRA_STORAGE_URL
and the 0016_mastra_schema migration.

Per docs/plans/2026-05-18-001-feat-admin-mastra-only-chat-channel-plan.md U6.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
up-tandem and others added 2 commits May 18, 2026 10:49
Replaces the five-channel provider table with a single Mastra +
OpenRouter description matching the post-convergence shape:

- Entry points: Mastra singleton, streamChatTurn, SSE route
- Model selection via OPENROUTER_EXPERIENCE_CHAT_MODELS ladder
- Memory in the dedicated 'mastra' Postgres schema (migration 0016)
- Error handling: typed error events, no provider fallback
- Local dev: pnpm mastra:dev playground

Also:
- Refine R9 in the brainstorm doc to match the Scope Boundaries (the
  Ollama embedding env vars are kept; only chat-only vars pruned; the
  EXPERIENCE_AI_ALLOW_CODEX_FALLBACK var stays for the legacy
  draft-generation flow until that flow is also removed).
- Flip the plan's frontmatter status from 'active' to 'completed'.

214/214 admin tests passing across 22 files at convergence.

Per docs/plans/2026-05-18-001-feat-admin-mastra-only-chat-channel-plan.md U7.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Small standalone smoke that exercises:
  getMastra().getAgentById('experience-default-chat').generate(prompt)

Verifies the Mastra singleton constructs, the agent is registered,
OpenRouter responds, and memory persists to the dedicated 'mastra'
Postgres schema. Useful for post-deploy verification or quick local
sanity checks without spinning up the full SSE pipeline.

Run: cd apps/admin && pnpm exec tsx --env-file=.env \
       src/scripts/smoke-mastra-chat.ts

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@railway-app
Copy link
Copy Markdown

railway-app Bot commented May 18, 2026

🚅 Deployed to the forge-pr-977 environment in forge

Service Status Web Updated (UTC)
@forge/admin ✅ Success (View Logs) Web May 18, 2026 at 11:02 am
@forge/roadmap ✅ Success (View Logs) May 18, 2026 at 11:02 am
@forge/manager ✅ Success (View Logs) May 18, 2026 at 11:02 am
@forge/cms ✅ Success (View Logs) May 18, 2026 at 11:01 am
@forge/web ❌ Build Failed (View Logs) May 18, 2026 at 10:57 am
2 services not affected by this PR
  • @forge/agentic-studio
  • @forge/agentic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants