Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/en/reference/server-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Error codes are grouped by band:
| `400xx` | Bad request | `40001` validation failed (`details` lists each field), `40003` provider is OAuth-managed, `40006` duplicate workspace source folder |
| `401xx` | Auth and readiness | `40101` unauthorized, `40110` no provider configured, `40113` model not resolved |
| `404xx` | Not found | `40401` session, `40408` MCP server, `40409` file path |
| `409xx` | State conflict | `40901` session busy, `40902` approval already resolved, `40922` page conditions mismatch `page_token`, `40931` session occupied by another client, `40932` session updated by another client |
| `409xx` | State conflict | `40901` session busy, `40902` approval already resolved, `40922` page conditions mismatch `page_token`, `40931` session occupied by another client, `40932` session updated by another client, `40935` Tower mode cannot be entered |
| `410xx` | Expired | `41001` approval timed out, `41002` question timed out, `41003` temporary file expired |
| `413xx` | Size or boundary exceeded | `41302` file read over 10 MB, `41304` path escapes the session directory |
| `429xx` | Rate limited | `42901` auth-failure ban, `42902` too many fs watches |
Expand Down
2 changes: 1 addition & 1 deletion docs/zh/reference/server-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ HTTP 状态码几乎总是 200,业务结果以 `code` 为准。例外情况:
| `400xx` | 请求参数错误 | `40001` 校验失败(`details` 逐字段说明)、`40003` 供应商由 OAuth 托管、`40006` 工作区源文件夹重复 |
| `401xx` | 鉴权与就绪状态 | `40101` 未授权、`40110` 未配置供应商、`40113` 模型未解析 |
| `404xx` | 资源不存在 | `40401` 会话、`40408` MCP 服务、`40409` 文件路径 |
| `409xx` | 状态冲突 | `40901` 会话忙、`40902` 审批已解决、`40922` 分页条件与 `page_token` 不符、`40931` 会话正被其他客户端使用、`40932` 会话已被其他客户端更新 |
| `409xx` | 状态冲突 | `40901` 会话忙、`40902` 审批已解决、`40922` 分页条件与 `page_token` 不符、`40931` 会话正被其他客户端使用、`40932` 会话已被其他客户端更新、`40935` 无法进入 Tower 模式 |
| `410xx` | 资源已过期 | `41001` 审批超时、`41002` 提问超时、`41003` 临时文件过期 |
| `413xx` | 体积或边界超限 | `41302` 读取文件超 10 MB、`41304` 路径越出会话目录 |
| `429xx` | 限流 | `42901` 鉴权失败封禁、`42902` 文件监听数超限 |
Expand Down
4 changes: 1 addition & 3 deletions packages/kap-server/src/error-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function installErrorHandler(app: ErrorHandlerHost): void {
if (isError2(err) && err.code === ErrorCodes.CONFIG_INVALID) {
reply
.status(200)
.send(errEnvelope(ErrorCode.VALIDATION_FAILED, err.message, requestId, err.stack));
.send(errEnvelope(ErrorCode.VALIDATION_FAILED, err.message, requestId));
return;
}
if (isError2(err) && err.code === ErrorCodes.WIRE_VERSION_TOO_LOW) {
Expand All @@ -31,7 +31,6 @@ export function installErrorHandler(app: ErrorHandlerHost): void {
ErrorCode.WIRE_VERSION_TOO_LOW,
err.message,
requestId,
err.stack,
err.details,
),
);
Expand All @@ -43,7 +42,6 @@ export function installErrorHandler(app: ErrorHandlerHost): void {
ErrorCode.INTERNAL_ERROR,
err.message !== undefined && err.message !== '' ? err.message : 'internal error',
requestId,
err.stack,
),
);
});
Expand Down
5 changes: 1 addition & 4 deletions packages/kap-server/src/protocol/envelope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export const envelopeSchema = <T extends z.ZodTypeAny>(data: T) =>
data: data.nullable(),
request_id: z.string(),
details: z.unknown().optional(),
stack: z.string().optional(),
});

