@oh-my-pi/pi-coding-agent 13.3.0 → 13.3.2
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 +14 -0
- package/package.json +7 -7
- package/src/cli/config-cli.ts +32 -20
- package/src/config/settings-schema.ts +60 -10
- package/src/discovery/helpers.ts +9 -2
- package/src/modes/components/settings-defs.ts +36 -0
- package/src/modes/controllers/selector-controller.ts +25 -0
- package/src/modes/theme/defaults/dark-poimandres.json +138 -0
- package/src/modes/theme/defaults/index.ts +4 -0
- package/src/modes/theme/defaults/light-poimandres.json +138 -0
- package/src/patch/index.ts +7 -8
- package/src/sdk.ts +5 -0
- package/src/task/render.ts +20 -8
- package/src/tools/review.ts +50 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [13.3.1] - 2026-02-26
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added `topP` setting to control nucleus sampling cutoff for model output diversity
|
|
10
|
+
- Added `topK` setting to sample from top-K tokens for controlled generation
|
|
11
|
+
- Added `minP` setting to enforce minimum probability threshold for token selection
|
|
12
|
+
- Added `presencePenalty` setting to penalize introduction of already-present tokens
|
|
13
|
+
- Added `repetitionPenalty` setting to penalize repeated tokens in model output
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Fixed skill discovery to continue loading project skills when user skills directory is missing
|
|
18
|
+
|
|
5
19
|
## [13.3.0] - 2026-02-26
|
|
6
20
|
|
|
7
21
|
### Breaking Changes
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "13.3.
|
|
4
|
+
"version": "13.3.2",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/can1357/oh-my-pi",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@mozilla/readability": "^0.6",
|
|
44
|
-
"@oh-my-pi/omp-stats": "13.3.
|
|
45
|
-
"@oh-my-pi/pi-agent-core": "13.3.
|
|
46
|
-
"@oh-my-pi/pi-ai": "13.3.
|
|
47
|
-
"@oh-my-pi/pi-natives": "13.3.
|
|
48
|
-
"@oh-my-pi/pi-tui": "13.3.
|
|
49
|
-
"@oh-my-pi/pi-utils": "13.3.
|
|
44
|
+
"@oh-my-pi/omp-stats": "13.3.2",
|
|
45
|
+
"@oh-my-pi/pi-agent-core": "13.3.2",
|
|
46
|
+
"@oh-my-pi/pi-ai": "13.3.2",
|
|
47
|
+
"@oh-my-pi/pi-natives": "13.3.2",
|
|
48
|
+
"@oh-my-pi/pi-tui": "13.3.2",
|
|
49
|
+
"@oh-my-pi/pi-utils": "13.3.2",
|
|
50
50
|
"@sinclair/typebox": "^0.34",
|
|
51
51
|
"@xterm/headless": "^6.0",
|
|
52
52
|
"ajv": "^8.18",
|
package/src/cli/config-cli.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Config CLI command handlers.
|
|
3
3
|
*
|
|
4
4
|
* Handles `omp config <command>` subcommands for managing settings.
|
|
5
|
-
* Uses settings
|
|
5
|
+
* Uses the settings schema as the source of truth for available settings.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { APP_NAME, getAgentDir } from "@oh-my-pi/pi-utils";
|
|
@@ -11,12 +11,13 @@ import {
|
|
|
11
11
|
getDefault,
|
|
12
12
|
getEnumValues,
|
|
13
13
|
getType,
|
|
14
|
+
getUi,
|
|
14
15
|
type SettingPath,
|
|
15
16
|
Settings,
|
|
16
17
|
type SettingValue,
|
|
17
18
|
settings,
|
|
18
19
|
} from "../config/settings";
|
|
19
|
-
import {
|
|
20
|
+
import { SETTINGS_SCHEMA } from "../config/settings-schema";
|
|
20
21
|
import { theme } from "../modes/theme/theme";
|
|
21
22
|
|
|
22
23
|
// =============================================================================
|
|
@@ -38,21 +39,32 @@ export interface ConfigCommandArgs {
|
|
|
38
39
|
// Setting Filtering
|
|
39
40
|
// =============================================================================
|
|
40
41
|
|
|
42
|
+
type CliSettingDef = {
|
|
43
|
+
path: SettingPath;
|
|
44
|
+
type: string;
|
|
45
|
+
description: string;
|
|
46
|
+
tab: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const ALL_SETTING_PATHS = Object.keys(SETTINGS_SCHEMA) as SettingPath[];
|
|
50
|
+
|
|
41
51
|
/** Find setting definition by path */
|
|
42
|
-
function findSettingDef(path: string):
|
|
43
|
-
|
|
52
|
+
function findSettingDef(path: string): CliSettingDef | undefined {
|
|
53
|
+
if (!(path in SETTINGS_SCHEMA)) return undefined;
|
|
54
|
+
const key = path as SettingPath;
|
|
55
|
+
const ui = getUi(key);
|
|
56
|
+
return {
|
|
57
|
+
path: key,
|
|
58
|
+
type: getType(key),
|
|
59
|
+
description: ui?.description ?? "",
|
|
60
|
+
tab: ui?.tab ?? "internal",
|
|
61
|
+
};
|
|
44
62
|
}
|
|
45
63
|
|
|
46
64
|
/** Get available values for a setting */
|
|
47
|
-
function getSettingValues(def:
|
|
65
|
+
function getSettingValues(def: CliSettingDef): readonly string[] | undefined {
|
|
48
66
|
if (def.type === "enum") {
|
|
49
|
-
return def.
|
|
50
|
-
}
|
|
51
|
-
if (def.type === "submenu") {
|
|
52
|
-
const options = def.options;
|
|
53
|
-
if (options.length > 0) {
|
|
54
|
-
return options.map(o => o.value);
|
|
55
|
-
}
|
|
67
|
+
return getEnumValues(def.path);
|
|
56
68
|
}
|
|
57
69
|
return undefined;
|
|
58
70
|
}
|
|
@@ -125,7 +137,7 @@ function formatValue(value: unknown): string {
|
|
|
125
137
|
return chalk.yellow(String(value));
|
|
126
138
|
}
|
|
127
139
|
|
|
128
|
-
function getTypeDisplay(def:
|
|
140
|
+
function getTypeDisplay(def: CliSettingDef): string {
|
|
129
141
|
if (def.type === "boolean") {
|
|
130
142
|
return "(boolean)";
|
|
131
143
|
}
|
|
@@ -199,13 +211,13 @@ export async function runConfigCommand(cmd: ConfigCommandArgs): Promise<void> {
|
|
|
199
211
|
}
|
|
200
212
|
|
|
201
213
|
function handleList(flags: { json?: boolean }): void {
|
|
202
|
-
const defs =
|
|
214
|
+
const defs = ALL_SETTING_PATHS.map(path => findSettingDef(path)).filter((def): def is CliSettingDef => !!def);
|
|
203
215
|
|
|
204
216
|
if (flags.json) {
|
|
205
217
|
const result: Record<string, { value: unknown; type: string; description: string }> = {};
|
|
206
218
|
for (const def of defs) {
|
|
207
219
|
result[def.path] = {
|
|
208
|
-
value: settings.get(def.path
|
|
220
|
+
value: settings.get(def.path),
|
|
209
221
|
type: def.type,
|
|
210
222
|
description: def.description,
|
|
211
223
|
};
|
|
@@ -216,7 +228,7 @@ function handleList(flags: { json?: boolean }): void {
|
|
|
216
228
|
|
|
217
229
|
console.log(chalk.bold("Settings:\n"));
|
|
218
230
|
|
|
219
|
-
const groups: Record<string,
|
|
231
|
+
const groups: Record<string, CliSettingDef[]> = {};
|
|
220
232
|
for (const def of defs) {
|
|
221
233
|
if (!groups[def.tab]) {
|
|
222
234
|
groups[def.tab] = [];
|
|
@@ -233,7 +245,7 @@ function handleList(flags: { json?: boolean }): void {
|
|
|
233
245
|
for (const group of sortedGroups) {
|
|
234
246
|
console.log(chalk.bold.blue(`[${group}]`));
|
|
235
247
|
for (const def of groups[group]) {
|
|
236
|
-
const value = settings.get(def.path
|
|
248
|
+
const value = settings.get(def.path);
|
|
237
249
|
const valueStr = formatValue(value);
|
|
238
250
|
const typeStr = getTypeDisplay(def);
|
|
239
251
|
console.log(` ${chalk.white(def.path)} = ${valueStr} ${chalk.dim(typeStr)}`);
|
|
@@ -256,7 +268,7 @@ function handleGet(key: string | undefined, flags: { json?: boolean }): void {
|
|
|
256
268
|
process.exit(1);
|
|
257
269
|
}
|
|
258
270
|
|
|
259
|
-
const value = settings.get(def.path
|
|
271
|
+
const value = settings.get(def.path);
|
|
260
272
|
|
|
261
273
|
if (flags.json) {
|
|
262
274
|
console.log(JSON.stringify({ key: def.path, value, type: def.type, description: def.description }, null, 2));
|
|
@@ -281,13 +293,13 @@ async function handleSet(key: string | undefined, value: string | undefined, fla
|
|
|
281
293
|
}
|
|
282
294
|
|
|
283
295
|
try {
|
|
284
|
-
parseAndSetValue(def.path
|
|
296
|
+
parseAndSetValue(def.path, value);
|
|
285
297
|
} catch (err) {
|
|
286
298
|
console.error(chalk.red(String(err)));
|
|
287
299
|
process.exit(1);
|
|
288
300
|
}
|
|
289
301
|
|
|
290
|
-
const newValue = settings.get(def.path
|
|
302
|
+
const newValue = settings.get(def.path);
|
|
291
303
|
|
|
292
304
|
if (flags.json) {
|
|
293
305
|
console.log(JSON.stringify({ key: def.path, value: newValue }));
|
|
@@ -197,16 +197,6 @@ export const SETTINGS_SCHEMA = {
|
|
|
197
197
|
submenu: true,
|
|
198
198
|
},
|
|
199
199
|
},
|
|
200
|
-
temperature: {
|
|
201
|
-
type: "number",
|
|
202
|
-
default: -1,
|
|
203
|
-
ui: {
|
|
204
|
-
tab: "agent",
|
|
205
|
-
label: "Temperature",
|
|
206
|
-
description: "Sampling temperature (0 = deterministic, 1 = creative, -1 = provider default)",
|
|
207
|
-
submenu: true,
|
|
208
|
-
},
|
|
209
|
-
},
|
|
210
200
|
hideThinkingBlock: {
|
|
211
201
|
type: "boolean",
|
|
212
202
|
default: false,
|
|
@@ -1048,6 +1038,66 @@ export const SETTINGS_SCHEMA = {
|
|
|
1048
1038
|
"statusLine.leftSegments": { type: "array", default: [] as StatusLineSegmentId[] },
|
|
1049
1039
|
"statusLine.rightSegments": { type: "array", default: [] as StatusLineSegmentId[] },
|
|
1050
1040
|
"statusLine.segmentOptions": { type: "record", default: {} as Record<string, unknown> },
|
|
1041
|
+
temperature: {
|
|
1042
|
+
type: "number",
|
|
1043
|
+
default: -1,
|
|
1044
|
+
ui: {
|
|
1045
|
+
tab: "agent",
|
|
1046
|
+
label: "Temperature",
|
|
1047
|
+
description: "Sampling temperature (0 = deterministic, 1 = creative, -1 = provider default)",
|
|
1048
|
+
submenu: true,
|
|
1049
|
+
},
|
|
1050
|
+
},
|
|
1051
|
+
topP: {
|
|
1052
|
+
type: "number",
|
|
1053
|
+
default: -1,
|
|
1054
|
+
ui: {
|
|
1055
|
+
tab: "agent",
|
|
1056
|
+
label: "Top P",
|
|
1057
|
+
description: "Nucleus sampling cutoff (0-1, -1 = provider default)",
|
|
1058
|
+
submenu: true,
|
|
1059
|
+
},
|
|
1060
|
+
},
|
|
1061
|
+
topK: {
|
|
1062
|
+
type: "number",
|
|
1063
|
+
default: -1,
|
|
1064
|
+
ui: {
|
|
1065
|
+
tab: "agent",
|
|
1066
|
+
label: "Top K",
|
|
1067
|
+
description: "Sample from top-K tokens (-1 = provider default)",
|
|
1068
|
+
submenu: true,
|
|
1069
|
+
},
|
|
1070
|
+
},
|
|
1071
|
+
minP: {
|
|
1072
|
+
type: "number",
|
|
1073
|
+
default: -1,
|
|
1074
|
+
ui: {
|
|
1075
|
+
tab: "agent",
|
|
1076
|
+
label: "Min P",
|
|
1077
|
+
description: "Minimum probability threshold (0-1, -1 = provider default)",
|
|
1078
|
+
submenu: true,
|
|
1079
|
+
},
|
|
1080
|
+
},
|
|
1081
|
+
presencePenalty: {
|
|
1082
|
+
type: "number",
|
|
1083
|
+
default: -1,
|
|
1084
|
+
ui: {
|
|
1085
|
+
tab: "agent",
|
|
1086
|
+
label: "Presence penalty",
|
|
1087
|
+
description: "Penalty for introducing already-present tokens (-1 = provider default)",
|
|
1088
|
+
submenu: true,
|
|
1089
|
+
},
|
|
1090
|
+
},
|
|
1091
|
+
repetitionPenalty: {
|
|
1092
|
+
type: "number",
|
|
1093
|
+
default: -1,
|
|
1094
|
+
ui: {
|
|
1095
|
+
tab: "agent",
|
|
1096
|
+
label: "Repetition penalty",
|
|
1097
|
+
description: "Penalty for repeated tokens (-1 = provider default)",
|
|
1098
|
+
submenu: true,
|
|
1099
|
+
},
|
|
1100
|
+
},
|
|
1051
1101
|
} as const;
|
|
1052
1102
|
|
|
1053
1103
|
// ═══════════════════════════════════════════════════════════════════════════
|
package/src/discovery/helpers.ts
CHANGED
|
@@ -284,8 +284,15 @@ export async function scanSkillsFromDir(
|
|
|
284
284
|
const warnings: string[] = [];
|
|
285
285
|
const { dir, level, providerId, requireDescription = false } = options;
|
|
286
286
|
|
|
287
|
-
|
|
288
|
-
|
|
287
|
+
let entries: fs.Dirent[];
|
|
288
|
+
try {
|
|
289
|
+
entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
290
|
+
} catch (error) {
|
|
291
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
292
|
+
warnings.push(`Failed to read skills directory: ${dir} (${String(error)})`);
|
|
293
|
+
}
|
|
294
|
+
return { items, warnings };
|
|
295
|
+
}
|
|
289
296
|
const loadSkill = async (skillPath: string) => {
|
|
290
297
|
try {
|
|
291
298
|
const content = await readFile(skillPath);
|
|
@@ -214,6 +214,42 @@ const OPTION_PROVIDERS: Partial<Record<SettingPath, OptionProvider>> = {
|
|
|
214
214
|
{ value: "0.7", label: "0.7", description: "Creative" },
|
|
215
215
|
{ value: "1", label: "1", description: "Maximum variety" },
|
|
216
216
|
],
|
|
217
|
+
topP: [
|
|
218
|
+
{ value: "-1", label: "Default", description: "Use provider default" },
|
|
219
|
+
{ value: "0.1", label: "0.1", description: "Very focused" },
|
|
220
|
+
{ value: "0.3", label: "0.3", description: "Focused" },
|
|
221
|
+
{ value: "0.5", label: "0.5", description: "Balanced" },
|
|
222
|
+
{ value: "0.9", label: "0.9", description: "Broad" },
|
|
223
|
+
{ value: "1", label: "1", description: "No nucleus filtering" },
|
|
224
|
+
],
|
|
225
|
+
topK: [
|
|
226
|
+
{ value: "-1", label: "Default", description: "Use provider default" },
|
|
227
|
+
{ value: "1", label: "1", description: "Greedy top token" },
|
|
228
|
+
{ value: "20", label: "20", description: "Focused" },
|
|
229
|
+
{ value: "40", label: "40", description: "Balanced" },
|
|
230
|
+
{ value: "100", label: "100", description: "Broad" },
|
|
231
|
+
],
|
|
232
|
+
minP: [
|
|
233
|
+
{ value: "-1", label: "Default", description: "Use provider default" },
|
|
234
|
+
{ value: "0.01", label: "0.01", description: "Very permissive" },
|
|
235
|
+
{ value: "0.05", label: "0.05", description: "Balanced" },
|
|
236
|
+
{ value: "0.1", label: "0.1", description: "Strict" },
|
|
237
|
+
],
|
|
238
|
+
presencePenalty: [
|
|
239
|
+
{ value: "-1", label: "Default", description: "Use provider default" },
|
|
240
|
+
{ value: "0", label: "0", description: "No penalty" },
|
|
241
|
+
{ value: "0.5", label: "0.5", description: "Mild novelty" },
|
|
242
|
+
{ value: "1", label: "1", description: "Encourage novelty" },
|
|
243
|
+
{ value: "2", label: "2", description: "Strong novelty" },
|
|
244
|
+
],
|
|
245
|
+
repetitionPenalty: [
|
|
246
|
+
{ value: "-1", label: "Default", description: "Use provider default" },
|
|
247
|
+
{ value: "0.8", label: "0.8", description: "Allow repetition" },
|
|
248
|
+
{ value: "1", label: "1", description: "No penalty" },
|
|
249
|
+
{ value: "1.1", label: "1.1", description: "Mild penalty" },
|
|
250
|
+
{ value: "1.2", label: "1.2", description: "Balanced" },
|
|
251
|
+
{ value: "1.5", label: "1.5", description: "Strong penalty" },
|
|
252
|
+
],
|
|
217
253
|
// Symbol preset
|
|
218
254
|
symbolPreset: [
|
|
219
255
|
{ value: "unicode", label: "Unicode", description: "Standard symbols (default)" },
|
|
@@ -288,6 +288,31 @@ export class SelectorController {
|
|
|
288
288
|
this.ctx.session.agent.temperature = temp >= 0 ? temp : undefined;
|
|
289
289
|
break;
|
|
290
290
|
}
|
|
291
|
+
case "topP": {
|
|
292
|
+
const topP = typeof value === "number" ? value : Number(value);
|
|
293
|
+
this.ctx.session.agent.topP = topP >= 0 ? topP : undefined;
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
case "topK": {
|
|
297
|
+
const topK = typeof value === "number" ? value : Number(value);
|
|
298
|
+
this.ctx.session.agent.topK = topK >= 0 ? topK : undefined;
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
case "minP": {
|
|
302
|
+
const minP = typeof value === "number" ? value : Number(value);
|
|
303
|
+
this.ctx.session.agent.minP = minP >= 0 ? minP : undefined;
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
case "presencePenalty": {
|
|
307
|
+
const presencePenalty = typeof value === "number" ? value : Number(value);
|
|
308
|
+
this.ctx.session.agent.presencePenalty = presencePenalty >= 0 ? presencePenalty : undefined;
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
case "repetitionPenalty": {
|
|
312
|
+
const repetitionPenalty = typeof value === "number" ? value : Number(value);
|
|
313
|
+
this.ctx.session.agent.repetitionPenalty = repetitionPenalty >= 0 ? repetitionPenalty : undefined;
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
291
316
|
case "statusLinePreset":
|
|
292
317
|
case "statusLineSeparator":
|
|
293
318
|
case "statusLineShowHooks":
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dark-poimandres",
|
|
3
|
+
"vars": {
|
|
4
|
+
"poimandresBg": "#1b1e28",
|
|
5
|
+
"poimandresFocus": "#303340",
|
|
6
|
+
"poimandresGray": "#a6accd",
|
|
7
|
+
"poimandresDarkerGray": "#767c9d",
|
|
8
|
+
"poimandresBluishGray": "#506477",
|
|
9
|
+
"poimandresOffWhite": "#e4f0fb",
|
|
10
|
+
"poimandresBrightMint": "#5DE4c7",
|
|
11
|
+
"poimandresStrongTurquoise": "#00CED1",
|
|
12
|
+
"poimandresLowerMint": "#5fb3a1",
|
|
13
|
+
"poimandresLightBlue": "#ADD7FF",
|
|
14
|
+
"poimandresLowerBlue": "#89ddff",
|
|
15
|
+
"poimandresDesaturatedGreen": "#7AC6B6",
|
|
16
|
+
"poimandresHotRed": "#d0679d",
|
|
17
|
+
"poimandresPink": "#f087bd",
|
|
18
|
+
"poimandresBrightYellow": "#fffac2",
|
|
19
|
+
"poimandresBluishGrayBrighter": "#7390AA",
|
|
20
|
+
"poimandresSelection": "#717cb425",
|
|
21
|
+
"poimandresWhite": "#ffffff",
|
|
22
|
+
"poimandresBlack": "#000000",
|
|
23
|
+
"poimandresBg256": 235,
|
|
24
|
+
"poimandresFocus256": 238,
|
|
25
|
+
"poimandresGray256": 109,
|
|
26
|
+
"poimandresDarkerGray256": 103,
|
|
27
|
+
"poimandresBluishGray256": 66,
|
|
28
|
+
"poimandresBrightMint256": 86,
|
|
29
|
+
"poimandresStrongTurquoise256": 44,
|
|
30
|
+
"poimandresLowerMint256": 79,
|
|
31
|
+
"poimandresLightBlue256": 153,
|
|
32
|
+
"poimandresLowerBlue256": 117,
|
|
33
|
+
"poimandresDesaturatedGreen256": 79,
|
|
34
|
+
"poimandresHotRed256": 169,
|
|
35
|
+
"poimandresPink256": 211,
|
|
36
|
+
"poimandresBrightYellow256": 229,
|
|
37
|
+
"poimandresBluishGrayBrighter256": 110,
|
|
38
|
+
"poimandresSubtleBg": "#1b1e28",
|
|
39
|
+
"poimandresMediumBg": "#23273a",
|
|
40
|
+
"poimandresBrightBg": "#303340"
|
|
41
|
+
},
|
|
42
|
+
"colors": {
|
|
43
|
+
"accent": "poimandresStrongTurquoise",
|
|
44
|
+
"border": "poimandresBluishGray",
|
|
45
|
+
"borderAccent": "poimandresDarkerGray",
|
|
46
|
+
"borderMuted": "poimandresBluishGray",
|
|
47
|
+
"success": "poimandresStrongTurquoise",
|
|
48
|
+
"error": "poimandresHotRed",
|
|
49
|
+
"warning": "poimandresBrightYellow",
|
|
50
|
+
"muted": "poimandresDarkerGray",
|
|
51
|
+
"dim": "poimandresBluishGray",
|
|
52
|
+
"text": "poimandresGray",
|
|
53
|
+
"thinkingText": "poimandresDarkerGray",
|
|
54
|
+
"selectedBg": "poimandresSelection",
|
|
55
|
+
"userMessageBg": "poimandresFocus",
|
|
56
|
+
"userMessageText": "poimandresWhite",
|
|
57
|
+
"customMessageBg": "poimandresFocus",
|
|
58
|
+
"customMessageText": "poimandresWhite",
|
|
59
|
+
"customMessageLabel": "poimandresStrongTurquoise",
|
|
60
|
+
"toolPendingBg": "poimandresFocus",
|
|
61
|
+
"toolSuccessBg": "poimandresMediumBg",
|
|
62
|
+
"toolErrorBg": "poimandresFocus",
|
|
63
|
+
"toolTitle": "poimandresBrightMint",
|
|
64
|
+
"toolOutput": "poimandresDarkerGray",
|
|
65
|
+
"mdHeading": "poimandresBrightMint",
|
|
66
|
+
"mdLink": "poimandresDesaturatedGreen",
|
|
67
|
+
"mdLinkUrl": "poimandresStrongTurquoise",
|
|
68
|
+
"mdCode": "poimandresStrongTurquoise",
|
|
69
|
+
"mdCodeBlock": "poimandresGray",
|
|
70
|
+
"mdCodeBlockBorder": "poimandresBluishGray",
|
|
71
|
+
"mdQuote": "poimandresDarkerGray",
|
|
72
|
+
"mdQuoteBorder": "poimandresBluishGray",
|
|
73
|
+
"mdHr": "poimandresDarkerGray",
|
|
74
|
+
"mdListBullet": "poimandresBrightMint",
|
|
75
|
+
"toolDiffAdded": "poimandresStrongTurquoise",
|
|
76
|
+
"toolDiffRemoved": "poimandresHotRed",
|
|
77
|
+
"toolDiffContext": "poimandresDarkerGray",
|
|
78
|
+
"syntaxComment": "poimandresDarkerGray",
|
|
79
|
+
"syntaxKeyword": "poimandresDesaturatedGreen",
|
|
80
|
+
"syntaxFunction": "poimandresBrightMint",
|
|
81
|
+
"syntaxVariable": "poimandresStrongTurquoise",
|
|
82
|
+
"syntaxString": "poimandresStrongTurquoise",
|
|
83
|
+
"syntaxNumber": "poimandresPink",
|
|
84
|
+
"syntaxType": "poimandresStrongTurquoise",
|
|
85
|
+
"syntaxOperator": "poimandresDesaturatedGreen",
|
|
86
|
+
"syntaxPunctuation": "poimandresGray",
|
|
87
|
+
"thinkingOff": "poimandresBluishGray",
|
|
88
|
+
"thinkingMinimal": "poimandresDarkerGray",
|
|
89
|
+
"thinkingLow": "poimandresBrightMint",
|
|
90
|
+
"thinkingMedium": "poimandresStrongTurquoise",
|
|
91
|
+
"thinkingHigh": "poimandresPink",
|
|
92
|
+
"thinkingXhigh": "poimandresHotRed",
|
|
93
|
+
"bashMode": "poimandresDesaturatedGreen",
|
|
94
|
+
"pythonMode": "poimandresStrongTurquoise",
|
|
95
|
+
"statusLineBg": "poimandresFocus",
|
|
96
|
+
"statusLineSep": 66,
|
|
97
|
+
"statusLineModel": "poimandresBrightMint",
|
|
98
|
+
"statusLinePath": "poimandresGray",
|
|
99
|
+
"statusLineGitClean": "poimandresStrongTurquoise",
|
|
100
|
+
"statusLineGitDirty": "poimandresHotRed",
|
|
101
|
+
"statusLineContext": "poimandresDarkerGray",
|
|
102
|
+
"statusLineSpend": "poimandresLowerMint",
|
|
103
|
+
"statusLineStaged": 44,
|
|
104
|
+
"statusLineDirty": 169,
|
|
105
|
+
"statusLineUntracked": 229,
|
|
106
|
+
"statusLineOutput": "poimandresLowerBlue",
|
|
107
|
+
"statusLineCost": "poimandresPink",
|
|
108
|
+
"statusLineSubagents": "poimandresDesaturatedGreen"
|
|
109
|
+
},
|
|
110
|
+
"export": {
|
|
111
|
+
"pageBg": "poimandresBg",
|
|
112
|
+
"cardBg": "poimandresFocus",
|
|
113
|
+
"infoBg": "poimandresFocus"
|
|
114
|
+
},
|
|
115
|
+
"symbols": {
|
|
116
|
+
"preset": "nerd",
|
|
117
|
+
"overrides": {
|
|
118
|
+
"status.success": "●",
|
|
119
|
+
"status.error": "✖",
|
|
120
|
+
"status.warning": "◆",
|
|
121
|
+
"status.info": "○",
|
|
122
|
+
"status.pending": "◌",
|
|
123
|
+
"nav.cursor": "▸",
|
|
124
|
+
"nav.selected": "▴",
|
|
125
|
+
"thinking.minimal": "◌",
|
|
126
|
+
"thinking.low": "◍",
|
|
127
|
+
"thinking.medium": "◎",
|
|
128
|
+
"thinking.high": "◉",
|
|
129
|
+
"thinking.xhigh": "●",
|
|
130
|
+
"icon.model": "◇",
|
|
131
|
+
"icon.plan": "◈",
|
|
132
|
+
"icon.folder": "▸",
|
|
133
|
+
"icon.pi": "π",
|
|
134
|
+
"format.bullet": "◦",
|
|
135
|
+
"md.bullet": "◦"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -27,6 +27,7 @@ import dark_nebula from "./dark-nebula.json" with { type: "json" };
|
|
|
27
27
|
import dark_nord from "./dark-nord.json" with { type: "json" };
|
|
28
28
|
import dark_ocean from "./dark-ocean.json" with { type: "json" };
|
|
29
29
|
import dark_one from "./dark-one.json" with { type: "json" };
|
|
30
|
+
import dark_poimandres from "./dark-poimandres.json" with { type: "json" };
|
|
30
31
|
import dark_rainforest from "./dark-rainforest.json" with { type: "json" };
|
|
31
32
|
import dark_reef from "./dark-reef.json" with { type: "json" };
|
|
32
33
|
import dark_retro from "./dark-retro.json" with { type: "json" };
|
|
@@ -73,6 +74,7 @@ import light_one from "./light-one.json" with { type: "json" };
|
|
|
73
74
|
import light_opal from "./light-opal.json" with { type: "json" };
|
|
74
75
|
import light_orchard from "./light-orchard.json" with { type: "json" };
|
|
75
76
|
import light_paper from "./light-paper.json" with { type: "json" };
|
|
77
|
+
import light_poimandres from "./light-poimandres.json" with { type: "json" };
|
|
76
78
|
import light_prism from "./light-prism.json" with { type: "json" };
|
|
77
79
|
import light_retro from "./light-retro.json" with { type: "json" };
|
|
78
80
|
import light_sand from "./light-sand.json" with { type: "json" };
|
|
@@ -125,6 +127,7 @@ export const defaultThemes = {
|
|
|
125
127
|
"dark-nord": dark_nord,
|
|
126
128
|
"dark-ocean": dark_ocean,
|
|
127
129
|
"dark-one": dark_one,
|
|
130
|
+
"dark-poimandres": dark_poimandres,
|
|
128
131
|
"dark-rainforest": dark_rainforest,
|
|
129
132
|
"dark-reef": dark_reef,
|
|
130
133
|
"dark-retro": dark_retro,
|
|
@@ -171,6 +174,7 @@ export const defaultThemes = {
|
|
|
171
174
|
"light-opal": light_opal,
|
|
172
175
|
"light-orchard": light_orchard,
|
|
173
176
|
"light-paper": light_paper,
|
|
177
|
+
"light-poimandres": light_poimandres,
|
|
174
178
|
"light-prism": light_prism,
|
|
175
179
|
"light-retro": light_retro,
|
|
176
180
|
"light-sand": light_sand,
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "light-poimandres",
|
|
3
|
+
"vars": {
|
|
4
|
+
"poimandresBg": "#e4f0fb",
|
|
5
|
+
"poimandresFocus": "#303340",
|
|
6
|
+
"poimandresGray": "#a6accd",
|
|
7
|
+
"poimandresDarkerGray": "#767c9d",
|
|
8
|
+
"poimandresBluishGray": "#506477",
|
|
9
|
+
"poimandresOffWhite": "#e4f0fb",
|
|
10
|
+
"poimandresBrightMint": "#5DE4c7",
|
|
11
|
+
"poimandresStrongTurquoise": "#00CED1",
|
|
12
|
+
"poimandresLowerMint": "#5fb3a1",
|
|
13
|
+
"poimandresLightBlue": "#ADD7FF",
|
|
14
|
+
"poimandresLowerBlue": "#89ddff",
|
|
15
|
+
"poimandresDesaturatedGreen": "#7AC6B6",
|
|
16
|
+
"poimandresHotRed": "#d0679d",
|
|
17
|
+
"poimandresPink": "#f087bd",
|
|
18
|
+
"poimandresBrightYellow": "#fffac2",
|
|
19
|
+
"poimandresBluishGrayBrighter": "#7390AA",
|
|
20
|
+
"poimandresSelection": "#717cb425",
|
|
21
|
+
"poimandresWhite": "#ffffff",
|
|
22
|
+
"poimandresBlack": "#000000",
|
|
23
|
+
"poimandresBg256": 235,
|
|
24
|
+
"poimandresFocus256": 238,
|
|
25
|
+
"poimandresGray256": 109,
|
|
26
|
+
"poimandresDarkerGray256": 103,
|
|
27
|
+
"poimandresBluishGray256": 66,
|
|
28
|
+
"poimandresBrightMint256": 86,
|
|
29
|
+
"poimandresStrongTurquoise256": 44,
|
|
30
|
+
"poimandresLowerMint256": 79,
|
|
31
|
+
"poimandresLightBlue256": 153,
|
|
32
|
+
"poimandresLowerBlue256": 117,
|
|
33
|
+
"poimandresDesaturatedGreen256": 79,
|
|
34
|
+
"poimandresHotRed256": 169,
|
|
35
|
+
"poimandresPink256": 211,
|
|
36
|
+
"poimandresBrightYellow256": 229,
|
|
37
|
+
"poimandresBluishGrayBrighter256": 110,
|
|
38
|
+
"poimandresSubtleBg": "#e4f0fb",
|
|
39
|
+
"poimandresMediumBg": "#d0d7e5",
|
|
40
|
+
"poimandresBrightBg": "#7390AA"
|
|
41
|
+
},
|
|
42
|
+
"colors": {
|
|
43
|
+
"accent": "poimandresStrongTurquoise",
|
|
44
|
+
"border": "poimandresDarkerGray",
|
|
45
|
+
"borderAccent": "poimandresBluishGray",
|
|
46
|
+
"borderMuted": "poimandresDarkerGray",
|
|
47
|
+
"success": "poimandresStrongTurquoise",
|
|
48
|
+
"error": "poimandresHotRed",
|
|
49
|
+
"warning": "poimandresBrightYellow",
|
|
50
|
+
"muted": "poimandresBluishGray",
|
|
51
|
+
"dim": "poimandresDarkerGray",
|
|
52
|
+
"text": "poimandresBluishGray",
|
|
53
|
+
"thinkingText": "poimandresBluishGray",
|
|
54
|
+
"selectedBg": "poimandresSelection",
|
|
55
|
+
"userMessageBg": "poimandresBluishGrayBrighter",
|
|
56
|
+
"userMessageText": "poimandresWhite",
|
|
57
|
+
"customMessageBg": "poimandresGray",
|
|
58
|
+
"customMessageText": "poimandresWhite",
|
|
59
|
+
"customMessageLabel": "poimandresStrongTurquoise",
|
|
60
|
+
"toolPendingBg": "poimandresBluishGrayBrighter",
|
|
61
|
+
"toolSuccessBg": "poimandresBluishGrayBrighter",
|
|
62
|
+
"toolErrorBg": "poimandresBluishGrayBrighter",
|
|
63
|
+
"toolTitle": "poimandresBrightMint",
|
|
64
|
+
"toolOutput": "poimandresBluishGray",
|
|
65
|
+
"mdHeading": "poimandresBrightMint",
|
|
66
|
+
"mdLink": "poimandresDesaturatedGreen",
|
|
67
|
+
"mdLinkUrl": "poimandresStrongTurquoise",
|
|
68
|
+
"mdCode": "poimandresStrongTurquoise",
|
|
69
|
+
"mdCodeBlock": "poimandresBluishGray",
|
|
70
|
+
"mdCodeBlockBorder": "poimandresGray",
|
|
71
|
+
"mdQuote": "poimandresDarkerGray",
|
|
72
|
+
"mdQuoteBorder": "poimandresBluishGray",
|
|
73
|
+
"mdHr": "poimandresDarkerGray",
|
|
74
|
+
"mdListBullet": "poimandresBrightMint",
|
|
75
|
+
"toolDiffAdded": "poimandresStrongTurquoise",
|
|
76
|
+
"toolDiffRemoved": "poimandresHotRed",
|
|
77
|
+
"toolDiffContext": "poimandresDarkerGray",
|
|
78
|
+
"syntaxComment": "poimandresDarkerGray",
|
|
79
|
+
"syntaxKeyword": "poimandresDesaturatedGreen",
|
|
80
|
+
"syntaxFunction": "poimandresBrightMint",
|
|
81
|
+
"syntaxVariable": "poimandresStrongTurquoise",
|
|
82
|
+
"syntaxString": "poimandresStrongTurquoise",
|
|
83
|
+
"syntaxNumber": "poimandresPink",
|
|
84
|
+
"syntaxType": "poimandresStrongTurquoise",
|
|
85
|
+
"syntaxOperator": "poimandresDesaturatedGreen",
|
|
86
|
+
"syntaxPunctuation": "poimandresBluishGray",
|
|
87
|
+
"thinkingOff": "poimandresDarkerGray",
|
|
88
|
+
"thinkingMinimal": "poimandresBluishGray",
|
|
89
|
+
"thinkingLow": "poimandresBrightMint",
|
|
90
|
+
"thinkingMedium": "poimandresStrongTurquoise",
|
|
91
|
+
"thinkingHigh": "poimandresPink",
|
|
92
|
+
"thinkingXhigh": "poimandresHotRed",
|
|
93
|
+
"bashMode": "poimandresDesaturatedGreen",
|
|
94
|
+
"pythonMode": "poimandresStrongTurquoise",
|
|
95
|
+
"statusLineBg": "poimandresBluishGrayBrighter",
|
|
96
|
+
"statusLineSep": 103,
|
|
97
|
+
"statusLineModel": "poimandresBrightMint",
|
|
98
|
+
"statusLinePath": "poimandresBluishGray",
|
|
99
|
+
"statusLineGitClean": "poimandresStrongTurquoise",
|
|
100
|
+
"statusLineGitDirty": "poimandresHotRed",
|
|
101
|
+
"statusLineContext": "poimandresBluishGray",
|
|
102
|
+
"statusLineSpend": "poimandresLowerMint",
|
|
103
|
+
"statusLineStaged": 44,
|
|
104
|
+
"statusLineDirty": 169,
|
|
105
|
+
"statusLineUntracked": 229,
|
|
106
|
+
"statusLineOutput": "poimandresLowerBlue",
|
|
107
|
+
"statusLineCost": "poimandresPink",
|
|
108
|
+
"statusLineSubagents": "poimandresDesaturatedGreen"
|
|
109
|
+
},
|
|
110
|
+
"export": {
|
|
111
|
+
"pageBg": "poimandresOffWhite",
|
|
112
|
+
"cardBg": "poimandresBluishGrayBrighter",
|
|
113
|
+
"infoBg": "poimandresFocus"
|
|
114
|
+
},
|
|
115
|
+
"symbols": {
|
|
116
|
+
"preset": "nerd",
|
|
117
|
+
"overrides": {
|
|
118
|
+
"status.success": "●",
|
|
119
|
+
"status.error": "✖",
|
|
120
|
+
"status.warning": "◆",
|
|
121
|
+
"status.info": "○",
|
|
122
|
+
"status.pending": "◌",
|
|
123
|
+
"nav.cursor": "▸",
|
|
124
|
+
"nav.selected": "▴",
|
|
125
|
+
"thinking.minimal": "◌",
|
|
126
|
+
"thinking.low": "◍",
|
|
127
|
+
"thinking.medium": "◎",
|
|
128
|
+
"thinking.high": "◉",
|
|
129
|
+
"thinking.xhigh": "●",
|
|
130
|
+
"icon.model": "◇",
|
|
131
|
+
"icon.plan": "◈",
|
|
132
|
+
"icon.folder": "▸",
|
|
133
|
+
"icon.pi": "π",
|
|
134
|
+
"format.bullet": "◦",
|
|
135
|
+
"md.bullet": "◦"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
package/src/patch/index.ts
CHANGED
|
@@ -104,8 +104,8 @@ const patchEditSchema = Type.Object({
|
|
|
104
104
|
export type ReplaceParams = Static<typeof replaceEditSchema>;
|
|
105
105
|
export type PatchParams = Static<typeof patchEditSchema>;
|
|
106
106
|
|
|
107
|
-
/** Pattern matching hashline display format: `LINE#ID:CONTENT` */
|
|
108
|
-
const HASHLINE_PREFIX_RE = /^\s*(?:>>>|>>)?\s
|
|
107
|
+
/** Pattern matching hashline display format prefixes: `LINE#ID:CONTENT` and `#ID:CONTENT` */
|
|
108
|
+
const HASHLINE_PREFIX_RE = /^\s*(?:>>>|>>)?\s*(?:\d+\s*#\s*|#)\s*[0-9a-zA-Z]{1,16}:/;
|
|
109
109
|
|
|
110
110
|
/** Pattern matching a unified-diff added-line `+` prefix (but not `++`). Does NOT match `-` to avoid corrupting Markdown list items. */
|
|
111
111
|
const DIFF_PLUS_RE = /^[+](?![+])/;
|
|
@@ -118,8 +118,9 @@ const DIFF_PLUS_RE = /^[+](?![+])/;
|
|
|
118
118
|
* output file. This strips them heuristically before application.
|
|
119
119
|
*/
|
|
120
120
|
export function stripNewLinePrefixes(lines: string[]): string[] {
|
|
121
|
-
//
|
|
122
|
-
//
|
|
121
|
+
// Hashline prefixes are highly specific to read output and should only be
|
|
122
|
+
// stripped when *every* non-empty line carries one.
|
|
123
|
+
// Diff '+' markers can be legitimate content less often, so keep majority mode.
|
|
123
124
|
let hashPrefixCount = 0;
|
|
124
125
|
let diffPlusCount = 0;
|
|
125
126
|
let nonEmpty = 0;
|
|
@@ -131,9 +132,8 @@ export function stripNewLinePrefixes(lines: string[]): string[] {
|
|
|
131
132
|
}
|
|
132
133
|
if (nonEmpty === 0) return lines;
|
|
133
134
|
|
|
134
|
-
const stripHash = hashPrefixCount > 0 && hashPrefixCount
|
|
135
|
+
const stripHash = hashPrefixCount > 0 && hashPrefixCount === nonEmpty;
|
|
135
136
|
const stripPlus = !stripHash && diffPlusCount > 0 && diffPlusCount >= nonEmpty * 0.5;
|
|
136
|
-
|
|
137
137
|
if (!stripHash && !stripPlus) return lines;
|
|
138
138
|
|
|
139
139
|
return lines.map(l => {
|
|
@@ -145,8 +145,7 @@ export function stripNewLinePrefixes(lines: string[]): string[] {
|
|
|
145
145
|
|
|
146
146
|
export function hashlineParseText(edit: string[] | string | null): string[] {
|
|
147
147
|
if (edit === null) return [];
|
|
148
|
-
|
|
149
|
-
const lines = stripNewLinePrefixes(edit.split("\n"));
|
|
148
|
+
const lines = stripNewLinePrefixes(Array.isArray(edit) ? edit : edit.split("\n"));
|
|
150
149
|
if (lines.length === 0) return [];
|
|
151
150
|
if (lines[lines.length - 1].trim() === "") return lines.slice(0, -1);
|
|
152
151
|
return lines;
|
package/src/sdk.ts
CHANGED
|
@@ -1281,6 +1281,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1281
1281
|
interruptMode: settings.get("interruptMode") ?? "immediate",
|
|
1282
1282
|
thinkingBudgets: settings.getGroup("thinkingBudgets"),
|
|
1283
1283
|
temperature: settings.get("temperature") >= 0 ? settings.get("temperature") : undefined,
|
|
1284
|
+
topP: settings.get("topP") >= 0 ? settings.get("topP") : undefined,
|
|
1285
|
+
topK: settings.get("topK") >= 0 ? settings.get("topK") : undefined,
|
|
1286
|
+
minP: settings.get("minP") >= 0 ? settings.get("minP") : undefined,
|
|
1287
|
+
presencePenalty: settings.get("presencePenalty") >= 0 ? settings.get("presencePenalty") : undefined,
|
|
1288
|
+
repetitionPenalty: settings.get("repetitionPenalty") >= 0 ? settings.get("repetitionPenalty") : undefined,
|
|
1284
1289
|
kimiApiFormat: settings.get("providers.kimiApiFormat") ?? "anthropic",
|
|
1285
1290
|
preferWebsockets: preferOpenAICodexWebsockets,
|
|
1286
1291
|
getToolContext: tc => toolContextStore.getContext(tc),
|
package/src/task/render.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
type FindingPriority,
|
|
23
23
|
getPriorityInfo,
|
|
24
24
|
PRIORITY_LABELS,
|
|
25
|
+
parseReportFindingDetails,
|
|
25
26
|
type ReportFindingDetails,
|
|
26
27
|
type SubmitReviewDetails,
|
|
27
28
|
} from "../tools/review";
|
|
@@ -68,6 +69,16 @@ function formatFindingSummary(findings: ReportFindingDetails[], theme: Theme): s
|
|
|
68
69
|
return `${theme.fg("dim", "Findings:")} ${parts.join(theme.sep.dot)}`;
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
function normalizeReportFindings(value: unknown): ReportFindingDetails[] {
|
|
73
|
+
if (!Array.isArray(value)) return [];
|
|
74
|
+
const findings: ReportFindingDetails[] = [];
|
|
75
|
+
for (const item of value) {
|
|
76
|
+
const finding = parseReportFindingDetails(item);
|
|
77
|
+
if (finding) findings.push(finding);
|
|
78
|
+
}
|
|
79
|
+
return findings;
|
|
80
|
+
}
|
|
81
|
+
|
|
71
82
|
function formatJsonScalar(value: unknown, _theme: Theme): string {
|
|
72
83
|
if (value === null) return "null";
|
|
73
84
|
if (typeof value === "string") {
|
|
@@ -569,13 +580,13 @@ function renderAgentProgress(
|
|
|
569
580
|
// For completed tasks, check for review verdict from submit_result tool
|
|
570
581
|
if (progress.status === "completed") {
|
|
571
582
|
const completeData = progress.extractedToolData.submit_result as Array<{ data: unknown }> | undefined;
|
|
572
|
-
const reportFindingData = progress.extractedToolData.report_finding
|
|
583
|
+
const reportFindingData = normalizeReportFindings(progress.extractedToolData.report_finding);
|
|
573
584
|
const reviewData = completeData
|
|
574
585
|
?.map(c => c.data as SubmitReviewDetails)
|
|
575
586
|
.filter(d => d && typeof d === "object" && "overall_correctness" in d);
|
|
576
587
|
if (reviewData && reviewData.length > 0) {
|
|
577
588
|
const summary = reviewData[reviewData.length - 1];
|
|
578
|
-
const findings = reportFindingData
|
|
589
|
+
const findings = reportFindingData;
|
|
579
590
|
lines.push(...renderReviewResult(summary, findings, continuePrefix, expanded, theme));
|
|
580
591
|
return lines; // Review result handles its own rendering
|
|
581
592
|
}
|
|
@@ -583,8 +594,9 @@ function renderAgentProgress(
|
|
|
583
594
|
|
|
584
595
|
for (const [toolName, dataArray] of Object.entries(progress.extractedToolData)) {
|
|
585
596
|
// Handle report_finding with tree formatting
|
|
586
|
-
if (toolName === "report_finding"
|
|
587
|
-
const findings = dataArray
|
|
597
|
+
if (toolName === "report_finding") {
|
|
598
|
+
const findings = normalizeReportFindings(dataArray);
|
|
599
|
+
if (findings.length === 0) continue;
|
|
588
600
|
lines.push(`${continuePrefix}${formatFindingSummary(findings, theme)}`);
|
|
589
601
|
lines.push(...renderFindings(findings, continuePrefix, expanded, theme));
|
|
590
602
|
continue;
|
|
@@ -693,7 +705,7 @@ function renderFindings(
|
|
|
693
705
|
|
|
694
706
|
const { color } = getPriorityInfo(finding.priority);
|
|
695
707
|
const titleText = finding.title?.replace(/^\[P\d\]\s*/, "") ?? "Untitled";
|
|
696
|
-
const loc = `${path.basename(finding.file_path)}:${finding.line_start}`;
|
|
708
|
+
const loc = `${path.basename(finding.file_path || "<unknown>")}:${finding.line_start}`;
|
|
697
709
|
|
|
698
710
|
lines.push(
|
|
699
711
|
`${continuePrefix}${findingPrefix} ${theme.fg(color, `[${finding.priority}]`)} ${titleText} ${theme.fg("dim", loc)}`,
|
|
@@ -773,7 +785,7 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
|
|
|
773
785
|
|
|
774
786
|
// Check for review result (submit_result with review schema + report_finding)
|
|
775
787
|
const completeData = result.extractedToolData?.submit_result as Array<{ data: unknown }> | undefined;
|
|
776
|
-
const reportFindingData = result.extractedToolData?.report_finding
|
|
788
|
+
const reportFindingData = normalizeReportFindings(result.extractedToolData?.report_finding);
|
|
777
789
|
|
|
778
790
|
// Extract review verdict from submit_result tool's data field if it matches SubmitReviewDetails
|
|
779
791
|
const reviewData = completeData
|
|
@@ -784,11 +796,11 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
|
|
|
784
796
|
if (submitReviewData && submitReviewData.length > 0) {
|
|
785
797
|
// Use combined review renderer
|
|
786
798
|
const summary = submitReviewData[submitReviewData.length - 1];
|
|
787
|
-
const findings = reportFindingData
|
|
799
|
+
const findings = reportFindingData;
|
|
788
800
|
lines.push(...renderReviewResult(summary, findings, continuePrefix, expanded, theme));
|
|
789
801
|
return lines;
|
|
790
802
|
}
|
|
791
|
-
if (reportFindingData
|
|
803
|
+
if (reportFindingData.length > 0) {
|
|
792
804
|
const hasCompleteData = completeData && completeData.length > 0;
|
|
793
805
|
const message = hasCompleteData
|
|
794
806
|
? "Review verdict missing expected fields"
|
package/src/tools/review.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
|
13
13
|
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
14
14
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
15
15
|
import { Container, Text } from "@oh-my-pi/pi-tui";
|
|
16
|
+
import { isRecord } from "@oh-my-pi/pi-utils";
|
|
16
17
|
import { Type } from "@sinclair/typebox";
|
|
17
18
|
import type { Theme, ThemeColor } from "../modes/theme/theme";
|
|
18
19
|
import { subprocessToolRegistry } from "../task/subprocess-tool-registry";
|
|
@@ -82,6 +83,51 @@ interface ReportFindingDetails {
|
|
|
82
83
|
line_end: number;
|
|
83
84
|
}
|
|
84
85
|
|
|
86
|
+
function isFindingPriority(value: unknown): value is FindingPriority {
|
|
87
|
+
return value === "P0" || value === "P1" || value === "P2" || value === "P3";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function parseReportFindingDetails(value: unknown): ReportFindingDetails | undefined {
|
|
91
|
+
if (!isRecord(value)) return undefined;
|
|
92
|
+
|
|
93
|
+
const title = typeof value.title === "string" ? value.title : undefined;
|
|
94
|
+
const body = typeof value.body === "string" ? value.body : undefined;
|
|
95
|
+
const priority = isFindingPriority(value.priority) ? value.priority : undefined;
|
|
96
|
+
const confidence =
|
|
97
|
+
typeof value.confidence === "number" &&
|
|
98
|
+
Number.isFinite(value.confidence) &&
|
|
99
|
+
value.confidence >= 0 &&
|
|
100
|
+
value.confidence <= 1
|
|
101
|
+
? value.confidence
|
|
102
|
+
: undefined;
|
|
103
|
+
const filePath = typeof value.file_path === "string" && value.file_path.length > 0 ? value.file_path : undefined;
|
|
104
|
+
const lineStart =
|
|
105
|
+
typeof value.line_start === "number" && Number.isFinite(value.line_start) ? value.line_start : undefined;
|
|
106
|
+
const lineEnd = typeof value.line_end === "number" && Number.isFinite(value.line_end) ? value.line_end : undefined;
|
|
107
|
+
|
|
108
|
+
if (
|
|
109
|
+
title === undefined ||
|
|
110
|
+
body === undefined ||
|
|
111
|
+
priority === undefined ||
|
|
112
|
+
confidence === undefined ||
|
|
113
|
+
filePath === undefined ||
|
|
114
|
+
lineStart === undefined ||
|
|
115
|
+
lineEnd === undefined
|
|
116
|
+
) {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
title,
|
|
122
|
+
body,
|
|
123
|
+
priority,
|
|
124
|
+
confidence,
|
|
125
|
+
file_path: filePath,
|
|
126
|
+
line_start: lineStart,
|
|
127
|
+
line_end: lineEnd,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
85
131
|
export const reportFindingTool: AgentTool<typeof ReportFindingParams, ReportFindingDetails, Theme> = {
|
|
86
132
|
name: "report_finding",
|
|
87
133
|
label: "Report Finding",
|
|
@@ -152,7 +198,10 @@ export type { ReportFindingDetails };
|
|
|
152
198
|
|
|
153
199
|
// Register report_finding handler
|
|
154
200
|
subprocessToolRegistry.register<ReportFindingDetails>("report_finding", {
|
|
155
|
-
extractData: event =>
|
|
201
|
+
extractData: event => {
|
|
202
|
+
if (event.isError) return undefined;
|
|
203
|
+
return parseReportFindingDetails(event.result?.details);
|
|
204
|
+
},
|
|
156
205
|
|
|
157
206
|
renderInline: (data, theme) => {
|
|
158
207
|
const { label, icon, color } = getPriorityDisplay(data.priority, theme);
|