Add directory-based project skills

This commit is contained in:
武阳
2026-04-28 10:17:23 +08:00
parent fed0999f55
commit a040d80096
21 changed files with 1795 additions and 119 deletions
+57 -13
View File
@@ -232,6 +232,61 @@ function appendToolCall({ name, args, result, isError }) {
els.chat.scrollTop = els.chat.scrollHeight;
}
function parseAssistantToolCalls(entry) {
if (!Array.isArray(entry?.tool_calls)) return [];
return entry.tool_calls.map((tc) => {
const fn = tc?.function || {};
let args = fn.arguments ?? tc?.arguments ?? "";
try {
if (typeof args === "string") args = JSON.parse(args);
} catch {}
return {
id: tc?.id || "",
name: fn.name || tc?.name || "tool",
args,
};
});
}
function renderTranscriptEntries(entries) {
const pendingToolCalls = new Map();
for (const entry of entries || []) {
if (!entry || entry.role === "system") continue;
if (entry.role === "assistant") {
if (entry.content && entry.content.trim()) {
appendMessage({ role: "assistant", content: entry.content });
}
for (const call of parseAssistantToolCalls(entry)) {
if (call.id) pendingToolCalls.set(call.id, call);
}
continue;
}
if (entry.role === "tool") {
const call = pendingToolCalls.get(entry.tool_call_id) || {};
let parsedResult = null;
try {
parsedResult = JSON.parse(entry.content || "{}");
} catch {}
appendToolCall({
name: call.name || entry.name || parsedResult?.tool || "tool",
args: call.args ?? "",
result: entry.content || "",
isError: parsedResult?.ok === false || entry.metadata?.error_kind,
});
if (entry.tool_call_id) pendingToolCalls.delete(entry.tool_call_id);
continue;
}
renderTranscriptEntry(entry);
}
for (const call of pendingToolCalls.values()) {
appendToolCall({
name: call.name,
args: call.args,
result: "(pending — no tool result message found)",
});
}
}
// ---------------------------------------------------------------------------
// Settings
// ---------------------------------------------------------------------------
@@ -314,9 +369,7 @@ async function openSession(sessionId) {
const session = await apiGet(`/api/sessions/${encodeURIComponent(sessionId)}`);
State.activeSessionId = sessionId;
clearChat();
for (const msg of session.messages) {
renderTranscriptEntry(msg);
}
renderTranscriptEntries(session.messages);
renderSessions();
setStatus("ready", `Session ${sessionId.slice(0, 8)}`);
} catch (e) {
@@ -494,16 +547,7 @@ function renderRunResult(data) {
}
}
const tail = transcript.slice(lastUserIndex + 1);
for (const entry of tail) {
if (entry.role === "assistant") {
// Only render if it has visible content; tool_calls already rendered.
if (Array.isArray(entry.tool_calls) && entry.tool_calls.length) {
// Skip — corresponding tool messages will follow.
continue;
}
}
renderTranscriptEntry(entry);
}
renderTranscriptEntries(tail);
// Always show the canonical final output if it isn't already present.
const lastMsg = els.chat.querySelector(".message.assistant:last-of-type .body");
if (!lastMsg || lastMsg.textContent.trim() !== (data.final_output || "").trim()) {