Skip to content

Commit 386707e

Browse files
authored
fix(agent): stabilize DeepSeek app previews (#130)
## Summary - route the included DeepSeek model through the official deepseek-v4-pro transport - show DeepSeek V4 Pro in the product catalog and bundled product knowledge - copy source-only app templates without archive metadata operations on Daytona FUSE ## Why Production diagnostics showed the sandbox starts correctly, but archive-mode template copies try to preserve metadata unsupported by the S3-backed workspace mount and can time out. A separate DeepSeek V4 Flash run also showed weak adherence to the managed app scaffold. This change removes the filesystem failure and moves the included model to V4 Pro for an exact production comparison. ## Verification - pnpm turbo typecheck lint build --force - pnpm architecture:check - pnpm deadcode - git diff --check - direct Daytona CLI inspection of the production sandbox and workspace mount - direct agent-browser production QA after deployment
1 parent 494791e commit 386707e

5 files changed

Lines changed: 21 additions & 18 deletions

File tree

apps/agent-worker/src/durable-objects/agent-run-app-builder-scaffold.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export async function scaffoldExpoApp(
8484
logger: AgentRunLogger,
8585
dir: string,
8686
): Promise<void> {
87-
// Copy the template CONTENTS (`src/.` → `dst/`), never `cp -a src dst`: the latter nests as
87+
// Copy the template CONTENTS (`src/.` → `dst/`), never `cp -R src dst`: the latter nests as
8888
// `dst/cheatcode-expo-template/` when `dst` already exists (the run-start `mkdir -p` of the
8989
// workspace dir can win the race), silently yielding a project with no package.json at its root.
9090
// `test -f` verifies the baked, lockfile-backed layout. A missing template means the immutable
@@ -102,7 +102,7 @@ export async function scaffoldAppBuilder(
102102
logger: AgentRunLogger,
103103
dir: string,
104104
): Promise<void> {
105-
// Copy template CONTENTS into the project dir (see scaffoldExpoApp): `cp -a src dst` nests as
105+
// Copy template CONTENTS into the project dir (see scaffoldExpoApp): `cp -R src dst` nests as
106106
// `dst/cheatcode-next-template/` when `dst` already exists, leaving no package.json at the root.
107107
if (await copyTemplateContents(sandbox, NEXT_TEMPLATE_DIR, dir)) {
108108
logger.info("sandbox_next_template_copied", { targetDir: dir });
@@ -216,19 +216,22 @@ export async function ensureExpoWebSupport(
216216
}
217217

218218
// Populate `dir` with the CONTENTS of a baked template (`src/.` copies dotfiles too), then verify a
219-
// package.json landed at the root. Returns false instead of throwing so callers fall back to a
220-
// generator only on a genuine failure. `dir` is a filesystem-safe /workspace/<slug> path (no shell
221-
// metacharacters), so the interpolation is safe; the whole script is shell-quoted by the exec layer.
219+
// package.json landed at the root. `/workspace` is Daytona's object-store FUSE mount: recursive copy
220+
// is intentional because archive mode tries to preserve ownership, modes, and timestamps that the
221+
// mount does not support, making a tiny source-only scaffold hang until its timeout. Immutable
222+
// dependencies remain on the snapshot-local filesystem. `dir` is a filesystem-safe
223+
// /workspace/<slug> path (no shell metacharacters), so interpolation is safe; the whole script is
224+
// shell-quoted by the exec layer.
222225
async function copyTemplateContents(
223226
sandbox: ProjectSandboxStub,
224227
templateDir: string,
225228
dir: string,
226229
): Promise<boolean> {
227230
const copied = await executeShellTerminal(
228231
{
229-
command: `mkdir -p ${dir} && cp -a ${templateDir}/. ${dir}/ && test -f ${dir}/package.json`,
232+
command: `mkdir -p ${dir} && cp -R -- ${templateDir}/. ${dir}/ && test -f ${dir}/package.json`,
230233
cwd: "/workspace",
231-
timeoutMs: 30_000,
234+
timeoutMs: 60_000,
232235
},
233236
{ sandbox },
234237
);

apps/agent-worker/src/durable-objects/llm-provider.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ async function resolveProviderKey(
200200

201201
/**
202202
* Transport rule: (a) the user's direct provider key
203-
* always wins. The platform DeepSeek key then serves the `deepseek-v4-flash` SKU —
203+
* always wins. The platform DeepSeek key then serves the `deepseek-v4-pro` SKU —
204204
* before OpenRouter when the user explicitly picked it, or after OpenRouter as the last
205205
* resort for an Auto/implicit run with no usable key. (c) Otherwise a non-OpenRouter
206206
* selection routes through OpenRouter when a key is present. Runs inside the caller's
@@ -219,12 +219,12 @@ async function resolveTransportKey(
219219
return transportCredential(directKey, logicalModelId, selection);
220220
}
221221

222-
const wantsPlatformFlash =
222+
const wantsPlatformPro =
223223
selection.provider === "deepseek" && selection.modelId === DEFAULT_DEEPSEEK_MODEL_ID;
224224
const platformKey = allowedPlatformKey(platformFallback);
225225

226226
// (b) Explicit platform-model pick → platform key before OpenRouter.
227-
if (wantsPlatformFlash && platformKey) {
227+
if (wantsPlatformPro && platformKey) {
228228
return platformTransport(platformKey);
229229
}
230230

packages/agent-core/src/mastra/agents/general.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ function createOpenRouterByokModel(
8181

8282
/**
8383
* DeepSeek model — serves both the included platform route and user BYOK keys.
84-
* Pass the bare provider id (`deepseek-v4-flash`); non-thinking mode is selected at the
84+
* Pass the bare provider id (`deepseek-v4-pro`); non-thinking mode is selected at the
8585
* stream call site via providerOptions so tool-calling stays clean.
8686
*/
8787
function createDeepSeekModel(

packages/types/src/models.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function logicalModelId<const Value extends string>(value: Value): Value & Logic
2121
const RAW_CATALOG_MODEL_IDS = {
2222
claudeOpus: "anthropic/claude-opus-4-8",
2323
claudeSonnet: "anthropic/claude-sonnet-4-6",
24-
deepseekFlash: "deepseek/deepseek-v4-flash",
24+
deepseekPro: "deepseek/deepseek-v4-pro",
2525
gptMini: "openai/gpt-5.4-mini",
2626
gptThinking: "openai/gpt-5.4-thinking",
2727
} as const;
@@ -31,14 +31,14 @@ const RAW_CATALOG_MODEL_ID_VALUES = [
3131
RAW_CATALOG_MODEL_IDS.claudeOpus,
3232
RAW_CATALOG_MODEL_IDS.gptThinking,
3333
RAW_CATALOG_MODEL_IDS.gptMini,
34-
RAW_CATALOG_MODEL_IDS.deepseekFlash,
34+
RAW_CATALOG_MODEL_IDS.deepseekPro,
3535
] as const;
3636

3737
/**
3838
* The single source of truth for the agent model catalog shown in the picker.
3939
*
4040
* Curated to the live Models list: Claude Sonnet 4.6, Claude Opus 4.8,
41-
* GPT-5.4 Thinking, GPT-5.4 Mini, and the included DeepSeek V4 model. Gemini 2.5
41+
* GPT-5.4 Thinking, GPT-5.4 Mini, and the included DeepSeek V4 Pro model. Gemini 2.5
4242
* Flash and the standalone OpenRouter-Auto row stay reachable as provider-prefixed
4343
* request ids routed through OpenRouter, but are not drawn in the picker.
4444
*
@@ -71,8 +71,8 @@ export const AGENT_MODEL_CATALOG = [
7171
description: "Fast fallback model for lower-cost utility runs.",
7272
},
7373
{
74-
id: logicalModelId(RAW_CATALOG_MODEL_IDS.deepseekFlash),
75-
label: "DeepSeek V4",
74+
id: logicalModelId(RAW_CATALOG_MODEL_IDS.deepseekPro),
75+
label: "DeepSeek V4 Pro",
7676
provider: "deepseek",
7777
description: "Included by Cheatcode with no provider key required.",
7878
},
@@ -92,7 +92,7 @@ export const FALLBACK_MODEL_ID = logicalModelId(
9292
* without a provider key and the only model served by Cheatcode's DeepSeek key.
9393
*/
9494
export const INCLUDED_DEEPSEEK_MODEL_ID = logicalModelId(
95-
RAW_CATALOG_MODEL_IDS.deepseekFlash,
95+
RAW_CATALOG_MODEL_IDS.deepseekPro,
9696
) satisfies CatalogModelId;
9797

9898
/** Validate against raw literals first; Zod enums cannot retain branded string tuples. */

skills/product-self-knowledge/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ The visible model catalog is:
4747
| Claude Opus 4.8 | Anthropic | Highest-capability Anthropic option |
4848
| GPT-5.4 Thinking | OpenAI | Reasoning-focused option |
4949
| GPT-5.4 Mini | OpenAI | Fast utility option |
50-
| DeepSeek V4 | DeepSeek | Included platform route |
50+
| DeepSeek V4 Pro | DeepSeek | Included platform route |
5151

5252
Cheatcode accepts provider-prefixed OpenRouter and Google model IDs even though those providers are not shown as separate catalog rows. BYOK keys are configured in Models and are decrypted only for the active request. Supported provider key families are Anthropic, OpenAI, Google, OpenRouter, DeepSeek, Exa, and Firecrawl. BYOK key counts are not limited by subscription-plan slots.
5353

0 commit comments

Comments
 (0)