feat: wire code agent runs to tool mode

This commit is contained in:
John
2026-07-02 07:16:47 +08:00
parent e17dcaf4a8
commit 0271d83756
6 changed files with 343 additions and 22 deletions
+78 -6
View File
@@ -2,6 +2,8 @@ import crypto from 'node:crypto';
const DEFAULT_RUN_RETRY_DELAYS_MS = [1500, 5000, 15000];
const TERMINAL_STATUSES = new Set(['succeeded', 'failed']);
const CODE_TOOL_MODES = new Set(['code', 'code-task', 'code_task', 'code-tool', 'code_tool', 'code_tool_task']);
const RUN_METADATA_KEY = 'memindRun';
function nowMs() {
return Date.now();
@@ -19,6 +21,50 @@ function serializeMessage(message) {
return JSON.stringify(message ?? {});
}
export function normalizeAgentRunToolMode(value) {
const normalized = String(value ?? 'chat').trim().toLowerCase();
if (!normalized || normalized === 'chat') return 'chat';
if (CODE_TOOL_MODES.has(normalized)) return 'code';
throw new Error(`不支持的 tool_mode: ${value}`);
}
function normalizeTaskType(value) {
const normalized = String(value ?? '').trim();
return normalized || null;
}
function withRunMetadata(userMessage, { toolMode = 'chat', taskType = null } = {}) {
const message = (userMessage && typeof userMessage === 'object' && !Array.isArray(userMessage))
? { ...userMessage }
: { value: userMessage };
const metadata = (message.metadata && typeof message.metadata === 'object' && !Array.isArray(message.metadata))
? { ...message.metadata }
: {};
metadata[RUN_METADATA_KEY] = {
...(metadata[RUN_METADATA_KEY] && typeof metadata[RUN_METADATA_KEY] === 'object'
? metadata[RUN_METADATA_KEY]
: {}),
toolMode: normalizeAgentRunToolMode(toolMode),
...(taskType ? { taskType } : {}),
};
return { ...message, metadata };
}
function getRunOptionsFromMessage(userMessage) {
const metadata = userMessage?.metadata;
const runMetadata = metadata?.[RUN_METADATA_KEY] ?? metadata?.agentRun ?? {};
let toolMode = 'chat';
try {
toolMode = normalizeAgentRunToolMode(runMetadata?.toolMode ?? metadata?.toolMode ?? 'chat');
} catch {
toolMode = 'chat';
}
return {
toolMode,
taskType: normalizeTaskType(runMetadata?.taskType ?? metadata?.taskType),
};
}
function projectRun(row) {
if (!row) return null;
return {
@@ -83,11 +129,19 @@ export function createAgentRunGateway({
return rows[0] ?? null;
}
async function createRun(userId, { sessionId = null, requestId, userMessage }) {
async function createRun(userId, {
sessionId = null,
requestId,
userMessage,
toolMode = 'chat',
taskType = null,
}) {
const normalizedRequestId = String(requestId ?? '').trim();
if (!normalizedRequestId) {
throw new Error('缺少 request_id');
}
const normalizedToolMode = normalizeAgentRunToolMode(toolMode);
const normalizedTaskType = normalizeTaskType(taskType);
const existing = await getRunByRequest(userId, normalizedRequestId);
if (existing) {
if (autoDispatch && !TERMINAL_STATUSES.has(existing.status)) dispatchRun(existing.id);
@@ -96,6 +150,10 @@ export function createAgentRunGateway({
const runId = crypto.randomUUID();
const createdAt = nowMs();
const runMessage = withRunMetadata(userMessage, {
toolMode: normalizedToolMode,
taskType: normalizedTaskType,
});
await pool.query(
`INSERT INTO h5_agent_runs
(id, user_id, agent_session_id, request_id, status, attempts,
@@ -106,12 +164,16 @@ export function createAgentRunGateway({
userId,
sessionId || null,
normalizedRequestId,
serializeMessage(userMessage),
serializeMessage(runMessage),
createdAt,
createdAt,
],
);
await appendEvent(runId, 'queued', { sessionId: sessionId || null });
await appendEvent(runId, 'queued', {
sessionId: sessionId || null,
toolMode: normalizedToolMode,
taskType: normalizedTaskType,
});
if (autoDispatch) dispatchRun(runId);
return projectRun(await getRunById(runId));
}
@@ -145,23 +207,33 @@ export function createAgentRunGateway({
await appendEvent(runId, 'running', { attempt: nextAttempt });
try {
const userMessage = safeJsonParse(row.user_message_json, {});
const runOptions = getRunOptionsFromMessage(userMessage);
let sessionId = row.agent_session_id ?? null;
if (!sessionId) {
const session = await tkmindProxy.startSessionForUser(row.user_id);
const sessionOptions = {};
if (runOptions.toolMode === 'code' && userAuth?.getCodeAgentSessionPolicy) {
sessionOptions.sessionPolicy = await userAuth.getCodeAgentSessionPolicy(row.user_id);
}
const session = await tkmindProxy.startSessionForUser(row.user_id, sessionOptions);
sessionId = session.id;
await pool.query(
`UPDATE h5_agent_runs SET agent_session_id = ?, updated_at = ? WHERE id = ?`,
[sessionId, nowMs(), runId],
);
await appendEvent(runId, 'session_started', { sessionId });
await appendEvent(runId, 'session_started', {
sessionId,
toolMode: runOptions.toolMode,
taskType: runOptions.taskType,
});
}
const userMessage = safeJsonParse(row.user_message_json, {});
await tkmindProxy.submitSessionReplyForUser(
row.user_id,
sessionId,
row.request_id,
userMessage,
{ toolMode: runOptions.toolMode },
);
await markRun(runId, 'succeeded', {
agent_session_id: sessionId,