refactor: unify tool reason requirements

This commit is contained in:
2026-10-28 16:43:04 +08:00
parent 7d47a2df86
commit c3050b602b
20 changed files with 97 additions and 46 deletions
-10
View File
@@ -877,16 +877,6 @@ export const streamPromptResponse = async ({
) {
emittedToolParts.add(part.id);
toolCallCount += 1;
if (!reason) {
logger.warn(
{
tool: part.tool,
sessionId: sessionId,
clientSessionId,
},
"llm tool request missing reason",
);
}
void writeLlmRequestAuditLog({
kind: "tool",
sessionId: sessionId,
+6 -4
View File
@@ -119,9 +119,11 @@ export const normalizeToolParams = (value: unknown): Record<string, unknown> =>
return {};
};
// New tools use reason; aliases are read-only compatibility for existing events.
const reasonKeys = ["reason", "request_reason", "why", "purpose", "rationale"];
export const extractRequestReason = (params: Record<string, unknown>) => {
const candidates = ["reason", "request_reason", "why", "purpose", "rationale"];
for (const key of candidates) {
for (const key of reasonKeys) {
const value = params[key];
if (typeof value === "string") {
const normalized = value.trim();
@@ -381,7 +383,7 @@ const truncateProgressText = (text: string, maxLength: number) =>
text.length > maxLength ? `${text.slice(0, maxLength - 3)}...` : text;
const summarizeToolParams = (params: Record<string, unknown>) => {
const ignoredKeys = new Set(["reason", "request_reason", "why", "purpose", "rationale"]);
const ignoredKeys = new Set(reasonKeys);
const summary = Object.entries(params)
.filter(([key]) => !ignoredKeys.has(key))
.slice(0, 4)
@@ -433,7 +435,7 @@ export const buildToolProgressDetail = (
error?: string,
) => {
const toolName = toolLabels[tool] ?? tool;
const reasonText = reason ? `;调用原因:${reason}` : "";
const reasonText = reason ? `;说明:${reason}` : "";
const paramsText = `;关键参数:${summarizeToolParams(params)}`;
if (status === "error") {
+8 -4
View File
@@ -9,19 +9,23 @@ import { type SkillStore } from "../skills/store.js";
const memoryInput = z.object({
action: z.enum(["add", "list", "replace", "remove"]),
scope: z.string().max(32),
reason: z.string().max(2000).optional(),
reason: z.string().trim().min(1).max(2000).optional(),
content: z.string().max(20000).optional(),
target_id: z.string().max(128).optional(),
}).strict();
}).strict().refine((input) => input.action === "list" || Boolean(input.reason), {
path: ["reason"], message: "reason is required for writes, updates and removals",
});
const skillInput = z.object({
action: z.enum(["list", "write_skill", "remove_skill", "append_pattern", "remove_pattern", "write_reference", "remove_reference", "write_script", "remove_script"]),
skill_path: z.string().max(512),
reason: z.string().max(2000).optional(),
reason: z.string().trim().min(1).max(2000).optional(),
content: z.string().max(200000).optional(),
file_path: z.string().max(512).optional(),
pattern: z.string().max(20000).optional(),
target_id: z.string().max(128).optional(),
}).strict();
}).strict().refine((input) => input.action === "list" || Boolean(input.reason), {
path: ["reason"], message: "reason is required for writes, updates and removals",
});
export const registerLearningToolBridge = (app: Express, options: {
internalToken: string;