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
@@ -6,7 +6,7 @@ import type { SessionId } from '@deepseek-ai/dsh-session'
import { SessionQueryError } from '@deepseek-ai/dsh-session-query'
import { isUserInvocable } from '@deepseek-ai/dsh-skill'
import type { ScopeKey } from '@deepseek-ai/dsh-scope'
import { Remote, TypertRemoteFailure, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'
import { Remote, RemoteError, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'
import type { SkillListRequest, SkillListValue } from './types.ts'
declare module '@deepseek-ai/cordis' {
@@ -30,7 +30,7 @@ export class SessionSkillCatalog extends TypertRemoteService {
* @param request - Session identity whose cwd and preset select the catalog view.
* @param signal - caller lifetime carried by the Remote transport; admitted catalog reads retain their existing completion semantics.
* @returns user-invocable skill metadata without loading skill bodies.
* @throws TypertRemoteFailure when the Session cannot be inspected or no registry can serve it.
* @throws RemoteError when the Session cannot be inspected or no registry can serve it.
*/
@Remote
async list(request: SkillListRequest, signal: AbortSignal): Promise<SkillListValue> {
@@ -48,19 +48,16 @@ export class SessionSkillCatalog extends TypertRemoteService {
} catch (error: unknown) {
if (error instanceof SessionQueryError
&& error.code === 'SESSION_QUERY_SESSION_NOT_FOUND') {
throw failure(
'session-not-found',
`session "${sessionId}" not found`,
{ sessionId },
)
throw new RemoteError('session/not-found', `session "${sessionId}" not found`, { sessionId })
}
throw failure(
'internal',
throw new RemoteError(
'gateway/internal',
`session "${sessionId}" could not be inspected: ${String(error)}`,
{},
)
}
if (cwd === undefined) {
throw failure('internal', `session "${sessionId}" has no project cwd`)
throw new RemoteError('gateway/internal', `session "${sessionId}" has no project cwd`, {})
}
const live = this.ctx.agents.get(sessionId)
@@ -68,9 +65,10 @@ export class SessionSkillCatalog extends TypertRemoteService {
const scoped = live === undefined ? undefined : presets?.serviceFor(live, 'skills')
const skillRegistry = scoped ?? this.ctx.get('skills')
if (skillRegistry === undefined) {
throw failure(
'internal',
throw new RemoteError(
'gateway/internal',
'skill registry is absent: neither this session\'s agent preset nor the host composition mounts @deepseek-ai/dsh-skill',
{},
)
}
@@ -86,7 +84,7 @@ export class SessionSkillCatalog extends TypertRemoteService {
})),
}
} catch (error: unknown) {
throw failure('internal', `skill listing failed: ${String(error)}`)
throw new RemoteError('gateway/internal', `skill listing failed: ${String(error)}`, {})
}
}
@@ -108,13 +106,4 @@ export class SessionSkillCatalog extends TypertRemoteService {
}
}
/** Build one stable Remote failure with optional typed details. */
function failure(
code: 'session-not-found' | 'internal',
message: string,
details: { readonly sessionId: SessionId } | Record<never, never> = {},
): TypertRemoteFailure {
return new TypertRemoteFailure({ code, message, details })
}
export default SessionSkillCatalog