feat: wire code agent runs to tool mode
This commit is contained in:
+78
-6
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user