mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-21 22:55:55 +00:00
- expand domain-layer map and add L3/L4 type-sharing exceptions - resolve bare domain imports (e.g. `#/turn`) via targetDomainOf - add `_serviceBrand` to externalHooks/permissionMode/permissionRules/profile services - mark injected constructor deps private readonly (cron/flag/goal) - build permission policies via instantiation.createInstance - add HookSlot.run and a cross-package `#/` import resolver for vitest - reorganize tests, add config/permissionRules/sessionStore coverage, drop legacy records tests
4.8 KiB
4.8 KiB
errors
Error infrastructure for agent-core-v2: base classes, the per-domain code contract, the public
ErrorCodesfacade, wire serialization, and the conventions domains follow when raising errors.
Base classes and serialization are centralized in _base/errors; error codes
are decentralized — each domain owns an errors.ts that contributes its
codes and metadata, and the src/errors.ts facade aggregates them into the
unified ErrorCodes const.
Where things live
src/_base/errors/errors.ts: base classes —KimiError,CancellationError,ExpectedError,ErrorNoTelemetry,BugIndicatingError,NotImplementedError.src/_base/errors/codes.ts: theErrorDomaincontract, theErrorCodetype (aliased to the protocol'sKimiErrorCode), the runtime registry (registerErrorDomain/errorInfo/isErrorCode), and the domain-independentCoreErrors(internal,not_implemented).src/_base/errors/serialize.ts:ErrorPayload,isCodedError,toErrorPayload,fromErrorPayload,makeErrorPayload. Reads retryability from the registry viaerrorInfo.src/_base/errors/errorMessage.ts:toErrorMessage(error, verbose?)for logs/CLI.src/_base/errors/unexpectedError.ts:onUnexpectedError/setUnexpectedErrorHandler/safelyCallListener.src/<domain>/errors.ts: each domain'sXxxErrorsdescriptor (codes + retryable list + per-code info overrides), self-registered on import.src/errors.ts: the facade — imports every domain'serrors.ts(triggering registration), builds the unifiedErrorCodesconst, and re-exports all error primitives. This is the import throw sites use.
Conventions (hard rules)
- Throw a coded error, not a bare string.
throw new KimiError(ErrorCodes.X, …).throw new Error('x')only for unreachable guards;NotImplementedError('feature')for stubs. - Define codes in the owning domain. A domain's codes live in
<domain>/errors.tsnext to its interfaces, exported as anXxxErrorsdescriptor — never in_base/errors. - One
codeper failure mode. Codes readdomain.reason(e.g.tool.unknown_tool). The set of valid code strings is fixed by the protocol (KimiErrorCode); adding a brand-new code means updating the protocol first. Renaming/removing a code is a major (breaks SDK clients). - Import from the facade. Throw sites and cross-domain consumers do
import { ErrorCodes, KimiError } from '#/errors'. A domain's ownerrors.tsreferences its own descriptor (LoopErrors.codes.X) and imports only from#/_base/errors(never from#/errors, to avoid cycles). - Translate foreign errors at the boundary. Provider/HTTP, fs, MCP errors are caught at the domain boundary and re-thrown as the domain's coded error.
_base/errorsnever imports a business domain. - Branch on
code, neverinstanceof, across the wire. Class identity does not survive serialization. In-process,instanceof KimiError/isCodedErrorare fine.
Adding a domain error (recipe)
In <domain>/errors.ts:
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors';
export const ToolErrors = {
codes: {
UNKNOWN_TOOL: 'tool.unknown_tool',
EXECUTION_FAILED: 'tool.execution_failed',
},
retryable: ['tool.execution_failed'],
info: {
'tool.unknown_tool': {
title: 'Unknown tool',
retryable: false,
public: true,
action: 'Check the tool name passed by the model.',
},
},
} as const satisfies ErrorDomain;
registerErrorDomain(ToolErrors);
Then wire it into the facade in src/errors.ts: import ToolErrors, add
...ToolErrors.codes to the ErrorCodes spread, and re-export it. The
satisfies ErrorDomain guarantees every code value is a protocol-known
ErrorCode, and registerErrorDomain makes its metadata available to
serialization.
Serialization & boundary translation
toErrorPayload(error):CancellationError→internal; any coded error (incl. deserialized shapes) → its code +retryablefromerrorInfo; anything else →internal.fromErrorPayload(payload): rehydrates aKimiErrorfor in-processinstanceof/isCodedErroruse at the SDK/RPC boundary.isCodedError(error): structural guard (checkscodeagainst the registry), so it works for bothKimiErrorinstances and plain objects revived from a payload.- The registry is populated when the facade is imported (the package
index.tsre-exports it); tests that import a single domain get that domain's codes via its self-registration.errorInfofalls back to{ title: code, retryable, public: true }for any unregistered code.
References
packages/agent-core-v2/src/_base/errors/— contract, registry, base classes, serialization.packages/agent-core-v2/src/errors.ts— the aggregating facade.packages/protocol/src/events.ts— the canonicalKimiErrorCodewire union.