@oh-my-pi/pi-coding-agent 16.0.11 → 16.1.1
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 +36 -0
- package/dist/cli.js +3166 -3202
- package/dist/types/config/settings-schema.d.ts +40 -39
- package/dist/types/lsp/types.d.ts +5 -3
- package/dist/types/modes/components/__tests__/skill-message.test.d.ts +1 -0
- package/dist/types/modes/components/assistant-message.d.ts +8 -0
- package/dist/types/modes/components/cache-invalidation-marker.d.ts +39 -0
- package/dist/types/modes/components/compaction-summary-message.d.ts +14 -1
- package/dist/types/modes/components/index.d.ts +0 -1
- package/dist/types/modes/components/message-frame.d.ts +6 -4
- package/dist/types/modes/interactive-mode.d.ts +2 -1
- package/dist/types/modes/theme/theme.d.ts +7 -1
- package/dist/types/modes/types.d.ts +7 -1
- package/dist/types/sdk.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +20 -1
- package/dist/types/session/session-context.d.ts +7 -0
- package/dist/types/session/session-dump-format.d.ts +1 -0
- package/dist/types/session/tool-choice-queue.d.ts +14 -0
- package/dist/types/system-prompt.d.ts +3 -3
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/resolve.d.ts +15 -5
- package/package.json +12 -12
- package/src/config/settings-schema.ts +48 -39
- package/src/config/settings.ts +40 -0
- package/src/debug/log-viewer.ts +4 -4
- package/src/debug/raw-sse.ts +4 -4
- package/src/edit/renderer.ts +2 -2
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/lsp/client.ts +9 -9
- package/src/lsp/render.ts +7 -7
- package/src/lsp/types.ts +6 -3
- package/src/modes/components/__tests__/skill-message.test.ts +92 -0
- package/src/modes/components/agent-dashboard.ts +1 -1
- package/src/modes/components/assistant-message.ts +21 -0
- package/src/modes/components/cache-invalidation-marker.ts +94 -0
- package/src/modes/components/chat-transcript-builder.ts +16 -2
- package/src/modes/components/compaction-summary-message.ts +29 -1
- package/src/modes/components/custom-message.ts +4 -1
- package/src/modes/components/dynamic-border.ts +1 -1
- package/src/modes/components/extensions/extension-dashboard.ts +1 -1
- package/src/modes/components/extensions/inspector-panel.ts +5 -5
- package/src/modes/components/hook-selector.ts +2 -2
- package/src/modes/components/index.ts +0 -1
- package/src/modes/components/message-frame.ts +10 -6
- package/src/modes/components/model-selector.ts +2 -2
- package/src/modes/components/overlay-box.ts +10 -9
- package/src/modes/components/settings-defs.ts +7 -0
- package/src/modes/components/skill-message.ts +39 -19
- package/src/modes/components/tiny-title-download-progress.ts +1 -1
- package/src/modes/components/welcome.ts +1 -1
- package/src/modes/controllers/event-controller.ts +14 -0
- package/src/modes/controllers/selector-controller.ts +7 -0
- package/src/modes/interactive-mode.ts +9 -1
- package/src/modes/theme/theme.ts +14 -0
- package/src/modes/types.ts +7 -1
- package/src/modes/utils/ui-helpers.ts +20 -2
- package/src/prompts/steering/user-interjection.md +3 -4
- package/src/sdk.ts +8 -6
- package/src/session/agent-session.ts +96 -23
- package/src/session/messages.ts +7 -9
- package/src/session/session-context.ts +54 -7
- package/src/session/session-dump-format.ts +3 -1
- package/src/session/snapcompact-inline.ts +2 -2
- package/src/session/tool-choice-queue.ts +59 -0
- package/src/system-prompt.ts +10 -9
- package/src/tools/bash-interactive.ts +4 -4
- package/src/tools/index.ts +4 -0
- package/src/tools/resolve.ts +66 -41
- package/src/tui/output-block.ts +9 -9
- package/dist/types/modes/components/branch-summary-message.d.ts +0 -13
- package/src/modes/components/branch-summary-message.ts +0 -46
package/src/tools/resolve.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
AgentTool,
|
|
3
|
+
AgentToolContext,
|
|
4
|
+
AgentToolResult,
|
|
5
|
+
AgentToolUpdateCallback,
|
|
6
|
+
CustomMessage,
|
|
7
|
+
} from "@oh-my-pi/pi-agent-core";
|
|
2
8
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
3
9
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
4
10
|
import { prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
@@ -28,11 +34,18 @@ export interface ResolveToolDetails {
|
|
|
28
34
|
sourceResultDetails?: unknown;
|
|
29
35
|
}
|
|
30
36
|
|
|
37
|
+
/** Monotonic suffix making each staged preview's pending-invoker id UNIQUE, so
|
|
38
|
+
* stacked previews never clobber one another by label. */
|
|
39
|
+
let pendingPreviewSeq = 0;
|
|
40
|
+
|
|
31
41
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
42
|
+
* Register a non-forcing resolve-protocol handler for a staged preview. Wraps the
|
|
43
|
+
* caller's apply/reject into an onInvoked closure (matching the resolve schema) and
|
|
44
|
+
* stores it on the tool-choice queue's pending-invoker registry under a UNIQUE id.
|
|
45
|
+
* The `resolve` tool dispatches to it; the agent-loop's SoftToolRequirement
|
|
46
|
+
* lifecycle injects the preview reminder and escalates to a forced `resolve` only
|
|
47
|
+
* if the model declines — so a compliant turn pays ZERO tool_choice change (no
|
|
48
|
+
* prompt-cache messages-cache invalidation).
|
|
36
49
|
*
|
|
37
50
|
* This is the canonical entry point for any tool that wants preview/apply
|
|
38
51
|
* semantics. No session-level abstraction is needed: callers pass their
|
|
@@ -48,46 +61,55 @@ export function queueResolveHandler(
|
|
|
48
61
|
},
|
|
49
62
|
): void {
|
|
50
63
|
const queue = session.getToolChoiceQueue?.();
|
|
51
|
-
|
|
52
|
-
if (!queue || !forced || typeof forced === "string") return;
|
|
64
|
+
if (!queue) return;
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
customType: "resolve-reminder",
|
|
57
|
-
content: [
|
|
58
|
-
"<system-reminder>",
|
|
59
|
-
"This is a preview. Call the `resolve` tool to apply or discard these changes.",
|
|
60
|
-
"</system-reminder>",
|
|
61
|
-
].join("\n"),
|
|
62
|
-
details: { toolName: options.sourceToolName },
|
|
63
|
-
});
|
|
64
|
-
};
|
|
66
|
+
// Unique per preview: stacked/sequential previews each get their own entry.
|
|
67
|
+
const id = `pending-action:${options.sourceToolName}:${pendingPreviewSeq++}`;
|
|
65
68
|
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// Apply threw (e.g. ast_edit overlapping replacements). Re-push the
|
|
79
|
-
// same directive so the preview remains pending and the model can
|
|
80
|
-
// `discard` or fix-and-retry on the next turn instead of being
|
|
81
|
-
// stranded with no pending action to address.
|
|
82
|
-
pushDirective();
|
|
83
|
-
steerReminder();
|
|
84
|
-
},
|
|
85
|
-
}),
|
|
69
|
+
const onInvoked = async (input: unknown): Promise<AgentToolResult<unknown>> => {
|
|
70
|
+
const result = await runResolveInvocation(input as ResolveParams, {
|
|
71
|
+
sourceToolName: options.sourceToolName,
|
|
72
|
+
label: options.label,
|
|
73
|
+
apply: options.apply,
|
|
74
|
+
reject: options.reject,
|
|
75
|
+
onApplyError: () => {
|
|
76
|
+
// Apply threw (e.g. ast_edit overlapping replacements). Keep the preview
|
|
77
|
+
// pending under the SAME id so the model can `discard` or fix-and-retry;
|
|
78
|
+
// runResolveInvocation rethrows, so the success-path removal below is skipped.
|
|
79
|
+
queue.registerPendingInvoker(id, options.sourceToolName, onInvoked);
|
|
80
|
+
},
|
|
86
81
|
});
|
|
82
|
+
// Resolved (apply succeeded, or discard): consume the staged action exactly once.
|
|
83
|
+
queue.removePendingInvoker(id);
|
|
84
|
+
return result;
|
|
87
85
|
};
|
|
88
86
|
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
// NON-FORCING: register so `resolve` can dispatch here WITHOUT changing
|
|
88
|
+
// tool_choice. The agent-loop injects the reminder (from the SoftToolRequirement
|
|
89
|
+
// the session builds) and forces a resolve turn only on non-compliance.
|
|
90
|
+
queue.registerPendingInvoker(id, options.sourceToolName, onInvoked);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The canonical preview reminder. The resolve mechanism owns the wording; the
|
|
95
|
+
* agent-loop delivers it via the session's `SoftToolRequirement.reminder` (injected
|
|
96
|
+
* once per pending-preview head) instead of a host-side steer, so it lands as a
|
|
97
|
+
* stable mid-history append and never churns the cached prefix.
|
|
98
|
+
*/
|
|
99
|
+
export function buildResolveReminderMessage(sourceToolName: string): CustomMessage {
|
|
100
|
+
return {
|
|
101
|
+
role: "custom",
|
|
102
|
+
customType: "resolve-reminder",
|
|
103
|
+
content: [
|
|
104
|
+
"<system-reminder>",
|
|
105
|
+
"This is a preview. Call the `resolve` tool to apply or discard these changes.",
|
|
106
|
+
"</system-reminder>",
|
|
107
|
+
].join("\n"),
|
|
108
|
+
display: false,
|
|
109
|
+
details: { toolName: sourceToolName },
|
|
110
|
+
attribution: "agent",
|
|
111
|
+
timestamp: Date.now(),
|
|
112
|
+
};
|
|
91
113
|
}
|
|
92
114
|
|
|
93
115
|
/**
|
|
@@ -185,7 +207,10 @@ export class ResolveTool implements AgentTool<typeof resolveSchema, ResolveToolD
|
|
|
185
207
|
_context?: AgentToolContext,
|
|
186
208
|
): Promise<AgentToolResult<ResolveToolDetails>> {
|
|
187
209
|
return untilAborted(signal, async () => {
|
|
188
|
-
const invoker =
|
|
210
|
+
const invoker =
|
|
211
|
+
this.session.peekQueueInvoker?.() ??
|
|
212
|
+
this.session.peekPendingInvoker?.() ??
|
|
213
|
+
this.session.peekStandingResolveHandler?.();
|
|
189
214
|
if (!invoker) {
|
|
190
215
|
// `discard` is a request to cancel/abort a staged action. When nothing is
|
|
191
216
|
// pending, the desired end-state (no staged change) already holds, so honor
|
package/src/tui/output-block.ts
CHANGED
|
@@ -48,8 +48,8 @@ function normalizeContentPaddingLeft(value: number | undefined): number {
|
|
|
48
48
|
|
|
49
49
|
export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): string[] {
|
|
50
50
|
const { header, headerMeta, state, sections = [], width, applyBg = true } = options;
|
|
51
|
-
const h = theme.
|
|
52
|
-
const v = theme.
|
|
51
|
+
const h = theme.boxRound.horizontal;
|
|
52
|
+
const v = theme.boxRound.vertical;
|
|
53
53
|
const cap = h.repeat(3);
|
|
54
54
|
const lineWidth = Math.max(0, width);
|
|
55
55
|
// Border colors: running/pending use accent, success uses dim (gray), error/warning keep their colors
|
|
@@ -84,8 +84,8 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
84
84
|
const rows: BlockRow[] = [];
|
|
85
85
|
rows.push({
|
|
86
86
|
kind: "bar",
|
|
87
|
-
leftChar: theme.
|
|
88
|
-
rightChar: theme.
|
|
87
|
+
leftChar: theme.boxRound.topLeft,
|
|
88
|
+
rightChar: theme.boxRound.topRight,
|
|
89
89
|
label: header,
|
|
90
90
|
meta: headerMeta,
|
|
91
91
|
});
|
|
@@ -99,15 +99,15 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
99
99
|
if (section.label) {
|
|
100
100
|
rows.push({
|
|
101
101
|
kind: "bar",
|
|
102
|
-
leftChar: theme.
|
|
103
|
-
rightChar: theme.
|
|
102
|
+
leftChar: theme.boxRound.teeRight,
|
|
103
|
+
rightChar: theme.boxRound.teeLeft,
|
|
104
104
|
label: section.label,
|
|
105
105
|
});
|
|
106
106
|
} else if (section.separator && sectionIndex > 0) {
|
|
107
107
|
rows.push({
|
|
108
108
|
kind: "bar",
|
|
109
|
-
leftChar: theme.
|
|
110
|
-
rightChar: theme.
|
|
109
|
+
leftChar: theme.boxRound.teeRight,
|
|
110
|
+
rightChar: theme.boxRound.teeLeft,
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
113
|
const allLines = section.lines.flatMap(l => l.split("\n"));
|
|
@@ -126,7 +126,7 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
rows.push({ kind: "bottom", leftChar: theme.
|
|
129
|
+
rows.push({ kind: "bottom", leftChar: theme.boxRound.bottomLeft, rightChar: theme.boxRound.bottomRight });
|
|
130
130
|
|
|
131
131
|
const H = rows.length;
|
|
132
132
|
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Box } from "@oh-my-pi/pi-tui";
|
|
2
|
-
import type { BranchSummaryMessage } from "../../session/messages";
|
|
3
|
-
/**
|
|
4
|
-
* Component that renders a branch summary message with collapsed/expanded state.
|
|
5
|
-
* Uses same background color as hook messages for visual consistency.
|
|
6
|
-
*/
|
|
7
|
-
export declare class BranchSummaryMessageComponent extends Box {
|
|
8
|
-
#private;
|
|
9
|
-
private readonly message;
|
|
10
|
-
constructor(message: BranchSummaryMessage);
|
|
11
|
-
setExpanded(expanded: boolean): void;
|
|
12
|
-
invalidate(): void;
|
|
13
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Box, Markdown, Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
2
|
-
import { getMarkdownTheme, theme } from "../../modes/theme/theme";
|
|
3
|
-
import type { BranchSummaryMessage } from "../../session/messages";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Component that renders a branch summary message with collapsed/expanded state.
|
|
7
|
-
* Uses same background color as hook messages for visual consistency.
|
|
8
|
-
*/
|
|
9
|
-
export class BranchSummaryMessageComponent extends Box {
|
|
10
|
-
#expanded = false;
|
|
11
|
-
|
|
12
|
-
constructor(private readonly message: BranchSummaryMessage) {
|
|
13
|
-
super(1, 1, t => theme.bg("customMessageBg", t));
|
|
14
|
-
this.setIgnoreTight(true);
|
|
15
|
-
this.#updateDisplay();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
setExpanded(expanded: boolean): void {
|
|
19
|
-
this.#expanded = expanded;
|
|
20
|
-
this.#updateDisplay();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
override invalidate(): void {
|
|
24
|
-
super.invalidate();
|
|
25
|
-
this.#updateDisplay();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
#updateDisplay(): void {
|
|
29
|
-
this.clear();
|
|
30
|
-
|
|
31
|
-
const label = theme.fg("customMessageLabel", theme.bold("[branch]"));
|
|
32
|
-
this.addChild(new Text(label, 0, 0));
|
|
33
|
-
this.addChild(new Spacer(1));
|
|
34
|
-
|
|
35
|
-
if (this.#expanded) {
|
|
36
|
-
const header = "**Branch Summary**\n\n";
|
|
37
|
-
this.addChild(
|
|
38
|
-
new Markdown(header + this.message.summary, 0, 0, getMarkdownTheme(), {
|
|
39
|
-
color: (text: string) => theme.fg("customMessageText", text),
|
|
40
|
-
}),
|
|
41
|
-
);
|
|
42
|
-
} else {
|
|
43
|
-
this.addChild(new Text(theme.fg("customMessageText", "Branch summary (ctrl+o to expand)"), 0, 0));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|