pi-agent-flow 1.2.2 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/ambient.d.ts +17 -0
- package/src/index.ts +7 -0
- package/src/timed-bash.ts +129 -0
package/package.json
CHANGED
package/src/ambient.d.ts
CHANGED
|
@@ -28,6 +28,23 @@ declare module "@mariozechner/pi-coding-agent" {
|
|
|
28
28
|
export const DEFAULT_MAX_BYTES: number;
|
|
29
29
|
export const DEFAULT_MAX_LINES: number;
|
|
30
30
|
export function truncateHead(text: string, options: { maxBytes?: number; maxLines?: number }): { content: string };
|
|
31
|
+
export function createBashToolDefinition(
|
|
32
|
+
cwd: string,
|
|
33
|
+
options?: {
|
|
34
|
+
shellPath?: string;
|
|
35
|
+
commandPrefix?: string;
|
|
36
|
+
operations?: any;
|
|
37
|
+
spawnHook?: any;
|
|
38
|
+
},
|
|
39
|
+
): {
|
|
40
|
+
name: string;
|
|
41
|
+
label: string;
|
|
42
|
+
description: string;
|
|
43
|
+
parameters: any;
|
|
44
|
+
execute: (...args: any[]) => Promise<any>;
|
|
45
|
+
renderCall?: (...args: any[]) => any;
|
|
46
|
+
renderResult?: (...args: any[]) => any;
|
|
47
|
+
};
|
|
31
48
|
}
|
|
32
49
|
|
|
33
50
|
declare module "@mariozechner/pi-tui" {
|
package/src/index.ts
CHANGED
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
looksLikeUrlPrompt,
|
|
39
39
|
looksLikeWebSearchPrompt,
|
|
40
40
|
} from "./web-tool.js";
|
|
41
|
+
import { createTimedBashToolDefinition } from "./timed-bash.js";
|
|
41
42
|
|
|
42
43
|
// ---------------------------------------------------------------------------
|
|
43
44
|
// Limits
|
|
@@ -784,6 +785,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
784
785
|
pi.registerTool(createBatchReadTool());
|
|
785
786
|
pi.registerTool(createBatchTool());
|
|
786
787
|
}
|
|
788
|
+
|
|
789
|
+
// Override built-in bash with timed wrapper so the LLM sees execution-time classification.
|
|
790
|
+
const timedBash = createTimedBashToolDefinition(ctx.cwd);
|
|
791
|
+
if (timedBash) {
|
|
792
|
+
pi.registerTool(timedBash);
|
|
793
|
+
}
|
|
787
794
|
});
|
|
788
795
|
|
|
789
796
|
// Re-apply active tools every turn to survive registry refreshes.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timed Bash Tool Wrapper
|
|
3
|
+
*
|
|
4
|
+
* Wraps the built-in bash tool to append execution-time classification
|
|
5
|
+
* to every result. This gives the LLM concrete feedback to self-correct
|
|
6
|
+
* strategy (e.g. switch from bash grep to grep tool, batch commands, etc.).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createBashToolDefinition } from "@mariozechner/pi-coding-agent";
|
|
10
|
+
|
|
11
|
+
export type TimingTier =
|
|
12
|
+
| "normal"
|
|
13
|
+
| "avg"
|
|
14
|
+
| "long"
|
|
15
|
+
| "extreme_long"
|
|
16
|
+
| "very_long";
|
|
17
|
+
|
|
18
|
+
export interface TimingReport {
|
|
19
|
+
tier: TimingTier;
|
|
20
|
+
seconds: number;
|
|
21
|
+
label: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Classify duration into user-defined tiers with actionable feedback. */
|
|
25
|
+
export function classifyDuration(ms: number): TimingReport {
|
|
26
|
+
const s = ms / 1000;
|
|
27
|
+
if (s < 10) {
|
|
28
|
+
return { tier: "normal", seconds: s, label: `${s.toFixed(1)}s (normal)` };
|
|
29
|
+
}
|
|
30
|
+
if (s < 30) {
|
|
31
|
+
return { tier: "avg", seconds: s, label: `${s.toFixed(1)}s (avg) — user feedback: consider improving the current commands or find a better solution` };
|
|
32
|
+
}
|
|
33
|
+
if (s < 60) {
|
|
34
|
+
return {
|
|
35
|
+
tier: "long",
|
|
36
|
+
seconds: s,
|
|
37
|
+
label: `${s.toFixed(1)}s (long) — user feedback: consider improving the whole scripts`,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (s < 300) {
|
|
41
|
+
return {
|
|
42
|
+
tier: "extreme_long",
|
|
43
|
+
seconds: s,
|
|
44
|
+
label: `${s.toFixed(1)}s (extreme long) — user feedback: should consider to improve the whole scripts`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
tier: "very_long",
|
|
49
|
+
seconds: s,
|
|
50
|
+
label: `${(s / 60).toFixed(1)}min (very long) — user feedback: consider to improve, only run when everything tested with other means`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Format the timing appendix that gets appended to bash output. */
|
|
55
|
+
export function formatTimingAppendix(report: TimingReport): string {
|
|
56
|
+
return `\n\n[Execution time: ${report.label}]`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Create a timed bash tool definition that wraps the built-in one.
|
|
61
|
+
* Extensions override built-in tools by name, so this replaces the
|
|
62
|
+
* default `bash` tool transparently.
|
|
63
|
+
*
|
|
64
|
+
* Returns `null` if the underlying `createBashToolDefinition` is not
|
|
65
|
+
* available (e.g. test environment or incompatible CLI version).
|
|
66
|
+
*/
|
|
67
|
+
export function createTimedBashToolDefinition(
|
|
68
|
+
cwd: string,
|
|
69
|
+
options?: {
|
|
70
|
+
shellPath?: string;
|
|
71
|
+
commandPrefix?: string;
|
|
72
|
+
operations?: any;
|
|
73
|
+
spawnHook?: any;
|
|
74
|
+
},
|
|
75
|
+
): any {
|
|
76
|
+
let original: any;
|
|
77
|
+
try {
|
|
78
|
+
original = createBashToolDefinition(cwd, options);
|
|
79
|
+
} catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
if (!original || typeof original.execute !== "function") {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
...original,
|
|
88
|
+
async execute(
|
|
89
|
+
toolCallId: string,
|
|
90
|
+
params: { command: string; timeout?: number },
|
|
91
|
+
signal: AbortSignal,
|
|
92
|
+
onUpdate: any,
|
|
93
|
+
ctx: any,
|
|
94
|
+
) {
|
|
95
|
+
const start = Date.now();
|
|
96
|
+
try {
|
|
97
|
+
const result = await original.execute(
|
|
98
|
+
toolCallId,
|
|
99
|
+
params,
|
|
100
|
+
signal,
|
|
101
|
+
onUpdate,
|
|
102
|
+
ctx,
|
|
103
|
+
);
|
|
104
|
+
const duration = Date.now() - start;
|
|
105
|
+
const report = classifyDuration(duration);
|
|
106
|
+
const appendix = formatTimingAppendix(report);
|
|
107
|
+
|
|
108
|
+
const textItem = result.content?.find(
|
|
109
|
+
(c: any) => c.type === "text",
|
|
110
|
+
);
|
|
111
|
+
if (textItem && typeof textItem.text === "string") {
|
|
112
|
+
textItem.text += appendix;
|
|
113
|
+
} else if (result.content) {
|
|
114
|
+
result.content.push({ type: "text", text: appendix.trim() });
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
} catch (err: any) {
|
|
118
|
+
const duration = Date.now() - start;
|
|
119
|
+
const report = classifyDuration(duration);
|
|
120
|
+
const appendix = formatTimingAppendix(report);
|
|
121
|
+
|
|
122
|
+
if (err?.message && typeof err.message === "string") {
|
|
123
|
+
err.message += appendix;
|
|
124
|
+
}
|
|
125
|
+
throw err;
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|