Skip to content

fix(scout): say yes to DeepSeek models, name both paths, and point OpenCode at its guide - #2347

Merged
lilyshen0722 merged 1 commit into
mainfrom
fix/scout-deepseek-truth
Oct 19, 2026
Merged

lilyshen0722 merged 1 commit into
mainfrom
fix/scout-deepseek-truth

Conversation

@lilyshen0722

Copy link
Copy Markdown
Contributor

What happened

On 10-19 a new person asked Scout whether DeepSeek Harness (dsh) could connect. Scout told them only Claude Code or Codex agents can join and that DeepSeek models can't be chosen here. They left within two minutes. Two of the last three outside signups who typed something asked for a non-Claude model.

Both of Scout's claims were wrong:

What changes

Scout's prompt (backend/config/native-agents/scout.ts):

  • DeepSeek models: yes, two ways. "Run it here", or the person's own OpenCode pointed at DeepSeek's API through docs/cli/opencode.md.
  • dsh can't connect yet, with no promise of when. When someone asks for dsh, Scout leads with the yes for DeepSeek models.
  • OpenCode connects from the command line through its guide, never through the connect card, which still sets up Claude Code or Codex only.
  • Qwen Code and pi are named as not ready for outside use. This replaces "The listener runs Claude Code or Codex. Do not claim it runs any other tool."
  • Gemini stays "can't join yet". It was walked on 10-19 and failed: TASK-291, and the guide's Gemini note.

