refactor(api): converge the Remote failure vocabulary and client surface

Single RemoteError with a merge-extensible, domain-prefixed code map;
owners throw at the failure point; streams surface marked failures;
clients consume ctx.remote directly with isRemoteFailure as the only
discrimination point and construct no failure instances.
This commit is contained in:
imccyu
2026-08-28 22:37:36 +08:00
parent 12d7b4ed0c
commit 804b1ffbfc
252 changed files with 3182 additions and 3832 deletions
+17 -26
View File
@@ -11,9 +11,9 @@ import type {} from '@deepseek-ai/dsh-agent-presets'
import { ReasoningEffortId } from '@deepseek-ai/dsh-llm'
import type { Session, SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session'
import { SessionQueryError, type SessionObservation } from '@deepseek-ai/dsh-session-query'
import { TypertLookupFailure } from '@deepseek-ai/dsh-typert-protocol'
import { RemoteError } from '@deepseek-ai/dsh-typert-protocol'
import type {} from '@deepseek-ai/dsh-typert-registry'
import type { ModelSelection, SessionError } from './types.ts'
import type { ModelSelection } from './types.ts'
/** Cold Session identity absent from persistence. */
export class ApiSessionNotFound extends Error {}
@@ -57,10 +57,7 @@ export class ApiSessionPresetConflict extends Error {
}
/** Failures produced while resolving one ordinary Session identity to its live Agent. */
export type ApiSessionAgentError = Extract<
SessionError,
{ readonly code: 'session-not-found' | 'agent-busy' | 'internal' }
>
export type ApiSessionAgentError = RemoteError<'session/not-found' | 'session/agent-busy' | 'gateway/internal'>
/** Result of resolving one ordinary Session identity to its live Agent. */
export type ApiSessionAgentResult =
@@ -97,11 +94,11 @@ export function hasApiSessionSubagentOwner(
* @returns a stable Session-domain failure.
*/
export function apiSessionSubagentOwnershipError(sessionId: SessionId): ApiSessionAgentError {
return {
code: 'agent-busy',
message: `session "${sessionId}" is owned by subagent routing`,
details: { reason: 'use subagent delivery for this child session' },
}
return new RemoteError(
'session/agent-busy',
`session "${sessionId}" is owned by subagent routing`,
{ reason: 'use subagent delivery for this child session' },
)
}
/**
@@ -145,17 +142,17 @@ export class ApiSessionAgentController {
constructor(private readonly ctx: Context) {
ctx.typert.lookups.configure('agent', async (sessionId: SessionId) => {
const found = await this.resolveAgent(sessionId)
if ('error' in found) throw new TypertLookupFailure(found.error)
if ('error' in found) throw found.error
return found.agent
})
ctx.typert.lookups.configure('session', async (sessionId: SessionId) => {
const found = await this.resolveAgent(sessionId)
if ('error' in found) throw new TypertLookupFailure(found.error)
if ('error' in found) throw found.error
return found.agent.session
})
ctx.typert.contexts.configureHost('agent', async (sessionId: SessionId) => {
const found = await this.resolveAgent(sessionId)
if ('error' in found) throw new TypertLookupFailure(found.error)
if ('error' in found) throw found.error
return found.agent.ctx
})
}
@@ -198,13 +195,7 @@ export class ApiSessionAgentController {
return { agent: await resume }
} catch (error: unknown) {
if (error instanceof ApiSessionNotFound) {
return {
error: {
code: 'session-not-found',
message: error.message,
details: { sessionId },
},
}
return { error: new RemoteError('session/not-found', error.message, { sessionId }) }
}
if (error instanceof ApiSessionSubagentOwnership) {
return { error: apiSessionSubagentOwnershipError(error.sessionId) }
@@ -216,11 +207,11 @@ export class ApiSessionAgentController {
return { error: apiSessionSubagentOwnershipError(sessionId) }
}
return {
error: {
code: 'internal',
message: `resume failed for session "${sessionId}": ${String(error)}`,
details: {},
},
error: new RemoteError(
'gateway/internal',
`resume failed for session "${sessionId}": ${String(error)}`,
{},
),
}
}
}