@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
package/src/tools/bash.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
ToolApprovalDecision,
|
|
8
8
|
} from "@oh-my-pi/pi-agent-core";
|
|
9
9
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
10
|
-
import { ImageProtocol, TERMINAL
|
|
10
|
+
import { ImageProtocol, TERMINAL } from "@oh-my-pi/pi-tui";
|
|
11
11
|
import { getProjectDir, isEnoent, logger, prompt } from "@oh-my-pi/pi-utils";
|
|
12
12
|
import * as z from "zod/v4";
|
|
13
13
|
import { AsyncJobManager } from "../async";
|
|
@@ -15,6 +15,7 @@ import { type BashResult, executeBash } from "../exec/bash-executor";
|
|
|
15
15
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
16
16
|
import { InternalUrlRouter } from "../internal-urls";
|
|
17
17
|
import { truncateToVisualLines } from "../modes/components/visual-truncate";
|
|
18
|
+
import { shimmerEnabled } from "../modes/theme/shimmer";
|
|
18
19
|
import { highlightCode, type Theme } from "../modes/theme/theme";
|
|
19
20
|
import bashDescription from "../prompts/tools/bash.md" with { type: "text" };
|
|
20
21
|
import type { ClientBridgeTerminalExitStatus, ClientBridgeTerminalOutput } from "../session/client-bridge";
|
|
@@ -129,6 +130,8 @@ export interface BashToolDetails {
|
|
|
129
130
|
timeoutSeconds?: number;
|
|
130
131
|
requestedTimeoutSeconds?: number;
|
|
131
132
|
wallTimeMs?: number;
|
|
133
|
+
/** Exit code of a command that ran to completion but failed (non-zero). */
|
|
134
|
+
exitCode?: number;
|
|
132
135
|
terminalId?: string;
|
|
133
136
|
async?: {
|
|
134
137
|
state: "running" | "completed" | "failed";
|
|
@@ -281,17 +284,19 @@ function formatWallTimeNotice(wallTimeMs: number): string {
|
|
|
281
284
|
return `Wall time: ${formatWallTimeSeconds(wallTimeMs)} seconds`;
|
|
282
285
|
}
|
|
283
286
|
|
|
287
|
+
function formatExitCodeNotice(exitCode: number): string {
|
|
288
|
+
return `Command exited with code ${exitCode}`;
|
|
289
|
+
}
|
|
290
|
+
|
|
284
291
|
/**
|
|
285
|
-
* Strip the trailing
|
|
286
|
-
* can
|
|
287
|
-
*
|
|
292
|
+
* Strip the trailing occurrence of `notice` (plus a single surrounding newline
|
|
293
|
+
* on each side) so the TUI can echo the value via a styled footer label
|
|
294
|
+
* instead of repeating it verbatim in the output pane. The notice is
|
|
295
|
+
* reconstructed from the same value the result was tagged with, so a literal
|
|
296
|
+
* sub-string match never strips a coincidental in-output token — only the
|
|
297
|
+
* exact line we appended in #buildCompletedResult.
|
|
288
298
|
*/
|
|
289
|
-
function
|
|
290
|
-
if (wallTimeMs === undefined) return text;
|
|
291
|
-
// Reconstruct the notice from the same value the result was tagged with so
|
|
292
|
-
// a literal sub-string match never strips a coincidental in-output token —
|
|
293
|
-
// only the exact line we appended in #buildCompletedResult.
|
|
294
|
-
const notice = formatWallTimeNotice(wallTimeMs);
|
|
299
|
+
function stripTrailingNotice(text: string, notice: string): string {
|
|
295
300
|
const idx = text.lastIndexOf(notice);
|
|
296
301
|
if (idx === -1) return text;
|
|
297
302
|
let start = idx;
|
|
@@ -301,6 +306,16 @@ function stripWallTimeNotice(text: string, wallTimeMs: number | undefined): stri
|
|
|
301
306
|
return (text.slice(0, start) + text.slice(end)).trimEnd();
|
|
302
307
|
}
|
|
303
308
|
|
|
309
|
+
function stripWallTimeNotice(text: string, wallTimeMs: number | undefined): string {
|
|
310
|
+
if (wallTimeMs === undefined) return text;
|
|
311
|
+
return stripTrailingNotice(text, formatWallTimeNotice(wallTimeMs));
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function stripExitCodeNotice(text: string, exitCode: number | undefined): string {
|
|
315
|
+
if (exitCode === undefined) return text;
|
|
316
|
+
return stripTrailingNotice(text, formatExitCodeNotice(exitCode));
|
|
317
|
+
}
|
|
318
|
+
|
|
304
319
|
/**
|
|
305
320
|
* Bash tool implementation.
|
|
306
321
|
*
|
|
@@ -357,7 +372,15 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
357
372
|
return outputText || "(no output)";
|
|
358
373
|
}
|
|
359
374
|
|
|
360
|
-
|
|
375
|
+
/**
|
|
376
|
+
* Throw for outcomes that are *not* a completed command: user/timeout
|
|
377
|
+
* aborts and a missing exit status. The foreground and bridge callers plus
|
|
378
|
+
* the async job manager rely on these throwing so cancellations surface as
|
|
379
|
+
* aborts and jobs are recorded as failed. A definite non-zero exit is a
|
|
380
|
+
* completed command that failed; #buildCompletedResult surfaces it as an
|
|
381
|
+
* error *result* (carrying execution details) rather than a throw.
|
|
382
|
+
*/
|
|
383
|
+
#throwIfUnfinished(result: BashResult | BashInteractiveResult, timeoutSec: number, outputText: string): void {
|
|
361
384
|
if (result.cancelled) {
|
|
362
385
|
throw new ToolError(normalizeResultOutput(result) || "Command aborted");
|
|
363
386
|
}
|
|
@@ -367,10 +390,6 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
367
390
|
if (result.exitCode === undefined) {
|
|
368
391
|
throw new ToolError(`${outputText}\n\nCommand failed: missing exit status`);
|
|
369
392
|
}
|
|
370
|
-
if (result.exitCode !== 0) {
|
|
371
|
-
throw new ToolError(`${outputText}\n\nCommand exited with code ${result.exitCode}`);
|
|
372
|
-
}
|
|
373
|
-
return outputText;
|
|
374
393
|
}
|
|
375
394
|
|
|
376
395
|
#buildCompletedResult(
|
|
@@ -383,6 +402,9 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
383
402
|
wallTimeMs?: number;
|
|
384
403
|
} = {},
|
|
385
404
|
): AgentToolResult<BashToolDetails> {
|
|
405
|
+
const exitCode = result.exitCode;
|
|
406
|
+
const failedExit = exitCode !== undefined && exitCode !== 0;
|
|
407
|
+
|
|
386
408
|
const outputLines = [this.#formatResultOutput(result)];
|
|
387
409
|
const notices: string[] = [];
|
|
388
410
|
if (options.wallTimeMs !== undefined) {
|
|
@@ -394,7 +416,12 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
394
416
|
}
|
|
395
417
|
}
|
|
396
418
|
if (notices.length > 0) outputLines.push("", ...notices);
|
|
419
|
+
if (failedExit) outputLines.push("", formatExitCodeNotice(exitCode));
|
|
397
420
|
const outputText = outputLines.join("\n");
|
|
421
|
+
|
|
422
|
+
// Aborts / timeouts / missing-status still propagate as thrown errors.
|
|
423
|
+
this.#throwIfUnfinished(result, timeoutSec, outputText);
|
|
424
|
+
|
|
398
425
|
const details: BashToolDetails = { timeoutSeconds: timeoutSec };
|
|
399
426
|
if (options.requestedTimeoutSec !== undefined && options.requestedTimeoutSec !== timeoutSec) {
|
|
400
427
|
details.requestedTimeoutSeconds = options.requestedTimeoutSec;
|
|
@@ -405,8 +432,11 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
405
432
|
if (options.wallTimeMs !== undefined) {
|
|
406
433
|
details.wallTimeMs = options.wallTimeMs;
|
|
407
434
|
}
|
|
435
|
+
if (failedExit) {
|
|
436
|
+
details.exitCode = exitCode;
|
|
437
|
+
}
|
|
408
438
|
const resultBuilder = toolResult(details).text(outputText).truncationFromSummary(result, { direction: "tail" });
|
|
409
|
-
|
|
439
|
+
if (failedExit) resultBuilder.error();
|
|
410
440
|
return resultBuilder.done();
|
|
411
441
|
}
|
|
412
442
|
|
|
@@ -500,7 +530,16 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
500
530
|
});
|
|
501
531
|
const finalText = this.#extractTextResult(finalResult);
|
|
502
532
|
latestText = finalText;
|
|
533
|
+
// Hand the detailed result to the foreground auto-background
|
|
534
|
+
// waiter (which renders it, footer included) before deciding
|
|
535
|
+
// the job's terminal state.
|
|
503
536
|
completion.resolve({ kind: "completed", result: finalResult });
|
|
537
|
+
if (finalResult.isError === true) {
|
|
538
|
+
// A non-zero exit is a completed command that failed. Re-enter
|
|
539
|
+
// the failure path so the job manager records it as failed and
|
|
540
|
+
// delivers the error text, matching prior throw-based behavior.
|
|
541
|
+
throw new ToolError(finalText);
|
|
542
|
+
}
|
|
504
543
|
await reportProgress(finalText, { async: { state: "completed", jobId, type: "bash" } });
|
|
505
544
|
return finalText;
|
|
506
545
|
} catch (error) {
|
|
@@ -1007,15 +1046,6 @@ export function getBashEnvForDisplay(args: BashRenderArgs): Record<string, strin
|
|
|
1007
1046
|
return args.env ?? partialEnv;
|
|
1008
1047
|
}
|
|
1009
1048
|
|
|
1010
|
-
export function formatBashCommand(args: BashRenderArgs): string {
|
|
1011
|
-
const command = replaceTabs(args.command || "…");
|
|
1012
|
-
const prompt = "$";
|
|
1013
|
-
const cwd = getProjectDir();
|
|
1014
|
-
const displayWorkdir = formatToolWorkingDirectory(args.cwd, cwd);
|
|
1015
|
-
const renderedCommand = [formatBashEnvAssignments(getBashEnvForDisplay(args)), command].filter(Boolean).join(" ");
|
|
1016
|
-
return displayWorkdir ? `${prompt} cd ${displayWorkdir} && ${renderedCommand}` : `${prompt} ${renderedCommand}`;
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
1049
|
/**
|
|
1020
1050
|
* Returns the bash command formatted for the result body: the dim `$ cd … &&`
|
|
1021
1051
|
* prefix joined with syntax-highlighted command lines. The prefix is applied
|
|
@@ -1050,10 +1080,20 @@ export function createShellRenderer<TArgs>(config: ShellRendererConfig<TArgs>) {
|
|
|
1050
1080
|
return {
|
|
1051
1081
|
renderCall(args: TArgs, options: RenderResultOptions, uiTheme: Theme): Component {
|
|
1052
1082
|
const renderArgs = toBashRenderArgs(args, config);
|
|
1053
|
-
const cmdText = formatBashCommand(renderArgs);
|
|
1054
1083
|
const title = config.resolveTitle(args, options);
|
|
1055
|
-
const
|
|
1056
|
-
|
|
1084
|
+
const cmdLines = formatBashCommandLines(renderArgs, uiTheme);
|
|
1085
|
+
const header = renderStatusLine({ icon: "pending", title }, uiTheme);
|
|
1086
|
+
const outputBlock = new CachedOutputBlock();
|
|
1087
|
+
return {
|
|
1088
|
+
render: (width: number): string[] =>
|
|
1089
|
+
outputBlock.render(
|
|
1090
|
+
{ header, state: "pending", sections: [{ lines: cmdLines }], width, animate: true },
|
|
1091
|
+
uiTheme,
|
|
1092
|
+
),
|
|
1093
|
+
invalidate: () => {
|
|
1094
|
+
outputBlock.invalidate();
|
|
1095
|
+
},
|
|
1096
|
+
};
|
|
1057
1097
|
},
|
|
1058
1098
|
|
|
1059
1099
|
renderResult(
|
|
@@ -1087,7 +1127,8 @@ export function createShellRenderer<TArgs>(config: ShellRendererConfig<TArgs>) {
|
|
|
1087
1127
|
// double-print it alongside the styled warning line below.
|
|
1088
1128
|
const rawOutput = renderContext?.output ?? result.content?.find(c => c.type === "text")?.text ?? "";
|
|
1089
1129
|
const strippedOutput = stripOutputNotice(rawOutput, details?.meta);
|
|
1090
|
-
const
|
|
1130
|
+
const withoutExit = stripExitCodeNotice(strippedOutput, details?.exitCode);
|
|
1131
|
+
const output = stripWallTimeNotice(withoutExit, details?.wallTimeMs);
|
|
1091
1132
|
const displayOutput = output.trimEnd();
|
|
1092
1133
|
const showingFullOutput = expanded && renderContext?.isFullOutput === true;
|
|
1093
1134
|
|
|
@@ -1106,6 +1147,9 @@ export function createShellRenderer<TArgs>(config: ShellRendererConfig<TArgs>) {
|
|
|
1106
1147
|
: `Timeout: ${timeoutSeconds}s`,
|
|
1107
1148
|
);
|
|
1108
1149
|
}
|
|
1150
|
+
if (isError && typeof details?.exitCode === "number") {
|
|
1151
|
+
statsParts.push(`Exit: ${details.exitCode}`);
|
|
1152
|
+
}
|
|
1109
1153
|
const timeoutLine =
|
|
1110
1154
|
statsParts.length > 0
|
|
1111
1155
|
? uiTheme.fg(
|
|
@@ -1162,6 +1206,7 @@ export function createShellRenderer<TArgs>(config: ShellRendererConfig<TArgs>) {
|
|
|
1162
1206
|
{ label: uiTheme.fg("toolTitle", "Output"), lines: outputLines },
|
|
1163
1207
|
],
|
|
1164
1208
|
width,
|
|
1209
|
+
animate: options.isPartial && shimmerEnabled(),
|
|
1165
1210
|
},
|
|
1166
1211
|
uiTheme,
|
|
1167
1212
|
);
|
|
@@ -917,7 +917,7 @@ export class WorkerCore {
|
|
|
917
917
|
dispatchEvent: (event: unknown) => boolean;
|
|
918
918
|
}
|
|
919
919
|
const select = el as unknown as SelectLike;
|
|
920
|
-
if (
|
|
920
|
+
if (select?.tagName !== "SELECT") throw new Error("tab.select() requires a <select> element");
|
|
921
921
|
const EventCtor = (
|
|
922
922
|
globalThis as unknown as { Event: new (type: string, init?: { bubbles: boolean }) => unknown }
|
|
923
923
|
).Event;
|
package/src/tools/eval.ts
CHANGED
|
@@ -10,10 +10,11 @@ import { defaultEvalSessionId } from "../eval/session-id";
|
|
|
10
10
|
import type { EvalCellResult, EvalDisplayOutput, EvalLanguage, EvalStatusEvent, EvalToolDetails } from "../eval/types";
|
|
11
11
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
12
12
|
import { truncateToVisualLines } from "../modes/components/visual-truncate";
|
|
13
|
+
import { shimmerEnabled } from "../modes/theme/shimmer";
|
|
13
14
|
import { getMarkdownTheme, type Theme } from "../modes/theme/theme";
|
|
14
15
|
import evalDescription from "../prompts/tools/eval.md" with { type: "text" };
|
|
15
16
|
import { DEFAULT_MAX_BYTES, OutputSink, type OutputSummary, TailBuffer } from "../session/streaming-output";
|
|
16
|
-
import { renderCodeCell } from "../tui";
|
|
17
|
+
import { borderShimmerTick, renderCodeCell } from "../tui";
|
|
17
18
|
import { formatDimensionNote, resizeImage } from "../utils/image-resize";
|
|
18
19
|
import { resolveEvalBackends, type ToolSession } from ".";
|
|
19
20
|
import { truncateForPrompt } from "./approval";
|
|
@@ -857,7 +858,7 @@ function formatCellOutputLines(
|
|
|
857
858
|
}
|
|
858
859
|
|
|
859
860
|
export const evalToolRenderer = {
|
|
860
|
-
renderCall(args: EvalRenderArgs,
|
|
861
|
+
renderCall(args: EvalRenderArgs, options: RenderResultOptions, uiTheme: Theme): Component {
|
|
861
862
|
const cells = getRenderCells(args);
|
|
862
863
|
|
|
863
864
|
if (cells.length === 0) {
|
|
@@ -870,7 +871,8 @@ export const evalToolRenderer = {
|
|
|
870
871
|
|
|
871
872
|
return {
|
|
872
873
|
render: (width: number): string[] => {
|
|
873
|
-
const
|
|
874
|
+
const animate = options.isPartial && shimmerEnabled();
|
|
875
|
+
const key = `${animate ? borderShimmerTick() : 0}|${cells.map(c => `${c.language}:${c.title ?? ""}:${c.code.length}`).join("|")}`;
|
|
874
876
|
if (cached && cached.key === key && cached.width === width) {
|
|
875
877
|
return cached.result;
|
|
876
878
|
}
|
|
@@ -889,6 +891,7 @@ export const evalToolRenderer = {
|
|
|
889
891
|
width,
|
|
890
892
|
codeMaxLines: EVAL_DEFAULT_PREVIEW_LINES,
|
|
891
893
|
expanded: true,
|
|
894
|
+
animate,
|
|
892
895
|
},
|
|
893
896
|
uiTheme,
|
|
894
897
|
);
|
|
@@ -951,7 +954,8 @@ export const evalToolRenderer = {
|
|
|
951
954
|
render: (width: number): string[] => {
|
|
952
955
|
const expanded = options.renderContext?.expanded ?? options.expanded;
|
|
953
956
|
const previewLines = options.renderContext?.previewLines ?? EVAL_DEFAULT_PREVIEW_LINES;
|
|
954
|
-
const
|
|
957
|
+
const animate = options.isPartial && shimmerEnabled();
|
|
958
|
+
const key = `${expanded}|${previewLines}|${options.spinnerFrame}|${animate ? borderShimmerTick() : 0}`;
|
|
955
959
|
if (cached && cached.key === key && cached.width === width) {
|
|
956
960
|
return cached.result;
|
|
957
961
|
}
|
|
@@ -988,6 +992,7 @@ export const evalToolRenderer = {
|
|
|
988
992
|
codeMaxLines: expanded ? Number.POSITIVE_INFINITY : EVAL_DEFAULT_PREVIEW_LINES,
|
|
989
993
|
expanded,
|
|
990
994
|
width,
|
|
995
|
+
animate,
|
|
991
996
|
},
|
|
992
997
|
uiTheme,
|
|
993
998
|
);
|
package/src/tools/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { GoalModeState, GoalRuntime } from "../goals";
|
|
|
11
11
|
import { GoalTool } from "../goals/tools/goal-tool";
|
|
12
12
|
import type { HindsightSessionState } from "../hindsight/state";
|
|
13
13
|
import { LspTool } from "../lsp";
|
|
14
|
+
import type { MnemosyneSessionState } from "../mnemosyne/state";
|
|
14
15
|
import type { PlanModeState } from "../plan-mode/state";
|
|
15
16
|
import { type AgentRegistry, MAIN_AGENT_ID } from "../registry/agent-registry";
|
|
16
17
|
import type { ArtifactManager } from "../session/artifacts";
|
|
@@ -33,15 +34,15 @@ import { DebugTool } from "./debug";
|
|
|
33
34
|
import { EvalTool } from "./eval";
|
|
34
35
|
import { FindTool } from "./find";
|
|
35
36
|
import { GithubTool } from "./gh";
|
|
36
|
-
import { HindsightRecallTool } from "./hindsight-recall";
|
|
37
|
-
import { HindsightReflectTool } from "./hindsight-reflect";
|
|
38
|
-
import { HindsightRetainTool } from "./hindsight-retain";
|
|
39
37
|
import { InspectImageTool } from "./inspect-image";
|
|
40
38
|
import { IrcTool } from "./irc";
|
|
41
39
|
import { JobTool } from "./job";
|
|
40
|
+
import { MemoryEditTool } from "./memory-edit";
|
|
41
|
+
import { MemoryRecallTool } from "./memory-recall";
|
|
42
|
+
import { MemoryReflectTool } from "./memory-reflect";
|
|
43
|
+
import { MemoryRetainTool } from "./memory-retain";
|
|
42
44
|
import { wrapToolWithMetaNotice } from "./output-meta";
|
|
43
45
|
import { ReadTool } from "./read";
|
|
44
|
-
import { RecipeTool } from "./recipe";
|
|
45
46
|
import { RenderMermaidTool } from "./render-mermaid";
|
|
46
47
|
import { createReportToolIssueTool, isAutoQaEnabled } from "./report-tool-issue";
|
|
47
48
|
import { ResolveTool } from "./resolve";
|
|
@@ -73,15 +74,15 @@ export * from "./debug";
|
|
|
73
74
|
export * from "./eval";
|
|
74
75
|
export * from "./find";
|
|
75
76
|
export * from "./gh";
|
|
76
|
-
export * from "./hindsight-recall";
|
|
77
|
-
export * from "./hindsight-reflect";
|
|
78
|
-
export * from "./hindsight-retain";
|
|
79
77
|
export * from "./image-gen";
|
|
80
78
|
export * from "./inspect-image";
|
|
81
79
|
export * from "./irc";
|
|
82
80
|
export * from "./job";
|
|
81
|
+
export * from "./memory-edit";
|
|
82
|
+
export * from "./memory-recall";
|
|
83
|
+
export * from "./memory-reflect";
|
|
84
|
+
export * from "./memory-retain";
|
|
83
85
|
export * from "./read";
|
|
84
|
-
export * from "./recipe";
|
|
85
86
|
export * from "./render-mermaid";
|
|
86
87
|
export * from "./report-tool-issue";
|
|
87
88
|
export * from "./resolve";
|
|
@@ -152,6 +153,8 @@ export interface ToolSession {
|
|
|
152
153
|
getSessionId?: () => string | null;
|
|
153
154
|
/** Get Hindsight runtime state for this agent session. */
|
|
154
155
|
getHindsightSessionState?: () => HindsightSessionState | undefined;
|
|
156
|
+
/** Get Mnemosyne runtime state for this agent session. */
|
|
157
|
+
getMnemosyneSessionState?: () => MnemosyneSessionState | undefined;
|
|
155
158
|
/** Agent identity used for IRC routing. Returns the registry id (e.g. "0-Main", "0-AuthLoader"). */
|
|
156
159
|
getAgentId?: () => string | null;
|
|
157
160
|
/** Look up a registered tool by name (used by the eval js backend's tool bridge). */
|
|
@@ -295,15 +298,15 @@ export const BUILTIN_TOOLS: Record<string, ToolFactory> = {
|
|
|
295
298
|
rewind: RewindTool.createIf,
|
|
296
299
|
task: s => TaskTool.create(s),
|
|
297
300
|
job: JobTool.createIf,
|
|
298
|
-
recipe: RecipeTool.createIf,
|
|
299
301
|
irc: IrcTool.createIf,
|
|
300
302
|
todo_write: s => new TodoWriteTool(s),
|
|
301
303
|
web_search: s => new WebSearchTool(s),
|
|
302
304
|
search_tool_bm25: SearchToolBm25Tool.createIf,
|
|
303
305
|
write: s => new WriteTool(s),
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
306
|
+
memory_edit: MemoryEditTool.createIf,
|
|
307
|
+
retain: MemoryRetainTool.createIf,
|
|
308
|
+
recall: MemoryRecallTool.createIf,
|
|
309
|
+
reflect: MemoryReflectTool.createIf,
|
|
307
310
|
};
|
|
308
311
|
|
|
309
312
|
export const HIDDEN_TOOLS: Record<string, ToolFactory> = {
|
|
@@ -410,14 +413,7 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
410
413
|
) {
|
|
411
414
|
requestedTools.push("ast_edit");
|
|
412
415
|
}
|
|
413
|
-
if (
|
|
414
|
-
requestedTools.includes("bash") &&
|
|
415
|
-
!requestedTools.includes("recipe") &&
|
|
416
|
-
session.settings.get("recipe.enabled")
|
|
417
|
-
) {
|
|
418
|
-
requestedTools.push("recipe");
|
|
419
|
-
}
|
|
420
|
-
if (session.settings.get("memory.backend") === "hindsight") {
|
|
416
|
+
if (["hindsight", "mnemosyne"].includes(session.settings.get("memory.backend") ?? "")) {
|
|
421
417
|
for (const name of ["recall", "retain", "reflect"]) {
|
|
422
418
|
if (!requestedTools.includes(name)) requestedTools.push(name);
|
|
423
419
|
}
|
|
@@ -461,9 +457,8 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
461
457
|
if (!session.settings.get("async.enabled") && session.getAgentId?.() === MAIN_AGENT_ID) return false;
|
|
462
458
|
return true;
|
|
463
459
|
}
|
|
464
|
-
if (name === "recipe") return session.settings.get("recipe.enabled");
|
|
465
460
|
if (name === "retain" || name === "recall" || name === "reflect") {
|
|
466
|
-
return session.settings.get("memory.backend")
|
|
461
|
+
return ["hindsight", "mnemosyne"].includes(session.settings.get("memory.backend") ?? "");
|
|
467
462
|
}
|
|
468
463
|
if (name === "task") {
|
|
469
464
|
const maxDepth = session.settings.get("task.maxRecursionDepth") ?? 2;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { AgentTool, AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import * as z from "zod/v4";
|
|
3
|
+
import memoryEditDescription from "../prompts/tools/memory-edit.md" with { type: "text" };
|
|
4
|
+
import type { ToolSession } from ".";
|
|
5
|
+
|
|
6
|
+
const memoryEditSchema = z.object({
|
|
7
|
+
op: z.enum(["update", "forget", "invalidate"]).describe("memory edit operation"),
|
|
8
|
+
id: z.string().describe("memory id from recall output"),
|
|
9
|
+
content: z.string().optional().describe("replacement content for update"),
|
|
10
|
+
importance: z.number().optional().describe("replacement importance for update, clamped to [0, 1]"),
|
|
11
|
+
replacement_id: z.string().optional().describe("replacement memory id for invalidate"),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export type MemoryEditParams = z.infer<typeof memoryEditSchema>;
|
|
15
|
+
|
|
16
|
+
export class MemoryEditTool implements AgentTool<typeof memoryEditSchema> {
|
|
17
|
+
readonly name = "memory_edit";
|
|
18
|
+
readonly approval = "read" as const;
|
|
19
|
+
readonly label = "Memory Edit";
|
|
20
|
+
readonly description = memoryEditDescription;
|
|
21
|
+
readonly parameters = memoryEditSchema;
|
|
22
|
+
readonly strict = true;
|
|
23
|
+
readonly loadMode = "discoverable";
|
|
24
|
+
readonly summary = "Update, forget, or invalidate Mnemosyne memories";
|
|
25
|
+
|
|
26
|
+
constructor(private readonly session: ToolSession) {}
|
|
27
|
+
|
|
28
|
+
static createIf(session: ToolSession): MemoryEditTool | null {
|
|
29
|
+
const backend = session.settings.get("memory.backend");
|
|
30
|
+
if (backend !== "mnemosyne") return null;
|
|
31
|
+
return new MemoryEditTool(session);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async execute(_id: string, params: MemoryEditParams): Promise<AgentToolResult> {
|
|
35
|
+
const state = this.session.getMnemosyneSessionState?.();
|
|
36
|
+
if (!state) {
|
|
37
|
+
throw new Error("Mnemosyne backend is not initialised for this session.");
|
|
38
|
+
}
|
|
39
|
+
if (params.op === "update" && params.content === undefined && params.importance === undefined) {
|
|
40
|
+
throw new Error("memory_edit update requires content or importance.");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const importance = params.importance === undefined ? undefined : Math.max(0, Math.min(1, params.importance));
|
|
44
|
+
const result = state.editScopedMemory(params.op, params.id, {
|
|
45
|
+
content: params.content,
|
|
46
|
+
importance,
|
|
47
|
+
replacementId: params.replacement_id,
|
|
48
|
+
});
|
|
49
|
+
const location = result.bank ? ` in bank ${result.bank}${result.store ? ` (${result.store})` : ""}` : "";
|
|
50
|
+
const text =
|
|
51
|
+
result.status === "not_found"
|
|
52
|
+
? `Memory ${params.id} was not found${location}.`
|
|
53
|
+
: `Memory ${params.id} ${result.status}${location}.`;
|
|
54
|
+
return {
|
|
55
|
+
content: [{ type: "text", text }],
|
|
56
|
+
details: result,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { AgentTool, AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import { logger, untilAborted } from "@oh-my-pi/pi-utils";
|
|
3
|
+
import * as z from "zod/v4";
|
|
4
|
+
import { formatCurrentTime, formatMemories } from "../hindsight/content";
|
|
5
|
+
import recallDescription from "../prompts/tools/recall.md" with { type: "text" };
|
|
6
|
+
import type { ToolSession } from ".";
|
|
7
|
+
|
|
8
|
+
const memoryRecallSchema = z.object({
|
|
9
|
+
query: z.string().describe("natural language search query"),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type MemoryRecallParams = z.infer<typeof memoryRecallSchema>;
|
|
13
|
+
|
|
14
|
+
export class MemoryRecallTool implements AgentTool<typeof memoryRecallSchema> {
|
|
15
|
+
readonly name = "recall";
|
|
16
|
+
readonly approval = "read" as const;
|
|
17
|
+
readonly label = "Recall";
|
|
18
|
+
readonly description = recallDescription;
|
|
19
|
+
readonly parameters = memoryRecallSchema;
|
|
20
|
+
readonly strict = true;
|
|
21
|
+
readonly loadMode = "discoverable";
|
|
22
|
+
readonly summary = "Search memory for relevant prior context";
|
|
23
|
+
|
|
24
|
+
constructor(private readonly session: ToolSession) {}
|
|
25
|
+
|
|
26
|
+
static createIf(session: ToolSession): MemoryRecallTool | null {
|
|
27
|
+
const backend = session.settings.get("memory.backend");
|
|
28
|
+
if (backend !== "hindsight" && backend !== "mnemosyne") return null;
|
|
29
|
+
return new MemoryRecallTool(session);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async execute(_id: string, params: MemoryRecallParams, signal?: AbortSignal): Promise<AgentToolResult> {
|
|
33
|
+
return untilAborted(signal, async () => {
|
|
34
|
+
const backend = this.session.settings.get("memory.backend");
|
|
35
|
+
if (backend === "mnemosyne") {
|
|
36
|
+
const state = this.session.getMnemosyneSessionState?.();
|
|
37
|
+
if (!state) {
|
|
38
|
+
throw new Error("Mnemosyne backend is not initialised for this session.");
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const results = state.recallResultsScoped(params.query);
|
|
42
|
+
if (results.length === 0) {
|
|
43
|
+
return {
|
|
44
|
+
content: [{ type: "text", text: "No relevant memories found." }],
|
|
45
|
+
details: {},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const formatted = state.formatScopedRecallWithIds(results);
|
|
49
|
+
return {
|
|
50
|
+
content: [
|
|
51
|
+
{
|
|
52
|
+
type: "text",
|
|
53
|
+
text: `Found ${results.length} relevant ${results.length === 1 ? "memory" : "memories"} (as of ${formatCurrentTime()} UTC):\n\n${formatted}`,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
details: {},
|
|
57
|
+
};
|
|
58
|
+
} catch (err) {
|
|
59
|
+
logger.warn("recall failed", { backend: "mnemosyne", bank: state.config.bank, error: String(err) });
|
|
60
|
+
throw err instanceof Error ? err : new Error(String(err));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const state = this.session.getHindsightSessionState?.();
|
|
65
|
+
if (!state) {
|
|
66
|
+
throw new Error("Hindsight backend is not initialised for this session.");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const response = await state.client.recall(state.bankId, params.query, {
|
|
71
|
+
budget: state.config.recallBudget,
|
|
72
|
+
maxTokens: state.config.recallMaxTokens,
|
|
73
|
+
types: state.config.recallTypes.length > 0 ? state.config.recallTypes : undefined,
|
|
74
|
+
tags: state.recallTags,
|
|
75
|
+
tagsMatch: state.recallTagsMatch,
|
|
76
|
+
});
|
|
77
|
+
const results = response.results ?? [];
|
|
78
|
+
if (results.length === 0) {
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: "text", text: "No relevant memories found." }],
|
|
81
|
+
details: {},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const formatted = formatMemories(results);
|
|
85
|
+
return {
|
|
86
|
+
content: [
|
|
87
|
+
{
|
|
88
|
+
type: "text",
|
|
89
|
+
text: `Found ${results.length} relevant ${results.length === 1 ? "memory" : "memories"} (as of ${formatCurrentTime()} UTC):\n\n${formatted}`,
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
details: {},
|
|
93
|
+
};
|
|
94
|
+
} catch (err) {
|
|
95
|
+
logger.warn("recall failed", { bankId: state.bankId, error: String(err) });
|
|
96
|
+
throw err instanceof Error ? err : new Error(String(err));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { AgentTool, AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import { logger, untilAborted } from "@oh-my-pi/pi-utils";
|
|
3
|
+
import * as z from "zod/v4";
|
|
4
|
+
import { ensureBankMission } from "../hindsight/bank";
|
|
5
|
+
import reflectDescription from "../prompts/tools/reflect.md" with { type: "text" };
|
|
6
|
+
import type { ToolSession } from ".";
|
|
7
|
+
|
|
8
|
+
const memoryReflectSchema = z.object({
|
|
9
|
+
query: z.string().describe("question to answer"),
|
|
10
|
+
context: z.string().describe("optional context").optional(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export type MemoryReflectParams = z.infer<typeof memoryReflectSchema>;
|
|
14
|
+
|
|
15
|
+
export class MemoryReflectTool implements AgentTool<typeof memoryReflectSchema> {
|
|
16
|
+
readonly name = "reflect";
|
|
17
|
+
readonly approval = "read" as const;
|
|
18
|
+
readonly label = "Reflect";
|
|
19
|
+
readonly description = reflectDescription;
|
|
20
|
+
readonly parameters = memoryReflectSchema;
|
|
21
|
+
readonly strict = true;
|
|
22
|
+
readonly loadMode = "discoverable";
|
|
23
|
+
readonly summary = "Synthesize an answer from long-term memory";
|
|
24
|
+
|
|
25
|
+
constructor(private readonly session: ToolSession) {}
|
|
26
|
+
|
|
27
|
+
static createIf(session: ToolSession): MemoryReflectTool | null {
|
|
28
|
+
const backend = session.settings.get("memory.backend");
|
|
29
|
+
if (backend !== "hindsight" && backend !== "mnemosyne") return null;
|
|
30
|
+
return new MemoryReflectTool(session);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async execute(_id: string, params: MemoryReflectParams, signal?: AbortSignal): Promise<AgentToolResult> {
|
|
34
|
+
return untilAborted(signal, async () => {
|
|
35
|
+
const backend = this.session.settings.get("memory.backend");
|
|
36
|
+
if (backend === "mnemosyne") {
|
|
37
|
+
const state = this.session.getMnemosyneSessionState?.();
|
|
38
|
+
if (!state) {
|
|
39
|
+
throw new Error("Mnemosyne backend is not initialised for this session.");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const query = params.context?.trim()
|
|
44
|
+
? `${params.query.trim()}\n\nAdditional context:\n${params.context.trim()}`
|
|
45
|
+
: params.query;
|
|
46
|
+
const results = state.recallResultsScoped(query);
|
|
47
|
+
if (results.length === 0) {
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: "text", text: "No relevant information found to reflect on." }],
|
|
50
|
+
details: {},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const summary = state.formatContextScoped(results);
|
|
54
|
+
return {
|
|
55
|
+
content: [{ type: "text", text: `Based on recalled memories:\n\n${summary}` }],
|
|
56
|
+
details: {},
|
|
57
|
+
};
|
|
58
|
+
} catch (err) {
|
|
59
|
+
logger.warn("reflect failed", { backend: "mnemosyne", bank: state.config.bank, error: String(err) });
|
|
60
|
+
throw err instanceof Error ? err : new Error(String(err));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const state = this.session.getHindsightSessionState?.();
|
|
65
|
+
if (!state) {
|
|
66
|
+
throw new Error("Hindsight backend is not initialised for this session.");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
await ensureBankMission(state.client, state.bankId, state.config, state.missionsSet);
|
|
71
|
+
const response = await state.client.reflect(state.bankId, params.query, {
|
|
72
|
+
context: params.context,
|
|
73
|
+
budget: state.config.recallBudget,
|
|
74
|
+
tags: state.recallTags,
|
|
75
|
+
tagsMatch: state.recallTagsMatch,
|
|
76
|
+
});
|
|
77
|
+
const text = response.text?.trim() || "No relevant information found to reflect on.";
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: "text", text }],
|
|
80
|
+
details: {},
|
|
81
|
+
};
|
|
82
|
+
} catch (err) {
|
|
83
|
+
logger.warn("reflect failed", { bankId: state.bankId, error: String(err) });
|
|
84
|
+
throw err instanceof Error ? err : new Error(String(err));
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|