Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,116 @@
# Changelog

## Franklin Agent 3.40.0 — priced but unreachable: the catalog gets a front door

**3.39.0 taught Franklin what the new models cost. It never taught anyone how
to ask for them.** That release added eleven chat models to `src/pricing.ts`
and stopped there — no shortcut, no picker row, no router wiring. The models
were live on the gateway, correctly priced, and reachable only by typing the
full `provider/model` id from memory. This release finishes the job.

**38 new shortcuts (107 → 145), covering every model 3.39.0 priced:**

| family | now reachable as |
|---|---|
| GPT-5.6 pro reasoning tier | `sol-pro`, `terra-pro`, `luna-pro` |
| GPT-5.5 Pro / ChatGPT default | `gpt-5.5-pro`, `chatgpt` / `instant` |
| Gemini 3.6 Flash + the Flash Lite line | `flash` (now 3.6), `flash-lite`, `gemini-3.1-flash-lite` |
| Qwen3.7 Plus / Flash | `qwen-plus`, `qwen-flash` |
| Tencent, Xiaomi (new providers) | `hy3` / `tencent`, `mimo` / `xiaomi` |
| GPT-4o + 4.1 mini/nano, o3-mini | `4o`, `gpt-4o-mini`, `gpt-4.1-mini`, `o3-mini` |

Worth knowing about the pro tier: **Terra Pro ($1/$6) and Luna Pro
($0.1/$0.6) undercut their own base tiers** while adding pro reasoning mode.
Sol Pro matches Sol exactly. `gpt` stays pinned to Sol — bare aliases follow
the gateway's flagship, not the cheapest sibling.

**New arrivals since 3.39.0.** `zai/glm-5.3` is Z.AI's flagship (1M context,
always-on reasoning, priced at 5.2's $1.4/$4.4) and `xai/grok-imagine-video-1.5`
joins VideoGen at $0.08/s.

One catalog fact worth writing down: **GLM-5.3 is Base-only.** The Solana
gateway lists 92 of Base's 93 models and 5.3 is the one it's missing (prices
are otherwise identical across chains). So `glm` stays pinned to 5.2 rather
than following the flagship — a bare alias is what people type from muscle
memory and has to resolve on *both* chains; pointing it at a Base-only id
would hand every Solana user an HTTP 400. 5.3 is one keystroke away as
`glm-5.3` and has its own picker row, which reconciliation drops automatically
for Solana users.

**The router's LLM classifier has been dead since 2026-07-27, silently.**
Its default model was `nvidia/qwen3-next-80b-a3b-instruct` — the same id
NVIDIA EOL'd, which the gateway now rides on `nemotron-3-super-120b`. That
substitute opens with *"Okay, let's see. The user wants to…"* and never
reaches a verdict inside the classifier's 16-token budget, so every
classification failed the strict parse and fell through to keyword-only
routing. The fallback is invisible by design, which is exactly why this went
three weeks without anyone noticing. Re-probed the free pool on the real
classifier prompt:

| free model | reply to a classification prompt |
|---|---|
| `qwen3-next` (old default) | prose, served by `nemotron-3-super-120b` |
| `nemotron-nano-9b-v2` | prose — *"Okay, let's see…"* |
| `nemotron-3-nano-omni` | **`MEDIUM`** — one bare word, served by itself |

`nemotron-3-nano-omni` is the new classifier. The lesson worth keeping: "good
free chat model" and "answers in one bare word under a tight cap" are
different requirements, and the free default is not automatically both.

**The 30B omni model started serving itself again.** In August it came back
as `gpt-oss-120b` — the pooled-substitute trap — which is why it had no alias
and led no chain. Re-probed 2026-08-19 on both the streaming and non-streaming
paths, it now answers as itself. It gets a shortcut (`omni`), a free picker
row, and second place in every free chain; the still-degraded
`mistral-nemotron` slides to third but stays as a genuinely different family.
`nvidia/step-3.7-flash` remains deliberately unaliased — it is billed at $0
and listed in the catalog, but live probes come back served by
`nemotron-3-super-120b`, and an alias that promises a model you don't get is
worse than no alias.

**Picker stays at its 24-row cap — new models displaced old ones.** GLM-5.3
takes GLM-5.2's slot. GPT-5.6 Terra Pro takes the row
`grok-4-1-fast-reasoning` held, which the gateway hides and reconciliation
dropped on every live render anyway. Qwen3.7 Flash ($0.03/$0.13, 1M context,
the cheapest paid model on the gateway) takes GLM-5's budget slot. Gemini 2.5
Pro's row retires from directly under 3.1 Pro. Every retired row keeps its
shortcut, per the long-standing hide-the-row-keep-the-alias rule, and `gemini`
now tracks the 3.1 Pro flagship like `gpt`, `grok` and `glm` already did.

