pi-advisor-flow 0.2.0 → 0.2.1
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/extensions/index.ts +15 -6
- package/package.json +12 -4
- package/src/commands.ts +123 -97
- package/src/config.ts +233 -178
- package/src/conversation.ts +43 -24
- package/src/herdr.ts +3 -6
- package/src/session-state.ts +14 -6
- package/src/tools.ts +282 -185
- package/src/ui.ts +107 -73
package/src/tools.ts
CHANGED
|
@@ -4,10 +4,14 @@ import {
|
|
|
4
4
|
stream,
|
|
5
5
|
} from "@earendil-works/pi-ai/compat";
|
|
6
6
|
import {
|
|
7
|
+
type AgentToolResult,
|
|
7
8
|
type ExtensionAPI,
|
|
8
9
|
type ExtensionContext,
|
|
9
10
|
getMarkdownTheme,
|
|
10
11
|
type Theme,
|
|
12
|
+
type ToolCallEvent,
|
|
13
|
+
type ToolCallEventResult,
|
|
14
|
+
type ToolRenderResultOptions,
|
|
11
15
|
} from "@earendil-works/pi-coding-agent";
|
|
12
16
|
import { Box, Markdown, Text } from "@earendil-works/pi-tui";
|
|
13
17
|
import { Type } from "typebox";
|
|
@@ -439,6 +443,267 @@ const failureEffect = (
|
|
|
439
443
|
return { block: true, effect: "session-blocked" as const, reason };
|
|
440
444
|
};
|
|
441
445
|
|
|
446
|
+
const reserveAdvisorCall = (
|
|
447
|
+
event: ToolCallEvent,
|
|
448
|
+
ctx: ExtensionContext,
|
|
449
|
+
session: AdvisorSessionState,
|
|
450
|
+
reservedCalls: Set<string>
|
|
451
|
+
): ToolCallEventResult | undefined => {
|
|
452
|
+
if (event.toolName !== "ask_advisor") {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
if (!session.canConsult(advisorMaxCallsPerSessionRef)) {
|
|
456
|
+
const message = "Advisor call budget exhausted for this session.";
|
|
457
|
+
if (ctx.hasUI) {
|
|
458
|
+
ctx.ui.notify(message, "warning");
|
|
459
|
+
}
|
|
460
|
+
notifyHerdrAdvisorFailure("Advisor budget exhausted", message);
|
|
461
|
+
return { block: true, reason: message };
|
|
462
|
+
}
|
|
463
|
+
session.consumeCall();
|
|
464
|
+
reservedCalls.add(event.toolCallId);
|
|
465
|
+
return {};
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
const sendAutomaticGateCall = (pi: ExtensionAPI, event: ToolCallEvent) => {
|
|
469
|
+
pi.sendMessage(
|
|
470
|
+
{
|
|
471
|
+
content: "Automatic Advisor loop review",
|
|
472
|
+
customType: "advisor-loop-call",
|
|
473
|
+
details: {
|
|
474
|
+
question: `Loop gate: ${event.toolName} repeated ${advisorLoopThresholdRef} times`,
|
|
475
|
+
},
|
|
476
|
+
display: true,
|
|
477
|
+
},
|
|
478
|
+
{ deliverAs: "steer" }
|
|
479
|
+
);
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
const sendAutomaticGateFailure = (pi: ExtensionAPI, markdown: string) => {
|
|
483
|
+
pi.sendMessage(
|
|
484
|
+
{
|
|
485
|
+
content: markdown,
|
|
486
|
+
customType: "advisor-loop-result",
|
|
487
|
+
details: { text: markdown },
|
|
488
|
+
display: true,
|
|
489
|
+
},
|
|
490
|
+
{ deliverAs: "steer" }
|
|
491
|
+
);
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
const sendAutomaticGateResult = (
|
|
495
|
+
pi: ExtensionAPI,
|
|
496
|
+
result: AdvisorGateResult
|
|
497
|
+
) => {
|
|
498
|
+
pi.sendMessage(
|
|
499
|
+
{
|
|
500
|
+
content: adviceForText(result),
|
|
501
|
+
customType: "advisor-loop-result",
|
|
502
|
+
details: {
|
|
503
|
+
advisor: result.model,
|
|
504
|
+
decision: result.decision,
|
|
505
|
+
text: result.markdown,
|
|
506
|
+
},
|
|
507
|
+
display: true,
|
|
508
|
+
},
|
|
509
|
+
{ deliverAs: "steer" }
|
|
510
|
+
);
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
const handleAutomaticGate = async (
|
|
514
|
+
pi: ExtensionAPI,
|
|
515
|
+
event: ToolCallEvent,
|
|
516
|
+
ctx: ExtensionContext,
|
|
517
|
+
session: AdvisorSessionState
|
|
518
|
+
): Promise<ToolCallEventResult | undefined> => {
|
|
519
|
+
if (
|
|
520
|
+
event.toolName === "ask_advisor" ||
|
|
521
|
+
!advisorAutoLoopGateRef ||
|
|
522
|
+
!session.recordToolCall(
|
|
523
|
+
event.toolName,
|
|
524
|
+
event.input,
|
|
525
|
+
advisorLoopThresholdRef
|
|
526
|
+
)
|
|
527
|
+
) {
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
const reason = `Advisor loop gate: normalized signature for ${event.toolName} repeated ${advisorLoopThresholdRef} times without a materially different tool action.`;
|
|
531
|
+
if (!session.canConsult(advisorMaxCallsPerSessionRef)) {
|
|
532
|
+
const failure = failureEffect(
|
|
533
|
+
"budget-exhausted",
|
|
534
|
+
"Advisor gate call budget is exhausted.",
|
|
535
|
+
ctx,
|
|
536
|
+
session
|
|
537
|
+
);
|
|
538
|
+
return failure.block ? { block: true, reason: failure.reason } : undefined;
|
|
539
|
+
}
|
|
540
|
+
session.consumeCall();
|
|
541
|
+
herdrAdvisorActivity.start();
|
|
542
|
+
sendAutomaticGateCall(pi, event);
|
|
543
|
+
try {
|
|
544
|
+
const result = await runAdvisorGate(
|
|
545
|
+
ctx,
|
|
546
|
+
`${reason} Review the repeated actions and recommend the smallest safe next step.`
|
|
547
|
+
);
|
|
548
|
+
if (!result.ok) {
|
|
549
|
+
session.recordInvocation({
|
|
550
|
+
executionEffect: gateFailureEffectForMode(advisorFailureModeRef),
|
|
551
|
+
failure: result.category,
|
|
552
|
+
kind: "gate",
|
|
553
|
+
model: advisorRef,
|
|
554
|
+
trigger: "repeated-tool-call",
|
|
555
|
+
});
|
|
556
|
+
const failure = failureEffect(
|
|
557
|
+
result.category,
|
|
558
|
+
result.message,
|
|
559
|
+
ctx,
|
|
560
|
+
session
|
|
561
|
+
);
|
|
562
|
+
sendAutomaticGateFailure(
|
|
563
|
+
pi,
|
|
564
|
+
`**Advisor gate failure (${result.category}):** ${result.message}`
|
|
565
|
+
);
|
|
566
|
+
return failure.block
|
|
567
|
+
? { block: true, reason: `${reason}\n${failure.reason}` }
|
|
568
|
+
: undefined;
|
|
569
|
+
}
|
|
570
|
+
session.recordInvocation({
|
|
571
|
+
cost: advisorUsageCost(result.usage),
|
|
572
|
+
decision: result.decision,
|
|
573
|
+
executionEffect: gateDecisionEffect(result.decision),
|
|
574
|
+
kind: "gate",
|
|
575
|
+
model: result.model,
|
|
576
|
+
trigger: result.trigger,
|
|
577
|
+
usage: result.usage,
|
|
578
|
+
});
|
|
579
|
+
sendAutomaticGateResult(pi, result);
|
|
580
|
+
if (result.decision === "proceed") {
|
|
581
|
+
session.resetRepetition();
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
const gateReason = `Advisor loop review: ${result.markdown}`;
|
|
585
|
+
if (result.decision === "blocked") {
|
|
586
|
+
session.block(gateReason);
|
|
587
|
+
herdrAdvisorBlock.set(gateReason);
|
|
588
|
+
if (advisorBlockOnBlockedRef) {
|
|
589
|
+
ctx.abort();
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return { block: true, reason: gateReason };
|
|
593
|
+
} finally {
|
|
594
|
+
herdrAdvisorActivity.finish();
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
interface AdvisorToolDetails {
|
|
599
|
+
advisor?: string;
|
|
600
|
+
question?: string;
|
|
601
|
+
text?: string;
|
|
602
|
+
thinking?: string;
|
|
603
|
+
}
|
|
604
|
+
interface AdvisorRenderState {
|
|
605
|
+
timerId?: ReturnType<typeof setInterval>;
|
|
606
|
+
}
|
|
607
|
+
interface AdvisorToolContext {
|
|
608
|
+
invalidate: () => void;
|
|
609
|
+
lastComponent: unknown;
|
|
610
|
+
state: AdvisorRenderState;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const advisorResultDetails = (result: AgentToolResult<AdvisorToolDetails>) =>
|
|
614
|
+
result.details;
|
|
615
|
+
|
|
616
|
+
const renderPartialAdvisorResult = (
|
|
617
|
+
box: Box,
|
|
618
|
+
result: AgentToolResult<AdvisorToolDetails>,
|
|
619
|
+
expanded: boolean,
|
|
620
|
+
theme: Theme,
|
|
621
|
+
context: AdvisorToolContext
|
|
622
|
+
) => {
|
|
623
|
+
if (!context.state.timerId) {
|
|
624
|
+
context.state.timerId = setInterval(() => context.invalidate(), 80);
|
|
625
|
+
}
|
|
626
|
+
const frame =
|
|
627
|
+
SPINNER_FRAMES[Math.floor(Date.now() / 80) % SPINNER_FRAMES.length];
|
|
628
|
+
const details = advisorResultDetails(result);
|
|
629
|
+
const lines = [
|
|
630
|
+
`${theme.fg("warning", theme.bold(`◆ ADVISOR ${frame}`))} ${theme.fg("dim", "· Working…")}`,
|
|
631
|
+
];
|
|
632
|
+
if (details?.thinking) {
|
|
633
|
+
const thought =
|
|
634
|
+
details.thinking.length > 200
|
|
635
|
+
? details.thinking.slice(-200)
|
|
636
|
+
: details.thinking;
|
|
637
|
+
lines.push(theme.fg("thinkingText", ` 💭 ${thought.replace(/\n/g, " ")}`));
|
|
638
|
+
}
|
|
639
|
+
box.addChild(new Text(lines.join("\n"), 0, 0));
|
|
640
|
+
if (details?.text) {
|
|
641
|
+
box.addChild(
|
|
642
|
+
new Markdown(
|
|
643
|
+
adviceForDisplay(details.text, expanded),
|
|
644
|
+
0,
|
|
645
|
+
0,
|
|
646
|
+
getMarkdownTheme()
|
|
647
|
+
)
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
const renderFinalAdvisorResult = (
|
|
653
|
+
box: Box,
|
|
654
|
+
result: AgentToolResult<AdvisorToolDetails>,
|
|
655
|
+
expanded: boolean,
|
|
656
|
+
theme: Theme,
|
|
657
|
+
context: AdvisorToolContext
|
|
658
|
+
) => {
|
|
659
|
+
if (context.state.timerId) {
|
|
660
|
+
clearInterval(context.state.timerId);
|
|
661
|
+
context.state.timerId = undefined;
|
|
662
|
+
}
|
|
663
|
+
const details = advisorResultDetails(result);
|
|
664
|
+
const lines = [theme.fg("warning", theme.bold("◆ ADVISOR RESPONSE"))];
|
|
665
|
+
if (details?.advisor) {
|
|
666
|
+
lines.push(theme.fg("dim", ` ${details.advisor}`));
|
|
667
|
+
}
|
|
668
|
+
if (details?.thinking) {
|
|
669
|
+
const thought = details.thinking.replace(/\n/g, " ").slice(0, 300);
|
|
670
|
+
lines.push(
|
|
671
|
+
theme.fg(
|
|
672
|
+
"thinkingText",
|
|
673
|
+
` 💭 ${thought}${details.thinking.length > 300 ? "…" : ""}`
|
|
674
|
+
)
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
const advice =
|
|
678
|
+
details?.text ||
|
|
679
|
+
textFrom(result.content) ||
|
|
680
|
+
"(Advisor returned no advice.)";
|
|
681
|
+
box.addChild(new Text(lines.join("\n"), 0, 0));
|
|
682
|
+
box.addChild(
|
|
683
|
+
new Markdown(adviceForDisplay(advice, expanded), 0, 0, getMarkdownTheme())
|
|
684
|
+
);
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
const renderAdvisorResult = (
|
|
688
|
+
result: AgentToolResult<AdvisorToolDetails>,
|
|
689
|
+
{ isPartial, expanded }: ToolRenderResultOptions,
|
|
690
|
+
theme: Theme,
|
|
691
|
+
context: AdvisorToolContext
|
|
692
|
+
) => {
|
|
693
|
+
const box =
|
|
694
|
+
context.lastComponent instanceof Box
|
|
695
|
+
? context.lastComponent
|
|
696
|
+
: new Box(1, 1, (text: string) => theme.bg("customMessageBg", text));
|
|
697
|
+
box.setBgFn((text) => theme.bg("customMessageBg", text));
|
|
698
|
+
box.clear();
|
|
699
|
+
if (isPartial) {
|
|
700
|
+
renderPartialAdvisorResult(box, result, expanded, theme, context);
|
|
701
|
+
} else {
|
|
702
|
+
renderFinalAdvisorResult(box, result, expanded, theme, context);
|
|
703
|
+
}
|
|
704
|
+
return box;
|
|
705
|
+
};
|
|
706
|
+
|
|
442
707
|
export const registerAdvisorTool = (pi: ExtensionAPI) => {
|
|
443
708
|
const session = advisorSessionState;
|
|
444
709
|
const reservedCalls = new Set<string>();
|
|
@@ -523,122 +788,22 @@ export const registerAdvisorTool = (pi: ExtensionAPI) => {
|
|
|
523
788
|
: undefined;
|
|
524
789
|
});
|
|
525
790
|
|
|
526
|
-
pi.on("tool_call",
|
|
791
|
+
pi.on("tool_call", (event, ctx) => {
|
|
527
792
|
if (!pi.getActiveTools().includes("ask_advisor")) {
|
|
528
793
|
return;
|
|
529
794
|
}
|
|
530
795
|
loadConfig(ctx);
|
|
531
|
-
if (
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
}
|
|
537
|
-
notifyHerdrAdvisorFailure("Advisor budget exhausted", message);
|
|
538
|
-
return { block: true, reason: message };
|
|
539
|
-
}
|
|
540
|
-
session.consumeCall();
|
|
541
|
-
reservedCalls.add(event.toolCallId);
|
|
542
|
-
return;
|
|
543
|
-
}
|
|
544
|
-
if (!advisorAutoLoopGateRef) {
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
if (
|
|
548
|
-
!session.recordToolCall(
|
|
549
|
-
event.toolName,
|
|
550
|
-
event.input,
|
|
551
|
-
advisorLoopThresholdRef
|
|
552
|
-
)
|
|
553
|
-
) {
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
const reason = `Advisor loop gate: normalized signature for ${event.toolName} repeated ${advisorLoopThresholdRef} times without a materially different tool action.`;
|
|
557
|
-
if (!session.canConsult(advisorMaxCallsPerSessionRef)) {
|
|
558
|
-
const failure = failureEffect(
|
|
559
|
-
"budget-exhausted",
|
|
560
|
-
"Advisor gate call budget is exhausted.",
|
|
561
|
-
ctx,
|
|
562
|
-
session
|
|
563
|
-
);
|
|
564
|
-
return failure.block
|
|
565
|
-
? { block: true, reason: failure.reason }
|
|
566
|
-
: undefined;
|
|
796
|
+
if (session.blocked) {
|
|
797
|
+
return {
|
|
798
|
+
block: true,
|
|
799
|
+
reason: session.blockedReason ?? "Advisor session is blocked.",
|
|
800
|
+
};
|
|
567
801
|
}
|
|
568
|
-
session
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
{
|
|
572
|
-
content: "Automatic Advisor loop review",
|
|
573
|
-
customType: "advisor-loop-call",
|
|
574
|
-
details: {
|
|
575
|
-
question: `Loop gate: ${event.toolName} repeated ${advisorLoopThresholdRef} times`,
|
|
576
|
-
},
|
|
577
|
-
display: true,
|
|
578
|
-
},
|
|
579
|
-
{ deliverAs: "steer" }
|
|
580
|
-
);
|
|
581
|
-
try {
|
|
582
|
-
const result = await runAdvisorGate(
|
|
583
|
-
ctx,
|
|
584
|
-
`${reason} Review the repeated actions and recommend the smallest safe next step.`
|
|
585
|
-
);
|
|
586
|
-
if (!result.ok) {
|
|
587
|
-
session.recordInvocation({
|
|
588
|
-
executionEffect: gateFailureEffectForMode(advisorFailureModeRef),
|
|
589
|
-
failure: result.category,
|
|
590
|
-
kind: "gate",
|
|
591
|
-
model: advisorRef,
|
|
592
|
-
trigger: "repeated-tool-call",
|
|
593
|
-
});
|
|
594
|
-
const failure = failureEffect(
|
|
595
|
-
result.category,
|
|
596
|
-
result.message,
|
|
597
|
-
ctx,
|
|
598
|
-
session
|
|
599
|
-
);
|
|
600
|
-
return failure.block
|
|
601
|
-
? { block: true, reason: `${reason}\n${failure.reason}` }
|
|
602
|
-
: undefined;
|
|
603
|
-
}
|
|
604
|
-
session.recordInvocation({
|
|
605
|
-
cost: advisorUsageCost(result.usage),
|
|
606
|
-
decision: result.decision,
|
|
607
|
-
executionEffect: gateDecisionEffect(result.decision),
|
|
608
|
-
kind: "gate",
|
|
609
|
-
model: result.model,
|
|
610
|
-
trigger: result.trigger,
|
|
611
|
-
usage: result.usage,
|
|
612
|
-
});
|
|
613
|
-
pi.sendMessage(
|
|
614
|
-
{
|
|
615
|
-
content: adviceForText(result),
|
|
616
|
-
customType: "advisor-loop-result",
|
|
617
|
-
details: {
|
|
618
|
-
advisor: result.model,
|
|
619
|
-
decision: result.decision,
|
|
620
|
-
text: result.markdown,
|
|
621
|
-
},
|
|
622
|
-
display: true,
|
|
623
|
-
},
|
|
624
|
-
{ deliverAs: "steer" }
|
|
625
|
-
);
|
|
626
|
-
if (result.decision === "proceed") {
|
|
627
|
-
session.resetRepetition();
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
const gateReason = `Advisor loop review: ${result.markdown}`;
|
|
631
|
-
if (result.decision === "blocked") {
|
|
632
|
-
session.block(gateReason);
|
|
633
|
-
herdrAdvisorBlock.set(gateReason);
|
|
634
|
-
if (advisorBlockOnBlockedRef) {
|
|
635
|
-
ctx.abort();
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
return { block: true, reason: gateReason };
|
|
639
|
-
} finally {
|
|
640
|
-
herdrAdvisorActivity.finish();
|
|
802
|
+
const reservation = reserveAdvisorCall(event, ctx, session, reservedCalls);
|
|
803
|
+
if (event.toolName === "ask_advisor") {
|
|
804
|
+
return reservation;
|
|
641
805
|
}
|
|
806
|
+
return handleAutomaticGate(pi, event, ctx, session);
|
|
642
807
|
});
|
|
643
808
|
|
|
644
809
|
pi.on("agent_settled", (_event, ctx) => {
|
|
@@ -739,81 +904,13 @@ export const registerAdvisorTool = (pi: ExtensionAPI) => {
|
|
|
739
904
|
renderCall(args, theme) {
|
|
740
905
|
return renderAdvisorCallBox(args.question?.trim(), theme);
|
|
741
906
|
},
|
|
742
|
-
renderResult(result,
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
if (isPartial) {
|
|
750
|
-
if (!context.state.timerId) {
|
|
751
|
-
context.state.timerId = setInterval(() => context.invalidate(), 80);
|
|
752
|
-
}
|
|
753
|
-
const frame =
|
|
754
|
-
SPINNER_FRAMES[Math.floor(Date.now() / 80) % SPINNER_FRAMES.length];
|
|
755
|
-
const d = result.details as
|
|
756
|
-
| { thinking?: string; text?: string }
|
|
757
|
-
| undefined;
|
|
758
|
-
const lines: string[] = [
|
|
759
|
-
`${theme.fg("warning", theme.bold(`◆ ADVISOR ${frame}`))} ${theme.fg("dim", "· Working…")}`,
|
|
760
|
-
];
|
|
761
|
-
if (d?.thinking) {
|
|
762
|
-
lines.push(
|
|
763
|
-
theme.fg(
|
|
764
|
-
"thinkingText",
|
|
765
|
-
` 💭 ${(d.thinking.length > 200 ? d.thinking.slice(-200) : d.thinking).replace(/\n/g, " ")}`
|
|
766
|
-
)
|
|
767
|
-
);
|
|
768
|
-
}
|
|
769
|
-
box.addChild(new Text(lines.join("\n"), 0, 0));
|
|
770
|
-
if (d?.text) {
|
|
771
|
-
box.addChild(
|
|
772
|
-
new Markdown(
|
|
773
|
-
adviceForDisplay(d.text, Boolean(expanded)),
|
|
774
|
-
0,
|
|
775
|
-
0,
|
|
776
|
-
getMarkdownTheme()
|
|
777
|
-
)
|
|
778
|
-
);
|
|
779
|
-
}
|
|
780
|
-
} else {
|
|
781
|
-
if (context.state.timerId) {
|
|
782
|
-
clearInterval(context.state.timerId);
|
|
783
|
-
context.state.timerId = undefined;
|
|
784
|
-
}
|
|
785
|
-
const d = result.details as
|
|
786
|
-
| { thinking?: string; text?: string; advisor?: string }
|
|
787
|
-
| undefined;
|
|
788
|
-
const lines: string[] = [
|
|
789
|
-
theme.fg("warning", theme.bold("◆ ADVISOR RESPONSE")),
|
|
790
|
-
];
|
|
791
|
-
if (d?.advisor) {
|
|
792
|
-
lines.push(theme.fg("dim", ` ${d.advisor}`));
|
|
793
|
-
}
|
|
794
|
-
if (d?.thinking) {
|
|
795
|
-
lines.push(
|
|
796
|
-
theme.fg(
|
|
797
|
-
"thinkingText",
|
|
798
|
-
` 💭 ${d.thinking.replace(/\n/g, " ").slice(0, 300)}${d.thinking.length > 300 ? "…" : ""}`
|
|
799
|
-
)
|
|
800
|
-
);
|
|
801
|
-
}
|
|
802
|
-
const advice =
|
|
803
|
-
d?.text ||
|
|
804
|
-
textFrom(result.content) ||
|
|
805
|
-
"(Advisor returned no advice.)";
|
|
806
|
-
box.addChild(new Text(lines.join("\n"), 0, 0));
|
|
807
|
-
box.addChild(
|
|
808
|
-
new Markdown(
|
|
809
|
-
adviceForDisplay(advice, Boolean(expanded)),
|
|
810
|
-
0,
|
|
811
|
-
0,
|
|
812
|
-
getMarkdownTheme()
|
|
813
|
-
)
|
|
814
|
-
);
|
|
815
|
-
}
|
|
816
|
-
return box;
|
|
907
|
+
renderResult(result, options, theme, context) {
|
|
908
|
+
return renderAdvisorResult(
|
|
909
|
+
result as AgentToolResult<AdvisorToolDetails>,
|
|
910
|
+
options,
|
|
911
|
+
theme,
|
|
912
|
+
context as AdvisorToolContext
|
|
913
|
+
);
|
|
817
914
|
},
|
|
818
915
|
renderShell: "self",
|
|
819
916
|
});
|