@moxxy/cli 1.2.7 → 1.2.9
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.
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -222,7 +222,9 @@ async function main() {
|
|
|
222
222
|
setup: { label: 'Setup', hint: 'init, gateway, doctor' },
|
|
223
223
|
agents: { label: 'Agents', hint: 'agents, skills, templates' },
|
|
224
224
|
security: { label: 'Security', hint: 'auth tokens & secrets' },
|
|
225
|
-
integrations: { label: 'Integrations', hint: '
|
|
225
|
+
integrations: { label: 'Integrations', hint: 'channels, MCP' },
|
|
226
|
+
providers: { label: 'Providers', hint: 'manage AI providers' },
|
|
227
|
+
plugins: { label: 'Plugins', hint: 'manage plugins & extensions' },
|
|
226
228
|
tools: { label: 'Tools', hint: 'events stream' },
|
|
227
229
|
system: { label: 'System', hint: 'settings, update & uninstall' },
|
|
228
230
|
};
|
|
@@ -243,12 +245,16 @@ async function main() {
|
|
|
243
245
|
{ value: 'vault', label: 'Vault', hint: 'manage secrets' },
|
|
244
246
|
],
|
|
245
247
|
integrations: [
|
|
246
|
-
{ value: 'provider', label: 'Provider', hint: 'list providers' },
|
|
247
248
|
{ value: 'channel', label: 'Channel', hint: 'manage Telegram/Discord channels' },
|
|
248
249
|
{ value: 'mcp', label: 'MCP', hint: 'manage MCP servers for agents' },
|
|
249
|
-
{ value: 'plugin', label: 'Plugin', hint: 'manage plugins & extensions' },
|
|
250
250
|
{ value: 'heartbeat', label: 'Heartbeat', hint: 'schedule heartbeat rules' },
|
|
251
251
|
],
|
|
252
|
+
providers: [
|
|
253
|
+
{ value: 'provider', label: 'Provider', hint: 'list providers' },
|
|
254
|
+
],
|
|
255
|
+
plugins: [
|
|
256
|
+
{ value: 'plugin', label: 'Plugin', hint: 'manage plugins & extensions' },
|
|
257
|
+
],
|
|
252
258
|
tools: [
|
|
253
259
|
{ value: 'events', label: 'Events', hint: 'stream live events' },
|
|
254
260
|
],
|
|
@@ -298,13 +304,18 @@ async function main() {
|
|
|
298
304
|
const submenu = SUBMENUS[selected];
|
|
299
305
|
if (!submenu) continue;
|
|
300
306
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
307
|
+
let subSelected;
|
|
308
|
+
if (submenu.length === 1) {
|
|
309
|
+
subSelected = submenu[0].value;
|
|
310
|
+
} else {
|
|
311
|
+
subSelected = await p.select({
|
|
312
|
+
message: `${MENU_GROUPS[selected].label}`,
|
|
313
|
+
options: submenu,
|
|
314
|
+
});
|
|
305
315
|
|
|
306
|
-
|
|
307
|
-
|
|
316
|
+
if (p.isCancel(subSelected)) {
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
308
319
|
}
|
|
309
320
|
|
|
310
321
|
try {
|
package/src/commands/channel.js
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
|
-
import { p, handleCancel, withSpinner, showResult } from '../ui.js';
|
|
1
|
+
import { p, handleCancel, isInteractive, withSpinner, showResult } from '../ui.js';
|
|
2
2
|
import { showHelp } from '../help.js';
|
|
3
3
|
import { parseFlags } from './auth.js';
|
|
4
4
|
|
|
5
5
|
export async function runChannel(client, args) {
|
|
6
|
-
|
|
6
|
+
let [subcommand, ...rest] = args;
|
|
7
|
+
|
|
8
|
+
if (!subcommand && isInteractive()) {
|
|
9
|
+
subcommand = await p.select({
|
|
10
|
+
message: 'Channel action',
|
|
11
|
+
options: [
|
|
12
|
+
{ value: 'list', label: 'List channels', hint: 'show registered channels' },
|
|
13
|
+
{ value: 'create', label: 'Create channel', hint: 'register a new channel' },
|
|
14
|
+
{ value: 'pair', label: 'Pair channel', hint: 'bind a channel to an agent' },
|
|
15
|
+
{ value: 'bindings', label: 'List bindings', hint: 'show channel-agent bindings' },
|
|
16
|
+
{ value: 'unbind', label: 'Unbind channel', hint: 'remove a channel-agent binding' },
|
|
17
|
+
{ value: 'delete', label: 'Delete channel', hint: 'remove a channel' },
|
|
18
|
+
],
|
|
19
|
+
});
|
|
20
|
+
handleCancel(subcommand);
|
|
21
|
+
}
|
|
7
22
|
|
|
8
23
|
switch (subcommand) {
|
|
9
24
|
case 'create':
|
package/src/commands/provider.js
CHANGED
|
@@ -340,27 +340,30 @@ function sleep(ms) {
|
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
function tryOpenUrl(url) {
|
|
343
|
-
|
|
344
|
-
let args;
|
|
343
|
+
const candidates = [];
|
|
345
344
|
|
|
346
345
|
if (process.platform === 'darwin') {
|
|
347
|
-
cmd
|
|
348
|
-
args = [url];
|
|
346
|
+
candidates.push({ cmd: 'open', args: [url] });
|
|
349
347
|
} else if (process.platform === 'win32') {
|
|
350
|
-
cmd
|
|
351
|
-
args = ['/c', 'start', '', url];
|
|
348
|
+
candidates.push({ cmd: 'cmd', args: ['/c', 'start', '', url] });
|
|
352
349
|
} else {
|
|
353
|
-
|
|
354
|
-
|
|
350
|
+
candidates.push(
|
|
351
|
+
{ cmd: 'xdg-open', args: [url] },
|
|
352
|
+
{ cmd: 'sensible-browser', args: [url] },
|
|
353
|
+
{ cmd: 'x-www-browser', args: [url] },
|
|
354
|
+
);
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
357
|
+
for (const { cmd, args } of candidates) {
|
|
358
|
+
try {
|
|
359
|
+
const child = spawn(cmd, args, { stdio: 'ignore', detached: true });
|
|
360
|
+
child.unref();
|
|
361
|
+
return true;
|
|
362
|
+
} catch {
|
|
363
|
+
// try next candidate
|
|
364
|
+
}
|
|
363
365
|
}
|
|
366
|
+
return false;
|
|
364
367
|
}
|
|
365
368
|
|
|
366
369
|
function createCodeVerifier() {
|
|
@@ -3,29 +3,59 @@ import { Box, Text } from 'ink';
|
|
|
3
3
|
import { THEME } from '../../theme.js';
|
|
4
4
|
|
|
5
5
|
export function SkillMessage({ msg, showDetails = false }) {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const isRunning = msg.status === 'running';
|
|
7
|
+
const isError = msg.status === 'error';
|
|
8
|
+
const steps = msg.steps || [];
|
|
8
9
|
|
|
10
|
+
// Header icon and color
|
|
11
|
+
let headerIcon = '⊞';
|
|
12
|
+
let headerColor = THEME.primary;
|
|
9
13
|
if (msg.status === 'completed') {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} else if (
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
headerIcon = '✓';
|
|
15
|
+
headerColor = THEME.success;
|
|
16
|
+
} else if (isError) {
|
|
17
|
+
headerIcon = '✗';
|
|
18
|
+
headerColor = THEME.error;
|
|
15
19
|
}
|
|
16
20
|
|
|
21
|
+
// Header text
|
|
22
|
+
const headerText = isRunning
|
|
23
|
+
? `Invoking ${msg.name}...`
|
|
24
|
+
: msg.name;
|
|
25
|
+
|
|
17
26
|
return (
|
|
18
27
|
<Box flexDirection="column">
|
|
19
28
|
<Text>
|
|
20
|
-
<Text color={
|
|
21
|
-
<Text bold color={
|
|
22
|
-
<Text color={THEME.
|
|
23
|
-
{msg.status === 'running' && <Text color={THEME.dim}> …</Text>}
|
|
24
|
-
{msg.error ? <Text color={THEME.error}> - {msg.error}</Text> : null}
|
|
29
|
+
<Text color={headerColor}>{headerIcon}</Text>
|
|
30
|
+
<Text bold color={headerColor}> {headerText}</Text>
|
|
31
|
+
{isError && msg.error ? <Text color={THEME.error}> - {msg.error}</Text> : null}
|
|
25
32
|
</Text>
|
|
26
|
-
{
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
{steps.map((step, i) => {
|
|
34
|
+
let stepIcon = '◷';
|
|
35
|
+
let stepColor = THEME.dim;
|
|
36
|
+
if (step.status === 'completed') {
|
|
37
|
+
stepIcon = '◷';
|
|
38
|
+
stepColor = THEME.dim;
|
|
39
|
+
} else if (step.status === 'error') {
|
|
40
|
+
stepIcon = '✗';
|
|
41
|
+
stepColor = THEME.error;
|
|
42
|
+
} else {
|
|
43
|
+
stepIcon = '⏳';
|
|
44
|
+
stepColor = THEME.warning;
|
|
45
|
+
}
|
|
46
|
+
const resultText = step.error
|
|
47
|
+
? step.error
|
|
48
|
+
: step.result
|
|
49
|
+
? (step.result.length > 60 ? step.result.slice(0, 60) + '…' : step.result)
|
|
50
|
+
: null;
|
|
51
|
+
return (
|
|
52
|
+
<Text key={i}>
|
|
53
|
+
<Text color={stepColor}>{stepIcon}</Text>
|
|
54
|
+
<Text bold> {step.name}</Text>
|
|
55
|
+
{resultText ? <Text color={THEME.dim}> → {resultText}</Text> : null}
|
|
56
|
+
</Text>
|
|
57
|
+
);
|
|
58
|
+
})}
|
|
29
59
|
</Box>
|
|
30
60
|
);
|
|
31
61
|
}
|
|
@@ -24,13 +24,17 @@ export function ToolGroup({ messages, expanded = false }) {
|
|
|
24
24
|
|
|
25
25
|
const icon = errors > 0 ? '✗' : '✓';
|
|
26
26
|
const color = errors > 0 ? THEME.error : THEME.success;
|
|
27
|
-
const
|
|
27
|
+
const skillMsgs = messages.filter(m => m.type === 'skill');
|
|
28
28
|
const tools = messages.filter(m => m.type === 'tool').length;
|
|
29
|
+
// Count total steps across all skills
|
|
30
|
+
const skillSteps = skillMsgs.reduce((sum, m) => sum + (m.steps ? m.steps.length : 0), 0);
|
|
29
31
|
const parts = [];
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
+
const totalTools = tools + skillSteps;
|
|
33
|
+
if (totalTools > 0) parts.push(`${totalTools} tool${totalTools > 1 ? 's' : ''}`);
|
|
34
|
+
if (skillMsgs.length > 0) parts.push(`${skillMsgs.length} skill${skillMsgs.length > 1 ? 's' : ''}`);
|
|
32
35
|
const label = parts.join(', ');
|
|
33
|
-
const
|
|
36
|
+
const totalDone = completed + skillSteps;
|
|
37
|
+
const detail = errors > 0 ? `${totalDone} done, ${errors} failed` : `${totalDone} done`;
|
|
34
38
|
|
|
35
39
|
if (!expanded) {
|
|
36
40
|
return (
|
|
@@ -8,9 +8,10 @@ const ERROR_EVENTS = new Set([
|
|
|
8
8
|
]);
|
|
9
9
|
|
|
10
10
|
// Error events that should be shown as user-friendly system messages
|
|
11
|
-
// instead of raw event brackets (brackets only in debug mode)
|
|
11
|
+
// instead of raw event brackets (brackets only in debug mode).
|
|
12
|
+
// NOTE: primitive.failed is handled separately (with skill awareness) before this check.
|
|
12
13
|
const FRIENDLY_ERROR_EVENTS = new Set([
|
|
13
|
-
'run.failed',
|
|
14
|
+
'run.failed',
|
|
14
15
|
]);
|
|
15
16
|
|
|
16
17
|
// Tool activity events always shown in chat as compact messages
|
|
@@ -104,6 +105,7 @@ export class EventsHandler {
|
|
|
104
105
|
this._thinkingTimer = null;
|
|
105
106
|
this.pendingAsk = null; // { questionId, question } = set when agent asks user
|
|
106
107
|
this._subAgents = new Map(); // agentId -> { name, task, buffer, status }
|
|
108
|
+
this._activeSkillIdx = null; // index into this.messages for the running skill
|
|
107
109
|
this._hiveStatus = null; // aggregated hive status tracker
|
|
108
110
|
this._version = 0;
|
|
109
111
|
this.messageVersion = 0;
|
|
@@ -597,6 +599,14 @@ export class EventsHandler {
|
|
|
597
599
|
clearTimeout(this._deltaTimer);
|
|
598
600
|
this._deltaTimer = null;
|
|
599
601
|
}
|
|
602
|
+
// Close active skill session on final message
|
|
603
|
+
if (this._activeSkillIdx != null) {
|
|
604
|
+
const skill = this.messages[this._activeSkillIdx];
|
|
605
|
+
if (skill && skill.status === 'running') {
|
|
606
|
+
skill.status = 'completed';
|
|
607
|
+
}
|
|
608
|
+
this._activeSkillIdx = null;
|
|
609
|
+
}
|
|
600
610
|
const finalContent = payload.content || payload.text || this._assistantBuffer;
|
|
601
611
|
this._assistantBuffer = '';
|
|
602
612
|
const last = this.messages[this.messages.length - 1];
|
|
@@ -614,6 +624,14 @@ export class EventsHandler {
|
|
|
614
624
|
// Stop thinking on run completion or errors
|
|
615
625
|
if (type === 'run.completed' || type === 'run.failed') {
|
|
616
626
|
if (this.thinking) this._stopThinking();
|
|
627
|
+
// Close active skill session on run end
|
|
628
|
+
if (this._activeSkillIdx != null) {
|
|
629
|
+
const skill = this.messages[this._activeSkillIdx];
|
|
630
|
+
if (skill) {
|
|
631
|
+
skill.status = type === 'run.failed' ? 'error' : 'completed';
|
|
632
|
+
}
|
|
633
|
+
this._activeSkillIdx = null;
|
|
634
|
+
}
|
|
617
635
|
}
|
|
618
636
|
|
|
619
637
|
// Silence errors for hidden tool prefixes (e.g. agent.*)
|
|
@@ -621,6 +639,58 @@ export class EventsHandler {
|
|
|
621
639
|
return;
|
|
622
640
|
}
|
|
623
641
|
|
|
642
|
+
// Handle primitive.failed with skill awareness BEFORE friendly error fallback
|
|
643
|
+
if (type === 'primitive.failed') {
|
|
644
|
+
const toolName = payload.name || 'unknown';
|
|
645
|
+
const errorMsg = payload.error || 'unknown error';
|
|
646
|
+
|
|
647
|
+
// skill.execute itself failed → mark the skill as error and close session
|
|
648
|
+
if (toolName === 'skill.execute' && this._activeSkillIdx != null) {
|
|
649
|
+
const skill = this.messages[this._activeSkillIdx];
|
|
650
|
+
if (skill) {
|
|
651
|
+
skill.status = 'error';
|
|
652
|
+
skill.error = errorMsg;
|
|
653
|
+
}
|
|
654
|
+
this._activeSkillIdx = null;
|
|
655
|
+
this.messageVersion++;
|
|
656
|
+
this._notify();
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// A tool within an active skill failed → mark the step as error
|
|
661
|
+
if (this._activeSkillIdx != null) {
|
|
662
|
+
const skill = this.messages[this._activeSkillIdx];
|
|
663
|
+
if (skill && skill.status === 'running') {
|
|
664
|
+
const step = [...skill.steps].reverse().find(s => s.name === toolName && s.status === 'running');
|
|
665
|
+
if (step) {
|
|
666
|
+
step.status = 'error';
|
|
667
|
+
step.error = errorMsg;
|
|
668
|
+
this.messageVersion++;
|
|
669
|
+
this._notify();
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// Update the last tool message for the same primitive if it was just invoked
|
|
676
|
+
const last = this.messages[this.messages.length - 1];
|
|
677
|
+
if (last && last.type === 'tool' && last.name === toolName && last.status === 'invoked') {
|
|
678
|
+
last.status = 'error';
|
|
679
|
+
last.error = errorMsg;
|
|
680
|
+
this.messageVersion++;
|
|
681
|
+
this._notify();
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// Fallback: show as friendly system message (non-debug mode)
|
|
686
|
+
if (!this.debug) {
|
|
687
|
+
this.messages.push({ type: 'system', content: `Tool error: ${errorMsg}`, ts: event.ts });
|
|
688
|
+
this.messageVersion++;
|
|
689
|
+
this._notify();
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
624
694
|
// For user-facing error events, show as a friendly system message
|
|
625
695
|
// (raw event format only in debug mode)
|
|
626
696
|
if (!this.debug && FRIENDLY_ERROR_EVENTS.has(type)) {
|
|
@@ -636,8 +706,48 @@ export class EventsHandler {
|
|
|
636
706
|
if (TOOL_ACTIVITY_EVENTS.has(type)) {
|
|
637
707
|
if (type === 'primitive.invoked') {
|
|
638
708
|
if (isHiddenTool(payload.name || '')) return;
|
|
709
|
+
const toolName = payload.name || 'unknown';
|
|
710
|
+
|
|
711
|
+
// Detect skill.execute → start a skill session
|
|
712
|
+
if (toolName === 'skill.execute') {
|
|
713
|
+
// Parse arguments — may be an object or a JSON string
|
|
714
|
+
let args = payload.arguments;
|
|
715
|
+
if (typeof args === 'string') {
|
|
716
|
+
try { args = JSON.parse(args); } catch { args = {}; }
|
|
717
|
+
}
|
|
718
|
+
const skillName = (args && args.name) || 'unknown';
|
|
719
|
+
|
|
720
|
+
// Close any previous active skill
|
|
721
|
+
if (this._activeSkillIdx != null) {
|
|
722
|
+
const prev = this.messages[this._activeSkillIdx];
|
|
723
|
+
if (prev && prev.status === 'running') {
|
|
724
|
+
prev.status = 'completed';
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
this.messages.push({
|
|
729
|
+
type: 'skill', name: skillName, status: 'running',
|
|
730
|
+
steps: [], ts: event.ts,
|
|
731
|
+
});
|
|
732
|
+
this._activeSkillIdx = this.messages.length - 1;
|
|
733
|
+
this.messageVersion++;
|
|
734
|
+
this._notify();
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// If a skill is active, nest this tool as a step
|
|
739
|
+
if (this._activeSkillIdx != null) {
|
|
740
|
+
const skill = this.messages[this._activeSkillIdx];
|
|
741
|
+
if (skill && skill.status === 'running') {
|
|
742
|
+
skill.steps.push({ name: toolName, status: 'running', result: null });
|
|
743
|
+
this.messageVersion++;
|
|
744
|
+
this._notify();
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
639
749
|
this.messages.push({
|
|
640
|
-
type: 'tool', name:
|
|
750
|
+
type: 'tool', name: toolName, status: 'invoked',
|
|
641
751
|
arguments: formatParams(payload.arguments),
|
|
642
752
|
rawArguments: payload.arguments,
|
|
643
753
|
ts: event.ts,
|
|
@@ -648,9 +758,41 @@ export class EventsHandler {
|
|
|
648
758
|
}
|
|
649
759
|
if (type === 'primitive.completed') {
|
|
650
760
|
if (isHiddenTool(payload.name || '')) return;
|
|
761
|
+
const toolName = payload.name || 'unknown';
|
|
762
|
+
|
|
763
|
+
// skill.execute completed → just absorb (skill stays running for subsequent tools)
|
|
764
|
+
if (toolName === 'skill.execute') {
|
|
765
|
+
// Update skill name from result if available
|
|
766
|
+
if (this._activeSkillIdx != null) {
|
|
767
|
+
const skill = this.messages[this._activeSkillIdx];
|
|
768
|
+
const resultName = payload.result && typeof payload.result === 'object' && payload.result.name;
|
|
769
|
+
if (skill && resultName) {
|
|
770
|
+
skill.name = resultName;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
this.messageVersion++;
|
|
774
|
+
this._notify();
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// If a skill is active, update the step
|
|
779
|
+
if (this._activeSkillIdx != null) {
|
|
780
|
+
const skill = this.messages[this._activeSkillIdx];
|
|
781
|
+
if (skill && skill.status === 'running') {
|
|
782
|
+
const step = [...skill.steps].reverse().find(s => s.name === toolName && s.status === 'running');
|
|
783
|
+
if (step) {
|
|
784
|
+
step.status = 'completed';
|
|
785
|
+
step.result = formatParams(payload.result);
|
|
786
|
+
}
|
|
787
|
+
this.messageVersion++;
|
|
788
|
+
this._notify();
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
651
793
|
// Update the last tool message for the same primitive if it was just invoked
|
|
652
794
|
const last = this.messages[this.messages.length - 1];
|
|
653
|
-
if (last && last.type === 'tool' && last.name ===
|
|
795
|
+
if (last && last.type === 'tool' && last.name === toolName && last.status === 'invoked') {
|
|
654
796
|
last.status = 'completed';
|
|
655
797
|
last.result = formatParams(payload.result);
|
|
656
798
|
last.rawResult = payload.result;
|
|
@@ -663,10 +805,18 @@ export class EventsHandler {
|
|
|
663
805
|
|
|
664
806
|
// Show skill activity events as compact bordered messages
|
|
665
807
|
if (type === 'skill.invoked') {
|
|
808
|
+
// Close any previous active skill
|
|
809
|
+
if (this._activeSkillIdx != null) {
|
|
810
|
+
const prev = this.messages[this._activeSkillIdx];
|
|
811
|
+
if (prev && prev.status === 'running') {
|
|
812
|
+
prev.status = 'completed';
|
|
813
|
+
}
|
|
814
|
+
}
|
|
666
815
|
this.messages.push({
|
|
667
816
|
type: 'skill', name: payload.name || 'unknown', status: 'running',
|
|
668
|
-
|
|
817
|
+
steps: [], ts: event.ts,
|
|
669
818
|
});
|
|
819
|
+
this._activeSkillIdx = this.messages.length - 1;
|
|
670
820
|
this.messageVersion++;
|
|
671
821
|
this._notify();
|
|
672
822
|
return;
|
|
@@ -680,6 +830,7 @@ export class EventsHandler {
|
|
|
680
830
|
break;
|
|
681
831
|
}
|
|
682
832
|
}
|
|
833
|
+
this._activeSkillIdx = null;
|
|
683
834
|
this.messageVersion++;
|
|
684
835
|
this._notify();
|
|
685
836
|
return;
|
|
@@ -699,27 +850,15 @@ export class EventsHandler {
|
|
|
699
850
|
if (!found) {
|
|
700
851
|
this.messages.push({
|
|
701
852
|
type: 'skill', name: payload.name || 'unknown', status: 'error',
|
|
702
|
-
error: payload.error || 'unknown error', ts: event.ts,
|
|
853
|
+
error: payload.error || 'unknown error', steps: [], ts: event.ts,
|
|
703
854
|
});
|
|
704
855
|
}
|
|
856
|
+
this._activeSkillIdx = null;
|
|
705
857
|
this.messageVersion++;
|
|
706
858
|
this._notify();
|
|
707
859
|
return;
|
|
708
860
|
}
|
|
709
861
|
|
|
710
|
-
// Show tool error events
|
|
711
|
-
if (type === 'primitive.failed') {
|
|
712
|
-
// Update the last tool message for the same primitive if it was just invoked
|
|
713
|
-
const last = this.messages[this.messages.length - 1];
|
|
714
|
-
if (last && last.type === 'tool' && last.name === (payload.name || 'unknown') && last.status === 'invoked') {
|
|
715
|
-
last.status = 'error';
|
|
716
|
-
last.error = payload.error || 'unknown error';
|
|
717
|
-
this.messageVersion++;
|
|
718
|
-
this._notify();
|
|
719
|
-
return;
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
|
|
723
862
|
// Show error events always; show all events in debug mode
|
|
724
863
|
if (ERROR_EVENTS.has(type) || this.debug) {
|
|
725
864
|
this.messages.push({ type: 'event', eventType: type, payload, ts: event.ts });
|