fix(coding): recover provider context failures

This commit is contained in:
2026-08-26 14:42:01 +08:00
parent 9f05e2d7e1
commit a09826676e
8 changed files with 349 additions and 9 deletions

View File

@@ -443,13 +443,13 @@ export class CodingConversationService {
try {
selected = await this.runtime.validateModel(model);
} catch (error) { runtimeError(error); }
await this.ensurePrepared(conversationId);
let snapshot: ConversationSnapshot;
try {
snapshot = await this.runtime.getSnapshot(conversationId);
} catch (error) { runtimeError(error); }
this.assertSnapshotAllowsMutation(snapshot);
if (conversation.modelResolution === 'resolved' && conversation.model) {
await this.ensurePrepared(conversationId);
let snapshot: ConversationSnapshot;
try {
snapshot = await this.runtime.getSnapshot(conversationId);
} catch (error) { runtimeError(error); }
this.assertSnapshotAllowsMutation(snapshot);
let state: ConversationModelState;
try {
state = await this.runtime.setModel({

View File

@@ -6,6 +6,7 @@ import type {
ConversationToolNode,
PublicUsage,
} from '../contracts';
import { isAIGatewayUserContextMissing } from '../../../shared/ai-gateway-error-details';
import type { PiRpcEvent } from './rpc-client';
import { subagentDetailsOfResult } from '../subagent-protocol';
import {
@@ -44,6 +45,17 @@ function retryFailure(message: string) {
};
}
function providerFailure(message: unknown) {
if (typeof message === 'string' && isAIGatewayUserContextMissing(message)) {
return {
code: 'CODING_PROVIDER_AUTH_REQUIRED' as const,
message: '模型服务身份上下文无效,请重试;若仍失败请重新登录。',
recoverable: true,
};
}
return retryFailure('模型服务请求失败,请稍后重试。');
}
function asRecord(value: unknown): Record<string, unknown> | null {
return value !== null && typeof value === 'object' && !Array.isArray(value)
? value as Record<string, unknown>
@@ -282,7 +294,7 @@ export class PiEventProjector {
...run,
status: 'error',
terminalReason: 'failed',
error: retryFailure('The local Agent retry failed'),
error: providerFailure(event.finalError),
},
}];
}
@@ -459,6 +471,25 @@ export class PiEventProjector {
];
}
if (event.type === 'agent_end' && event.willRetry === false && Array.isArray(event.messages)) {
const assistant = [...event.messages]
.reverse()
.map(asRecord)
.find((message) => message?.role === 'assistant');
if (assistant?.stopReason === 'error') {
return [{
op: 'run.state',
run: {
...snapshot.run,
status: 'error',
terminalReason: 'failed',
error: providerFailure(assistant.errorMessage),
},
}];
}
return [];
}
if (event.type === 'extension_ui_request'
&& typeof event.id === 'string'
&& typeof event.method === 'string'