chore: rebuild release package
This commit is contained in:
163
public/app.js
163
public/app.js
@@ -54,6 +54,12 @@
|
||||
{ cmd: '/help', desc: '显示帮助' },
|
||||
];
|
||||
|
||||
function isKnownSlashCommandText(text) {
|
||||
const [command = ''] = String(text || '').trim().split(/\s+/, 1);
|
||||
const normalized = command.toLowerCase();
|
||||
return SLASH_COMMANDS.some((item) => item.cmd.toLowerCase() === normalized);
|
||||
}
|
||||
|
||||
const MODE_LABELS = {
|
||||
default: '默认',
|
||||
plan: 'Plan',
|
||||
@@ -5545,11 +5551,7 @@
|
||||
pendingText = msg.text || '';
|
||||
flushRender();
|
||||
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
||||
const mergedCollabTool = mergeCollabAgentTools(msg.toolCalls);
|
||||
const resumeToolCalls = [
|
||||
...(mergedCollabTool ? [mergedCollabTool] : []),
|
||||
...msg.toolCalls.filter((tc) => toolKind(tc) !== 'collab_agent_tool_call'),
|
||||
];
|
||||
const resumeToolCalls = renderToolCallsWithMergedCollab(msg.toolCalls);
|
||||
for (const tc of resumeToolCalls) {
|
||||
activeToolCalls.set(tc.id, {
|
||||
name: tc.name,
|
||||
@@ -6314,9 +6316,34 @@
|
||||
let renderEpoch = 0;
|
||||
|
||||
function toolKind(tool) {
|
||||
if (isSubAgentActivityTool(tool)) return 'collab_agent_tool_call';
|
||||
return tool?.kind || tool?.meta?.kind || '';
|
||||
}
|
||||
|
||||
function isSubAgentActivityTool(tool) {
|
||||
const kind = String(tool?.kind || tool?.meta?.kind || tool?.type || '').trim();
|
||||
const name = String(tool?.name || tool?.tool || '').trim();
|
||||
const inputData = effectiveObject(tool?.input);
|
||||
const resultData = effectiveObject(tool?.result);
|
||||
const payload = {
|
||||
...tool,
|
||||
...inputData,
|
||||
...resultData,
|
||||
};
|
||||
const inputType = String(inputData.type || '').trim();
|
||||
const resultType = String(resultData.type || '').trim();
|
||||
const activitySignal = inputData.kind || inputData.activityKind || inputData.activity_kind || inputData.status
|
||||
|| resultData.kind || resultData.activityKind || resultData.activity_kind || resultData.status;
|
||||
const hasActivitySignal = kind === 'subAgentActivity'
|
||||
|| inputType === 'subAgentActivity'
|
||||
|| resultType === 'subAgentActivity'
|
||||
|| (
|
||||
name === 'subAgentActivity'
|
||||
&& !!activitySignal
|
||||
);
|
||||
return hasActivitySignal && !!getSubAgentActivityThreadId(payload);
|
||||
}
|
||||
|
||||
function normalizeDisplayPath(filePath) {
|
||||
const rawPath = typeof filePath === 'string' ? filePath.trim() : '';
|
||||
if (!rawPath) return '';
|
||||
@@ -6595,9 +6622,86 @@
|
||||
return normalizeCollabAgentAction(value);
|
||||
}
|
||||
|
||||
function collabAgentBasename(value) {
|
||||
const text = cleanCollabAgentText(value).replace(/\\/g, '/');
|
||||
if (!text) return '';
|
||||
return text.split('/').filter(Boolean).pop() || text;
|
||||
}
|
||||
|
||||
function normalizeSubAgentActivityStatus(value, done = false) {
|
||||
const normalized = String(value || '').trim().toLowerCase().replace(/[\s_-]/g, '');
|
||||
if (/^(started|interacted|interaction|message|delta|progress|updated|update)$/.test(normalized)) return 'running';
|
||||
if (/^(returned|return)$/.test(normalized)) return 'returned';
|
||||
if (/^(completed|complete|done|finished|finish|success|succeeded)$/.test(normalized)) return 'completed';
|
||||
if (/^(closed|close|closing|stopped|stop)$/.test(normalized)) return 'closed';
|
||||
if (/^(failed|fail|error|errored|cancelled|canceled|aborted|rejected)$/.test(normalized)) return 'failed';
|
||||
return done ? 'completed' : 'running';
|
||||
}
|
||||
|
||||
function getSubAgentActivityThreadId(activity = {}) {
|
||||
return cleanCollabAgentText(
|
||||
activity.agentThreadId
|
||||
|| activity.agent_thread_id
|
||||
|| activity.threadId
|
||||
|| activity.thread_id
|
||||
|| activity.childThreadId
|
||||
|| activity.child_thread_id
|
||||
|| ''
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeSubAgentActivityData(tool, inputData, resultData) {
|
||||
const activity = {
|
||||
...inputData,
|
||||
...resultData,
|
||||
};
|
||||
const threadId = getSubAgentActivityThreadId(activity);
|
||||
if (!threadId) return null;
|
||||
const activityKind = cleanCollabAgentText(activity.kind || activity.activityKind || activity.activity_kind || activity.status || '');
|
||||
const agentTitle = collabAgentBasename(activity.agentPath || activity.agent_path || activity.agent || activity.role || activity.name || '');
|
||||
const prompt = cleanCollabAgentText(activity.prompt || activity.taskDescription || activity.task_description || '');
|
||||
const state = {
|
||||
...activity,
|
||||
label: agentTitle || activity.label || activity.title || activity.name || '',
|
||||
title: agentTitle || activity.title || activity.label || activity.name || '',
|
||||
name: agentTitle || activity.name || activity.label || activity.title || '',
|
||||
role: cleanCollabAgentText(activity.role || activity.agentRole || activity.agent_role || ''),
|
||||
status: normalizeSubAgentActivityStatus(activityKind, !!tool?.done),
|
||||
activityKind,
|
||||
agentPath: activity.agentPath || activity.agent_path || '',
|
||||
hasReadableSourceTitle: !!agentTitle,
|
||||
};
|
||||
if (prompt) state.taskDescription = prompt;
|
||||
return {
|
||||
...activity,
|
||||
type: 'subAgentActivity',
|
||||
tool: 'subAgentActivity',
|
||||
prompt,
|
||||
status: state.status,
|
||||
receiverThreadIds: [threadId],
|
||||
agentsStates: {
|
||||
[threadId]: state,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function aggregateCollabAgentStatus(receiverThreadIds, states, fallbackStatus = '', done = false) {
|
||||
const ids = Array.isArray(receiverThreadIds) ? receiverThreadIds : [];
|
||||
const tones = ids.map((id) => collabStateTone(states?.[id]?.status));
|
||||
if (tones.length === 0) return fallbackStatus || (done ? 'completed' : 'running');
|
||||
if (tones.some((tone) => tone === 'running')) return 'running';
|
||||
if (tones.every((tone) => tone === 'closed')) return 'closed';
|
||||
if (tones.some((tone) => tone === 'error')) return 'failed';
|
||||
if (tones.every((tone) => tone === 'done' || tone === 'closed')) return 'completed';
|
||||
if (tones.some((tone) => tone === 'pending')) return 'pending';
|
||||
return fallbackStatus || (done ? 'completed' : 'running');
|
||||
}
|
||||
|
||||
function normalizeCollabAgentData(tool) {
|
||||
const inputData = effectiveObject(tool?.input);
|
||||
const resultData = effectiveObject(tool?.result);
|
||||
const activityData = isSubAgentActivityTool(tool) ? normalizeSubAgentActivityData(tool, inputData, resultData) : null;
|
||||
if (activityData) return activityData;
|
||||
const merged = {
|
||||
...inputData,
|
||||
...resultData,
|
||||
@@ -6953,14 +7057,18 @@
|
||||
const data = normalizeCollabAgentData(tool);
|
||||
const action = getCollabAgentAction(tool, data);
|
||||
const isCloseAction = action === 'close_agent';
|
||||
const fallbackId = tool.id || 'tool-1';
|
||||
receiverThreadIds.push(fallbackId);
|
||||
states[fallbackId] = {
|
||||
...mergeCollabAgentTaskState({}, { label: '子代理' }, data.prompt, fallbackId, 0),
|
||||
status: isCloseAction ? 'closed' : (data.status || (tool.done ? 'completed' : 'running')),
|
||||
};
|
||||
if (!['wait_agent', 'close_agent'].includes(action)) {
|
||||
const fallbackId = tool.id || 'tool-1';
|
||||
receiverThreadIds.push(fallbackId);
|
||||
states[fallbackId] = {
|
||||
...mergeCollabAgentTaskState({}, { label: '子代理' }, data.prompt, fallbackId, 0),
|
||||
status: isCloseAction ? 'closed' : (data.status || (tool.done ? 'completed' : 'running')),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (receiverThreadIds.length === 0) return null;
|
||||
|
||||
receiverThreadIds.forEach((id, index) => {
|
||||
const nextStatus = localClosedIds.has(id) ? 'closed' : (states[id]?.status || 'pending');
|
||||
states[id] = rememberCollabAgentState(
|
||||
@@ -6977,9 +7085,7 @@
|
||||
};
|
||||
});
|
||||
|
||||
const allClosed = receiverThreadIds.length > 0
|
||||
&& receiverThreadIds.every((id) => collabStateTone(states[id]?.status) === 'closed');
|
||||
const mergedStatus = allClosed ? 'closed' : (status || (done ? 'completed' : 'running'));
|
||||
const mergedStatus = aggregateCollabAgentStatus(receiverThreadIds, states, status, done);
|
||||
|
||||
return {
|
||||
id: list[0].id || 'collab-agent-merged',
|
||||
@@ -6996,6 +7102,15 @@
|
||||
};
|
||||
}
|
||||
|
||||
function renderToolCallsWithMergedCollab(toolCalls, options = {}) {
|
||||
const calls = Array.isArray(toolCalls) ? toolCalls : [];
|
||||
const mergedCollabTool = mergeCollabAgentTools(calls, options);
|
||||
return [
|
||||
...(mergedCollabTool ? [mergedCollabTool] : []),
|
||||
...calls.filter((tc) => toolKind(tc) !== 'collab_agent_tool_call'),
|
||||
];
|
||||
}
|
||||
|
||||
function collabStateTone(statusText) {
|
||||
const normalized = String(statusText || '').toLowerCase();
|
||||
if (!normalized) return 'pending';
|
||||
@@ -7220,11 +7335,7 @@
|
||||
const toolMount = bubble.querySelector(':scope > .cross-conversation-reply-body') || bubble;
|
||||
const FOLD_AT = 3;
|
||||
let grouped = false;
|
||||
const mergedCollabTool = mergeCollabAgentTools(m.toolCalls);
|
||||
const renderToolCalls = [
|
||||
...(mergedCollabTool ? [mergedCollabTool] : []),
|
||||
...m.toolCalls.filter((tc) => toolKind(tc) !== 'collab_agent_tool_call'),
|
||||
];
|
||||
const renderToolCalls = renderToolCallsWithMergedCollab(m.toolCalls);
|
||||
for (const tc of renderToolCalls) {
|
||||
if (isEmptyReasoningTool(tc)) continue;
|
||||
const details = createToolCallElement(tc.id || `saved-${Math.random().toString(36).slice(2)}`, tc, true);
|
||||
@@ -8403,17 +8514,9 @@
|
||||
const cursor = typeof msgInput.selectionStart === 'number' ? msgInput.selectionStart : value.length;
|
||||
const before = value.slice(0, cursor);
|
||||
|
||||
if (!before.includes('\n') && value.startsWith('/') && cursor > 0) {
|
||||
const nextWhitespace = value.search(/\s/);
|
||||
const end = nextWhitespace >= 0 ? Math.min(cursor, nextWhitespace) : cursor;
|
||||
if (cursor <= end || nextWhitespace < 0) {
|
||||
return { trigger: '/', query: value.slice(1, cursor), start: 0, end: cursor };
|
||||
}
|
||||
}
|
||||
|
||||
const lineStart = Math.max(before.lastIndexOf('\n'), before.lastIndexOf('\r')) + 1;
|
||||
const line = before.slice(lineStart);
|
||||
const match = line.match(/(^|\s)([@$])([^\s]*)$/);
|
||||
const match = line.match(/(^|\s)([\/@$])([^\s]*)$/);
|
||||
if (!match) return null;
|
||||
const prefixLength = match[1] ? match[1].length : 0;
|
||||
const start = lineStart + match.index + prefixLength;
|
||||
@@ -8710,7 +8813,7 @@
|
||||
appendError('Codex App 运行中插入暂不支持图片附件,请先移除图片。');
|
||||
return;
|
||||
}
|
||||
if (text.startsWith('/')) {
|
||||
if (isKnownSlashCommandText(text)) {
|
||||
appendError('Codex App 运行中暂不支持 slash 指令插入。');
|
||||
return;
|
||||
}
|
||||
@@ -8742,7 +8845,7 @@
|
||||
}
|
||||
|
||||
// Slash commands: don't show as user bubble
|
||||
if (text.startsWith('/')) {
|
||||
if (isKnownSlashCommandText(text)) {
|
||||
if (pendingAttachments.length > 0) {
|
||||
appendError('命令消息暂不支持附带图片,请先移除图片或发送普通消息。');
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user