Files
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
6.7 KiB
JSON

{"repo": "atomicstrata/epistemic", "files": {"packages/omp/src/omp-upstream/packages/coding-agent/test/issue-985-subagent-auth-fallback.test.ts": {"6561f99cca46b8acc233f40424a1f4dadf352765": {"t": 1786068364.400731, "n": 6090, "h": "72dd913b1289f0e4", "c": "import { describe, expect, test } from \"bun:test\";\nimport type { Api, Model } from \"@oh-my-pi/pi-ai\";\nimport { kNoAuth } from \"@oh-my-pi/pi-coding-agent/config/model-registry\";\nimport {\n\ttype ModelLookupRegistry,\n\tresolveModelOverrideWithAuthFallback,\n} from \"@oh-my-pi/pi-coding-agent/config/model-resolver\";\n\n/**\n * Regression test for #985.\n *\n * Reporter screenshot showed parent session on DeepSeek V4 Pro dispatching a\n * task subagent that resolved to `qwen3.6-plus-free` — an opencode-zen model\n * the user has no working credentials for. The dispatch hit a provider that\n * could not serve the model and surfaced a confusing API rejection instead of\n * silently using the parent's already-authenticated model.\n *\n * The fix: at dispatch time, if the resolved subagent model has no working\n * credentials, fall back to the parent session's active model (which by\n * definition has working auth — the parent turn is using it).\n */\n\nconst parentModel: Model<Api> = {\n\tid: \"deepseek-v4-pro\",\n\tname: \"DeepSeek V4 Pro\",\n\tapi: \"openai-completions\",\n\tprovider: \"deepseek\",\n\tbaseUrl: \"https://api.deepseek.com\",\n\treasoning: false,\n\tinput: [\"text\"],\n\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\tcontextWindow: 128000,\n\tmaxTokens: 8192,\n};\n\nconst unauthedTaskModel: Model<Api> = {\n\tid: \"qwen3.6-plus-free\",\n\tname: \"Qwen3.6 Plus Free\",\n\tapi: \"openai-completions\",\n\tprovider: \"opencode-zen\",\n\tbaseUrl: \"https://opencode.ai/zen/v1\",\n\treasoning: false,\n\tinput: [\"text\"],\n\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\tcontextWindow: 128000,\n\tmaxTokens: 8192,\n};\n\nconst sharedModel: Model<Api> = {\n\tid: \"shared-id\",\n\tname: \"Shared\",\n\tapi: \"openai-completions\",\n\tprovider: \"deepseek\",\n\tbaseUrl: \"https://api.deepseek.com\",\n\treasoning: false,\n\tinput: [\"text\"],\n\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\tcontextWindow: 128000,\n\tmaxTokens: 8192,\n};\n\ninterface MockRegistryOptions {\n\tmodels: Model<Api>[];\n\tauthedProviders: Set<string>;\n}\n\nfunction createMockRegistry(options: MockRegistryOptions): ModelLookupRegistry & {\n\tgetApiKey(model: Model<Api>): Promise<string | undefined>;\n} {\n\treturn {\n\t\tgetAvailable: () => options.models,\n\t\tgetApiKey: async (model: Model<Api>) =>\n\t\t\toptions.authedProviders.has(model.provider) ? \"sk-test-token\" : undefined,\n\t} as unknown as ModelLookupRegistry & { getApiKey(model: Model<Api>): Promise<string | undefined> };\n}\n\ndescribe(\"issue #985: subagent dispatch auth fallback\", () => {\n\ttest(\"falls back to parent active model when resolved subagent model has no auth\", async () => {\n\t\tconst registry = createMockRegistry({\n\t\t\tmodels: [parentModel, unauthedTaskModel],\n\t\t\tauthedProviders: new Set([\"deepseek\"]), // user has DeepSeek; opencode-zen unauthed\n\t\t});\n\n\t\tconst result = await resolveModelOverrideWithAuthFallback(\n\t\t\t[\"qwen3.6-plus-free\"],\n\t\t\t\"deepseek/deepseek-v4-pro\",\n\t\t\tregistry,\n\t\t);\n\n\t\texpect(result.authFallbackUsed).toBe(true);\n\t\texpect(result.model?.provider).toBe(\"deepseek\");\n\t\texpect(result.model?.id).toBe(\"deepseek-v4-pro\");\n\t});\n\n\ttest(\"does not fall back when resolved subagent model has working auth\", async () => {\n\t\tconst registry = createMockRegistry({\n\t\t\tmodels: [parentModel, unauthedTaskModel],\n\t\t\tauthedProviders: new Set([\"deepseek\", \"opencode-zen\"]),\n\t\t});\n\n\t\tconst result = await resolveModelOverrideWithAuthFallback(\n\t\t\t[\"qwen3.6-plus-free\"],\n\t\t\t\"deepseek/deepseek-v4-pro\",\n\t\t\tregistry,\n\t\t);\n\n\t\texpect(result.authFallbackUsed).toBe(false);\n\t\texpect(result.model?.provider).toBe(\"opencode-zen\");\n\t\texpect(result.model?.id).toBe(\"qwen3.6-plus-free\");\n\t});\n\n\ttest(\"returns primary unchanged when parent active model also has no auth\", async () => {\n\t\tconst registry = createMockRegistry({\n\t\t\tmodels: [parentModel, unauthedTaskModel],\n\t\t\tauthedProviders: new Set(), // nothing authed\n\t\t});\n\n\t\tconst result = await resolveModelOverrideWithAuthFallback(\n\t\t\t[\"qwen3.6-plus-free\"],\n\t\t\t\"deepseek/deepseek-v4-pro\",\n\t\t\tregistry,\n\t\t);\n\n\t\texpect(result.authFallbackUsed).toBe(false);\n\t\texpect(result.model?.provider).toBe(\"opencode-zen\");\n\t\texpect(result.model?.id).toBe(\"qwen3.6-plus-free\");\n\t});\n\n\ttest(\"returns primary unchanged when no parent active model is provided\", async () => {\n\t\tconst registry = createMockRegistry({\n\t\t\tmodels: [parentModel, unauthedTaskModel],\n\t\t\tauthedProviders: new Set([\"deepseek\"]),\n\t\t});\n\n\t\tconst result = await resolveModelOverrideWithAuthFallback([\"qwen3.6-plus-free\"], undefined, registry);\n\n\t\texpect(result.authFallbackUsed).toBe(false);\n\t\texpect(result.model?.provider).toBe(\"opencode-zen\");\n\t});\n\n\ttest(\"does not fall back when subagent and parent resolve to the same model\", async () => {\n\t\tconst registry = createMockRegistry({\n\t\t\tmodels: [sharedModel],\n\t\t\tauthedProviders: new Set(), // even with no auth, identical model means no benefit\n\t\t});\n\n\t\tconst result = await resolveModelOverrideWithAuthFallback([\"deepseek/shared-id\"], \"deepseek/shared-id\", registry);\n\n\t\texpect(result.authFallbackUsed).toBe(false);\n\t\texpect(result.model?.id).toBe(\"shared-id\");\n\t});\n\n\ttest(\"treats keyless providers (kNoAuth marker) as authenticated\", async () => {\n\t\t// Keyless-by-design providers (Ollama, llama.cpp, lm-studio) advertise the\n\t\t// kNoAuth sentinel from getApiKey to signal that they do not require\n\t\t// credentials. The helper treats this as authenticated so an explicitly\n\t\t// configured local model is never silently rerouted to the parent's\n\t\t// remote provider (see #1008).\n\t\tconst registry: ModelLookupRegistry & { getApiKey(model: Model<Api>): Promise<string | undefined> } = {\n\t\t\tgetAvailable: () => [parentModel, unauthedTaskModel],\n\t\t\tgetApiKey: async (model: Model<Api>) => {\n\t\t\t\tif (model.provider === \"deepseek\") return \"sk-test\";\n\t\t\t\tif (model.provider === \"opencode-zen\") return kNoAuth;\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t} as never;\n\n\t\tconst result = await resolveModelOverrideWithAuthFallback(\n\t\t\t[\"qwen3.6-plus-free\"],\n\t\t\t\"deepseek/deepseek-v4-pro\",\n\t\t\tregistry,\n\t\t);\n\n\t\texpect(result.authFallbackUsed).toBe(false);\n\t\texpect(result.model?.provider).toBe(\"opencode-zen\");\n\t\texpect(result.model?.id).toBe(\"qwen3.6-plus-free\");\n\t});\n});\n"}}}}