**Also:** the offline picker fallback had stale prices (deepseek at
$0.20/$0.40, corrected to $0.14/$0.28 — live renders were already right since
the gateway is the source of truth for price). Brand numbers re-synced: 95
models visible, 8 video, 5 free. Model-family guidance now recognises
`chat-latest` as a strong model and routes Tencent/Xiaomi to balanced
guidance.

**Second pass — the tables the aliases exposed.** Surfacing the models turned
up three hand-curated tables that had drifted behind the catalog:

- **`xai/grok-4.5` was missing from the vision allowlist.** It is what `grok`
resolves to, and it is vision-capable — so every image turn on the xAI
flagship was quietly rerouted to a "vision sibling" the user never asked
for. Eleven other vision models were missing too (the GPT-5.6 pro tier,
`chat-latest`, `gpt-5.3`, `gpt-4o`, Gemini 3.6 Flash, the free omni model).
A new test pins the invariant: every bare flagship alias must be in the
allowlist, so the next flagship fails CI instead of someone's session.
- **Context windows.** `grok-4.5` (500K), `grok-4.3` (1M) and `glm-5.3` (1M)
had no entry and match no inference pattern, so a cold catalog cache fell
through to the blind 128k default — compacting a 1M window eight times too
early. Twelve entries added.
- **Model-family guidance.** The weak-model branch matched on bare `glm`,
which dates from GLM-4.x. `glm` now resolves to GLM-5.3 — 1M context,
always-on reasoning, priced above Gemini 3.1 Pro on input — and it was being
told to make ONE tool call and stay under 300 words. GLM-5.x moves to
balanced guidance.
- The Brain's third extraction fallback was `nvidia/nemotron-super-49b`, gone
from the catalog; now the current free default.

All 647 local tests pass. The five hidden-but-resolvable ids Franklin still
pins (`opus-4.6`, `gpt-5-nano`, `grok-3`, `grok-4-0709`,
`grok-4-1-fast-reasoning`) were each re-probed and still return 402, not 400 —
they stay.

## Franklin Agent 3.39.0 — the gateway moved for three weeks and Franklin didn't

