111 lines
3.5 KiB
TypeScript
111 lines
3.5 KiB
TypeScript
export type AgentRunCreateOptions = {
|
|
toolMode?: 'chat' | 'code';
|
|
taskType?: string | null;
|
|
validation?: AgentRunValidation | null;
|
|
validationInstruction?: string | null;
|
|
};
|
|
|
|
export type AgentRunValidationFile = {
|
|
path: string;
|
|
contains?: string;
|
|
};
|
|
|
|
export type AgentRunValidation = {
|
|
expectedFile?: AgentRunValidationFile | string;
|
|
expectedFiles?: Array<AgentRunValidationFile | string>;
|
|
};
|
|
|
|
function envFlag(value: unknown): boolean {
|
|
const normalized = String(value ?? '').trim().toLowerCase();
|
|
return ['1', 'true', 'yes', 'on'].includes(normalized);
|
|
}
|
|
|
|
export const agentCodeRunsEnabled = envFlag(import.meta.env.VITE_AGENT_CODE_RUNS_ENABLED);
|
|
export const agentCodeRunsAutodetectEnabled = envFlag(
|
|
import.meta.env.VITE_AGENT_CODE_RUNS_AUTODETECT,
|
|
);
|
|
|
|
function parseUserIdSet(value: unknown): Set<string> {
|
|
return new Set(
|
|
String(value ?? '')
|
|
.split(',')
|
|
.map((item) => item.trim())
|
|
.filter(Boolean),
|
|
);
|
|
}
|
|
|
|
const agentCodeRunUserIds = parseUserIdSet(import.meta.env.VITE_AGENT_CODE_RUNS_USER_IDS);
|
|
|
|
export function agentCodeRunsEnabledForUser(userId?: string | null): boolean {
|
|
if (!agentCodeRunsEnabled) return false;
|
|
if (agentCodeRunUserIds.size === 0) return true;
|
|
return Boolean(userId && agentCodeRunUserIds.has(userId));
|
|
}
|
|
|
|
const CODE_TASK_PATTERNS = [
|
|
/\b(repo|repository|branch|commit|pull request|pr|diff|patch)\b/i,
|
|
/\b(aider|openhands|codex|codebase|workspace)\b/i,
|
|
/\b(refactor|debug|fix bug|implement|add test|unit test)\b/i,
|
|
/(修改|修复|重构|调试|实现|新增|编写|更新).{0,12}(代码|仓库|分支|文件|测试|组件|接口)/,
|
|
/(代码|仓库|项目|文件|组件|接口).{0,12}(修改|修复|重构|调试|实现|新增|编写|更新)/,
|
|
];
|
|
|
|
function sanitizeRequestIdForPath(requestId: string): string {
|
|
const normalized = String(requestId ?? '').trim().replace(/[^a-zA-Z0-9._-]/g, '-');
|
|
return normalized || 'unknown-request';
|
|
}
|
|
|
|
export function buildAgentRunValidationReceipt(requestId: string): {
|
|
validation: AgentRunValidation;
|
|
instruction: string;
|
|
} {
|
|
const normalizedRequestId = String(requestId ?? '').trim();
|
|
const safeRequestId = sanitizeRequestIdForPath(normalizedRequestId);
|
|
const receiptPath = `.memind/agent-runs/${safeRequestId}.json`;
|
|
const marker = normalizedRequestId || safeRequestId;
|
|
return {
|
|
validation: {
|
|
expectedFile: {
|
|
path: receiptPath,
|
|
contains: marker,
|
|
},
|
|
},
|
|
instruction: [
|
|
'',
|
|
'[Memind code-run validation]',
|
|
`Before finishing, create or update ${receiptPath}.`,
|
|
`The file must be valid JSON and include this requestId value: ${marker}.`,
|
|
'Do not skip this receipt even if the user task itself is complete.',
|
|
].join('\n'),
|
|
};
|
|
}
|
|
|
|
export function resolveAgentRunOptions(
|
|
text: string,
|
|
{
|
|
taskType = 'code_task',
|
|
forceCode = false,
|
|
allowAutodetect = agentCodeRunsAutodetectEnabled,
|
|
userId = null,
|
|
requestId = null,
|
|
}: {
|
|
taskType?: string;
|
|
forceCode?: boolean;
|
|
allowAutodetect?: boolean;
|
|
userId?: string | null;
|
|
requestId?: string | null;
|
|
} = {},
|
|
): AgentRunCreateOptions {
|
|
if (!agentCodeRunsEnabledForUser(userId)) return {};
|
|
const normalizedText = String(text ?? '').trim();
|
|
const shouldUseCode = forceCode || (allowAutodetect && CODE_TASK_PATTERNS.some((pattern) => pattern.test(normalizedText)));
|
|
if (!shouldUseCode) return {};
|
|
const receipt = buildAgentRunValidationReceipt(requestId ?? crypto.randomUUID());
|
|
return {
|
|
toolMode: 'code',
|
|
taskType,
|
|
validation: receipt.validation,
|
|
validationInstruction: receipt.instruction,
|
|
};
|
|
}
|