@giladbarnea/pi-user-agents 0.0.9 → 0.0.11
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/INTERNALS.md +1 -1
- package/PARSER_SPEC.md +5 -3
- package/autocomplete.ts +9 -2
- package/package.json +4 -3
- package/runner.ts +22 -8
- package/shared.ts +2 -0
package/INTERNALS.md
CHANGED
|
@@ -113,7 +113,7 @@ Type `/agent -` and the option menu opens immediately — no Tab is required. Sh
|
|
|
113
113
|
|
|
114
114
|
The finite value menus are thinking levels, live providers, live models, and the session's live tool catalog. Models from the configured `enabledModels` scope lead the unfiltered model menu; once you type a query, Pi's fuzzy relevance controls the order and scope only breaks equal-score ties. `--provider` narrows the model menu for either `-m` or `--model`. A completed boolean, thinking level, provider, or model leaves exactly one trailing space.
|
|
115
115
|
|
|
116
|
-
`--tools`/`-t` and `--exclude-tools`/`-xt` complete one comma-delimited segment at a time. Accepting `grep` produces `--tools grep│` — the menu closes without inserting a space or comma. Type `,` to open the next segment immediately; already selected tools are omitted. Type a normal space when the tool list is finished.
|
|
116
|
+
`--tools`/`-t` and `--exclude-tools`/`-xt` complete one comma-delimited segment at a time. Accepting `grep` produces `--tools grep│` — the menu closes without inserting a space or comma. Type `,` to open the next segment immediately; already selected tools are omitted. Type a normal space when the tool list is finished. In `--tools`, a `+name`/`-name` entry keeps its sign: `+gr` completes to `+grep`.
|
|
117
117
|
|
|
118
118
|
Free-form values are guarded instead of guessed. Selecting `--system-prompt` produces `/agent --system-prompt "│" `, with the cursor between the quotes and the trailing separator already preserved.
|
|
119
119
|
|
package/PARSER_SPEC.md
CHANGED
|
@@ -205,7 +205,8 @@ The finite value domains implemented today are:
|
|
|
205
205
|
- tool names from the live public `pi.getAllTools()` catalog for `--tools`/`-t` and
|
|
206
206
|
`--exclude-tools`/`-xt`.
|
|
207
207
|
|
|
208
|
-
Tool completion is local to the active comma-delimited segment.
|
|
208
|
+
Tool completion is local to the active comma-delimited segment. In `--tools`, a leading `+` or
|
|
209
|
+
`-` stays in place and completion replaces only the name after it. Accepting a tool replaces only
|
|
209
210
|
that segment and closes the menu without adding a space or comma. Typing `,` immediately opens
|
|
210
211
|
the next segment and excludes every tool already selected elsewhere in the value. The user
|
|
211
212
|
types a normal space to finish the complete tool list. Other non-path value options remain
|
|
@@ -247,8 +248,9 @@ source spans:
|
|
|
247
248
|
- `value` — the value consumed by a leading value-taking option. A quoted value's span
|
|
248
249
|
includes its surrounding quotes;
|
|
249
250
|
- `invalid-value` — a leading closed-set value rejected by the same validation used at
|
|
250
|
-
submission and session creation: Pi's argument parser for thinking levels
|
|
251
|
-
|
|
251
|
+
submission and session creation: Pi's argument parser for thinking levels and tool-list
|
|
252
|
+
syntax (`+name`/`-name` entries cannot mix with plain names), exact live model IDs or
|
|
253
|
+
user-defined aliases, and the live provider and tool catalogs;
|
|
252
254
|
- `blocked` — a blocked option in args mode, plus the value a blocked value-taking option
|
|
253
255
|
would consume (`--theme ./theme.json` yields two `blocked` tokens). Unlike
|
|
254
256
|
`parseAgentCommand`, the scan never throws: it records the first blocked token and keeps
|
package/autocomplete.ts
CHANGED
|
@@ -322,13 +322,20 @@ function getToolSegment(
|
|
|
322
322
|
): ToolSegment {
|
|
323
323
|
const value = line.slice(expectation.replacementStart, expectation.replacementEnd);
|
|
324
324
|
const cursorOffset = cursorCol - expectation.replacementStart;
|
|
325
|
-
const
|
|
325
|
+
const commaEnd = value.lastIndexOf(",", cursorOffset - 1) + 1;
|
|
326
|
+
// Pi's --tools takes +name/-name entries; completion replaces only the name after the sign.
|
|
327
|
+
const signLength =
|
|
328
|
+
expectation.option.semanticId === "tools" && /^[+-]/.test(value.slice(commaEnd, cursorOffset))
|
|
329
|
+
? 1
|
|
330
|
+
: 0;
|
|
331
|
+
const segmentStart = commaEnd + signLength;
|
|
326
332
|
const nextComma = value.indexOf(",", cursorOffset);
|
|
327
333
|
const segmentEnd = nextComma === -1 ? value.length : nextComma;
|
|
328
334
|
const selectedNames = new Set(
|
|
329
335
|
value
|
|
330
336
|
.split(",")
|
|
331
|
-
.filter((_name, index) => index !== value.slice(0,
|
|
337
|
+
.filter((_name, index) => index !== value.slice(0, commaEnd).split(",").length - 1)
|
|
338
|
+
.map((name) => name.replace(/^[+-]/, "")),
|
|
332
339
|
);
|
|
333
340
|
return {
|
|
334
341
|
fragment: value.slice(segmentStart, cursorOffset),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@giladbarnea/pi-user-agents",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "Run, view, and control background Pi agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"test": "bun test"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@earendil-works/pi-coding-agent": "
|
|
36
|
+
"@earendil-works/pi-coding-agent": ">=1.1.0",
|
|
37
37
|
"@earendil-works/pi-tui": "*"
|
|
38
38
|
},
|
|
39
39
|
"publishConfig": {
|
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
]
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@earendil-works/pi-
|
|
48
|
+
"@earendil-works/pi-ai": "1.1.0",
|
|
49
|
+
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
49
50
|
"@earendil-works/pi-tui": "0.85.1"
|
|
50
51
|
}
|
|
51
52
|
}
|
package/runner.ts
CHANGED
|
@@ -422,7 +422,12 @@ export function createAgentValueValidator(
|
|
|
422
422
|
}
|
|
423
423
|
if (option.completionDomain === "tool") {
|
|
424
424
|
const parsed = parseArgs([option.names[0]!, value]);
|
|
425
|
-
|
|
425
|
+
if (parsed.diagnostics.some((diagnostic) => diagnostic.type === "error")) return false;
|
|
426
|
+
// A --tools list of +name/-name entries names its tools after the sign.
|
|
427
|
+
const requestedNames =
|
|
428
|
+
option.semanticId === "tools"
|
|
429
|
+
? parsed.tools?.map((entry) => entry.replace(/^[+-]/, ""))
|
|
430
|
+
: parsed.excludeTools;
|
|
426
431
|
const knownNames = new Set(getToolNames());
|
|
427
432
|
return (requestedNames ?? []).every((name) => knownNames.has(name));
|
|
428
433
|
}
|
|
@@ -625,7 +630,9 @@ export async function runChildTurns(
|
|
|
625
630
|
): Promise<void> {
|
|
626
631
|
let instruction = initialInstruction;
|
|
627
632
|
while (true) {
|
|
633
|
+
if (runningAgent.aborted) return;
|
|
628
634
|
const turnMessageStart = session.agent.state.messages.length;
|
|
635
|
+
runningAgent.runAborted = false;
|
|
629
636
|
if (!runningAgent.interruptRequested) {
|
|
630
637
|
logSteering(runningAgent.id, "turn-prompt-started", {
|
|
631
638
|
streaming: session.isStreaming,
|
|
@@ -633,8 +640,13 @@ export async function runChildTurns(
|
|
|
633
640
|
});
|
|
634
641
|
await session.prompt(instruction);
|
|
635
642
|
}
|
|
636
|
-
if (runningAgent.
|
|
637
|
-
|
|
643
|
+
if (runningAgent.aborted) return;
|
|
644
|
+
if (runningAgent.interruptRequested || runningAgent.runAborted) {
|
|
645
|
+
const response = interruptedTurnResponse(
|
|
646
|
+
session,
|
|
647
|
+
turnMessageStart,
|
|
648
|
+
runningAgent.interruptRequested ? "Interrupted by user." : "Run cancelled.",
|
|
649
|
+
);
|
|
638
650
|
runningAgent.interruptRequested = false;
|
|
639
651
|
runningAgent.mainContextState = "separate";
|
|
640
652
|
runningAgent.status = "done-waiting-to-post";
|
|
@@ -693,14 +705,14 @@ export async function runChildTurns(
|
|
|
693
705
|
}
|
|
694
706
|
}
|
|
695
707
|
|
|
696
|
-
function interruptedTurnResponse(session: AgentSession, turnMessageStart: number): string {
|
|
708
|
+
function interruptedTurnResponse(session: AgentSession, turnMessageStart: number, reason: string): string {
|
|
697
709
|
const assistantMessages = session.agent.state.messages
|
|
698
710
|
.slice(turnMessageStart)
|
|
699
711
|
.filter((message) => message.role === "assistant");
|
|
700
712
|
const lastAssistantMessage = assistantMessages.at(-1);
|
|
701
713
|
const partialResponse = lastAssistantMessage ? assistantText(lastAssistantMessage).trim() : "";
|
|
702
|
-
if (!partialResponse) return
|
|
703
|
-
return
|
|
714
|
+
if (!partialResponse) return reason;
|
|
715
|
+
return `${reason}\n\n${partialResponse}`;
|
|
704
716
|
}
|
|
705
717
|
|
|
706
718
|
async function createChildSession(
|
|
@@ -835,8 +847,10 @@ export function subscribeToChildSession(
|
|
|
835
847
|
streaming: session.isStreaming,
|
|
836
848
|
messageCount: event.messages.length,
|
|
837
849
|
});
|
|
838
|
-
if (event.type === "agent_settled")
|
|
839
|
-
|
|
850
|
+
if (event.type === "agent_settled") {
|
|
851
|
+
runningAgent.runAborted = event.aborted;
|
|
852
|
+
logSteering(runningAgent.id, "child-agent-settled", { streaming: session.isStreaming, aborted: event.aborted });
|
|
853
|
+
}
|
|
840
854
|
if (event.type === "turn_start")
|
|
841
855
|
logSteering(runningAgent.id, "turn-started", { streaming: session.isStreaming });
|
|
842
856
|
if (event.type === "turn_end")
|
package/shared.ts
CHANGED
|
@@ -144,6 +144,8 @@ export type RunningAgent = {
|
|
|
144
144
|
aborted?: boolean;
|
|
145
145
|
/** Set when the user interrupts only the active turn, leaving the child session alive. */
|
|
146
146
|
interruptRequested?: boolean;
|
|
147
|
+
/** Cancellation outcome of the current prompt, reported at session-level settlement. */
|
|
148
|
+
runAborted?: boolean;
|
|
147
149
|
};
|
|
148
150
|
|
|
149
151
|
export type CompletedAgent = {
|