@mariozechner/pi-coding-agent 0.34.1 → 0.35.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 +224 -18
- package/README.md +233 -105
- package/dist/cli/args.d.ts +3 -4
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +13 -18
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +39 -50
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +166 -197
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +3 -3
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +6 -5
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/event-bus.d.ts +9 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +25 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/exec.d.ts +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +1 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/extensions/index.d.ts +10 -0
- package/dist/core/extensions/index.d.ts.map +1 -0
- package/dist/core/extensions/index.js +9 -0
- package/dist/core/extensions/index.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +21 -0
- package/dist/core/extensions/loader.d.ts.map +1 -0
- package/dist/core/extensions/loader.js +400 -0
- package/dist/core/extensions/loader.js.map +1 -0
- package/dist/core/extensions/runner.d.ts +88 -0
- package/dist/core/extensions/runner.d.ts.map +1 -0
- package/dist/core/{hooks → extensions}/runner.js +52 -141
- package/dist/core/extensions/runner.js.map +1 -0
- package/dist/core/extensions/types.d.ts +461 -0
- package/dist/core/extensions/types.d.ts.map +1 -0
- package/dist/core/{hooks → extensions}/types.js +7 -4
- package/dist/core/extensions/types.js.map +1 -0
- package/dist/core/extensions/wrapper.d.ts +25 -0
- package/dist/core/extensions/wrapper.d.ts.map +1 -0
- package/dist/core/{hooks/tool-wrapper.js → extensions/wrapper.js} +39 -24
- package/dist/core/extensions/wrapper.js.map +1 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/messages.d.ts +7 -7
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +4 -4
- package/dist/core/messages.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +40 -0
- package/dist/core/prompt-templates.d.ts.map +1 -0
- package/dist/core/{slash-commands.js → prompt-templates.js} +31 -31
- package/dist/core/prompt-templates.js.map +1 -0
- package/dist/core/sdk.d.ts +29 -52
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +111 -211
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +17 -17
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +25 -10
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -6
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +4 -11
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +4 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +36 -33
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +7 -2
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +93 -4
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +1 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +2 -2
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +4 -4
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +18 -0
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-message.js → custom-message.js} +3 -3
- package/dist/modes/interactive/components/custom-message.js.map +1 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts +2 -2
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +2 -2
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/{hook-editor.d.ts → extension-editor.d.ts} +3 -3
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-editor.js → extension-editor.js} +4 -4
- package/dist/modes/interactive/components/extension-editor.js.map +1 -0
- package/dist/modes/interactive/components/{hook-input.d.ts → extension-input.d.ts} +3 -3
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-input.js → extension-input.js} +3 -3
- package/dist/modes/interactive/components/extension-input.js.map +1 -0
- package/dist/modes/interactive/components/{hook-selector.d.ts → extension-selector.d.ts} +3 -3
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-selector.js → extension-selector.js} +3 -3
- package/dist/modes/interactive/components/extension-selector.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +3 -3
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +8 -8
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +3 -3
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +9 -9
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +37 -44
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +143 -189
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +10 -33
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +3 -3
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +3 -3
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +2 -2
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +33 -57
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +16 -16
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/extensions.md +1053 -0
- package/docs/rpc.md +4 -4
- package/docs/sdk.md +62 -93
- package/docs/session.md +22 -19
- package/docs/skills.md +1 -1
- package/docs/tui.md +1 -1
- package/examples/README.md +9 -15
- package/examples/extensions/README.md +141 -0
- package/examples/{hooks → extensions}/auto-commit-on-exit.ts +3 -3
- package/examples/extensions/chalk-logger.ts +26 -0
- package/examples/{hooks → extensions}/confirm-destructive.ts +3 -3
- package/examples/{hooks → extensions}/custom-compaction.ts +6 -6
- package/examples/{hooks → extensions}/dirty-repo-guard.ts +8 -4
- package/examples/{hooks → extensions}/file-trigger.ts +3 -3
- package/examples/{hooks → extensions}/git-checkpoint.ts +3 -3
- package/examples/{hooks → extensions}/handoff.ts +3 -3
- package/examples/extensions/hello.ts +25 -0
- package/examples/{hooks → extensions}/permission-gate.ts +3 -3
- package/examples/{hooks → extensions}/pirate.ts +5 -5
- package/examples/{hooks → extensions}/plan-mode.ts +6 -6
- package/examples/{hooks → extensions}/protected-paths.ts +3 -3
- package/examples/{hooks → extensions}/qna.ts +3 -3
- package/examples/{custom-tools/question/index.ts → extensions/question.ts} +13 -17
- package/examples/{hooks → extensions}/snake.ts +3 -3
- package/examples/{hooks → extensions}/status-line.ts +3 -3
- package/examples/{custom-tools → extensions}/subagent/README.md +15 -15
- package/examples/{custom-tools → extensions}/subagent/index.ts +22 -43
- package/examples/{custom-tools/todo/index.ts → extensions/todo.ts} +122 -39
- package/examples/{hooks → extensions}/tools.ts +5 -5
- package/examples/extensions/with-deps/index.ts +40 -0
- package/examples/extensions/with-deps/package-lock.json +31 -0
- package/examples/extensions/with-deps/package.json +16 -0
- package/examples/sdk/01-minimal.ts +1 -1
- package/examples/sdk/05-tools.ts +7 -41
- package/examples/sdk/06-extensions.ts +81 -0
- package/examples/sdk/08-prompt-templates.ts +42 -0
- package/examples/sdk/12-full-control.ts +10 -29
- package/examples/sdk/README.md +5 -5
- package/package.json +4 -4
- package/dist/core/custom-tools/index.d.ts +0 -7
- package/dist/core/custom-tools/index.d.ts.map +0 -1
- package/dist/core/custom-tools/index.js +0 -6
- package/dist/core/custom-tools/index.js.map +0 -1
- package/dist/core/custom-tools/loader.d.ts +0 -30
- package/dist/core/custom-tools/loader.d.ts.map +0 -1
- package/dist/core/custom-tools/loader.js +0 -276
- package/dist/core/custom-tools/loader.js.map +0 -1
- package/dist/core/custom-tools/types.d.ts +0 -144
- package/dist/core/custom-tools/types.d.ts.map +0 -1
- package/dist/core/custom-tools/types.js +0 -8
- package/dist/core/custom-tools/types.js.map +0 -1
- package/dist/core/custom-tools/wrapper.d.ts +0 -15
- package/dist/core/custom-tools/wrapper.d.ts.map +0 -1
- package/dist/core/custom-tools/wrapper.js +0 -23
- package/dist/core/custom-tools/wrapper.js.map +0 -1
- package/dist/core/hooks/index.d.ts +0 -6
- package/dist/core/hooks/index.d.ts.map +0 -1
- package/dist/core/hooks/index.js +0 -6
- package/dist/core/hooks/index.js.map +0 -1
- package/dist/core/hooks/loader.d.ts +0 -146
- package/dist/core/hooks/loader.d.ts.map +0 -1
- package/dist/core/hooks/loader.js +0 -275
- package/dist/core/hooks/loader.js.map +0 -1
- package/dist/core/hooks/runner.d.ts +0 -173
- package/dist/core/hooks/runner.d.ts.map +0 -1
- package/dist/core/hooks/runner.js.map +0 -1
- package/dist/core/hooks/tool-wrapper.d.ts +0 -17
- package/dist/core/hooks/tool-wrapper.d.ts.map +0 -1
- package/dist/core/hooks/tool-wrapper.js.map +0 -1
- package/dist/core/hooks/types.d.ts +0 -767
- package/dist/core/hooks/types.d.ts.map +0 -1
- package/dist/core/hooks/types.js.map +0 -1
- package/dist/core/slash-commands.d.ts +0 -40
- package/dist/core/slash-commands.d.ts.map +0 -1
- package/dist/core/slash-commands.js.map +0 -1
- package/dist/modes/interactive/components/hook-editor.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-editor.js.map +0 -1
- package/dist/modes/interactive/components/hook-input.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-input.js.map +0 -1
- package/dist/modes/interactive/components/hook-message.d.ts +0 -18
- package/dist/modes/interactive/components/hook-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-message.js.map +0 -1
- package/dist/modes/interactive/components/hook-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-selector.js.map +0 -1
- package/docs/custom-tools.md +0 -514
- package/docs/extension-loading.md +0 -1004
- package/docs/hooks.md +0 -979
- package/docs/session-tree-plan.md +0 -441
- package/examples/custom-tools/README.md +0 -114
- package/examples/custom-tools/hello/index.ts +0 -21
- package/examples/hooks/README.md +0 -60
- package/examples/hooks/todo/index.ts +0 -134
- package/examples/sdk/06-hooks.ts +0 -61
- package/examples/sdk/08-slash-commands.ts +0 -42
- /package/examples/{custom-tools → extensions}/subagent/agents/planner.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents/reviewer.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents/scout.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents/worker.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents.ts +0 -0
- /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/implement-and-review.md +0 -0
- /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/implement.md +0 -0
- /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/scout-and-plan.md +0 -0
|
@@ -19,19 +19,13 @@ import * as path from "node:path";
|
|
|
19
19
|
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
|
20
20
|
import type { Message } from "@mariozechner/pi-ai";
|
|
21
21
|
import { StringEnum } from "@mariozechner/pi-ai";
|
|
22
|
-
import {
|
|
23
|
-
type CustomTool,
|
|
24
|
-
type CustomToolAPI,
|
|
25
|
-
type CustomToolFactory,
|
|
26
|
-
getMarkdownTheme,
|
|
27
|
-
} from "@mariozechner/pi-coding-agent";
|
|
22
|
+
import { type ExtensionAPI, getMarkdownTheme } from "@mariozechner/pi-coding-agent";
|
|
28
23
|
import { Container, Markdown, Spacer, Text } from "@mariozechner/pi-tui";
|
|
29
24
|
import { Type } from "@sinclair/typebox";
|
|
30
|
-
import { type AgentConfig, type AgentScope, discoverAgents
|
|
25
|
+
import { type AgentConfig, type AgentScope, discoverAgents } from "./agents.js";
|
|
31
26
|
|
|
32
27
|
const MAX_PARALLEL_TASKS = 8;
|
|
33
28
|
const MAX_CONCURRENCY = 4;
|
|
34
|
-
const MAX_AGENTS_IN_DESCRIPTION = 10;
|
|
35
29
|
const COLLAPSED_ITEM_COUNT = 10;
|
|
36
30
|
|
|
37
31
|
function formatTokens(count: number): string {
|
|
@@ -224,7 +218,7 @@ function writePromptToTempFile(agentName: string, prompt: string): { dir: string
|
|
|
224
218
|
type OnUpdateCallback = (partial: AgentToolResult<SubagentDetails>) => void;
|
|
225
219
|
|
|
226
220
|
async function runSingleAgent(
|
|
227
|
-
|
|
221
|
+
defaultCwd: string,
|
|
228
222
|
agents: AgentConfig[],
|
|
229
223
|
agentName: string,
|
|
230
224
|
task: string,
|
|
@@ -289,7 +283,7 @@ async function runSingleAgent(
|
|
|
289
283
|
let wasAborted = false;
|
|
290
284
|
|
|
291
285
|
const exitCode = await new Promise<number>((resolve) => {
|
|
292
|
-
const proc = spawn("pi", args, { cwd: cwd ??
|
|
286
|
+
const proc = spawn("pi", args, { cwd: cwd ?? defaultCwd, shell: false, stdio: ["ignore", "pipe", "pipe"] });
|
|
293
287
|
let buffer = "";
|
|
294
288
|
|
|
295
289
|
const processLine = (line: string) => {
|
|
@@ -410,32 +404,21 @@ const SubagentParams = Type.Object({
|
|
|
410
404
|
cwd: Type.Optional(Type.String({ description: "Working directory for the agent process (single mode)" })),
|
|
411
405
|
});
|
|
412
406
|
|
|
413
|
-
|
|
414
|
-
|
|
407
|
+
export default function (pi: ExtensionAPI) {
|
|
408
|
+
pi.registerTool({
|
|
415
409
|
name: "subagent",
|
|
416
410
|
label: "Subagent",
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const projectSuffix = projectList.remaining > 0 ? `; ... and ${projectList.remaining} more` : "";
|
|
424
|
-
const projectDirNote = project.projectAgentsDir ? ` (from ${project.projectAgentsDir})` : "";
|
|
425
|
-
return [
|
|
426
|
-
"Delegate tasks to specialized subagents with isolated context.",
|
|
427
|
-
"Modes: single (agent + task), parallel (tasks array), chain (sequential with {previous} placeholder).",
|
|
428
|
-
'Default agent scope is "user" (from ~/.pi/agent/agents).',
|
|
429
|
-
'To enable project-local agents in .pi/agents, set agentScope: "both" (or "project").',
|
|
430
|
-
`User agents: ${userList.text}${userSuffix}.`,
|
|
431
|
-
`Project agents${projectDirNote}: ${projectList.text}${projectSuffix}.`,
|
|
432
|
-
].join(" ");
|
|
433
|
-
},
|
|
411
|
+
description: [
|
|
412
|
+
"Delegate tasks to specialized subagents with isolated context.",
|
|
413
|
+
"Modes: single (agent + task), parallel (tasks array), chain (sequential with {previous} placeholder).",
|
|
414
|
+
'Default agent scope is "user" (from ~/.pi/agent/agents).',
|
|
415
|
+
'To enable project-local agents in .pi/agents, set agentScope: "both" (or "project").',
|
|
416
|
+
].join(" "),
|
|
434
417
|
parameters: SubagentParams,
|
|
435
418
|
|
|
436
|
-
async execute(_toolCallId, params, onUpdate,
|
|
419
|
+
async execute(_toolCallId, params, onUpdate, ctx, signal) {
|
|
437
420
|
const agentScope: AgentScope = params.agentScope ?? "user";
|
|
438
|
-
const discovery = discoverAgents(
|
|
421
|
+
const discovery = discoverAgents(ctx.cwd, agentScope);
|
|
439
422
|
const agents = discovery.agents;
|
|
440
423
|
const confirmProjectAgents = params.confirmProjectAgents ?? true;
|
|
441
424
|
|
|
@@ -466,7 +449,7 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
466
449
|
};
|
|
467
450
|
}
|
|
468
451
|
|
|
469
|
-
if ((agentScope === "project" || agentScope === "both") && confirmProjectAgents &&
|
|
452
|
+
if ((agentScope === "project" || agentScope === "both") && confirmProjectAgents && ctx.hasUI) {
|
|
470
453
|
const requestedAgentNames = new Set<string>();
|
|
471
454
|
if (params.chain) for (const step of params.chain) requestedAgentNames.add(step.agent);
|
|
472
455
|
if (params.tasks) for (const t of params.tasks) requestedAgentNames.add(t.agent);
|
|
@@ -479,7 +462,7 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
479
462
|
if (projectAgentsRequested.length > 0) {
|
|
480
463
|
const names = projectAgentsRequested.map((a) => a.name).join(", ");
|
|
481
464
|
const dir = discovery.projectAgentsDir ?? "(unknown)";
|
|
482
|
-
const ok = await
|
|
465
|
+
const ok = await ctx.ui.confirm(
|
|
483
466
|
"Run project-local agents?",
|
|
484
467
|
`Agents: ${names}\nSource: ${dir}\n\nProject agents are repo-controlled. Only continue for trusted repositories.`,
|
|
485
468
|
);
|
|
@@ -515,7 +498,7 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
515
498
|
: undefined;
|
|
516
499
|
|
|
517
500
|
const result = await runSingleAgent(
|
|
518
|
-
|
|
501
|
+
ctx.cwd,
|
|
519
502
|
agents,
|
|
520
503
|
step.agent,
|
|
521
504
|
taskWithContext,
|
|
@@ -589,7 +572,7 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
589
572
|
|
|
590
573
|
const results = await mapWithConcurrencyLimit(params.tasks, MAX_CONCURRENCY, async (t, index) => {
|
|
591
574
|
const result = await runSingleAgent(
|
|
592
|
-
|
|
575
|
+
ctx.cwd,
|
|
593
576
|
agents,
|
|
594
577
|
t.agent,
|
|
595
578
|
t.task,
|
|
@@ -629,7 +612,7 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
629
612
|
|
|
630
613
|
if (params.agent && params.task) {
|
|
631
614
|
const result = await runSingleAgent(
|
|
632
|
-
|
|
615
|
+
ctx.cwd,
|
|
633
616
|
agents,
|
|
634
617
|
params.agent,
|
|
635
618
|
params.task,
|
|
@@ -707,7 +690,7 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
707
690
|
},
|
|
708
691
|
|
|
709
692
|
renderResult(result, { expanded }, theme) {
|
|
710
|
-
const
|
|
693
|
+
const details = result.details as SubagentDetails | undefined;
|
|
711
694
|
if (!details || details.results.length === 0) {
|
|
712
695
|
const text = result.content[0];
|
|
713
696
|
return new Text(text?.type === "text" ? text.text : "(no output)", 0, 0);
|
|
@@ -976,9 +959,5 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
976
959
|
const text = result.content[0];
|
|
977
960
|
return new Text(text?.type === "text" ? text.text : "(no output)", 0, 0);
|
|
978
961
|
},
|
|
979
|
-
};
|
|
980
|
-
|
|
981
|
-
return tool;
|
|
982
|
-
};
|
|
983
|
-
|
|
984
|
-
export default factory;
|
|
962
|
+
});
|
|
963
|
+
}
|
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Todo
|
|
2
|
+
* Todo Extension - Demonstrates state management via session entries
|
|
3
3
|
*
|
|
4
|
-
* This
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* This extension:
|
|
5
|
+
* - Registers a `todo` tool for the LLM to manage todos
|
|
6
|
+
* - Registers a `/todos` command for users to view the list
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* State is stored in tool result details (not external files), which allows
|
|
9
|
+
* proper branching - when you branch, the todo state is automatically
|
|
10
|
+
* correct for that point in history.
|
|
9
11
|
*/
|
|
10
12
|
|
|
11
13
|
import { StringEnum } from "@mariozechner/pi-ai";
|
|
12
|
-
import type {
|
|
13
|
-
|
|
14
|
-
CustomToolContext,
|
|
15
|
-
CustomToolFactory,
|
|
16
|
-
CustomToolSessionEvent,
|
|
17
|
-
} from "@mariozechner/pi-coding-agent";
|
|
18
|
-
import { Text } from "@mariozechner/pi-tui";
|
|
14
|
+
import type { ExtensionAPI, ExtensionContext, Theme } from "@mariozechner/pi-coding-agent";
|
|
15
|
+
import { matchesKey, Text, truncateToWidth } from "@mariozechner/pi-tui";
|
|
19
16
|
import { Type } from "@sinclair/typebox";
|
|
20
17
|
|
|
21
18
|
interface Todo {
|
|
@@ -24,7 +21,6 @@ interface Todo {
|
|
|
24
21
|
done: boolean;
|
|
25
22
|
}
|
|
26
23
|
|
|
27
|
-
// State stored in tool result details
|
|
28
24
|
interface TodoDetails {
|
|
29
25
|
action: "list" | "add" | "toggle" | "clear";
|
|
30
26
|
todos: Todo[];
|
|
@@ -32,14 +28,81 @@ interface TodoDetails {
|
|
|
32
28
|
error?: string;
|
|
33
29
|
}
|
|
34
30
|
|
|
35
|
-
// Define schema separately for proper type inference
|
|
36
31
|
const TodoParams = Type.Object({
|
|
37
32
|
action: StringEnum(["list", "add", "toggle", "clear"] as const),
|
|
38
33
|
text: Type.Optional(Type.String({ description: "Todo text (for add)" })),
|
|
39
34
|
id: Type.Optional(Type.Number({ description: "Todo ID (for toggle)" })),
|
|
40
35
|
});
|
|
41
36
|
|
|
42
|
-
|
|
37
|
+
/**
|
|
38
|
+
* UI component for the /todos command
|
|
39
|
+
*/
|
|
40
|
+
class TodoListComponent {
|
|
41
|
+
private todos: Todo[];
|
|
42
|
+
private theme: Theme;
|
|
43
|
+
private onClose: () => void;
|
|
44
|
+
private cachedWidth?: number;
|
|
45
|
+
private cachedLines?: string[];
|
|
46
|
+
|
|
47
|
+
constructor(todos: Todo[], theme: Theme, onClose: () => void) {
|
|
48
|
+
this.todos = todos;
|
|
49
|
+
this.theme = theme;
|
|
50
|
+
this.onClose = onClose;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
handleInput(data: string): void {
|
|
54
|
+
if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
|
|
55
|
+
this.onClose();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
render(width: number): string[] {
|
|
60
|
+
if (this.cachedLines && this.cachedWidth === width) {
|
|
61
|
+
return this.cachedLines;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const lines: string[] = [];
|
|
65
|
+
const th = this.theme;
|
|
66
|
+
|
|
67
|
+
lines.push("");
|
|
68
|
+
const title = th.fg("accent", " Todos ");
|
|
69
|
+
const headerLine =
|
|
70
|
+
th.fg("borderMuted", "─".repeat(3)) + title + th.fg("borderMuted", "─".repeat(Math.max(0, width - 10)));
|
|
71
|
+
lines.push(truncateToWidth(headerLine, width));
|
|
72
|
+
lines.push("");
|
|
73
|
+
|
|
74
|
+
if (this.todos.length === 0) {
|
|
75
|
+
lines.push(truncateToWidth(` ${th.fg("dim", "No todos yet. Ask the agent to add some!")}`, width));
|
|
76
|
+
} else {
|
|
77
|
+
const done = this.todos.filter((t) => t.done).length;
|
|
78
|
+
const total = this.todos.length;
|
|
79
|
+
lines.push(truncateToWidth(` ${th.fg("muted", `${done}/${total} completed`)}`, width));
|
|
80
|
+
lines.push("");
|
|
81
|
+
|
|
82
|
+
for (const todo of this.todos) {
|
|
83
|
+
const check = todo.done ? th.fg("success", "✓") : th.fg("dim", "○");
|
|
84
|
+
const id = th.fg("accent", `#${todo.id}`);
|
|
85
|
+
const text = todo.done ? th.fg("dim", todo.text) : th.fg("text", todo.text);
|
|
86
|
+
lines.push(truncateToWidth(` ${check} ${id} ${text}`, width));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
lines.push("");
|
|
91
|
+
lines.push(truncateToWidth(` ${th.fg("dim", "Press Escape to close")}`, width));
|
|
92
|
+
lines.push("");
|
|
93
|
+
|
|
94
|
+
this.cachedWidth = width;
|
|
95
|
+
this.cachedLines = lines;
|
|
96
|
+
return lines;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
invalidate(): void {
|
|
100
|
+
this.cachedWidth = undefined;
|
|
101
|
+
this.cachedLines = undefined;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export default function (pi: ExtensionAPI) {
|
|
43
106
|
// In-memory state (reconstructed from session on load)
|
|
44
107
|
let todos: Todo[] = [];
|
|
45
108
|
let nextId = 1;
|
|
@@ -48,18 +111,14 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
48
111
|
* Reconstruct state from session entries.
|
|
49
112
|
* Scans tool results for this tool and applies them in order.
|
|
50
113
|
*/
|
|
51
|
-
const reconstructState = (
|
|
114
|
+
const reconstructState = (ctx: ExtensionContext) => {
|
|
52
115
|
todos = [];
|
|
53
116
|
nextId = 1;
|
|
54
117
|
|
|
55
|
-
// Use getBranch() to get entries on the current branch
|
|
56
118
|
for (const entry of ctx.sessionManager.getBranch()) {
|
|
57
119
|
if (entry.type !== "message") continue;
|
|
58
120
|
const msg = entry.message;
|
|
59
|
-
|
|
60
|
-
// Tool results have role "toolResult"
|
|
61
|
-
if (msg.role !== "toolResult") continue;
|
|
62
|
-
if (msg.toolName !== "todo") continue;
|
|
121
|
+
if (msg.role !== "toolResult" || msg.toolName !== "todo") continue;
|
|
63
122
|
|
|
64
123
|
const details = msg.details as TodoDetails | undefined;
|
|
65
124
|
if (details) {
|
|
@@ -69,15 +128,19 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
69
128
|
}
|
|
70
129
|
};
|
|
71
130
|
|
|
72
|
-
|
|
131
|
+
// Reconstruct state on session events
|
|
132
|
+
pi.on("session_start", async (_event, ctx) => reconstructState(ctx));
|
|
133
|
+
pi.on("session_switch", async (_event, ctx) => reconstructState(ctx));
|
|
134
|
+
pi.on("session_branch", async (_event, ctx) => reconstructState(ctx));
|
|
135
|
+
pi.on("session_tree", async (_event, ctx) => reconstructState(ctx));
|
|
136
|
+
|
|
137
|
+
// Register the todo tool for the LLM
|
|
138
|
+
pi.registerTool({
|
|
73
139
|
name: "todo",
|
|
74
140
|
label: "Todo",
|
|
75
141
|
description: "Manage a todo list. Actions: list, add (text), toggle (id), clear",
|
|
76
142
|
parameters: TodoParams,
|
|
77
143
|
|
|
78
|
-
// Called on session start/switch/branch/clear
|
|
79
|
-
onSession: reconstructState,
|
|
80
|
-
|
|
81
144
|
async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
|
|
82
145
|
switch (params.action) {
|
|
83
146
|
case "list":
|
|
@@ -90,21 +153,21 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
90
153
|
: "No todos",
|
|
91
154
|
},
|
|
92
155
|
],
|
|
93
|
-
details: { action: "list", todos: [...todos], nextId },
|
|
156
|
+
details: { action: "list", todos: [...todos], nextId } as TodoDetails,
|
|
94
157
|
};
|
|
95
158
|
|
|
96
159
|
case "add": {
|
|
97
160
|
if (!params.text) {
|
|
98
161
|
return {
|
|
99
162
|
content: [{ type: "text", text: "Error: text required for add" }],
|
|
100
|
-
details: { action: "add", todos: [...todos], nextId, error: "text required" },
|
|
163
|
+
details: { action: "add", todos: [...todos], nextId, error: "text required" } as TodoDetails,
|
|
101
164
|
};
|
|
102
165
|
}
|
|
103
166
|
const newTodo: Todo = { id: nextId++, text: params.text, done: false };
|
|
104
167
|
todos.push(newTodo);
|
|
105
168
|
return {
|
|
106
169
|
content: [{ type: "text", text: `Added todo #${newTodo.id}: ${newTodo.text}` }],
|
|
107
|
-
details: { action: "add", todos: [...todos], nextId },
|
|
170
|
+
details: { action: "add", todos: [...todos], nextId } as TodoDetails,
|
|
108
171
|
};
|
|
109
172
|
}
|
|
110
173
|
|
|
@@ -112,20 +175,25 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
112
175
|
if (params.id === undefined) {
|
|
113
176
|
return {
|
|
114
177
|
content: [{ type: "text", text: "Error: id required for toggle" }],
|
|
115
|
-
details: { action: "toggle", todos: [...todos], nextId, error: "id required" },
|
|
178
|
+
details: { action: "toggle", todos: [...todos], nextId, error: "id required" } as TodoDetails,
|
|
116
179
|
};
|
|
117
180
|
}
|
|
118
181
|
const todo = todos.find((t) => t.id === params.id);
|
|
119
182
|
if (!todo) {
|
|
120
183
|
return {
|
|
121
184
|
content: [{ type: "text", text: `Todo #${params.id} not found` }],
|
|
122
|
-
details: {
|
|
185
|
+
details: {
|
|
186
|
+
action: "toggle",
|
|
187
|
+
todos: [...todos],
|
|
188
|
+
nextId,
|
|
189
|
+
error: `#${params.id} not found`,
|
|
190
|
+
} as TodoDetails,
|
|
123
191
|
};
|
|
124
192
|
}
|
|
125
193
|
todo.done = !todo.done;
|
|
126
194
|
return {
|
|
127
195
|
content: [{ type: "text", text: `Todo #${todo.id} ${todo.done ? "completed" : "uncompleted"}` }],
|
|
128
|
-
details: { action: "toggle", todos: [...todos], nextId },
|
|
196
|
+
details: { action: "toggle", todos: [...todos], nextId } as TodoDetails,
|
|
129
197
|
};
|
|
130
198
|
}
|
|
131
199
|
|
|
@@ -135,14 +203,19 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
135
203
|
nextId = 1;
|
|
136
204
|
return {
|
|
137
205
|
content: [{ type: "text", text: `Cleared ${count} todos` }],
|
|
138
|
-
details: { action: "clear", todos: [], nextId: 1 },
|
|
206
|
+
details: { action: "clear", todos: [], nextId: 1 } as TodoDetails,
|
|
139
207
|
};
|
|
140
208
|
}
|
|
141
209
|
|
|
142
210
|
default:
|
|
143
211
|
return {
|
|
144
212
|
content: [{ type: "text", text: `Unknown action: ${params.action}` }],
|
|
145
|
-
details: {
|
|
213
|
+
details: {
|
|
214
|
+
action: "list",
|
|
215
|
+
todos: [...todos],
|
|
216
|
+
nextId,
|
|
217
|
+
error: `unknown action: ${params.action}`,
|
|
218
|
+
} as TodoDetails,
|
|
146
219
|
};
|
|
147
220
|
}
|
|
148
221
|
},
|
|
@@ -155,13 +228,12 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
155
228
|
},
|
|
156
229
|
|
|
157
230
|
renderResult(result, { expanded }, theme) {
|
|
158
|
-
const
|
|
231
|
+
const details = result.details as TodoDetails | undefined;
|
|
159
232
|
if (!details) {
|
|
160
233
|
const text = result.content[0];
|
|
161
234
|
return new Text(text?.type === "text" ? text.text : "", 0, 0);
|
|
162
235
|
}
|
|
163
236
|
|
|
164
|
-
// Error
|
|
165
237
|
if (details.error) {
|
|
166
238
|
return new Text(theme.fg("error", `Error: ${details.error}`), 0, 0);
|
|
167
239
|
}
|
|
@@ -208,9 +280,20 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
208
280
|
return new Text(theme.fg("success", "✓ ") + theme.fg("muted", "Cleared all todos"), 0, 0);
|
|
209
281
|
}
|
|
210
282
|
},
|
|
211
|
-
};
|
|
283
|
+
});
|
|
212
284
|
|
|
213
|
-
|
|
214
|
-
|
|
285
|
+
// Register the /todos command for users
|
|
286
|
+
pi.registerCommand("todos", {
|
|
287
|
+
description: "Show all todos on the current branch",
|
|
288
|
+
handler: async (_args, ctx) => {
|
|
289
|
+
if (!ctx.hasUI) {
|
|
290
|
+
ctx.ui.notify("/todos requires interactive mode", "error");
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
215
293
|
|
|
216
|
-
|
|
294
|
+
await ctx.ui.custom<void>((_tui, theme, done) => {
|
|
295
|
+
return new TodoListComponent(todos, theme, () => done());
|
|
296
|
+
});
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tools
|
|
2
|
+
* Tools Extension
|
|
3
3
|
*
|
|
4
4
|
* Provides a /tools command to enable/disable tools interactively.
|
|
5
5
|
* Tool selection persists across session reloads and respects branch navigation.
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
|
-
* 1. Copy this file to ~/.pi/agent/
|
|
8
|
+
* 1. Copy this file to ~/.pi/agent/extensions/ or your project's .pi/extensions/
|
|
9
9
|
* 2. Use /tools to open the tool selector
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
12
13
|
import { getSettingsListTheme } from "@mariozechner/pi-coding-agent";
|
|
13
|
-
import type { HookAPI, HookContext } from "@mariozechner/pi-coding-agent/hooks";
|
|
14
14
|
import { Container, type SettingItem, SettingsList } from "@mariozechner/pi-tui";
|
|
15
15
|
|
|
16
16
|
// State persisted to session
|
|
@@ -18,7 +18,7 @@ interface ToolsState {
|
|
|
18
18
|
enabledTools: string[];
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export default function
|
|
21
|
+
export default function toolsExtension(pi: ExtensionAPI) {
|
|
22
22
|
// Track enabled tools
|
|
23
23
|
let enabledTools: Set<string> = new Set();
|
|
24
24
|
let allTools: string[] = [];
|
|
@@ -36,7 +36,7 @@ export default function toolsHook(pi: HookAPI) {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// Find the last tools-config entry in the current branch
|
|
39
|
-
function restoreFromBranch(ctx:
|
|
39
|
+
function restoreFromBranch(ctx: ExtensionContext) {
|
|
40
40
|
allTools = pi.getAllTools();
|
|
41
41
|
|
|
42
42
|
// Get entries in current branch only
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example extension with its own npm dependencies.
|
|
3
|
+
* Tests that jiti resolves modules from the extension's own node_modules.
|
|
4
|
+
*
|
|
5
|
+
* Requires: npm install in this directory
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
9
|
+
import { Type } from "@sinclair/typebox";
|
|
10
|
+
import ms from "ms";
|
|
11
|
+
|
|
12
|
+
export default function (pi: ExtensionAPI) {
|
|
13
|
+
// Use the ms package to prove it loaded
|
|
14
|
+
const uptime = ms(process.uptime() * 1000, { long: true });
|
|
15
|
+
console.log(`[with-deps] Extension loaded. Process uptime: ${uptime}`);
|
|
16
|
+
|
|
17
|
+
// Register a tool that uses ms
|
|
18
|
+
pi.registerTool({
|
|
19
|
+
name: "parse_duration",
|
|
20
|
+
label: "Parse Duration",
|
|
21
|
+
description: "Parse a human-readable duration string (e.g., '2 days', '1h', '5m') to milliseconds",
|
|
22
|
+
parameters: Type.Object({
|
|
23
|
+
duration: Type.String({ description: "Duration string like '2 days', '1h', '5m'" }),
|
|
24
|
+
}),
|
|
25
|
+
execute: async (_toolCallId, params) => {
|
|
26
|
+
const result = ms(params.duration as ms.StringValue);
|
|
27
|
+
if (result === undefined) {
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: `Invalid duration: "${params.duration}"` }],
|
|
30
|
+
isError: true,
|
|
31
|
+
details: {},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
content: [{ type: "text", text: `${params.duration} = ${result} milliseconds` }],
|
|
36
|
+
details: {},
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-extension-with-deps",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "pi-extension-with-deps",
|
|
9
|
+
"version": "1.0.0",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"ms": "^2.1.3"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/ms": "^2.1.0"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"node_modules/@types/ms": {
|
|
18
|
+
"version": "2.1.0",
|
|
19
|
+
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
|
|
20
|
+
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
|
|
21
|
+
"dev": true,
|
|
22
|
+
"license": "MIT"
|
|
23
|
+
},
|
|
24
|
+
"node_modules/ms": {
|
|
25
|
+
"version": "2.1.3",
|
|
26
|
+
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
|
27
|
+
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
|
28
|
+
"license": "MIT"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
package/examples/sdk/05-tools.ts
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tools Configuration
|
|
3
3
|
*
|
|
4
|
-
* Use built-in tool sets
|
|
4
|
+
* Use built-in tool sets or individual tools.
|
|
5
5
|
*
|
|
6
6
|
* IMPORTANT: When using a custom `cwd`, you must use the tool factory functions
|
|
7
7
|
* (createCodingTools, createReadOnlyTools, createReadTool, etc.) to ensure
|
|
8
8
|
* tools resolve paths relative to your cwd, not process.cwd().
|
|
9
|
+
*
|
|
10
|
+
* For custom tools, see 06-extensions.ts - custom tools are now registered
|
|
11
|
+
* via the extensions system using pi.registerTool().
|
|
9
12
|
*/
|
|
10
13
|
|
|
11
14
|
import {
|
|
12
|
-
bashTool,
|
|
13
|
-
type CustomTool,
|
|
15
|
+
bashTool,
|
|
14
16
|
createAgentSession,
|
|
15
17
|
createBashTool,
|
|
16
|
-
createCodingTools,
|
|
18
|
+
createCodingTools,
|
|
17
19
|
createGrepTool,
|
|
18
20
|
createReadTool,
|
|
19
21
|
grepTool,
|
|
20
|
-
readOnlyTools,
|
|
22
|
+
readOnlyTools,
|
|
21
23
|
readTool,
|
|
22
24
|
SessionManager,
|
|
23
25
|
} from "@mariozechner/pi-coding-agent";
|
|
24
|
-
import { Type } from "@sinclair/typebox";
|
|
25
26
|
|
|
26
27
|
// Read-only mode (no edit/write) - uses process.cwd()
|
|
27
28
|
await createAgentSession({
|
|
@@ -53,38 +54,3 @@ await createAgentSession({
|
|
|
53
54
|
sessionManager: SessionManager.inMemory(),
|
|
54
55
|
});
|
|
55
56
|
console.log("Specific tools with custom cwd session created");
|
|
56
|
-
|
|
57
|
-
// Inline custom tool (needs TypeBox schema)
|
|
58
|
-
const weatherTool: CustomTool = {
|
|
59
|
-
name: "get_weather",
|
|
60
|
-
label: "Get Weather",
|
|
61
|
-
description: "Get current weather for a city",
|
|
62
|
-
parameters: Type.Object({
|
|
63
|
-
city: Type.String({ description: "City name" }),
|
|
64
|
-
}),
|
|
65
|
-
execute: async (_toolCallId, params) => ({
|
|
66
|
-
content: [{ type: "text", text: `Weather in ${(params as { city: string }).city}: 22°C, sunny` }],
|
|
67
|
-
details: {},
|
|
68
|
-
}),
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const { session } = await createAgentSession({
|
|
72
|
-
customTools: [{ tool: weatherTool }],
|
|
73
|
-
sessionManager: SessionManager.inMemory(),
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
session.subscribe((event) => {
|
|
77
|
-
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
|
|
78
|
-
process.stdout.write(event.assistantMessageEvent.delta);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
await session.prompt("What's the weather in Tokyo?");
|
|
83
|
-
console.log();
|
|
84
|
-
|
|
85
|
-
// Merge with discovered tools from cwd/.pi/tools and ~/.pi/agent/tools:
|
|
86
|
-
// const discovered = await discoverCustomTools();
|
|
87
|
-
// customTools: [...discovered, { tool: myTool }]
|
|
88
|
-
|
|
89
|
-
// Or add paths without replacing discovery:
|
|
90
|
-
// additionalCustomToolPaths: ["/extra/tools"]
|