Add directory-based project skills
This commit is contained in:
+57
-13
@@ -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()) {
|
||||
|
||||
Reference in New Issue
Block a user