fix(web,llm): address review — document the card contract, pin the host diagnosis, gate the probe
This commit is contained in:
@@ -31,6 +31,10 @@ const retryScenarioDir = join(snapshotsDir, 'provider-retry')
|
||||
const retryConfigPath = fileURLToPath(new URL('../retry.cordis.snapshot.yml', import.meta.url))
|
||||
const credentialsScenarioDir = join(snapshotsDir, 'missing-credential')
|
||||
const credentialsConfigPath = fileURLToPath(new URL('../credentials.cordis.snapshot.yml', import.meta.url))
|
||||
// Same keyless composition as the missing-credential scenario: the endpoint is
|
||||
// never dialed either way, because a supplied-but-unusable key fails credential
|
||||
// resolution exactly where an absent one does.
|
||||
const invalidCredentialScenarioDir = join(snapshotsDir, 'invalid-credential')
|
||||
const ralphScenarioDir = join(snapshotsDir, 'ralph-loop')
|
||||
const ralphConfigPath = fileURLToPath(new URL('../ralph.cordis.snapshot.yml', import.meta.url))
|
||||
const startupFailureConfigPath = fileURLToPath(new URL('./fixtures/startup-activation-error/cordis.yml', import.meta.url))
|
||||
@@ -254,6 +258,42 @@ describe('headless stream-json snapshots', () => {
|
||||
expect(normalized).toContain('as a last resort')
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
|
||||
it('logs actionable invalid-credential guidance through the one-shot app', async () => {
|
||||
const streamExpected = join(invalidCredentialScenarioDir, 'stream-json.expected.jsonl')
|
||||
let runCwd = ''
|
||||
const result = await runLoaderSmoke({
|
||||
label: 'invalid-credential headless stream-json snapshot',
|
||||
tempDirPrefix: 'headless-snapshot-invalid-credential-',
|
||||
binScript,
|
||||
configPath: credentialsConfigPath,
|
||||
binArgs: ['--config', credentialsConfigPath, '--output-format', 'stream-json', 'say pong'],
|
||||
tsconfigPath,
|
||||
env: {
|
||||
// A key that exists but no HTTP header can carry — the paste this
|
||||
// change exists for. Before it, `fetch` refused to build the header
|
||||
// and the turn ended on a retried ByteString TypeError.
|
||||
DEEPSEEK_API_KEY: 'sk-\u{1F600}pasted-from-a-chat-window',
|
||||
DEEPSEEK_BASE_URL: '',
|
||||
NODE_OPTIONS: [process.env.NODE_OPTIONS, '--disable-warning=ExperimentalWarning'].filter(Boolean).join(' '),
|
||||
},
|
||||
prepare: (cwd) => { runCwd = cwd },
|
||||
})
|
||||
|
||||
expect(result.stderr).toBe('')
|
||||
const normalized = normalizeHeadlessStream(result.stdout, runCwd)
|
||||
if (refreshing) await writeFile(streamExpected, normalized)
|
||||
expect(normalized).toBe(await readFile(streamExpected, 'utf8'))
|
||||
// The durable failure names the reference to correct and the writer that
|
||||
// usually owns it, and stays true in a composition that mounts no Models
|
||||
// page at all.
|
||||
expect(normalized).toContain('the API key resolved from DEEPSEEK_API_KEY contains characters')
|
||||
expect(normalized).toContain('the web Models page writes it')
|
||||
// Neither the key nor the transport-level symptom it used to produce may
|
||||
// reach the user: the code point of one character is still the key.
|
||||
expect(normalized).not.toContain('pasted-from-a-chat-window')
|
||||
expect(normalized).not.toContain('ByteString')
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
|
||||
it('logs the model default and a dynamic next-step reasoning effort', async () => {
|
||||
const result = await runLoaderSmoke({
|
||||
label: 'reasoning effort headless stream-json snapshot',
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":0,"time":0,"data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"say pong"}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"}]}}}
|
||||
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"turn/start","seq":1,"time":0,"data":{"turn":1}}}
|
||||
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":2,"time":0,"data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}}
|
||||
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":3,"time":0,"data":{"turn":1,"step":1}}}
|
||||
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":4,"time":0,"data":{"content":[{"type":"text","text":"say pong"}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}}
|
||||
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"session/title","seq":5,"time":0,"data":{"title":"say pong","messageSeqs":[4],"source":{"kind":"fallback"}}}}
|
||||
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/header","seq":6,"time":0,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash","maxTokens":256000,"reasoningEffort":"high"},"adapterDefaults":{"reasoningEffort":true,"maxTokens":true},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}}
|
||||
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/context","seq":7,"time":0,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash","contextWindow":1000000}}}
|
||||
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":8,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"error","failure":{"message":"llm-deepseek: the API key resolved from DEEPSEEK_API_KEY contains characters no HTTP header can carry; set DEEPSEEK_API_KEY to the raw key alone (the web Models page writes it)","code":"INVALID_CREDENTIAL"}}}}}}
|
||||
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":9,"time":0,"data":{"turn":1,"step":1}}}
|
||||
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"turn/end","seq":10,"time":0,"data":{"turn":1,"reason":{"kind":"error","error":{"message":"llm-deepseek: the API key resolved from DEEPSEEK_API_KEY contains characters no HTTP header can carry; set DEEPSEEK_API_KEY to the raw key alone (the web Models page writes it)","code":"INVALID_CREDENTIAL"}}}}}
|
||||
{"type":"result","sessionId":"{{sessionId}}","output":""}
|
||||
Reference in New Issue
Block a user