@oh-my-pi/pi-coding-agent 15.5.15 → 15.7.0
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/CHANGELOG.md +81 -0
- package/dist/types/capability/rule-buckets.d.ts +30 -0
- package/dist/types/capability/rule.d.ts +7 -0
- package/dist/types/cli/classify-install-target.d.ts +0 -10
- package/dist/types/cli/completion-gen.d.ts +80 -0
- package/dist/types/cli/initial-message.d.ts +1 -1
- package/dist/types/cli/tiny-models-cli.d.ts +9 -0
- package/dist/types/commands/complete.d.ts +6 -0
- package/dist/types/commands/completions.d.ts +13 -0
- package/dist/types/commands/setup.d.ts +10 -1
- package/dist/types/commands/tiny-models.d.ts +22 -0
- package/dist/types/commit/analysis/conventional.d.ts +1 -1
- package/dist/types/commit/analysis/summary.d.ts +1 -1
- package/dist/types/commit/changelog/generate.d.ts +1 -1
- package/dist/types/commit/changelog/index.d.ts +2 -2
- package/dist/types/commit/map-reduce/map-phase.d.ts +1 -1
- package/dist/types/commit/map-reduce/reduce-phase.d.ts +1 -1
- package/dist/types/config/model-id-affixes.d.ts +10 -0
- package/dist/types/config/settings-schema.d.ts +402 -17
- package/dist/types/discovery/builtin-defaults.d.ts +1 -0
- package/dist/types/discovery/builtin-rules/index.d.ts +7 -0
- package/dist/types/discovery/helpers.d.ts +1 -1
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/discovery/substitute-plugin-root.d.ts +0 -4
- package/dist/types/edit/hashline/block-resolver.d.ts +9 -0
- package/dist/types/edit/hashline/index.d.ts +1 -0
- package/dist/types/eval/js/shared/rewrite-imports.d.ts +16 -1
- package/dist/types/eval/py/kernel.d.ts +3 -0
- package/dist/types/eval/py/runtime.d.ts +11 -1
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/internal-urls/agent-protocol.d.ts +2 -1
- package/dist/types/internal-urls/artifact-protocol.d.ts +2 -1
- package/dist/types/internal-urls/local-protocol.d.ts +2 -1
- package/dist/types/internal-urls/memory-protocol.d.ts +2 -1
- package/dist/types/internal-urls/omp-protocol.d.ts +2 -1
- package/dist/types/internal-urls/router.d.ts +8 -1
- package/dist/types/internal-urls/rule-protocol.d.ts +2 -1
- package/dist/types/internal-urls/skill-protocol.d.ts +2 -1
- package/dist/types/internal-urls/types.d.ts +26 -0
- package/dist/types/main.d.ts +1 -0
- package/dist/types/memory-backend/index.d.ts +1 -0
- package/dist/types/memory-backend/resolve.d.ts +2 -1
- package/dist/types/memory-backend/types.d.ts +7 -1
- package/dist/types/mnemosyne/backend.d.ts +4 -0
- package/dist/types/mnemosyne/config.d.ts +29 -0
- package/dist/types/mnemosyne/index.d.ts +3 -0
- package/dist/types/mnemosyne/state.d.ts +72 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -3
- package/dist/types/modes/components/hook-selector.d.ts +27 -0
- package/dist/types/modes/components/index.d.ts +2 -0
- package/dist/types/modes/components/segment-track.d.ts +22 -0
- package/dist/types/modes/components/status-line/context-thresholds.d.ts +6 -0
- package/dist/types/modes/components/tiny-title-download-progress.d.ts +11 -0
- package/dist/types/modes/components/welcome.d.ts +22 -0
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +4 -1
- package/dist/types/modes/gradient-highlight.d.ts +23 -0
- package/dist/types/modes/interactive-mode.d.ts +7 -4
- package/dist/types/modes/internal-url-autocomplete.d.ts +43 -0
- package/dist/types/modes/orchestrate.d.ts +10 -0
- package/dist/types/modes/setup-wizard/index.d.ts +16 -0
- package/dist/types/modes/setup-wizard/scenes/glyph.d.ts +2 -0
- package/dist/types/modes/setup-wizard/scenes/outro.d.ts +2 -0
- package/dist/types/modes/setup-wizard/scenes/providers.d.ts +2 -0
- package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +19 -0
- package/dist/types/modes/setup-wizard/scenes/splash.d.ts +11 -0
- package/dist/types/modes/setup-wizard/scenes/theme.d.ts +2 -0
- package/dist/types/modes/setup-wizard/scenes/types.d.ts +43 -0
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +19 -0
- package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +14 -0
- package/dist/types/modes/theme/defaults/index.d.ts +8406 -8406
- package/dist/types/modes/theme/shimmer.d.ts +2 -0
- package/dist/types/modes/theme/theme.d.ts +11 -0
- package/dist/types/modes/types.d.ts +5 -1
- package/dist/types/modes/ultrathink.d.ts +3 -3
- package/dist/types/modes/utils/keybinding-matchers.d.ts +5 -0
- package/dist/types/sdk.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +33 -0
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +2 -0
- package/dist/types/task/render.d.ts +5 -1
- package/dist/types/tiny/device.d.ts +78 -0
- package/dist/types/tiny/dtype.d.ts +85 -0
- package/dist/types/tiny/models.d.ts +185 -0
- package/dist/types/tiny/text.d.ts +19 -0
- package/dist/types/tiny/title-client.d.ts +32 -0
- package/dist/types/tiny/title-protocol.d.ts +74 -0
- package/dist/types/tiny/worker.d.ts +2 -0
- package/dist/types/tools/bash.d.ts +3 -2
- package/dist/types/tools/eval.d.ts +1 -1
- package/dist/types/tools/index.d.ts +7 -4
- package/dist/types/tools/memory-edit.d.ts +40 -0
- package/dist/types/tools/{hindsight-recall.d.ts → memory-recall.d.ts} +6 -6
- package/dist/types/tools/{hindsight-reflect.d.ts → memory-reflect.d.ts} +6 -6
- package/dist/types/tools/memory-render.d.ts +60 -0
- package/dist/types/tools/{hindsight-retain.d.ts → memory-retain.d.ts} +6 -6
- package/dist/types/tools/todo-write.d.ts +8 -0
- package/dist/types/tools/tool-result.d.ts +2 -0
- package/dist/types/tui/code-cell.d.ts +2 -0
- package/dist/types/tui/output-block.d.ts +17 -0
- package/dist/types/utils/title-generator.d.ts +3 -0
- package/package.json +18 -14
- package/scripts/build-binary.ts +1 -0
- package/src/capability/rule-buckets.ts +64 -0
- package/src/capability/rule.ts +8 -0
- package/src/cli/completion-gen.ts +550 -0
- package/src/cli/setup-cli.ts +5 -3
- package/src/cli/tiny-models-cli.ts +127 -0
- package/src/cli-commands.ts +3 -0
- package/src/cli.ts +9 -15
- package/src/commands/complete.ts +66 -0
- package/src/commands/completions.ts +60 -0
- package/src/commands/setup.ts +29 -4
- package/src/commands/tiny-models.ts +36 -0
- package/src/config/model-equivalence.ts +43 -2
- package/src/config/model-id-affixes.ts +64 -0
- package/src/config/model-registry.ts +84 -10
- package/src/config/settings-schema.ts +275 -15
- package/src/discovery/builtin-defaults.ts +39 -0
- package/src/discovery/builtin-rules/index.ts +48 -0
- package/src/discovery/builtin-rules/rs-box-leak.md +48 -0
- package/src/discovery/builtin-rules/rs-future-prelude.md +23 -0
- package/src/discovery/builtin-rules/rs-lazylock.md +51 -0
- package/src/discovery/builtin-rules/rs-match-ergonomics.md +67 -0
- package/src/discovery/builtin-rules/rs-parking-lot.md +44 -0
- package/src/discovery/builtin-rules/rs-result-type.md +19 -0
- package/src/discovery/builtin-rules/ts-bare-catch.md +38 -0
- package/src/discovery/builtin-rules/ts-import-type.md +42 -0
- package/src/discovery/builtin-rules/ts-no-any.md +56 -0
- package/src/discovery/builtin-rules/ts-no-dynamic-import.md +39 -0
- package/src/discovery/builtin-rules/ts-no-return-type.md +45 -0
- package/src/discovery/builtin-rules/ts-no-tiny-functions.md +50 -0
- package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +65 -0
- package/src/discovery/builtin-rules/ts-set-map.md +28 -0
- package/src/discovery/index.ts +1 -0
- package/src/edit/hashline/block-resolver.ts +14 -0
- package/src/edit/hashline/diff.ts +9 -8
- package/src/edit/hashline/execute.ts +2 -1
- package/src/edit/hashline/index.ts +1 -0
- package/src/eval/__tests__/shared-executors.test.ts +36 -0
- package/src/eval/js/shared/local-module-loader.ts +13 -1
- package/src/eval/js/shared/rewrite-imports.ts +31 -26
- package/src/eval/py/kernel.ts +37 -15
- package/src/eval/py/runtime.ts +57 -28
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +0 -12
- package/src/export/ttsr.ts +2 -0
- package/src/internal-urls/agent-protocol.ts +18 -1
- package/src/internal-urls/artifact-protocol.ts +19 -1
- package/src/internal-urls/docs-index.generated.ts +8 -7
- package/src/internal-urls/local-protocol.ts +14 -1
- package/src/internal-urls/memory-protocol.ts +6 -1
- package/src/internal-urls/omp-protocol.ts +5 -1
- package/src/internal-urls/router.ts +20 -1
- package/src/internal-urls/rule-protocol.ts +8 -1
- package/src/internal-urls/skill-protocol.ts +8 -1
- package/src/internal-urls/types.ts +27 -0
- package/src/lsp/render.ts +1 -1
- package/src/main.ts +18 -1
- package/src/mcp/oauth-flow.ts +2 -2
- package/src/memory-backend/index.ts +1 -0
- package/src/memory-backend/resolve.ts +4 -1
- package/src/memory-backend/types.ts +8 -1
- package/src/mnemosyne/backend.ts +374 -0
- package/src/mnemosyne/config.ts +160 -0
- package/src/mnemosyne/index.ts +3 -0
- package/src/mnemosyne/state.ts +548 -0
- package/src/modes/acp/acp-agent.ts +11 -6
- package/src/modes/components/agent-dashboard.ts +4 -4
- package/src/modes/components/custom-editor.ts +3 -2
- package/src/modes/components/diff.ts +2 -2
- package/src/modes/components/extensions/extension-list.ts +3 -2
- package/src/modes/components/footer.ts +5 -6
- package/src/modes/components/history-search.ts +3 -3
- package/src/modes/components/hook-selector.ts +92 -8
- package/src/modes/components/index.ts +2 -0
- package/src/modes/components/mcp-add-wizard.ts +3 -3
- package/src/modes/components/model-selector.ts +5 -4
- package/src/modes/components/oauth-selector.ts +3 -3
- package/src/modes/components/segment-track.ts +52 -0
- package/src/modes/components/session-observer-overlay.ts +19 -13
- package/src/modes/components/session-selector.ts +3 -3
- package/src/modes/components/settings-defs.ts +7 -0
- package/src/modes/components/status-line/context-thresholds.ts +11 -0
- package/src/modes/components/status-line/segments.ts +2 -2
- package/src/modes/components/tiny-title-download-progress.ts +90 -0
- package/src/modes/components/tips.txt +13 -0
- package/src/modes/components/tool-execution.ts +72 -4
- package/src/modes/components/tree-selector.ts +3 -3
- package/src/modes/components/user-message-selector.ts +3 -3
- package/src/modes/components/welcome.ts +102 -43
- package/src/modes/controllers/command-controller.ts +16 -1
- package/src/modes/controllers/extension-ui-controller.ts +3 -1
- package/src/modes/controllers/input-controller.ts +69 -21
- package/src/modes/gradient-highlight.ts +70 -0
- package/src/modes/interactive-mode.ts +75 -114
- package/src/modes/internal-url-autocomplete.ts +143 -0
- package/src/modes/orchestrate.ts +36 -0
- package/src/modes/prompt-action-autocomplete.ts +12 -0
- package/src/modes/setup-wizard/index.ts +88 -0
- package/src/modes/setup-wizard/scenes/glyph.ts +96 -0
- package/src/modes/setup-wizard/scenes/outro.ts +35 -0
- package/src/modes/setup-wizard/scenes/providers.ts +69 -0
- package/src/modes/setup-wizard/scenes/sign-in.ts +193 -0
- package/src/modes/setup-wizard/scenes/splash.ts +201 -0
- package/src/modes/setup-wizard/scenes/theme.ts +299 -0
- package/src/modes/setup-wizard/scenes/types.ts +48 -0
- package/src/modes/setup-wizard/scenes/web-search.ts +128 -0
- package/src/modes/setup-wizard/wizard-overlay.ts +275 -0
- package/src/modes/theme/shimmer.ts +5 -0
- package/src/modes/theme/theme.ts +44 -20
- package/src/modes/types.ts +6 -1
- package/src/modes/ultrathink.ts +9 -53
- package/src/modes/utils/keybinding-matchers.ts +11 -0
- package/src/prompts/system/memory-consolidation-system.md +8 -0
- package/src/prompts/system/memory-extraction-system.md +26 -0
- package/src/prompts/{commands/orchestrate.md → system/orchestrate-notice.md} +6 -17
- package/src/prompts/system/system-prompt.md +2 -0
- package/src/prompts/system/tiny-title-system.md +8 -0
- package/src/prompts/tools/memory-edit.md +8 -0
- package/src/prompts/tools/read.md +4 -0
- package/src/prompts/tools/task.md +4 -7
- package/src/sdk.ts +13 -21
- package/src/session/agent-session.ts +128 -44
- package/src/slash-commands/builtin-registry.ts +18 -1
- package/src/system-prompt.ts +4 -0
- package/src/task/commands.ts +1 -5
- package/src/task/executor.ts +8 -0
- package/src/task/index.ts +2 -0
- package/src/task/render.ts +69 -26
- package/src/tiny/device.ts +117 -0
- package/src/tiny/dtype.ts +101 -0
- package/src/tiny/models.ts +218 -0
- package/src/tiny/text.ts +54 -0
- package/src/tiny/title-client.ts +395 -0
- package/src/tiny/title-protocol.ts +51 -0
- package/src/tiny/worker.ts +587 -0
- package/src/tools/bash.ts +74 -29
- package/src/tools/browser/tab-worker.ts +1 -1
- package/src/tools/eval.ts +9 -4
- package/src/tools/index.ts +17 -22
- package/src/tools/memory-edit.ts +59 -0
- package/src/tools/memory-recall.ts +100 -0
- package/src/tools/memory-reflect.ts +88 -0
- package/src/tools/memory-render.ts +185 -0
- package/src/tools/memory-retain.ts +91 -0
- package/src/tools/read.ts +1 -0
- package/src/tools/renderers.ts +4 -2
- package/src/tools/todo-write.ts +128 -29
- package/src/tools/tool-result.ts +8 -0
- package/src/tui/code-cell.ts +6 -1
- package/src/tui/output-block.ts +199 -38
- package/src/utils/title-generator.ts +115 -13
- package/dist/types/tools/recipe/index.d.ts +0 -46
- package/dist/types/tools/recipe/render.d.ts +0 -36
- package/dist/types/tools/recipe/runner.d.ts +0 -60
- package/dist/types/tools/recipe/runners/cargo.d.ts +0 -16
- package/dist/types/tools/recipe/runners/index.d.ts +0 -2
- package/dist/types/tools/recipe/runners/just.d.ts +0 -2
- package/dist/types/tools/recipe/runners/make.d.ts +0 -2
- package/dist/types/tools/recipe/runners/pkg.d.ts +0 -2
- package/dist/types/tools/recipe/runners/task.d.ts +0 -2
- package/src/prompts/tools/recipe.md +0 -16
- package/src/tools/hindsight-recall.ts +0 -69
- package/src/tools/hindsight-reflect.ts +0 -58
- package/src/tools/hindsight-retain.ts +0 -57
- package/src/tools/recipe/index.ts +0 -81
- package/src/tools/recipe/render.ts +0 -19
- package/src/tools/recipe/runner.ts +0 -219
- package/src/tools/recipe/runners/cargo.ts +0 -131
- package/src/tools/recipe/runners/index.ts +0 -8
- package/src/tools/recipe/runners/just.ts +0 -73
- package/src/tools/recipe/runners/make.ts +0 -101
- package/src/tools/recipe/runners/pkg.ts +0 -167
- package/src/tools/recipe/runners/task.ts +0 -72
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline TUI renderers for the long-term memory tools (`retain`, `recall`,
|
|
3
|
+
* `reflect`).
|
|
4
|
+
*
|
|
5
|
+
* These keep the transcript terse — one status line plus, for `retain`, one
|
|
6
|
+
* `Remember: …` line per stored item — instead of the generic JSON arg tree,
|
|
7
|
+
* which exploded multi-line memory blobs into an unreadable wall.
|
|
8
|
+
*/
|
|
9
|
+
import type { Component } from "@oh-my-pi/pi-tui";
|
|
10
|
+
import { Text } from "@oh-my-pi/pi-tui";
|
|
11
|
+
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
12
|
+
import type { Theme } from "../modes/theme/theme";
|
|
13
|
+
import { Ellipsis, renderStatusLine, truncateToWidth } from "../tui";
|
|
14
|
+
import {
|
|
15
|
+
createCachedComponent,
|
|
16
|
+
formatErrorMessage,
|
|
17
|
+
formatExpandHint,
|
|
18
|
+
PREVIEW_LIMITS,
|
|
19
|
+
replaceTabs,
|
|
20
|
+
type ToolUIStatus,
|
|
21
|
+
} from "./render-utils";
|
|
22
|
+
|
|
23
|
+
// Each stored memory renders as `<bullet> <content>`; the bullet glyph comes
|
|
24
|
+
// from the active theme (`•` by default, a nerd-font dot under nerd themes).
|
|
25
|
+
|
|
26
|
+
interface RetainRenderArgs {
|
|
27
|
+
items?: Array<{ content?: string; context?: string }>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface QueryRenderArgs {
|
|
31
|
+
query?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function retainContents(args: RetainRenderArgs | undefined): string[] {
|
|
35
|
+
return (args?.items ?? []).map(item => replaceTabs((item?.content ?? "").trim())).filter(line => line.length > 0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function resultText(result: { content?: Array<{ type: string; text?: string }> }): string {
|
|
39
|
+
return (result.content?.find(c => c.type === "text")?.text ?? "").trim();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Single-line query header used by `recall`/`reflect` calls and results. */
|
|
43
|
+
function queryHeader(
|
|
44
|
+
title: string,
|
|
45
|
+
query: string | undefined,
|
|
46
|
+
icon: ToolUIStatus,
|
|
47
|
+
theme: Theme,
|
|
48
|
+
meta?: string[],
|
|
49
|
+
): string {
|
|
50
|
+
const trimmed = replaceTabs((query ?? "").trim());
|
|
51
|
+
const description = trimmed ? truncateToWidth(trimmed, 80, Ellipsis.Unicode) : undefined;
|
|
52
|
+
return renderStatusLine({ icon, title, description, meta }, theme);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function retainComponent(contents: string[], header: string, getExpanded: () => boolean, theme: Theme): Component {
|
|
56
|
+
return createCachedComponent(getExpanded, (width, expanded) => {
|
|
57
|
+
const lines = [header];
|
|
58
|
+
const limit = expanded ? contents.length : PREVIEW_LIMITS.COLLAPSED_ITEMS;
|
|
59
|
+
const shown = contents.slice(0, limit);
|
|
60
|
+
const bullet = theme.format.bullet;
|
|
61
|
+
const contentWidth = Math.max(8, width - 2 - Bun.stringWidth(bullet) - 1);
|
|
62
|
+
for (const content of shown) {
|
|
63
|
+
const value = truncateToWidth(content, contentWidth, Ellipsis.Unicode);
|
|
64
|
+
lines.push(` ${theme.fg("muted", bullet)} ${theme.fg("toolOutput", value)}`);
|
|
65
|
+
}
|
|
66
|
+
const remaining = contents.length - shown.length;
|
|
67
|
+
if (remaining > 0) {
|
|
68
|
+
lines.push(` ${theme.fg("dim", `… ${remaining} more`)} ${formatExpandHint(theme, expanded, true)}`);
|
|
69
|
+
}
|
|
70
|
+
return lines.map(line => truncateToWidth(line, width, Ellipsis.Omit));
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const retainToolRenderer = {
|
|
75
|
+
inline: true,
|
|
76
|
+
mergeCallAndResult: true,
|
|
77
|
+
renderCall(args: RetainRenderArgs, options: RenderResultOptions, theme: Theme): Component {
|
|
78
|
+
const contents = retainContents(args);
|
|
79
|
+
const header = renderStatusLine({ icon: "pending", title: "Retain" }, theme);
|
|
80
|
+
return retainComponent(contents, header, () => options.expanded, theme);
|
|
81
|
+
},
|
|
82
|
+
renderResult(
|
|
83
|
+
result: { content: Array<{ type: string; text?: string }>; details?: { count?: number }; isError?: boolean },
|
|
84
|
+
options: RenderResultOptions,
|
|
85
|
+
theme: Theme,
|
|
86
|
+
args?: RetainRenderArgs,
|
|
87
|
+
): Component {
|
|
88
|
+
if (result.isError) {
|
|
89
|
+
return new Text(formatErrorMessage(resultText(result) || "Retain failed", theme), 0, 0);
|
|
90
|
+
}
|
|
91
|
+
const contents = retainContents(args);
|
|
92
|
+
// `summary` is the tool's own "N memories stored/queued." line; drop the
|
|
93
|
+
// trailing period so it reads cleanly as a status meta segment.
|
|
94
|
+
const summary = resultText(result).replace(/\.$/, "");
|
|
95
|
+
const header = renderStatusLine(
|
|
96
|
+
{ icon: "success", title: "Retain", meta: summary ? [summary] : undefined },
|
|
97
|
+
theme,
|
|
98
|
+
);
|
|
99
|
+
return retainComponent(contents, header, () => options.expanded, theme);
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const recallToolRenderer = {
|
|
104
|
+
inline: true,
|
|
105
|
+
mergeCallAndResult: true,
|
|
106
|
+
renderCall(args: QueryRenderArgs, _options: RenderResultOptions, theme: Theme): Component {
|
|
107
|
+
return new Text(queryHeader("Recall", args.query, "pending", theme), 0, 0);
|
|
108
|
+
},
|
|
109
|
+
renderResult(
|
|
110
|
+
result: { content: Array<{ type: string; text?: string }>; isError?: boolean },
|
|
111
|
+
options: RenderResultOptions,
|
|
112
|
+
theme: Theme,
|
|
113
|
+
args?: QueryRenderArgs,
|
|
114
|
+
): Component {
|
|
115
|
+
if (result.isError) {
|
|
116
|
+
return new Text(formatErrorMessage(resultText(result) || "Recall failed", theme), 0, 0);
|
|
117
|
+
}
|
|
118
|
+
const text = resultText(result);
|
|
119
|
+
const match = text.match(/^Found (\d+) relevant/);
|
|
120
|
+
const found = match ? Number(match[1]) : 0;
|
|
121
|
+
const icon: ToolUIStatus = found > 0 ? "success" : "warning";
|
|
122
|
+
const meta = [found > 0 ? `${found} found` : "no matches"];
|
|
123
|
+
const header = queryHeader("Recall", args?.query, icon, theme, meta);
|
|
124
|
+
if (found === 0) {
|
|
125
|
+
return new Text(header, 0, 0);
|
|
126
|
+
}
|
|
127
|
+
// Collapsed view is the header alone; expand to inspect the recalled
|
|
128
|
+
// memories without dumping the whole block into the transcript.
|
|
129
|
+
const body = text.replace(/^[^\n]*\n+/, "");
|
|
130
|
+
return createCachedComponent(
|
|
131
|
+
() => options.expanded,
|
|
132
|
+
(width, expanded) => {
|
|
133
|
+
const lines = [header];
|
|
134
|
+
if (expanded) {
|
|
135
|
+
const bodyLines = body.split("\n").slice(0, PREVIEW_LIMITS.OUTPUT_EXPANDED);
|
|
136
|
+
for (const line of bodyLines) {
|
|
137
|
+
lines.push(` ${theme.fg("muted", replaceTabs(line))}`);
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
lines.push(` ${formatExpandHint(theme, false, true)}`);
|
|
141
|
+
}
|
|
142
|
+
return lines.map(line => truncateToWidth(line, width, Ellipsis.Omit));
|
|
143
|
+
},
|
|
144
|
+
);
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const reflectToolRenderer = {
|
|
149
|
+
inline: true,
|
|
150
|
+
mergeCallAndResult: true,
|
|
151
|
+
renderCall(args: QueryRenderArgs, _options: RenderResultOptions, theme: Theme): Component {
|
|
152
|
+
return new Text(queryHeader("Reflect", args.query, "pending", theme), 0, 0);
|
|
153
|
+
},
|
|
154
|
+
renderResult(
|
|
155
|
+
result: { content: Array<{ type: string; text?: string }>; isError?: boolean },
|
|
156
|
+
options: RenderResultOptions,
|
|
157
|
+
theme: Theme,
|
|
158
|
+
args?: QueryRenderArgs,
|
|
159
|
+
): Component {
|
|
160
|
+
if (result.isError) {
|
|
161
|
+
return new Text(formatErrorMessage(resultText(result) || "Reflect failed", theme), 0, 0);
|
|
162
|
+
}
|
|
163
|
+
const header = queryHeader("Reflect", args?.query, "success", theme);
|
|
164
|
+
const answer = resultText(result);
|
|
165
|
+
const answerLines = answer.split("\n").filter(line => line.trim().length > 0);
|
|
166
|
+
return createCachedComponent(
|
|
167
|
+
() => options.expanded,
|
|
168
|
+
(width, expanded) => {
|
|
169
|
+
const limit = expanded ? PREVIEW_LIMITS.OUTPUT_EXPANDED : PREVIEW_LIMITS.OUTPUT_COLLAPSED;
|
|
170
|
+
const shown = answerLines.slice(0, limit);
|
|
171
|
+
const lines = [header];
|
|
172
|
+
for (const line of shown) {
|
|
173
|
+
lines.push(` ${theme.fg("toolOutput", replaceTabs(line))}`);
|
|
174
|
+
}
|
|
175
|
+
const remaining = answerLines.length - shown.length;
|
|
176
|
+
if (remaining > 0) {
|
|
177
|
+
lines.push(
|
|
178
|
+
` ${theme.fg("dim", `… ${remaining} more lines`)} ${formatExpandHint(theme, expanded, true)}`,
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return lines.map(line => truncateToWidth(line, width, Ellipsis.Omit));
|
|
182
|
+
},
|
|
183
|
+
);
|
|
184
|
+
},
|
|
185
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { AgentTool, AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import * as z from "zod/v4";
|
|
3
|
+
import retainDescription from "../prompts/tools/retain.md" with { type: "text" };
|
|
4
|
+
import type { ToolSession } from ".";
|
|
5
|
+
|
|
6
|
+
const memoryRetainSchema = z.object({
|
|
7
|
+
items: z
|
|
8
|
+
.array(
|
|
9
|
+
z.object({
|
|
10
|
+
content: z.string().describe("information to remember"),
|
|
11
|
+
context: z.string().describe("source context").optional(),
|
|
12
|
+
}),
|
|
13
|
+
)
|
|
14
|
+
.min(1)
|
|
15
|
+
.describe("memories to retain"),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export type MemoryRetainParams = z.infer<typeof memoryRetainSchema>;
|
|
19
|
+
export class MemoryRetainTool implements AgentTool<typeof memoryRetainSchema> {
|
|
20
|
+
readonly name = "retain";
|
|
21
|
+
readonly approval = "read" as const;
|
|
22
|
+
readonly label = "Retain";
|
|
23
|
+
readonly description = retainDescription;
|
|
24
|
+
readonly parameters = memoryRetainSchema;
|
|
25
|
+
readonly strict = true;
|
|
26
|
+
readonly loadMode = "discoverable";
|
|
27
|
+
readonly summary = "Store important facts in long-term memory";
|
|
28
|
+
|
|
29
|
+
constructor(private readonly session: ToolSession) {}
|
|
30
|
+
|
|
31
|
+
static createIf(session: ToolSession): MemoryRetainTool | null {
|
|
32
|
+
const backend = session.settings.get("memory.backend");
|
|
33
|
+
if (backend !== "hindsight" && backend !== "mnemosyne") return null;
|
|
34
|
+
return new MemoryRetainTool(session);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async execute(_id: string, params: MemoryRetainParams): Promise<AgentToolResult> {
|
|
38
|
+
const backend = this.session.settings.get("memory.backend");
|
|
39
|
+
if (backend === "mnemosyne") {
|
|
40
|
+
const state = this.session.getMnemosyneSessionState?.();
|
|
41
|
+
if (!state) {
|
|
42
|
+
throw new Error("Mnemosyne backend is not initialised for this session.");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (const item of params.items) {
|
|
46
|
+
state.rememberScoped(item.content, {
|
|
47
|
+
source: "coding-agent-retain",
|
|
48
|
+
importance: 0.75,
|
|
49
|
+
metadata: {
|
|
50
|
+
session_id: state.sessionId,
|
|
51
|
+
cwd: state.session.sessionManager.getCwd(),
|
|
52
|
+
context: item.context ?? null,
|
|
53
|
+
tool: "retain",
|
|
54
|
+
},
|
|
55
|
+
scope: "bank",
|
|
56
|
+
extract: true,
|
|
57
|
+
extractEntities: true,
|
|
58
|
+
veracity: "tool",
|
|
59
|
+
memoryType: "fact",
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const count = params.items.length;
|
|
64
|
+
const noun = count === 1 ? "memory" : "memories";
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: "text", text: `${count} ${noun} stored.` }],
|
|
67
|
+
details: { count },
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const state = this.session.getHindsightSessionState?.();
|
|
72
|
+
if (!state) {
|
|
73
|
+
throw new Error("Hindsight backend is not initialised for this session.");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Push every item onto the session-owned queue and return immediately.
|
|
77
|
+
// The queue flushes either when it reaches its batch threshold or when
|
|
78
|
+
// its debounce timer fires. If the eventual batch fails, the queue
|
|
79
|
+
// surfaces a UI-only warning notice — the LLM is not informed.
|
|
80
|
+
for (const item of params.items) {
|
|
81
|
+
state.enqueueRetain(item.content, item.context);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const count = params.items.length;
|
|
85
|
+
const noun = count === 1 ? "memory" : "memories";
|
|
86
|
+
return {
|
|
87
|
+
content: [{ type: "text", text: `${count} ${noun} queued.` }],
|
|
88
|
+
details: { count },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
package/src/tools/read.ts
CHANGED
|
@@ -689,6 +689,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
689
689
|
DEFAULT_MAX_LINES: String(DEFAULT_MAX_LINES),
|
|
690
690
|
IS_HL_MODE: displayMode.hashLines,
|
|
691
691
|
IS_LINE_NUMBER_MODE: !displayMode.hashLines && displayMode.lineNumbers,
|
|
692
|
+
INSPECT_IMAGE_ENABLED: this.#inspectImageEnabled,
|
|
692
693
|
});
|
|
693
694
|
}
|
|
694
695
|
|
package/src/tools/renderers.ts
CHANGED
|
@@ -22,8 +22,8 @@ import { findToolRenderer } from "./find";
|
|
|
22
22
|
import { githubToolRenderer } from "./gh-renderer";
|
|
23
23
|
import { inspectImageToolRenderer } from "./inspect-image-renderer";
|
|
24
24
|
import { jobToolRenderer } from "./job";
|
|
25
|
+
import { recallToolRenderer, reflectToolRenderer, retainToolRenderer } from "./memory-render";
|
|
25
26
|
import { readToolRenderer } from "./read";
|
|
26
|
-
import { recipeToolRenderer } from "./recipe/render";
|
|
27
27
|
import { resolveToolRenderer } from "./resolve";
|
|
28
28
|
import { searchToolRenderer } from "./search";
|
|
29
29
|
import { searchToolBm25Renderer } from "./search-tool-bm25";
|
|
@@ -50,7 +50,6 @@ export const toolRenderers: Record<string, ToolRenderer> = {
|
|
|
50
50
|
ast_edit: astEditToolRenderer as ToolRenderer,
|
|
51
51
|
bash: bashToolRenderer as ToolRenderer,
|
|
52
52
|
browser: browserToolRenderer as ToolRenderer,
|
|
53
|
-
recipe: recipeToolRenderer as ToolRenderer,
|
|
54
53
|
debug: debugToolRenderer as ToolRenderer,
|
|
55
54
|
eval: evalToolRenderer as ToolRenderer,
|
|
56
55
|
edit: editToolRenderer as ToolRenderer,
|
|
@@ -62,6 +61,9 @@ export const toolRenderers: Record<string, ToolRenderer> = {
|
|
|
62
61
|
read: readToolRenderer as ToolRenderer,
|
|
63
62
|
job: jobToolRenderer as ToolRenderer,
|
|
64
63
|
resolve: resolveToolRenderer as ToolRenderer,
|
|
64
|
+
retain: retainToolRenderer as ToolRenderer,
|
|
65
|
+
recall: recallToolRenderer as ToolRenderer,
|
|
66
|
+
reflect: reflectToolRenderer as ToolRenderer,
|
|
65
67
|
search_tool_bm25: searchToolBm25Renderer as ToolRenderer,
|
|
66
68
|
ssh: sshToolRenderer as ToolRenderer,
|
|
67
69
|
task: taskToolRenderer as ToolRenderer,
|
package/src/tools/todo-write.ts
CHANGED
|
@@ -35,9 +35,15 @@ export interface TodoPhase {
|
|
|
35
35
|
tasks: TodoItem[];
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export interface TodoCompletionTransition {
|
|
39
|
+
phase: string;
|
|
40
|
+
content: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
38
43
|
export interface TodoWriteToolDetails {
|
|
39
44
|
phases: TodoPhase[];
|
|
40
45
|
storage: "session" | "memory";
|
|
46
|
+
completedTasks?: TodoCompletionTransition[];
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
// =============================================================================
|
|
@@ -97,6 +103,31 @@ function clonePhases(phases: TodoPhase[]): TodoPhase[] {
|
|
|
97
103
|
return phases.map(phase => ({ name: phase.name, tasks: phase.tasks.map(cloneTask) }));
|
|
98
104
|
}
|
|
99
105
|
|
|
106
|
+
function todoTransitionKey(phase: string, content: string): string {
|
|
107
|
+
return `${phase}\u0000${content}`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function getCompletionTransitions(previous: TodoPhase[], updated: TodoPhase[]): TodoCompletionTransition[] {
|
|
111
|
+
const previousStatuses = new Map<string, TodoStatus>();
|
|
112
|
+
for (const phase of previous) {
|
|
113
|
+
for (const task of phase.tasks) {
|
|
114
|
+
previousStatuses.set(todoTransitionKey(phase.name, task.content), task.status);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const transitions: TodoCompletionTransition[] = [];
|
|
119
|
+
for (const phase of updated) {
|
|
120
|
+
for (const task of phase.tasks) {
|
|
121
|
+
if (task.status !== "completed") continue;
|
|
122
|
+
const previousStatus = previousStatuses.get(todoTransitionKey(phase.name, task.content));
|
|
123
|
+
if (previousStatus && previousStatus !== "completed") {
|
|
124
|
+
transitions.push({ phase: phase.name, content: task.content });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return transitions;
|
|
129
|
+
}
|
|
130
|
+
|
|
100
131
|
function normalizeInProgressTask(phases: TodoPhase[]): void {
|
|
101
132
|
const orderedTasks = phases.flatMap(phase => phase.tasks);
|
|
102
133
|
if (orderedTasks.length === 0) return;
|
|
@@ -577,13 +608,16 @@ export class TodoWriteTool implements AgentTool<typeof todoWriteSchema, TodoWrit
|
|
|
577
608
|
_context?: AgentToolContext,
|
|
578
609
|
): Promise<AgentToolResult<TodoWriteToolDetails>> {
|
|
579
610
|
const previousPhases = clonePhases(this.session.getTodoPhases?.() ?? []);
|
|
580
|
-
const { phases: updated, errors } = applyParams(previousPhases, params);
|
|
611
|
+
const { phases: updated, errors } = applyParams(clonePhases(previousPhases), params);
|
|
612
|
+
const completedTasks = getCompletionTransitions(previousPhases, updated);
|
|
581
613
|
this.session.setTodoPhases?.(updated);
|
|
582
614
|
const storage = this.session.getSessionFile() ? "session" : "memory";
|
|
615
|
+
const details: TodoWriteToolDetails = { phases: updated, storage };
|
|
616
|
+
if (completedTasks.length > 0) details.completedTasks = completedTasks;
|
|
583
617
|
|
|
584
618
|
return {
|
|
585
619
|
content: [{ type: "text", text: formatSummary(updated, errors) }],
|
|
586
|
-
details
|
|
620
|
+
details,
|
|
587
621
|
isError: errors.length > 0 ? true : undefined,
|
|
588
622
|
};
|
|
589
623
|
}
|
|
@@ -667,16 +701,55 @@ function noteMarker(count: number, uiTheme: Theme): string {
|
|
|
667
701
|
return uiTheme.fg("dim", chalk.italic(` \u207a${toSuperscript(count)}`));
|
|
668
702
|
}
|
|
669
703
|
|
|
670
|
-
|
|
704
|
+
export const TODO_WRITE_STRIKE_HOLD_FRAMES = 2;
|
|
705
|
+
export const TODO_WRITE_STRIKE_REVEAL_FRAMES = 12;
|
|
706
|
+
export const TODO_WRITE_STRIKE_TOTAL_FRAMES = TODO_WRITE_STRIKE_HOLD_FRAMES + TODO_WRITE_STRIKE_REVEAL_FRAMES;
|
|
707
|
+
const EMPTY_COMPLETION_KEYS = new Set<string>();
|
|
708
|
+
const STRIKE_START = "\x1b[9m";
|
|
709
|
+
const STRIKE_END = "\x1b[29m";
|
|
710
|
+
|
|
711
|
+
function strikethroughText(text: string): string {
|
|
712
|
+
return `${STRIKE_START}${text}${STRIKE_END}`;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function partialStrikethrough(text: string, visibleChars: number): string {
|
|
716
|
+
if (visibleChars <= 0) return text;
|
|
717
|
+
const chars = [...text];
|
|
718
|
+
if (visibleChars >= chars.length) return strikethroughText(text);
|
|
719
|
+
return `${strikethroughText(chars.slice(0, visibleChars).join(""))}${chars.slice(visibleChars).join("")}`;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function strikeRevealCount(text: string, frame: number | undefined): number | undefined {
|
|
723
|
+
if (frame === undefined) return undefined;
|
|
724
|
+
if (frame <= TODO_WRITE_STRIKE_HOLD_FRAMES) return 0;
|
|
725
|
+
const chars = [...text];
|
|
726
|
+
if (chars.length === 0) return undefined;
|
|
727
|
+
const revealFrame = Math.min(frame - TODO_WRITE_STRIKE_HOLD_FRAMES, TODO_WRITE_STRIKE_REVEAL_FRAMES);
|
|
728
|
+
return Math.ceil((chars.length * revealFrame) / TODO_WRITE_STRIKE_REVEAL_FRAMES);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function formatTodoLine(
|
|
732
|
+
item: TodoItem,
|
|
733
|
+
uiTheme: Theme,
|
|
734
|
+
prefix: string,
|
|
735
|
+
completionKeys: Set<string>,
|
|
736
|
+
frame: number | undefined,
|
|
737
|
+
): string {
|
|
671
738
|
const checkbox = uiTheme.checkbox;
|
|
672
739
|
const marker = noteMarker(item.notes?.length ?? 0, uiTheme);
|
|
673
740
|
switch (item.status) {
|
|
674
|
-
case "completed":
|
|
675
|
-
|
|
741
|
+
case "completed": {
|
|
742
|
+
const revealCount = completionKeys.has(item.content) ? strikeRevealCount(item.content, frame) : undefined;
|
|
743
|
+
const content =
|
|
744
|
+
revealCount === undefined
|
|
745
|
+
? strikethroughText(item.content)
|
|
746
|
+
: partialStrikethrough(item.content, revealCount);
|
|
747
|
+
return uiTheme.fg("success", `${prefix}${checkbox.checked} ${content}`) + marker;
|
|
748
|
+
}
|
|
676
749
|
case "in_progress":
|
|
677
750
|
return uiTheme.fg("accent", `${prefix}${checkbox.unchecked} ${item.content}`) + marker;
|
|
678
751
|
case "abandoned":
|
|
679
|
-
return uiTheme.fg("error", `${prefix}${checkbox.unchecked} ${
|
|
752
|
+
return uiTheme.fg("error", `${prefix}${checkbox.unchecked} ${strikethroughText(item.content)}`) + marker;
|
|
680
753
|
default:
|
|
681
754
|
return uiTheme.fg("dim", `${prefix}${checkbox.unchecked} ${item.content}`) + marker;
|
|
682
755
|
}
|
|
@@ -722,6 +795,16 @@ export const todoWriteToolRenderer = {
|
|
|
722
795
|
_args?: TodoWriteRenderArgs,
|
|
723
796
|
): Component {
|
|
724
797
|
const phases = (result.details?.phases ?? []).filter(phase => phase.tasks.length > 0);
|
|
798
|
+
const completedTasks = result.details?.completedTasks ?? [];
|
|
799
|
+
const completionKeysByPhase = new Map<string, Set<string>>();
|
|
800
|
+
for (const task of completedTasks) {
|
|
801
|
+
let keys = completionKeysByPhase.get(task.phase);
|
|
802
|
+
if (!keys) {
|
|
803
|
+
keys = new Set<string>();
|
|
804
|
+
completionKeysByPhase.set(task.phase, keys);
|
|
805
|
+
}
|
|
806
|
+
keys.add(task.content);
|
|
807
|
+
}
|
|
725
808
|
const allTasks = phases.flatMap(phase => phase.tasks);
|
|
726
809
|
const header = renderStatusLine(
|
|
727
810
|
{ icon: "success", title: "Todo Write", meta: [`${allTasks.length} tasks`] },
|
|
@@ -732,29 +815,45 @@ export const todoWriteToolRenderer = {
|
|
|
732
815
|
return new Text(`${header}\n${uiTheme.fg("dim", fallback)}`, 0, 0);
|
|
733
816
|
}
|
|
734
817
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
{
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
818
|
+
let cachedKey: string | undefined;
|
|
819
|
+
let cachedLines: string[] | undefined;
|
|
820
|
+
return {
|
|
821
|
+
invalidate(): void {
|
|
822
|
+
cachedKey = undefined;
|
|
823
|
+
cachedLines = undefined;
|
|
824
|
+
},
|
|
825
|
+
render(width: number): string[] {
|
|
826
|
+
const { expanded, spinnerFrame } = options;
|
|
827
|
+
const key = `${expanded ? 1 : 0}:${spinnerFrame ?? -1}:${width}`;
|
|
828
|
+
if (cachedKey === key && cachedLines) return cachedLines;
|
|
829
|
+
|
|
830
|
+
const lines: string[] = [header];
|
|
831
|
+
for (let p = 0; p < phases.length; p++) {
|
|
832
|
+
const phase = phases[p];
|
|
833
|
+
if (phases.length > 1) {
|
|
834
|
+
lines.push(uiTheme.fg("accent", chalk.bold(` ${formatPhaseDisplayName(phase.name, p + 1)}`)));
|
|
835
|
+
}
|
|
836
|
+
const completionKeys = completionKeysByPhase.get(phase.name) ?? EMPTY_COMPLETION_KEYS;
|
|
837
|
+
const treeLines = renderTreeList(
|
|
838
|
+
{
|
|
839
|
+
items: phase.tasks,
|
|
840
|
+
expanded,
|
|
841
|
+
maxCollapsed: PREVIEW_LIMITS.COLLAPSED_ITEMS,
|
|
842
|
+
itemType: "todo",
|
|
843
|
+
renderItem: todo => formatTodoLine(todo, uiTheme, "", completionKeys, spinnerFrame),
|
|
844
|
+
},
|
|
845
|
+
uiTheme,
|
|
846
|
+
);
|
|
847
|
+
for (const line of treeLines) {
|
|
848
|
+
lines.push(` ${line}`);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
lines.push(...renderNoteAttachments(phases, uiTheme));
|
|
852
|
+
cachedKey = key;
|
|
853
|
+
cachedLines = lines;
|
|
854
|
+
return lines;
|
|
855
|
+
},
|
|
856
|
+
};
|
|
758
857
|
},
|
|
759
858
|
mergeCallAndResult: true,
|
|
760
859
|
};
|
package/src/tools/tool-result.ts
CHANGED
|
@@ -12,6 +12,7 @@ export class ToolResultBuilder<TDetails extends DetailsWithMeta> {
|
|
|
12
12
|
#details: TDetails;
|
|
13
13
|
#meta = outputMeta();
|
|
14
14
|
#content: ToolContent = [];
|
|
15
|
+
#isError = false;
|
|
15
16
|
|
|
16
17
|
constructor(details?: TDetails) {
|
|
17
18
|
this.#details = details ?? ({} as TDetails);
|
|
@@ -67,6 +68,12 @@ export class ToolResultBuilder<TDetails extends DetailsWithMeta> {
|
|
|
67
68
|
return this;
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
/** Flag the result as a non-throwing failure (agent-loop surfaces it as a tool error). */
|
|
72
|
+
error(value = true): this {
|
|
73
|
+
this.#isError = value;
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
|
|
70
77
|
done(): AgentToolResult<TDetails> {
|
|
71
78
|
const meta = this.#meta.get();
|
|
72
79
|
if (meta) {
|
|
@@ -77,6 +84,7 @@ export class ToolResultBuilder<TDetails extends DetailsWithMeta> {
|
|
|
77
84
|
return {
|
|
78
85
|
content: this.#content,
|
|
79
86
|
details: hasDetails ? this.#details : undefined,
|
|
87
|
+
...(this.#isError ? { isError: true } : {}),
|
|
80
88
|
};
|
|
81
89
|
}
|
|
82
90
|
}
|
package/src/tui/code-cell.ts
CHANGED
|
@@ -26,6 +26,8 @@ export interface CodeCellOptions {
|
|
|
26
26
|
outputMaxLines?: number;
|
|
27
27
|
codeMaxLines?: number;
|
|
28
28
|
expanded?: boolean;
|
|
29
|
+
/** Animate the cell border with a sweeping segment while pending/running. */
|
|
30
|
+
animate?: boolean;
|
|
29
31
|
width: number;
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -130,7 +132,10 @@ export function renderCodeCell(options: CodeCellOptions, theme: Theme): string[]
|
|
|
130
132
|
sections.push({ label: theme.fg("toolTitle", "Output"), lines: outputLines });
|
|
131
133
|
}
|
|
132
134
|
|
|
133
|
-
return renderOutputBlock(
|
|
135
|
+
return renderOutputBlock(
|
|
136
|
+
{ header: title, headerMeta: meta, state, sections, width, animate: options.animate },
|
|
137
|
+
theme,
|
|
138
|
+
);
|
|
134
139
|
}
|
|
135
140
|
|
|
136
141
|
export interface MarkdownCellOptions {
|