fix(apiproxy): title-invalid only for the input's fault, presentable messages

The rename impl narrows on SessionTitleInvalidError: only an
empty-normalizing title maps to title-invalid (its message renders verbatim
in the rename dialog alert), while liveness/disposal races fall to internal;
the absent-service message trims to one presentable sentence. rpc-schemas
gains the title-invalid accept/missing-details lines; cosmetic ordering
(type-only import comment, tsconfig reference, schema import order) restored.
This commit is contained in:
imccyu
2026-07-29 20:11:19 +08:00
parent c8374e916f
commit 1c3fa6edcd
6 changed files with 45 additions and 14 deletions
+16 -6
View File
@@ -36,10 +36,10 @@ import type {} from '@deepseek-ai/dsh-session-projection-cache'
import { GoalError } from '@deepseek-ai/dsh-goal'
import type { GoalRef as CoreGoalRef } from '@deepseek-ai/dsh-goal'
// Type-only edges: resolve `ctx.get('commands')`, the `commands/change` event, and `ctx.get('skills')`.
// Type-only edge: resolves `ctx.get('sessionTitle')` for the rename impl.
import type {} from '@deepseek-ai/dsh-session-title'
import type {} from '@deepseek-ai/dsh-commands'
import type {} from '@deepseek-ai/dsh-skill'
// Value edge: the rename impl narrows the title service's validation failure; the import also resolves `ctx.get('sessionTitle')`.
import { SessionTitleInvalidError } from '@deepseek-ai/dsh-session-title'
import type { CallId } from '@deepseek-ai/dsh-llm/brand'
import type { ApprovalOutcome, ApprovalRequestId } from '@deepseek-ai/dsh-user-approval'
// Side-effect type import: resolves the `approval/request` waterfall and
@@ -1057,16 +1057,26 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
if ('error' in found) return err(request, found.error)
const titles = ctx.get('sessionTitle')
if (titles === undefined) {
return err(request, { code: 'internal', message: 'session-title service is absent: this deployment does not mount @deepseek-ai/dsh-session-title in its composition (cordis.yml or explicit assembly)', details: {} })
return err(request, { code: 'internal', message: 'renaming is unavailable: this deployment mounts no session-title service', details: {} })
}
try {
const accepted = titles.rename(found.agent.session, title)
return ok(request, { title: accepted.title, seq: accepted.eventSeq })
} catch (error: unknown) {
// Only the input's fault maps to title-invalid (the message is
// product-user-visible in the rename dialog); liveness and disposal
// races are deployment trouble, not a bad title.
if (error instanceof SessionTitleInvalidError) {
return err(request, {
code: 'title-invalid',
message: error.message,
details: { sessionId },
})
}
return err(request, {
code: 'title-invalid',
message: `rename rejected for session "${sessionId}": ${String(error)}`,
details: { sessionId },
code: 'internal',
message: `failed to rename session "${sessionId}": ${String(error)}`,
details: {},
})
}
},
+1 -1
View File
@@ -20,11 +20,11 @@ import {
import {
sessionCancelValueSchema,
sessionCreateValueSchema,
sessionRenameValueSchema,
sessionHistoryValueSchema,
sessionListValueSchema,
sessionModelsValueSchema,
sessionPromptValueSchema,
sessionRenameValueSchema,
sessionSelectModelValueSchema,
} from '../api/sessions.schema.ts'
import {
+1 -1
View File
@@ -17,11 +17,11 @@ import { clientRequestSchema, clientResponseSchema } from '../api/rpc.schema.ts'
import {
sessionCancelRequestSchema,
sessionCreateRequestSchema,
sessionRenameRequestSchema,
sessionHistoryRequestSchema,
sessionListRequestSchema,
sessionModelsRequestSchema,
sessionPromptRequestSchema,
sessionRenameRequestSchema,
sessionSelectModelRequestSchema,
} from '../api/sessions.schema.ts'
import {