-
Notifications
You must be signed in to change notification settings - Fork 1
fix(intelligence): replace Workers AI model deprecated 2026-05-30 #290
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| /** | ||
| * Workers AI model resolution for the ChittyConnect intelligence layer. | ||
| * | ||
| * `@cf/meta/llama-3.1-8b-instruct` aliases `@cf/meta/infire-llama-3.1-8b-instruct`, | ||
| * which Cloudflare deprecated on 2026-05-30. Calls to it fail with error 5028, so | ||
| * every intelligence-layer AI path that hardcoded it has been silently degraded | ||
| * since that date. Resolve the model through this module instead of inlining an id, | ||
| * so the next deprecation is a single env var away from being handled. | ||
| */ | ||
|
|
||
| export const AI_MODEL_DEFAULT = "@cf/meta/llama-4-scout-17b-16e-instruct"; | ||
|
|
||
| /** | ||
| * @param {{AI_MODEL_PRIMARY?: string}} env | ||
| * @returns {string} model id to pass to env.AI.run() | ||
| */ | ||
| export function resolveAiModel(env) { | ||
| return env?.AI_MODEL_PRIMARY || AI_MODEL_DEFAULT; | ||
| } | ||
|
|
||
| /** | ||
| * Workers AI returns a chat-completions envelope that carries the generated text | ||
| * both as a top-level `response` string and under `choices[0].message.content`. | ||
| * Read both so a model whose envelope omits either shape does not degrade to | ||
| * `undefined` — an undefined summary is a silent failure, which is worse than the | ||
| * loud one it would replace. | ||
| * | ||
| * @param {unknown} result value returned by env.AI.run() | ||
| * @returns {string} generated text, or "" when the envelope carries none | ||
| */ | ||
| export function extractAiText(result) { | ||
| if (typeof result === "string") return result; | ||
| if (!result || typeof result !== "object") return ""; | ||
| if (typeof result.response === "string") return result.response; | ||
| const choice = Array.isArray(result.choices) ? result.choices[0] : null; | ||
| const content = choice?.message?.content; | ||
| return typeof content === "string" ? content : ""; | ||
|
chitcommit marked this conversation as resolved.
Outdated
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| /** | ||
| * Tests for Workers AI model resolution. | ||
| * | ||
| * The envelopes below are not hand-written fixtures — they are the verbatim | ||
| * payloads returned by production Workers AI on 2026-09-04 via | ||
| * POST https://connect.chitty.cc/api/thirdparty/cloudflare/ai/run, recorded so | ||
| * the parser is exercised against the shape the platform actually emits rather | ||
| * than the shape we assume it emits. | ||
| */ | ||
|
|
||
| import { describe, it, expect } from "vitest"; | ||
| import { | ||
| AI_MODEL_DEFAULT, | ||
| resolveAiModel, | ||
| extractAiText, | ||
| } from "../../src/lib/ai-model.js"; | ||
|
|
||
| // Recorded live: model "@cf/meta/llama-4-scout-17b-16e-instruct", prompt "reply with the word ok" | ||
| const LIVE_SCOUT_ENVELOPE = { | ||
| choices: [ | ||
| { | ||
| finish_reason: "stop", | ||
| index: 0, | ||
| logprobs: null, | ||
| message: { | ||
| annotations: null, | ||
| audio: null, | ||
| content: "ok", | ||
| function_call: null, | ||
| reasoning: null, | ||
| refusal: null, | ||
| role: "assistant", | ||
| }, | ||
| routed_experts: null, | ||
| stop_reason: null, | ||
| token_ids: null, | ||
| }, | ||
| ], | ||
| created: 1788561543, | ||
| id: "chatcmpl-a318096f-ca2c-423a-a8bc-4813ca68c36f", | ||
| model: "@cf/meta/llama-4-scout-17b-16e-instruct", | ||
| object: "chat.completion", | ||
| response: "ok", | ||
| tool_calls: [], | ||
| usage: { prompt_tokens: 15, completion_tokens: 2, total_tokens: 17 }, | ||
| }; | ||
|
|
||
| describe("resolveAiModel", () => { | ||
| it("defaults to a model that is live in production, not the 2026-05-30 deprecated one", () => { | ||
| expect(resolveAiModel({})).toBe(AI_MODEL_DEFAULT); | ||
| expect(AI_MODEL_DEFAULT).not.toContain("llama-3.1-8b-instruct"); | ||
| }); | ||
|
|
||
| it("honours the AI_MODEL_PRIMARY override so the next deprecation needs no code change", () => { | ||
| expect( | ||
| resolveAiModel({ | ||
| AI_MODEL_PRIMARY: "@cf/meta/llama-3.3-70b-instruct-fp8-fast", | ||
| }), | ||
| ).toBe("@cf/meta/llama-3.3-70b-instruct-fp8-fast"); | ||
| }); | ||
|
|
||
| it("tolerates a missing env rather than throwing inside a catch-wrapped AI path", () => { | ||
| expect(resolveAiModel(undefined)).toBe(AI_MODEL_DEFAULT); | ||
| }); | ||
| }); | ||
|
|
||
| describe("extractAiText", () => { | ||
| it("reads the live production envelope", () => { | ||
| expect(extractAiText(LIVE_SCOUT_ENVELOPE)).toBe("ok"); | ||
| }); | ||
|
|
||
| it("still reads the envelope when the compat `response` field is absent", () => { | ||
| const { response: _dropped, ...choicesOnly } = LIVE_SCOUT_ENVELOPE; | ||
| expect(extractAiText(choicesOnly)).toBe("ok"); | ||
| }); | ||
|
|
||
| it("returns empty string — never undefined — for an envelope carrying no text", () => { | ||
| // A caller that stores undefined turns a loud failure into a silent one. | ||
| for (const empty of [ | ||
| {}, | ||
| { choices: [] }, | ||
| { choices: [{ message: {} }] }, | ||
| null, | ||
| 7, | ||
| ]) { | ||
| expect(extractAiText(empty)).toBe(""); | ||
| } | ||
| }); | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.