Skip to content

feat(GTM-38): let the MozFest hosted agent run on a Fireworks model - #1359

Merged
humantorch merged 3 commits into
mainfrom
scott/gtm-38-mozfest-fireworks-agent-model
Oct 11, 2026
Merged

humantorch merged 3 commits into
mainfrom
scott/gtm-38-mozfest-fireworks-agent-model

Conversation

@humantorch

@humantorch humantorch commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Why

#1333 seeded Fireworks prices and taught the ledger the fireworks provider; #1346 gave the backend a shared provider connection factory. The hosted-agent endpoint still hardcoded Anthropic. MozFest runs on GLM 5.3 via Fireworks, so this is the last piece of the agent path.

What

  • Provider from the model table. AGENT_MODEL resolves to a provider through the same managed-model data /v1/chat uses, not by sniffing the id prefix. Startup refuses an id it cannot place (a typo, a model in another Fireworks account, a bare id) with an error naming the id and the two supported shapes, so a misconfiguration fails at boot instead of 503ing every request. claude-opus-5 is no longer accepted as AGENT_MODEL even though its price row still exists. No new setting.
  • Model factory. createAgentModel builds Fireworks through @ai-sdk/openai-compatible with includeUsage: true (so the stream's final chunk carries usage the ledger can bill) over createManagedProviderConnection('fireworks', ..., { source: 'agent' }), so the key, base URL, instrumented fetch and the agent source label are all shared with /v1/chat.
  • Admission and ledger use the Fireworks identity, so the 0033 prices apply.
  • Startup refuses AGENT_ENABLED=true with a Fireworks model and no FIREWORKS_API_KEY, via the factory's existing check, same path as the Anthropic refusal.
  • Reasoning is not forwarded (sendReasoning: false), so visitors never see raw chain-of-thought from GLM or MiniMax, matching the Anthropic path. Fireworks requests carry x-prompt-cache-isolation-key derived from a hash of the user id so one account's prompt cache cannot be probed from another.
  • No file parts. The hosted agent takes text only for now, whatever the model: a request with a file part gets 400 AGENT_FILES_UNSUPPORTED before admission. feat(GTM-36): use the hosted agent in the web app for MozFest #1353 stops the client sending them.
  • A usage chunk with null token counts logs agent_usage_missing instead of landing a silent zero-cost row.
  • Dependency: @ai-sdk/openai-compatible@^2.0.81, the current ai-v6 line. It shares @ai-sdk/provider and provider-utils with the existing ai@6 stack; the only nested copy is tinfoil's pre-existing 3.x.
  • Docs: .env.example and configuration.md (Hosted agent block, AGENT_MODEL and FIREWORKS_API_KEY rows), models.md (the "follow-up release" sentence now describes current behaviour, and the seed migration list includes 0035).

Tests

Derivation (both seeded ids, Anthropic ids, lookalikes), startup refusal, a Fireworks request landing on https://api.fireworks.ai/inference/v1/chat/completions with the bearer key and stream_options.include_usage, admission seeing { provider: 'fireworks', model }, and a ledger row against migrated PGlite costed from the 0033 GLM row (184,000 nano-USD for 100 in / 10 out). Six revert checks.

  • bun test src/hosted-agent src/inference --randomize --rerun-each 5: 1740 pass, 0 fail
  • tsc, eslint, prettier clean

Live smoke against Fireworks was not run (no key in the dev env). Steps: PORT=8011 AGENT_ENABLED=true AGENT_MODEL=accounts/fireworks/models/glm-5p3 bun run dev, one anonymous chat through /v1/agent/chat, check inference_usage for a fireworks row.

Size

Against main: 16 files changed, 469 insertions(+), 119 deletions(-), including the lockfile. Over the 400-line guideline after the review round (table-based provider resolution, the file-part rejection and the new tests).

AGENT_MODEL now picks the provider from its id: accounts/fireworks/models/* runs on Fireworks through the AI SDK's OpenAI-compatible provider, built on createManagedProviderConnection('fireworks'), so the key, base URL and instrumented fetch are shared. Admission and the ledger use the Fireworks identity, so the prices seeded in 0033 apply. Startup refuses a Fireworks model without FIREWORKS_API_KEY. Anthropic behaviour is unchanged.
@humantorch
humantorch requested a review from darkbanjo October 8, 2026 18:15
@greptile-apps

greptile-apps Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[High impact] Adds Fireworks model support to the hosted agent.

The required helper comments still need to be added before merging.

Findings

  1. P2 New helpers lack required comments ▶

Summary

The hosted agent can now use supported Fireworks models alongside Anthropic.

  • The hosted agent routes supported model IDs to Anthropic or Fireworks.
  • The hosted agent refuses requests that include file attachments.
  • Hosted-agent replies keep reasoning private and isolate Fireworks prompt caches by user.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[AGENT_MODEL] --> B[Managed model table]
  B --> C[Anthropic connection]
  B --> D[Fireworks connection]
  E[Text-only request] --> F[Admission check]
  F --> C
  F --> D
  C --> G[Reply without reasoning]
  D --> G
  C --> H[Usage ledger]
  D --> H
Loading

Reviews (3) · Last reviewed commit: "test(GTM-38): boot the wiring test with ..." · Reviewed by Greptile

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

Semgrep Security Scan

No security issues found.

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

PR Metrics

Metric Value
Lines changed (prod code) +197 / -58
JS bundle size (gzipped) 🟢 653.1 KB → 652.9 KB (-184 B, -0.0%)
Test coverage 🟢 82.85% → 82.85% (+0.0%)
Performance (preview) Preview not ready — Render deploy may have timed out
Accessibility —
Best Practices —
SEO —

Updated Sun, 11 Oct 2026 19:57:57 GMT · run #3410

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔭 thunder-deep-review (advisory)

Reviewed the diff — no issues to report. ✅ Never approves, never requests changes, never gates merge.
head: 40c796c5c571 · mode: single

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Preview environment destroyed 🧹

Stack preview-pr-1359 and its Cloudflare subdomain have been cleaned up.

@darkbanjo darkbanjo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

did a deep pass, comments are tagged blocking / convention / nit. the real end-to-end billing test is great. a few things outside the diff:

  • convention: fireworks caches prompts by default at about a fifth of the input price, but the ledger zeroes cache tokens for non-anthropic providers (usage-ledger.ts:79-82). the agent resends the whole conversation every turn, so from turn two most prompt tokens bill at ~5x real cost and the anonymous 10¢ window runs out well before real spend does. worth pricing cache reads before the event, or at least dropping "slightly" in models.md:94?
  • nit: a usage chunk with null token counts becomes 0, so the run lands as a zero-cost row with no agent_usage_missing log. and history.test.ts:107-112 only covers the forged providerMetadata case with an anthropic key, an openaiCompatible one would pin the boundary this provider now relies on.
  • follow-ups: a run cut at the 120s timeout is never billed (fireworks only reports usage in the last chunk), and with client system messages dropped and an empty AGENT_SYSTEM_PROMPT, reply language falls to the model's default, which changes going from claude to glm.

Comment thread backend/src/hosted-agent/model.ts Outdated
Comment thread backend/src/hosted-agent/model.ts Outdated
Comment thread backend/src/hosted-agent/model.ts
Comment thread backend/src/hosted-agent/model.ts Outdated
Comment thread backend/src/hosted-agent/routes.test.ts Outdated
Comment thread backend/src/hosted-agent/routes.ts
Comment thread backend/src/hosted-agent/model.ts Outdated
Comment thread backend/.env.example Outdated
Comment thread backend/src/hosted-agent/routes.test.ts
Blocking: AGENT_MODEL no longer picks its provider by sniffing the id prefix.
It resolves through the same managed-model data /v1/chat uses, and startup
refuses an id it cannot place with an error naming the id and the supported
shapes, so a typo or another account's model fails at boot instead of 503ing
every request. The hosted agent takes no file parts for now: a request
carrying one gets 400 AGENT_FILES_UNSUPPORTED before admission.

Also: reasoning is not forwarded to visitors (sendReasoning false), Fireworks
requests carry a per-user x-prompt-cache-isolation-key derived from a hash of
the user id, a usage chunk with null counts logs agent_usage_missing instead
of a silent zero-cost row, test fixtures tidied with a test-owned price row,
and the docs and comments Jordan listed.
@humantorch

Copy link
Copy Markdown
Contributor Author

Thanks for the review, and for the cache-pricing catch. Everything tagged is addressed in 2e39e2a and answered on its thread. The items outside the diff:

  • Cache-read pricing in the ledger is ticketed in Linear and being picked up now; models.md no longer says "slightly".
  • A usage chunk with null token counts logs agent_usage_missing instead of landing a silent zero-cost row, and history.test.ts has the openaiCompatible forged-providerMetadata case beside the Anthropic one.
  • The 120 s timeout billing gap and reply language are ticketed in Linear as follow-ups.

One behaviour change worth knowing: with the table-based resolution, claude-opus-5 is no longer accepted as AGENT_MODEL even though migration 0028 still seeds its price. The live Fireworks smoke is still unrun for lack of a key in the dev env.

})
const filePartSchema = z.object({ type: z.literal('file') })

const containsFilePart = (body: unknown): boolean => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 New helpers lack required comments

containsFilePart has no JSDoc comment. This violates the repository directive: “Add JSDoc comments to new utility functions.” The new createFilesUnsupportedResponse helper in backend/src/hosted-agent/routes.ts also needs one. Add short comments explaining both helpers before merging.

Context Used: CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

The hosted-agent wiring test used a fake AGENT_MODEL that the table-based
resolution now refuses at startup. It takes the id from managedDirectRuntimes
so it cannot drift, and inserts its price row with a conflict guard because a
migration already seeds that model.
@humantorch
humantorch merged commit db22b28 into main Oct 11, 2026
43 checks passed
@humantorch
humantorch deleted the scott/gtm-38-mozfest-fireworks-agent-model branch October 11, 2026 19:58
humantorch added a commit that referenced this pull request Oct 12, 2026
…a passes

Merges origin/main (two doc tables conflicted with the #1359 and #1360 rows;
both sides kept, line refs re-verified).

With CAPTCHA_PROVIDER=altcha a POST without x-captcha-token spent a point
from the deployment-wide anonymous sign-in budget before the 403, so a script
behind a raised per-IP limit could drain the hourly budget without solving a
challenge. The budget is now charged in the Better Auth before-hook after the
captcha verification and session-fixation guard pass; the per-IP bucket still
runs first, and with the none provider every sign-in is charged as before.
Tests: tokenless requests leave the budget untouched, a valid solution charges
it once and its replay does not, none charges every sign-in, and moving the
charge back ahead of verification fails the altcha tests. Docs say the budget
counts only sign-ins that passed the captcha.

This branch was successfully deployed

1 active deployment
preview — 27be6034 Deployed Oct 11, 2026 by humantorch via deploy / deploy #3747
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