export interface Envelope<T> {
Expand All @@ -16,7 +15,6 @@ export interface Envelope<T> {
data: T | null;
request_id: string;
details?: unknown;
stack?: string;
}

export function okEnvelope<T>(data: T, requestId: string): Envelope<T> {
Expand All @@ -27,8 +25,7 @@ export function errEnvelope(
code: number,
msg: string,
requestId: string,
stack?: string,
details?: unknown,
): Envelope<null> {
return { code, msg, data: null, request_id: requestId, stack, details };
return { code, msg, data: null, request_id: requestId, details };
}
3 changes: 1 addition & 2 deletions packages/kap-server/src/protocol/error-codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ export const ErrorCode = {
SUCCESS: 0,

VALIDATION_FAILED: 40001,
REQUEST_MALFORMED: 40002,
PROVIDER_OAUTH_MANAGED: 40003,
CATALOG_IMPORT_INVALID: 40004,
REGISTRY_IMPORT_INVALID: 40005,
Expand All @@ -26,7 +25,6 @@ export const ErrorCode = {
PROVIDER_NOT_FOUND: 40412,
MODEL_NOT_FOUND: 40413,
SKILL_NOT_FOUND: 40415,
TOOL_CALL_NOT_FOUND: 40416,
CATALOG_ENTRY_NOT_FOUND: 40417,
CAPABILITY_NOT_FOUND: 40418,
PLUGIN_NOT_FOUND: 40419,
Expand Down Expand Up @@ -66,6 +64,7 @@ export const ErrorCode = {
SESSION_STALE: 40932,
TASK_NOT_DETACHABLE: 40933,
PLUGIN_CATALOG_CHANGED: 40934,
TOWER_MODE_INVALID: 40935,

APPROVAL_EXPIRED: 41001,
QUESTION_EXPIRED: 41002,
Expand Down
3 changes: 1 addition & 2 deletions packages/kap-server/src/routes/capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,11 @@ const CAPABILITY_ERROR_MAP: Readonly<Record<string, ErrorCode>> = {
function mapCapabilityError(error: unknown, requestId: string) {
const mapped = isError2(error) ? CAPABILITY_ERROR_MAP[error.code] : undefined;
if (mapped !== undefined && isError2(error)) {
return errEnvelope(mapped, error.message, requestId, error.stack);
return errEnvelope(mapped, error.message, requestId);
}
return errEnvelope(
ErrorCode.INTERNAL_ERROR,
error instanceof Error ? error.message : String(error),
requestId,
error instanceof Error ? error.stack : undefined,
);
}
30 changes: 14 additions & 16 deletions packages/kap-server/src/routes/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -883,58 +883,57 @@ function sendMappedError(reply: Reply, req: { id: string }, err: unknown): void
if (isError2(err)) {
switch (err.code) {
case ErrorCodes.FS_PATH_ESCAPES:
reply.send(errEnvelope(ErrorCode.FS_PATH_ESCAPES_SESSION, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_PATH_ESCAPES_SESSION, err.message, requestId));
return;
case ErrorCodes.FS_PATH_NOT_FOUND:
reply.send(errEnvelope(ErrorCode.FS_PATH_NOT_FOUND, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_PATH_NOT_FOUND, err.message, requestId));
return;
case ErrorCodes.FS_IS_DIRECTORY:
reply.send(errEnvelope(ErrorCode.FS_IS_DIRECTORY, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_IS_DIRECTORY, err.message, requestId));
return;
case ErrorCodes.FS_ALREADY_EXISTS:
reply.send(errEnvelope(ErrorCode.FS_ALREADY_EXISTS, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_ALREADY_EXISTS, err.message, requestId));
return;
case ErrorCodes.FS_IS_BINARY:
reply.send(errEnvelope(ErrorCode.FS_IS_BINARY, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_IS_BINARY, err.message, requestId));
return;
case ErrorCodes.FS_TOO_LARGE:
reply.send(errEnvelope(ErrorCode.FS_TOO_LARGE, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_TOO_LARGE, err.message, requestId));
return;
case ErrorCodes.FS_TOO_MANY_RESULTS:
reply.send(errEnvelope(ErrorCode.FS_TOO_MANY_RESULTS, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_TOO_MANY_RESULTS, err.message, requestId));
return;
case ErrorCodes.FS_GREP_TIMEOUT:
reply.send(errEnvelope(ErrorCode.FS_GREP_TIMEOUT, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_GREP_TIMEOUT, err.message, requestId));
return;
case ErrorCodes.FS_GIT_UNAVAILABLE:
reply.send(errEnvelope(ErrorCode.FS_GIT_UNAVAILABLE, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_GIT_UNAVAILABLE, err.message, requestId));
return;
case ErrorCodes.SESSION_NOT_FOUND:
reply.send(errEnvelope(ErrorCode.SESSION_NOT_FOUND, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.SESSION_NOT_FOUND, err.message, requestId));
return;
case ErrorCodes.WIRE_VERSION_TOO_LOW:
reply.send(
errEnvelope(
ErrorCode.WIRE_VERSION_TOO_LOW,
err.message,
requestId,
err.stack,
err.details,
),
);
return;
case ErrorCodes.OS_FS_NOT_FOUND:
case ErrorCodes.OS_FS_NOT_DIRECTORY:
reply.send(errEnvelope(ErrorCode.FS_PATH_NOT_FOUND, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_PATH_NOT_FOUND, err.message, requestId));
return;
case ErrorCodes.OS_FS_IS_DIRECTORY:
reply.send(errEnvelope(ErrorCode.FS_IS_DIRECTORY, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_IS_DIRECTORY, err.message, requestId));
return;
case ErrorCodes.OS_FS_ALREADY_EXISTS:
reply.send(errEnvelope(ErrorCode.FS_ALREADY_EXISTS, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_ALREADY_EXISTS, err.message, requestId));
return;
case ErrorCodes.OS_FS_PERMISSION_DENIED:
reply.send(errEnvelope(ErrorCode.FS_PERMISSION_DENIED, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.FS_PERMISSION_DENIED, err.message, requestId));
return;
}
}
Expand All @@ -944,7 +943,6 @@ function sendMappedError(reply: Reply, req: { id: string }, err: unknown): void
ErrorCode.INTERNAL_ERROR,
err instanceof Error ? err.message : String(err),
requestId,
err instanceof Error ? err.stack : undefined,
),
);
}
Expand Down
12 changes: 6 additions & 6 deletions packages/kap-server/src/routes/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ export function registerMessagesRoutes(app: MessageRouteHost, core: Scope): void
const { session_id } = req.params;
const page = await listMessages(core, session_id, req.query);
reply.send(okEnvelope(page, req.id));
} catch (err) {
sendMappedError(reply, req, err);
} catch (error) {
sendMappedError(reply, req, error);
}
},
);
Expand Down Expand Up @@ -106,8 +106,8 @@ export function registerMessagesRoutes(app: MessageRouteHost, core: Scope): void
const { session_id, message_id } = req.params;
const message = await getMessage(core, session_id, message_id);
reply.send(okEnvelope(message, req.id));
} catch (err) {
sendMappedError(reply, req, err);
} catch (error) {
sendMappedError(reply, req, error);
}
},
);
Expand All @@ -125,11 +125,11 @@ function sendMappedError(
): void {
const requestId = req.id;
if (err instanceof SessionNotFoundError) {
reply.send(errEnvelope(ErrorCode.SESSION_NOT_FOUND, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.SESSION_NOT_FOUND, err.message, requestId));
return;
}
if (err instanceof MessageNotFoundError) {
reply.send(errEnvelope(ErrorCode.MESSAGE_NOT_FOUND, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.MESSAGE_NOT_FOUND, err.message, requestId));
return;
}
sendSessionMappedError(reply, req, err);
Expand Down
6 changes: 3 additions & 3 deletions packages/kap-server/src/routes/modelCatalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -742,11 +742,11 @@ function sendMappedError(
): boolean {
if (!isError2(err)) return false;
if (err.code === 'provider.not_found') {
reply.send(errEnvelope(ErrorCode.PROVIDER_NOT_FOUND, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.PROVIDER_NOT_FOUND, err.message, requestId));
return true;
}
if (err.code === 'model.not_found') {
reply.send(errEnvelope(ErrorCode.MODEL_NOT_FOUND, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.MODEL_NOT_FOUND, err.message, requestId));
return true;
}
return false;
Expand All @@ -768,7 +768,7 @@ function sendModelsDevImportError(
if (!isError2(err)) return false;
const numeric = MODELS_DEV_IMPORT_ERROR_CODES[err.code];
if (numeric === undefined) return false;
reply.send(errEnvelope(numeric, err.message, requestId, err.stack));
reply.send(errEnvelope(numeric, err.message, requestId));
return true;
}

Expand Down
3 changes: 1 addition & 2 deletions packages/kap-server/src/routes/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,12 +347,11 @@ const PLUGIN_ERROR_MAP: Readonly<Record<string, ErrorCode>> = {
function mapPluginError(error: unknown, requestId: string) {
const mapped = isError2(error) ? PLUGIN_ERROR_MAP[error.code] : undefined;
if (mapped !== undefined && isError2(error)) {
return errEnvelope(mapped, error.message, requestId, error.stack);
return errEnvelope(mapped, error.message, requestId);
}
return errEnvelope(
ErrorCode.INTERNAL_ERROR,
error instanceof Error ? error.message : String(error),
requestId,
error instanceof Error ? error.stack : undefined,
);
}
2 changes: 1 addition & 1 deletion packages/kap-server/src/routes/remoteControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export function registerRemoteControlRoutes(
if (error instanceof RemoteControlAlreadyRunningError) {
opts.telemetry?.track2('remote_control_toggle', { enabled, outcome: 'already_running' });
reply.send(
errEnvelope(ErrorCode.REMOTE_CONTROL_ALREADY_RUNNING, error.message, req.id, undefined, {
errEnvelope(ErrorCode.REMOTE_CONTROL_ALREADY_RUNNING, error.message, req.id, {
pid: error.holder.pid,
local_origin: error.holder.localOrigin,
device_id: error.holder.deviceId,
Expand Down
3 changes: 1 addition & 2 deletions packages/kap-server/src/routes/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export function registerSearchRoutes(app: SearchRouteHost, core: Scope): void {
error instanceof GlobalSearchError &&
(error.reason === 'invalid_query' || error.reason === 'invalid_page_token')
) {
reply.send(errEnvelope(ErrorCode.VALIDATION_FAILED, error.message, req.id, error.stack));
reply.send(errEnvelope(ErrorCode.VALIDATION_FAILED, error.message, req.id));
return;
}
requestLog(req)?.error({ err: error }, 'global search request failed');
Expand All @@ -105,7 +105,6 @@ export function registerSearchRoutes(app: SearchRouteHost, core: Scope): void {
ErrorCode.INTERNAL_ERROR,
error instanceof Error ? error.message : String(error),
req.id,
error instanceof Error ? error.stack : undefined,
),
);
}
Expand Down
1 change: 0 additions & 1 deletion packages/kap-server/src/routes/sessionErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export function sendMappedError(
msg: error.message,
data: error.details ?? null,
request_id: req.id,
stack: error.stack,
});
return;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/kap-server/src/routes/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ function sendMappedError(
err: unknown,
): void {
if (err instanceof Error2 && err.code === ErrorCodes.MCP_SERVER_NOT_FOUND) {
reply.send(errEnvelope(ErrorCode.MCP_SERVER_NOT_FOUND, err.message, requestId, err.stack));
reply.send(errEnvelope(ErrorCode.MCP_SERVER_NOT_FOUND, err.message, requestId));
return;
}
throw err;
Expand Down
Loading
Loading