The hosted model, without a copy in the prompt (backend/services/nativeRuntimeService.ts):

  • The commonly_offer_hosted_agent description now says a hosted agent runs on HOSTED_MODEL_NAME and that the person can't choose another model today.
  • HOSTED_MODEL_NAME is built from DEFAULT_MODEL, the same value a hosted turn runs on, because hostedNativeRunConfig leaves model unset. So it follows LITELLM_CHAT_MODEL the way the limits line does (feat(hosted): the plan line — 30 hosted turns a day free, 200 on Pro (TASK-268) #2237).
  • Scout names the model only when someone asks which model or runtime it uses (Cofounder's ruling). The prompt test still bans the model name from the prompt.

Tests

  • nativeAgents.scoutKnowledge.test.js:
    • The DeepSeek and OpenCode lines are pinned.
    • The guide is checked to exist.
    • The hosted-offer description is checked twice:
      • with the default model, it names DeepSeek V4 Flash;
      • with LITELLM_CHAT_MODEL=some-other-model it follows the deployment. A mutation that hard-codes the name turns that arm red.
  • docsSiteFacts.test.js: a comment corrected; no assertion changed.

Behaviour check

The new prompt and tool list were sent to the live model from the backend pod. The key stayed in the pod env.

Asked Scout
"Can I connect dsh here? DeepSeek Harness" "Not yet — dsh itself can't connect. DeepSeek's models can, though, two ways…" (OpenCode guide, or Run it here)
"Which model does Run it here use? Can I pick a different one?" Names DeepSeek V4 Flash and says it can't be changed today
"Hi! What can you do?" No mention of DeepSeek
"Can I bring Qwen Code in?" "Not yet — Qwen Code isn't ready for outside use…"

After deploy

Each person's Scout keeps the prompt from signup. After the deploy, run node dist/scripts/refresh-native-agent-configs.js --app scout in the backend pod: a dry run first, then --apply. Report the count.

Focused suites: 26/26 on Node 22 locally.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Wkz5axAzCvoLEFkZ5KtkKG

…enCode at its guide

A new person asked Scout whether DeepSeek Harness could connect and heard
that DeepSeek models could not be used here. They left within two minutes.
Hosted agents already run on DeepSeek V4 Flash, and OpenCode on a DeepSeek
model was walked end to end the same day.

- The hosted offer's description names the model a hosted turn runs on,
  built from the same default the runtime uses (LITELLM_CHAT_MODEL), so it
  follows the deployment the way the limits line does. Scout names it only
  when asked about models or runtime.
- Scout says yes to DeepSeek models two ways (Run it here, or OpenCode on
  DeepSeek's API through docs/cli/opencode.md), says dsh itself can't
  connect yet without promising when, and stops claiming the only tools
  are Claude Code and Codex. Qwen Code and pi are named as not ready.
- Gemini stays "can't join yet".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wkz5axAzCvoLEFkZ5KtkKG

@lilyshen0722 lilyshen0722 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Written by Sprint Review, a Commonly agent — code gate at 071bdbefff9bc783663a4de330f4d9542693e9b0 (TASK-311 / Scout), requested by lily-shen in pod message 79209.

Both halves of the stated property hold. BASE and RESTORED both 2 suites / 22 passed. Every claim below is checked against code or against a dated walk, not against the PR body's table.

The model reaches Scout only from the deployment — and it is enforced, not merely unexposed

The plumbing is tighter than the row claims, and the stronger fact is worth having on the record. At nativeRuntimeService.ts:1311-1314 a hosted-native turn replaces the config outright:

const cfg = hostedNative
  ? normalizeConfig(hostedNativeRunConfig(installation, hostedTurnsPerDay, {...}))
  : installedCfg;

The stored installedCfg is discarded for hosted turns, and hostedNativeRunConfig returns no model key (0 occurrences). So cfg.model is undefined on every hosted turn and :1607's String(cfg.model || DEFAULT_MODEL) resolves to DEFAULT_MODEL unconditionally. "The person cannot choose another model today" is true by construction — even a stored install carrying a model could not change it, so the claim does not rest on the absence of a UI control.

DEFAULT_MODEL is process.env.LITELLM_CHAT_MODEL || 'deepseek-v4-flash' (:87), and the live backend deployment declares LITELLM_CHAT_MODEL = deepseek-v4-flash, so the sentence Scout will actually speak in production today is the true one rather than a coincidence of the fallback.

mutation (needle asserted at 1) red
HOSTED_MODEL_NAME becomes the literal 'DeepSeek V4 Flash' follows LITELLM_CHAT_MODEL when the deployment changes it
MODEL_DISPLAY_NAMES emptied (falls back to the raw id) names DeepSeek V4 Flash for the default model, and says it cannot be changed
the model name copied into the prompt names Codex as the GPT path… — via expect(prompt).not.toMatch(/v4[ -]?flash/i)
the dsh caveat turned into a promise says yes to DeepSeek models and names both paths, without promising dsh
Do not claim any other tool connects removed connects OpenCode through its guide, never through the connect card

The third row is the one that matters most for this PR's shape: the prompt is held to naming no model, so the only route is the tool description. Both directions are pinned — the description must follow the env, and the prompt must not duplicate it.

The last row also answers a question the diff raises. The old guard line "The listener runs Claude Code or Codex. Do not claim it runs any other tool" is removed, which on its face loosens Scout. It does not: the replacement carries Do not claim any other tool connects in a wider frame (own-agent paths rather than listener-only), and removing that sentence reds a test. The guard survived the rewrite with a reader attached.

The product claims, one at a time

  • DeepSeek hosted — true: hosted turns run on DEFAULT_MODEL, live value deepseek-v4-flash.
  • DeepSeek through OpenCode — the guide Scout names exists at this head (docs/cli/opencode.md, 128 lines) and actually describes the thing claimed: a chosen provider with your own key, provider.id / baseURL / keyFile in environment.json, with a DeepSeek example. It also says in its own text that Linux and Windows have not been walked, matching Scout's "walked on a Mac only". The suite now asserts the file exists, so the citation cannot rot silently.
  • dsh cannot connect — true by absence of any path: a word-boundary search for dsh across cli/ and backend/ (excluding tests) returns exactly one hit, Scout's own sentence. There is no adapter, no route, nothing to connect with.
  • OpenCode never through the connect card — true: the page types the listener adapter 'claude' | 'codex' (4 occurrences in V2AgentBYO.tsx) and ADAPTERS_WITH_GRANT_BROKER is exactly {claude, codex} (default-environment.js:51), so serverAdapterBindingRefusal refuses opencode on a Connect-page key.
  • Gemini unchanged — correct, and now the best-evidenced claim in the set: TASK-291's 10-19 walk returned NO, with the cause one layer above anything the route check could see (Gemini 3 requires thought_signature echoed on every functionCall, which @ai-sdk/openai-compatible does not carry).
  • Qwen Code and pi "not ready for outside use" — this is the one I can only partly verify, and I would rather say so than imply a check I did not run. What I confirmed: neither is in the broker set, neither is offered by the page, and host-check.js records that pi refuses a declared sandbox by design ("confining pi belongs to pi's own sandbox work"). That supports not offered and not confined. "Not ready" is a product judgement on top of that, and nothing in the code contradicts it.

Notes, neither blocking

  1. MODEL_DISPLAY_NAMES holds one entry, so any other deployment value is spoken as its raw id — "A hosted agent runs on deepseek-v4-flash-0711". Accurate but unpolished, and the fallback has its own arm, so this is a deliberate trade rather than a gap.
  2. docsSiteFacts.test.js still asserts the docs-site quickstart and connect pages contain no --adapter (qwen|opencode|pi), while Scout now points at a repo guide that necessarily does. Those are different surfaces and the comment was updated to say so, so there is no conflict today — but the two now encode opposite expectations about the same adapter name, and a future reader moving the guide's content onto the docs site would trip the assertion. Worth a line in the test naming which surface the ban applies to.

CI at this exact head: 14 pass, 0 pending or failing, including Test & Coverage, E2E Tests and Service Tests (Tier 1 — real DBs). merge-tree clean against main 0c3d25c8e — re-fetched and re-read rather than reusing the sha from my previous gate, after misnaming it on #2337 earlier today. Head unchanged from the one requested.

No defects.

GATE: PASS

@lilyshen0722
lilyshen0722 added this pull request to the merge queue Oct 19, 2026
Merged via the queue into main with commit e94e2ab Oct 19, 2026
17 checks passed
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.

1 participant