llm_meta_widget 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2503371d1d6229fbe6e57a807fb8d672190de589ccdb877d2a90a06feae20be0
|
|
4
|
+
data.tar.gz: bce91755bb903ab02f886be7e9ab90733566699359e468624f3244f1202ad17a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d833790ba0fcdb48cb291a9cde65ab45e2c07284a18a9699c755289a2ded830695e84b3125e552f770c66db8e9930e9c28410baaef2c5e0459d75ef9b93636a4
|
|
7
|
+
data.tar.gz: 819cd9aa17be97c44b3828980b9faa6a3f79476a2802337b3e59a4149c17a45058a0355a7e5a29f39594ed8c8dfae373cb6040dde762795b6c031b9467d70128
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
// onTextDelta: (str) => {},
|
|
33
33
|
// onThinkingDelta: (str) => {},
|
|
34
34
|
// onToolCall: (tc) => {}, // { id, name, arguments }
|
|
35
|
+
// onToolDispatched: ({toolCall, value, error}) => {}, // after it ran
|
|
35
36
|
// onPhase: (name) => {}, // 'thinking' | 'tool_execution' | ...
|
|
36
37
|
// signal: abortController.signal
|
|
37
38
|
// })
|
|
@@ -329,6 +330,11 @@ export async function runChatLoop(opts) {
|
|
|
329
330
|
onTextDelta,
|
|
330
331
|
onThinkingDelta,
|
|
331
332
|
onToolCall,
|
|
333
|
+
// Fired as each tool finishes, so a caller can show what ran WHILE the
|
|
334
|
+
// turn is still going. The returned `dispatched` array says the same
|
|
335
|
+
// thing, but only once the whole loop ends — which on a slow model is
|
|
336
|
+
// minutes after the work happened, with the user watching unnamed tools.
|
|
337
|
+
onToolDispatched,
|
|
332
338
|
onPhase,
|
|
333
339
|
...singleOpts
|
|
334
340
|
} = opts
|
|
@@ -454,7 +460,8 @@ export async function runChatLoop(opts) {
|
|
|
454
460
|
// the write. It also means a failed action is something the model can
|
|
455
461
|
// see and correct, instead of a red mark only the user notices.
|
|
456
462
|
const roundTripResults = []
|
|
457
|
-
for (const { toolCall, error } of localOut.dispatched) {
|
|
463
|
+
for (const { toolCall, value, error } of localOut.dispatched) {
|
|
464
|
+
onToolDispatched?.({ toolCall, value, error })
|
|
458
465
|
roundTripResults.push({
|
|
459
466
|
tc: toolCall,
|
|
460
467
|
result: error ? { error: String(error.message || error) } : { ok: true, applied: toolCall.name }
|
|
@@ -468,9 +475,11 @@ export async function runChatLoop(opts) {
|
|
|
468
475
|
try {
|
|
469
476
|
const value = await callMcpTool({ endpoint: tool.endpoint, name: tc.name, args, signal })
|
|
470
477
|
allDispatched.push({ toolCall: tc, value })
|
|
478
|
+
onToolDispatched?.({ toolCall: tc, value })
|
|
471
479
|
roundTripResults.push({ tc, result: value })
|
|
472
480
|
} catch (error) {
|
|
473
481
|
allDispatched.push({ toolCall: tc, error })
|
|
482
|
+
onToolDispatched?.({ toolCall: tc, error })
|
|
474
483
|
roundTripResults.push({ tc, result: { error: String(error.message || error) } })
|
|
475
484
|
}
|
|
476
485
|
}
|
|
@@ -488,9 +497,11 @@ export async function runChatLoop(opts) {
|
|
|
488
497
|
signal
|
|
489
498
|
})
|
|
490
499
|
allDispatched.push({ toolCall: tc, value })
|
|
500
|
+
onToolDispatched?.({ toolCall: tc, value })
|
|
491
501
|
roundTripResults.push({ tc, result: value })
|
|
492
502
|
} catch (error) {
|
|
493
503
|
allDispatched.push({ toolCall: tc, error })
|
|
504
|
+
onToolDispatched?.({ toolCall: tc, error })
|
|
494
505
|
// Feed the error text back to the LLM as the tool result — better
|
|
495
506
|
// than dropping it (the LLM can react, apologize, retry differently).
|
|
496
507
|
roundTripResults.push({ tc, result: { error: String(error.message || error) } })
|
|
@@ -1070,6 +1070,48 @@
|
|
|
1070
1070
|
label.textContent = roleLabel("assistant");
|
|
1071
1071
|
}
|
|
1072
1072
|
|
|
1073
|
+
// Tool chips, written as the tools run rather than assembled at the end.
|
|
1074
|
+
// The end-of-turn footer was invisible for as long as the turn lasted —
|
|
1075
|
+
// minutes on a thinking model — so a visitor watched tools execute with
|
|
1076
|
+
// no idea which ones.
|
|
1077
|
+
var liveChips = null; // the container inside the current bubble
|
|
1078
|
+
var pendingChips = []; // chips awaiting their outcome, oldest first
|
|
1079
|
+
|
|
1080
|
+
function chipRow() {
|
|
1081
|
+
if (liveChips && liveChips.parentNode) return liveChips;
|
|
1082
|
+
if (!activeAssistantBody || !activeAssistantBody.parentNode) return null;
|
|
1083
|
+
liveChips = document.createElement("div");
|
|
1084
|
+
liveChips.className = "lmw-tool-chips";
|
|
1085
|
+
// Inside the bubble but OUTSIDE .message-content: every text delta
|
|
1086
|
+
// re-renders that element's markdown from scratch, which silently
|
|
1087
|
+
// erased any chip already written into it.
|
|
1088
|
+
activeAssistantBody.parentNode.appendChild(liveChips);
|
|
1089
|
+
return liveChips;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
function announceToolCall(toolCall) {
|
|
1093
|
+
var row = chipRow();
|
|
1094
|
+
if (!row) return;
|
|
1095
|
+
var chip = document.createElement("span");
|
|
1096
|
+
chip.className = "lmw-tool-chip running";
|
|
1097
|
+
chip.textContent = "⏳ " + toolCall.name;
|
|
1098
|
+
chip.dataset.tool = toolCall.name;
|
|
1099
|
+
row.appendChild(chip);
|
|
1100
|
+
pendingChips.push(chip);
|
|
1101
|
+
historyEl.scrollTop = historyEl.scrollHeight;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
function resolveToolCall(outcome) {
|
|
1105
|
+
// Match by name, oldest first: ids are not always echoed back, and a
|
|
1106
|
+
// repeated name resolves in call order.
|
|
1107
|
+
var idx = pendingChips.findIndex(function(c) { return c.dataset.tool === outcome.toolCall.name; });
|
|
1108
|
+
var chip = idx === -1 ? null : pendingChips.splice(idx, 1)[0];
|
|
1109
|
+
if (!chip) return;
|
|
1110
|
+
chip.className = "lmw-tool-chip" + (outcome.error ? " error" : "");
|
|
1111
|
+
chip.textContent = (outcome.error ? "❌ " : "🔧 ") + outcome.toolCall.name;
|
|
1112
|
+
if (outcome.error) chip.title = outcome.error.message || String(outcome.error);
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1073
1115
|
var currentThinkingBlock = null;
|
|
1074
1116
|
var currentThinkingBody = null;
|
|
1075
1117
|
// The assistant bubble of the turn in flight. Reasoning belongs ABOVE that
|
|
@@ -1196,6 +1238,8 @@
|
|
|
1196
1238
|
|
|
1197
1239
|
var assistantBody = appendTurn("assistant", "");
|
|
1198
1240
|
activeAssistantBody = assistantBody;
|
|
1241
|
+
liveChips = null;
|
|
1242
|
+
pendingChips = [];
|
|
1199
1243
|
markWorking(assistantBody.roleLabel);
|
|
1200
1244
|
var assistantMarkdown = ""; // accumulate raw markdown, re-render on each delta
|
|
1201
1245
|
|
|
@@ -1222,6 +1266,8 @@
|
|
|
1222
1266
|
aiActions: window[ACTIONS_GLOBAL] || {},
|
|
1223
1267
|
maxRounds: MAX_ROUNDS,
|
|
1224
1268
|
signal: currentAbort.signal,
|
|
1269
|
+
onToolCall: function(toolCall) { announceToolCall(toolCall); },
|
|
1270
|
+
onToolDispatched: function(outcome) { resolveToolCall(outcome); },
|
|
1225
1271
|
onPhase: function(name) {
|
|
1226
1272
|
// 'thinking' covers the long silence before the first
|
|
1227
1273
|
// token; 'responding' means text is on its way.
|
|
@@ -1258,23 +1304,15 @@
|
|
|
1258
1304
|
conversation.push({ role: "user", content: userText });
|
|
1259
1305
|
conversation.push({ role: "assistant", content: result.content });
|
|
1260
1306
|
|
|
1261
|
-
//
|
|
1262
|
-
//
|
|
1263
|
-
//
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
var chip = document.createElement("span");
|
|
1271
|
-
chip.className = "lmw-tool-chip" + (d.error ? " error" : "");
|
|
1272
|
-
chip.textContent = (d.error ? "❌ " : "🔧 ") + d.toolCall.name;
|
|
1273
|
-
if (d.error) chip.title = d.error.message;
|
|
1274
|
-
chips.appendChild(chip);
|
|
1275
|
-
});
|
|
1276
|
-
assistantBody.appendChild(chips);
|
|
1277
|
-
}
|
|
1307
|
+
// Anything still pending never reported an outcome (a class that
|
|
1308
|
+
// does not round-trip, or a dispatch that vanished). Reconcile
|
|
1309
|
+
// from the loop's own record so no chip is left spinning.
|
|
1310
|
+
result.dispatched.forEach(function(d) { resolveToolCall(d); });
|
|
1311
|
+
pendingChips.forEach(function(chip) {
|
|
1312
|
+
chip.className = "lmw-tool-chip";
|
|
1313
|
+
chip.textContent = "🔧 " + chip.dataset.tool;
|
|
1314
|
+
});
|
|
1315
|
+
pendingChips = [];
|
|
1278
1316
|
|
|
1279
1317
|
// Skipped = LLM tried a tool that doesn't exist. Real signal.
|
|
1280
1318
|
if (result.skipped.length > 0) {
|