**Franklin's free default was a dead model, and the whole catalog had drifted.**
Expand Down
14 changes: 7 additions & 7 deletions brand-numbers.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@
"version": 1,
"models": {
"chatVisible": 71,
"totalVisible": 93,
"free": 6,
"freeWithheld": 19,
"totalVisible": 95,
"free": 5,
"freeWithheld": 20,
"image": 9,
"video": 6,
"video": 8,
"music": 1,
"speech": 5,
"soundfx": 1,
"withFallback": 46,
"withFallbackAllEntries": 79
"withFallback": 44,
"withFallbackAllEntries": 78
},
"clawrouter": {
"dimensions": 15,
"tiers": 4,
"profiles": 4,
"aliases": 202
"aliases": 229
},
"mcp": {
"tools": 20
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@blockrun/franklin",
"version": "3.39.0",
"version": "3.40.0",
"description": "Franklin Agent — The AI agent with a wallet. Spends USDC autonomously to get real work done. Pay per action, no subscriptions.",
"type": "module",
"exports": {
Expand Down
21 changes: 15 additions & 6 deletions src/agent/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ You run on the BlockRun AI Gateway. When the user asks you to "test the BlockRun
- \`GET /.well-known/x402\` — x402 resource list with prices

**LLM (POST, x402-paid)**
- \`POST /v1/chat/completions\` — OpenAI-compatible. Body: \`{ model, messages, stream?, tools?, max_tokens?, temperature? }\`. \`model\` MUST come from \`GET /v1/models\` (real frontier examples on the gateway, verified live 2026-08-12: \`anthropic/claude-sonnet-5\`, \`anthropic/claude-opus-5\`, \`deepseek/deepseek-v4-pro\`, \`zai/glm-5.2\`, \`xai/grok-4.5\`, \`nvidia/nemotron-nano-9b-v2\` (free)). Do NOT invent versions like \`openai/gpt-5.1\` or \`xai/grok-5\` — those don't exist; the gateway 400s with the valid list in the error body, so when in doubt fetch \`GET /v1/models\` first.
- \`POST /v1/chat/completions\` — OpenAI-compatible. Body: \`{ model, messages, stream?, tools?, max_tokens?, temperature? }\`. \`model\` MUST come from \`GET /v1/models\` (real frontier examples on the gateway, verified live 2026-08-19: \`anthropic/claude-sonnet-5\`, \`anthropic/claude-opus-5\`, \`openai/gpt-5.6-sol\`, \`deepseek/deepseek-v4-pro\`, \`zai/glm-5.3\`, \`xai/grok-4.5\`, \`qwen/qwen3.7-flash\`, \`nvidia/nemotron-nano-9b-v2\` (free)). Do NOT invent versions like \`openai/gpt-5.1\` or \`xai/grok-5\` — those don't exist; the gateway 400s with the valid list in the error body, so when in doubt fetch \`GET /v1/models\` first.
- \`POST /v1/messages\` — Anthropic-compatible. Body: \`{ model, messages, max_tokens, system?, tools? }\`.

**Media (POST, x402-paid; GET to poll async jobs)**
Expand Down Expand Up @@ -548,8 +548,14 @@ export function assembleInstructions(workingDir: string, model?: string): string
export function getModelGuidance(model: string): string {
const m = model.toLowerCase();

// Weak/cheap models: strict discipline to prevent looping and hallucination
if (m.includes('glm') || m.includes('gpt-oss') || m.includes('nemotron') ||
// Weak/cheap models: strict discipline to prevent looping and hallucination.
// The bare `glm` match dates from the GLM-4.x era. The paid Z.AI GLM-5 line
// is a different animal — 1M context, always-on reasoning, priced above
// Gemini 3.1 Pro on input — and `glm` now resolves to 5.3, so matching it
// here was telling a flagship to make ONE tool call and stay under 300
// words. GLM-5.x moves to the balanced branch; glm-4.7 and friends stay.
if ((m.includes('glm') && !m.includes('glm-5')) ||
m.includes('gpt-oss') || m.includes('nemotron') ||
m.includes('minimax') || m.includes('devstral') || m.includes('llama-4')) {
return `# Execution Discipline (strict — this model requires guardrails)
- Make ONE tool call per task. Do NOT retry the same tool with query variations.
Expand All @@ -560,10 +566,13 @@ export function getModelGuidance(model: string): string {
}

// Medium models: balanced guidance. The bare `qwen` match dates from when
// every qwen id on the gateway was a free NVIDIA SKU — qwen3.7-max is a paid
// 1M-context flagship and belongs in the strong branch below.
// every qwen id on the gateway was a free NVIDIA SKU. The paid Qwen line is
// now Max + Plus + Flash — all 1M-context with reasoning — so only the Max
// flagship graduates to the strong branch; Plus and Flash stay here, and the
// legacy free `nvidia/qwen*` ids keep matching as before.
if (m.includes('kimi') || m.includes('grok') || m.includes('flash') ||
m.includes('haiku') || m.includes('deepseek') ||
m.includes('hy3') || m.includes('mimo') || m.includes('glm-5') ||
(m.includes('qwen') && !m.includes('qwen3.7-max'))) {
return `# Execution Guidance
- Use tools to verify facts before stating them. Do not answer from memory when a tool can confirm.
Expand All @@ -576,7 +585,7 @@ export function getModelGuidance(model: string): string {
if (m.includes('claude') || m.includes('gpt-5') || m.includes('opus') ||
m.includes('sonnet') || m.includes('gemini-2.5-pro') || m.includes('gemini-3') ||
m.includes('o3') || m.includes('o1') || m.includes('codex') ||
m.includes('qwen3.7-max')) {
m.includes('chat-latest') || m.includes('qwen3.7-max')) {
return `# Quality Standards (strong model)
- Keep calling tools until the task is complete AND the result is verified. Don't stop at "this should work" — prove it works.
- Before finalizing: check correctness, grounding in tool output, and formatting.
Expand Down
18 changes: 17 additions & 1 deletion src/agent/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,15 @@ const MODEL_CONTEXT_WINDOWS: Record<string, number> = {
'openai/gpt-5.2': 128_000,
'openai/gpt-5-mini': 128_000,
'openai/gpt-5-nano': 128_000,
'openai/gpt-5.2-pro': 400_000,
'openai/gpt-4.1': 1_000_000,
'openai/gpt-4.1-mini': 128_000,
'openai/gpt-4.1-nano': 128_000,
'openai/gpt-4o': 128_000,
'openai/gpt-4o-mini': 128_000,
'openai/o1': 200_000,
'openai/o3': 200_000,
'openai/o3-mini': 128_000,
'openai/o4-mini': 200_000,
// Google
'google/gemini-2.5-pro': 1_000_000,
Expand All @@ -259,18 +266,27 @@ const MODEL_CONTEXT_WINDOWS: Record<string, number> = {
'google/gemini-3.1-pro': 1_000_000,
'google/gemini-3.5-flash': 1_000_000,
'google/gemini-3.1-flash-lite': 1_000_000,
'google/gemini-3-flash-preview': 1_048_576,
// DeepSeek (V4 family — gateway aliased deepseek-chat / -reasoner to V4
// Flash on 2026-05-03; context bumped 128K → 1M for both, 65K out)
'deepseek/deepseek-chat': 1_000_000,
'deepseek/deepseek-reasoner': 1_000_000,
'deepseek/deepseek-v4-pro': 1_000_000,
// xAI
// xAI. grok-4.5 / 4.3 / build were missing until 2026-08-20: neither matches
// any inference pattern below, so a cold catalog cache fell through to the
// blind 128k default and compacted a 500K–1M window ~4-8x too early.
'xai/grok-4.5': 500_000,
'xai/grok-4.3': 1_000_000,
'xai/grok-build-0.1': 256_000,
'xai/grok-3': 131_072,
'xai/grok-4-0709': 131_072,
'xai/grok-4-1-fast-reasoning': 131_072,
// Others
'zai/glm-5.3': 1_000_000, // flagship 2026-08 — 1M context, always-on reasoning
'zai/glm-5.2': 1_000_000, // flagship bump 2026-06 — context jumped 200K → 1M
'zai/glm-5.1': 200_000,
'zai/glm-5': 200_000,
'zai/glm-5-turbo': 200_000,
'moonshot/kimi-k3': 1_048_576,
'moonshot/kimi-k2.7': 256_000,
'moonshot/kimi-k2.6': 256_000,
Expand Down
7 changes: 6 additions & 1 deletion src/brain/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ import {
addObservation, upsertRelation, isJunkEntityName,
} from './store.js';

// Last entry is the free safety net. nvidia/nemotron-super-49b held it until
// 2026-08-20, by which point it had left the catalog entirely — the free pool
// answers for it with a substitute, so the "free fallback" was neither the
// model named nor reliably shaped. nemotron-nano-9b-v2 is the current free
// default and verifiably serves itself.
const EXTRACTION_MODELS = [
'google/gemini-2.5-flash-lite',
'google/gemini-2.5-flash',
'nvidia/nemotron-super-49b',
'nvidia/nemotron-nano-9b-v2',
];

const VALID_TYPES = new Set<EntityType>(['person', 'project', 'company', 'product', 'concept']);
Expand Down
1 change: 1 addition & 0 deletions src/pricing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export const MODEL_PRICING: Record<string, { input: number; output: number; perC
'zai/glm-5': { input: 1.0, output: 3.2 }, // flat promo ended 2026-06-06; raised upstream 2026-08-07
'zai/glm-5.1': { input: 1.40, output: 4.40 }, // launch promo ended 2026-06-05 — per-token now
'zai/glm-5.2': { input: 1.40, output: 4.40 }, // new flagship 2026-06 — 1M context, same per-token price as 5.1
'zai/glm-5.3': { input: 1.40, output: 4.40 }, // flagship 2026-08 — 1M context, always-on reasoning, priced at 5.2
'zai/glm-5-turbo': { input: 1.2, output: 4.0 }, // flat promo ended 2026-06-06 — per-token now
'zai/glm-5.1-turbo': { input: 1.2, output: 4.0 }, // client alias for zai/glm-5-turbo
};
Expand Down
52 changes: 37 additions & 15 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,10 +414,23 @@ function classicRouteRequest(
// that can't be async (proxy, LLM-client bootstrap) keep using the sync
// `routeRequest`, which silently does keyword-only routing.

// llama-4-maverick: clean one-word classification output. glm-4.7 + qwen-
// thinking emit reasoning into thinking blocks and leave text empty under
// tight max_tokens — fine for chat, wrong shape for single-word dispatch.
const CLASSIFIER_MODEL = process.env.FRANKLIN_ROUTER_MODEL || 'nvidia/qwen3-next-80b-a3b-instruct';
// The classifier needs a free model that answers with ONE BARE WORD under a
// tight max_tokens. That is a narrower requirement than "is a good free chat
// model", and most of the free pool fails it by streaming chain-of-thought
// into `content` (glm-4.7 and the qwen-thinking builds emit reasoning and
// leave text empty; nemotron-nano-9b-v2 opens with "Okay, let's see. The user
// wants to…" and never reaches a verdict inside the budget).
//
// 2026-08-19: the previous default, nvidia/qwen3-next-80b-a3b-instruct, was
// EOL'd by NVIDIA (410 on 2026-07-27) — the gateway now rides its calls on
// nemotron-3-super-120b, which leaks prose. Every classification has been
// failing the strict parse and falling through to keyword-only routing ever
// since, silently, because the fallback is by design invisible.
//
// nemotron-3-nano-omni is the replacement: live-probed on this exact prompt
// shape it returns "MEDIUM" and nothing else, and it verifiably serves itself
// rather than riding a pooled substitute.
const CLASSIFIER_MODEL = process.env.FRANKLIN_ROUTER_MODEL || 'nvidia/nemotron-3-nano-omni-30b-a3b-reasoning';
const CLASSIFIER_TIMEOUT_MS = 2_500;

const CLASSIFIER_SYSTEM = `You classify a user's message into ONE routing tier for a CLI agent. Reply with EXACTLY ONE WORD from the allowed set. No explanation, no punctuation, no quotes.
Expand Down Expand Up @@ -771,22 +784,31 @@ export function getFallbackChain(
// verifiably serves ITSELF on the streaming path Franklin uses (verified live
// through the binary today). mistral-nemotron is DEGRADED at NVIDIA — stream
// calls 400 ("DEGRADED function cannot be invoked") and non-stream calls ride
// the gateway's disclosed fallback — so it sits second: it still answers
// non-streaming turns, and it upgrades the chain automatically if NVIDIA
// restores it. step-3.7-flash leaks thinking prose into content, and the 30B
// omni model came back served as nvidia/gpt-oss-120b (the pooled-substitute
// trap this comment already warns about).
// the gateway's disclosed fallback.
// 2026-08-19: nvidia/nemotron-3-nano-omni-30b-a3b-reasoning promoted to
// second. When it was last probed it came back served as gpt-oss-120b — the
// pooled-substitute trap this comment warns about — but NVIDIA has since
// fixed it: it now answers as ITSELF on both the streaming and non-streaming
// paths, and it returns clean single-word output under tight max_tokens (it
// is also the router's classifier for that reason). mistral-nemotron drops to
// third: still DEGRADED at NVIDIA, kept as a genuinely different family for
// the case where both Nemotron nano builds are down. The catalog's fifth free
// id, step-3.7-flash, stays out of every chain — it leaks thinking prose into
// content AND comes back served by nemotron-3-super-120b.
const OMNI = 'nvidia/nemotron-3-nano-omni-30b-a3b-reasoning';

const FREE_MODELS_BY_CATEGORY: Record<Category, string[]> = {
coding: ['nvidia/nemotron-nano-9b-v2', 'nvidia/mistral-nemotron'],
trading: ['nvidia/nemotron-nano-9b-v2', 'nvidia/mistral-nemotron'],
research: ['nvidia/nemotron-nano-9b-v2', 'nvidia/mistral-nemotron'],
reasoning: ['nvidia/nemotron-nano-9b-v2', 'nvidia/mistral-nemotron'],
chat: ['nvidia/nemotron-nano-9b-v2', 'nvidia/mistral-nemotron'],
creative: ['nvidia/nemotron-nano-9b-v2', 'nvidia/mistral-nemotron'],
coding: ['nvidia/nemotron-nano-9b-v2', OMNI, 'nvidia/mistral-nemotron'],
trading: ['nvidia/nemotron-nano-9b-v2', OMNI, 'nvidia/mistral-nemotron'],
research: ['nvidia/nemotron-nano-9b-v2', OMNI, 'nvidia/mistral-nemotron'],
reasoning: ['nvidia/nemotron-nano-9b-v2', OMNI, 'nvidia/mistral-nemotron'],
chat: ['nvidia/nemotron-nano-9b-v2', OMNI, 'nvidia/mistral-nemotron'],
creative: ['nvidia/nemotron-nano-9b-v2', OMNI, 'nvidia/mistral-nemotron'],
};

const DEFAULT_FREE_CHAIN: string[] = [
'nvidia/nemotron-nano-9b-v2',
OMNI,
'nvidia/mistral-nemotron',
];

Expand Down
Loading
Loading