@wjarka/cezarion 0.11.2-pr60.91 → 0.11.2-pr61.92
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/dist/contract/index.js +1 -2
- package/dist/contract/workspace.d.ts +0 -14
- package/dist/core/opencode-model-catalog.d.ts +5 -5
- package/dist/core/opencode-model-catalog.js +34 -96
- package/dist/core/opencode-model-catalog.js.map +1 -1
- package/dist/core/pi-model-catalog.d.ts +0 -7
- package/dist/core/pi-model-catalog.js +26 -123
- package/dist/core/pi-model-catalog.js.map +1 -1
- package/dist/core/pi-ui-mapper.js +29 -3
- package/dist/core/pi-ui-mapper.js.map +1 -1
- package/dist/core/runner-model-catalog.d.ts +0 -2
- package/dist/core/runner-model-catalog.js.map +1 -1
- package/dist/server/server.d.ts +0 -1
- package/dist/workflows/run.d.ts +3 -0
- package/dist/workflows/run.js +48 -21
- package/dist/workflows/run.js.map +1 -1
- package/package.json +3 -3
- package/scripts/mock-pi-rpc.mjs +49 -2
- package/web/dist/assets/{alert-dialog-Bib2-aHJ.js → alert-dialog-g-GVThSw.js} +1 -1
- package/web/dist/assets/arrow-down-BzmL0uj0.js +1 -0
- package/web/dist/assets/arrow-left-DtUM7GFU.js +1 -0
- package/web/dist/assets/{centered-state-TyZe3tga.js → centered-state-DdbE_pNl.js} +1 -1
- package/web/dist/assets/chevron-right-DnLh0uM2.js +1 -0
- package/web/dist/assets/{collapsible-DTRw1YnV.js → collapsible-R1r7zUOB.js} +1 -1
- package/web/dist/assets/{commit-list-BKtzO28W.js → commit-list-Bgb1DHBX.js} +1 -1
- package/web/dist/assets/{compare-variants--E1SPJzi.js → compare-variants-DKnJOU1u.js} +1 -1
- package/web/dist/assets/{diff-DtXK3tZy.js → diff-Cv3z9esx.js} +2 -2
- package/web/dist/assets/{diff-stat-CJSJmLcb.js → diff-stat-ydfu0_5T.js} +1 -1
- package/web/dist/assets/{diff-view-wZScCPoa.js → diff-view-DnPdkmk2.js} +1 -1
- package/web/dist/assets/{dropdown-menu-CQp168wo.js → dropdown-menu-CPP9gEmn.js} +1 -1
- package/web/dist/assets/editable-title-D_bWdmY0.js +1 -0
- package/web/dist/assets/{ellipsis-vertical-BXllsyll.js → ellipsis-vertical-WNkaehnw.js} +1 -1
- package/web/dist/assets/{file-BgcgwEU-.js → file-RvhJlchx.js} +1 -1
- package/web/dist/assets/{folder-DGrkgLg9.js → folder-Dz-weqBo.js} +1 -1
- package/web/dist/assets/{git-toolbar-D9Wu2J60.js → git-toolbar-YW5Bv-c1.js} +1 -1
- package/web/dist/assets/{github-xAF2VFFK.js → github-YBpFZMf3.js} +1 -1
- package/web/dist/assets/{image-preview-Cd7b7Evu.js → image-preview-DYiOSYoY.js} +1 -1
- package/web/dist/assets/index-EgV1pTsY.js +7 -0
- package/web/dist/assets/{markdown-Cvzv-jvo.js → markdown-DQHRRO9e.js} +1 -1
- package/web/dist/assets/new-task-form-D2KlpqYC.js +1 -0
- package/web/dist/assets/{pill-B9vrSbT6.js → pill-FAFXjmY6.js} +1 -1
- package/web/dist/assets/{project-router-CF-1GU39.js → project-router-Dzc0JK2j.js} +1 -1
- package/web/dist/assets/{prompt-templates-CSmaXZ5G.js → prompt-templates-DmqtzSPL.js} +1 -1
- package/web/dist/assets/{refresh-cw-D5a-hkgq.js → refresh-cw-BP4TkA4M.js} +1 -1
- package/web/dist/assets/{repo-git-BicCjDSy.js → repo-git-Cwt6VGcW.js} +1 -1
- package/web/dist/assets/{run-diff-DWzdGMTg.js → run-diff-CvcsWwew.js} +1 -1
- package/web/dist/assets/run-header-C3B5P5qD.js +1 -0
- package/web/dist/assets/{search-x-DJIOs-nB.js → search-x-Drnmsmd0.js} +1 -1
- package/web/dist/assets/{skill-empty-hint-BcecPZ6K.js → skill-empty-hint-D2l_OqZ5.js} +1 -1
- package/web/dist/assets/skills-BWIlWIZB.js +1 -0
- package/web/dist/assets/{sparkles-C-1JzGqe.js → sparkles-B9ja4FHw.js} +1 -1
- package/web/dist/assets/{square-terminal-CnrkOecA.js → square-terminal-CB2du-YG.js} +1 -1
- package/web/dist/assets/{tab-link-CQgzNUwP.js → tab-link-C5FWJ66Y.js} +1 -1
- package/web/dist/assets/{task-changes--AyxNXvn.js → task-changes-DicvDkAm.js} +1 -1
- package/web/dist/assets/{task-commits-DlBBODPF.js → task-commits-C6o-VVhC.js} +1 -1
- package/web/dist/assets/{task-files-DZ49FGVz.js → task-files-Jd4n1rYe.js} +1 -1
- package/web/dist/assets/task-thread-ChnQQtXZ.js +9 -0
- package/web/dist/assets/{textarea-BPMIukW0.js → textarea-Sm6doUPO.js} +1 -1
- package/web/dist/assets/{thread-loading-C9cWYGbd.js → thread-loading-DojNeADh.js} +1 -1
- package/web/dist/assets/{trash-2-CwmIdbv2.js → trash-2-C_lGBXG2.js} +1 -1
- package/web/dist/assets/{triangle-alert-BU7Fnc0D.js → triangle-alert-Brk_ldFl.js} +1 -1
- package/web/dist/assets/{upload-B54t9i6X.js → upload-Cxs1UROt.js} +1 -1
- package/web/dist/assets/{use-desktop-Co7z3Xov.js → use-desktop-CVVHXF_O.js} +1 -1
- package/web/dist/assets/{use-submit-shortcut-DfJM2Y1U.js → use-submit-shortcut-DzeqN3GK.js} +1 -1
- package/web/dist/assets/{utils-BLZyueuK.js → utils-Unt0mZvU.js} +1 -1
- package/web/dist/assets/{workflows-CfC6b8y4.js → workflows-Cottripv.js} +1 -1
- package/web/dist/assets/{zoomable-image-BQMum6hd.js → zoomable-image-ByySCppM.js} +1 -1
- package/web/dist/index.html +22 -22
- package/web/dist/assets/arrow-down-DF9UfPoy.js +0 -1
- package/web/dist/assets/arrow-left-BVgebuvi.js +0 -1
- package/web/dist/assets/chevron-right-W2B4c3Bn.js +0 -1
- package/web/dist/assets/editable-title-BWosq6YG.js +0 -1
- package/web/dist/assets/index-CKWqcYjr.js +0 -7
- package/web/dist/assets/new-task-form-CZAdHx_5.js +0 -1
- package/web/dist/assets/run-header-Cc7KFOMX.js +0 -1
- package/web/dist/assets/skills-BKYATWFF.js +0 -1
- package/web/dist/assets/task-thread-D10akRi2.js +0 -9
package/dist/contract/index.js
CHANGED
|
@@ -1333,8 +1333,7 @@ function runnerDiscoversModels(runner) {
|
|
|
1333
1333
|
var runnerModelOptionSchema = z9.object({
|
|
1334
1334
|
id: z9.string(),
|
|
1335
1335
|
label: z9.string(),
|
|
1336
|
-
description: z9.string()
|
|
1337
|
-
effortLevels: z9.array(effortLevelSchema).optional()
|
|
1336
|
+
description: z9.string()
|
|
1338
1337
|
});
|
|
1339
1338
|
var runnerModelCatalogResponseSchema = z9.object({
|
|
1340
1339
|
runner: runnerSchema,
|
|
@@ -517,13 +517,6 @@ export declare const runnerModelOptionSchema: z.ZodObject<{
|
|
|
517
517
|
id: z.ZodString;
|
|
518
518
|
label: z.ZodString;
|
|
519
519
|
description: z.ZodString;
|
|
520
|
-
effortLevels: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
521
|
-
high: "high";
|
|
522
|
-
low: "low";
|
|
523
|
-
max: "max";
|
|
524
|
-
medium: "medium";
|
|
525
|
-
xhigh: "xhigh";
|
|
526
|
-
}>>>;
|
|
527
520
|
}, z.core.$strip>;
|
|
528
521
|
export type RunnerModelOption = z.infer<typeof runnerModelOptionSchema>;
|
|
529
522
|
/** `GET /api/v1/models?runner=codex|opencode|pi` — the models discovered from that runner's own
|
|
@@ -540,13 +533,6 @@ export declare const runnerModelCatalogResponseSchema: z.ZodObject<{
|
|
|
540
533
|
id: z.ZodString;
|
|
541
534
|
label: z.ZodString;
|
|
542
535
|
description: z.ZodString;
|
|
543
|
-
effortLevels: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
544
|
-
high: "high";
|
|
545
|
-
low: "low";
|
|
546
|
-
max: "max";
|
|
547
|
-
medium: "medium";
|
|
548
|
-
xhigh: "xhigh";
|
|
549
|
-
}>>>;
|
|
550
536
|
}, z.core.$strip>>;
|
|
551
537
|
source: z.ZodEnum<{
|
|
552
538
|
cache: "cache";
|
|
@@ -22,11 +22,11 @@ export declare function resolveOpencodeExecutable(bin?: string): string;
|
|
|
22
22
|
*/
|
|
23
23
|
export declare function discoverOpencodeModels(options: OpencodeModelDiscoveryOptions): Promise<ModelOption[]>;
|
|
24
24
|
/**
|
|
25
|
-
* Turn `opencode models
|
|
26
|
-
* Each model id starts a segment whose remaining lines are its JSON metadata. Invalid metadata is
|
|
27
|
-
* isolated to that model: the id remains usable and the cockpit applies its per-model fallback.
|
|
25
|
+
* Turn `opencode models` output into picker options, preserving OpenCode's own order.
|
|
28
26
|
*
|
|
29
|
-
* Empty output is a legitimate answer (no provider configured yet) and yields no models
|
|
30
|
-
* that contains lines but NO recognizable id is treated as a
|
|
27
|
+
* Empty output is a legitimate answer (no provider configured yet) and yields no models, so the
|
|
28
|
+
* picker shows `auto` alone. Output that contains lines but NO recognizable id is treated as a
|
|
29
|
+
* failure instead: the CLI said something we cannot read, and reporting "unavailable" is more
|
|
30
|
+
* honest than an empty catalog that looks like "you have no models".
|
|
31
31
|
*/
|
|
32
32
|
export declare function parseOpencodeModels(stdout: string): ModelOption[];
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { spawn as nodeSpawn } from 'node:child_process';
|
|
2
|
-
import { effortLevelSchema } from '../contract/index.js';
|
|
3
2
|
import { trackChildExit } from './agent-runner.js';
|
|
4
3
|
import { buildChildEnv } from './agent-env.js';
|
|
5
4
|
const DEFAULT_DISCOVERY_TIMEOUT_MS = 10_000;
|
|
@@ -33,69 +32,50 @@ export function resolveOpencodeExecutable(bin) {
|
|
|
33
32
|
*/
|
|
34
33
|
export async function discoverOpencodeModels(options) {
|
|
35
34
|
const bin = resolveOpencodeExecutable(options.bin);
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
try {
|
|
39
|
-
return await runOpencodeProbe(bin, ['models', '--verbose'], options.cwd, spawn, deadline);
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
if (!(error instanceof OpencodeNonzeroExitError) || Date.now() >= deadline)
|
|
43
|
-
throw error;
|
|
44
|
-
// Older OpenCode releases know `models` but not `--verbose`. Preserve their existing model
|
|
45
|
-
// picker and let every model use the cockpit's metadata fallback.
|
|
46
|
-
return runOpencodeProbe(bin, ['models'], options.cwd, spawn, deadline);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
class OpencodeNonzeroExitError extends Error {
|
|
50
|
-
}
|
|
51
|
-
async function runOpencodeProbe(bin, args, cwd, spawn, deadline) {
|
|
52
|
-
const child = spawn(bin, args, cwd);
|
|
35
|
+
const args = ['models'];
|
|
36
|
+
const child = (options.spawn ?? spawnOpencode)(bin, args, options.cwd);
|
|
53
37
|
const kill = teardown(child);
|
|
38
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_DISCOVERY_TIMEOUT_MS;
|
|
54
39
|
let timeout;
|
|
55
40
|
try {
|
|
56
|
-
|
|
41
|
+
return await new Promise((resolve, reject) => {
|
|
57
42
|
let stdout = '';
|
|
58
|
-
let
|
|
59
|
-
const fail = (
|
|
60
|
-
|
|
61
|
-
return;
|
|
62
|
-
settled = true;
|
|
63
|
-
reject(error);
|
|
43
|
+
let overflowed = false;
|
|
44
|
+
const fail = (message) => {
|
|
45
|
+
reject(new Error(message));
|
|
64
46
|
kill();
|
|
65
47
|
};
|
|
66
|
-
timeout = setTimeout(() => fail(
|
|
48
|
+
timeout = setTimeout(() => fail('OpenCode model discovery timed out'), timeoutMs);
|
|
67
49
|
timeout.unref?.();
|
|
68
50
|
child.stdout.setEncoding('utf8');
|
|
69
51
|
child.stdout.on('data', (chunk) => {
|
|
70
|
-
if (
|
|
52
|
+
if (overflowed)
|
|
71
53
|
return;
|
|
72
54
|
stdout += chunk;
|
|
73
55
|
if (stdout.length > MAX_OUTPUT_CHARS) {
|
|
74
|
-
|
|
56
|
+
overflowed = true;
|
|
57
|
+
fail('OpenCode model discovery exceeded the output limit');
|
|
75
58
|
}
|
|
76
59
|
});
|
|
60
|
+
// Drained but ignored: OpenCode prints provider warnings here, and an unread pipe would
|
|
61
|
+
// eventually stall the child.
|
|
77
62
|
child.stderr.resume();
|
|
78
|
-
child.
|
|
79
|
-
child.once('error', () => fail(new Error('OpenCode model discovery child failed')));
|
|
63
|
+
child.once('error', () => fail('OpenCode model discovery child failed'));
|
|
80
64
|
child.once('close', (code) => {
|
|
81
|
-
if (
|
|
65
|
+
if (overflowed)
|
|
82
66
|
return;
|
|
83
67
|
if (code !== 0) {
|
|
84
|
-
fail(
|
|
68
|
+
fail(`OpenCode model discovery child exited (${code ?? 'unknown'})`);
|
|
85
69
|
return;
|
|
86
70
|
}
|
|
87
71
|
try {
|
|
88
|
-
|
|
89
|
-
settled = true;
|
|
90
|
-
resolve(models);
|
|
72
|
+
resolve(parseOpencodeModels(stdout));
|
|
91
73
|
}
|
|
92
74
|
catch (error) {
|
|
93
|
-
|
|
75
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
94
76
|
}
|
|
95
77
|
});
|
|
96
78
|
});
|
|
97
|
-
child.stdin.end();
|
|
98
|
-
return await result;
|
|
99
79
|
}
|
|
100
80
|
finally {
|
|
101
81
|
if (timeout)
|
|
@@ -104,12 +84,12 @@ async function runOpencodeProbe(bin, args, cwd, spawn, deadline) {
|
|
|
104
84
|
}
|
|
105
85
|
}
|
|
106
86
|
/**
|
|
107
|
-
* Turn `opencode models
|
|
108
|
-
* Each model id starts a segment whose remaining lines are its JSON metadata. Invalid metadata is
|
|
109
|
-
* isolated to that model: the id remains usable and the cockpit applies its per-model fallback.
|
|
87
|
+
* Turn `opencode models` output into picker options, preserving OpenCode's own order.
|
|
110
88
|
*
|
|
111
|
-
* Empty output is a legitimate answer (no provider configured yet) and yields no models
|
|
112
|
-
* that contains lines but NO recognizable id is treated as a
|
|
89
|
+
* Empty output is a legitimate answer (no provider configured yet) and yields no models, so the
|
|
90
|
+
* picker shows `auto` alone. Output that contains lines but NO recognizable id is treated as a
|
|
91
|
+
* failure instead: the CLI said something we cannot read, and reporting "unavailable" is more
|
|
92
|
+
* honest than an empty catalog that looks like "you have no models".
|
|
113
93
|
*/
|
|
114
94
|
export function parseOpencodeModels(stdout) {
|
|
115
95
|
const lines = stdout
|
|
@@ -117,73 +97,31 @@ export function parseOpencodeModels(stdout) {
|
|
|
117
97
|
.split('\n')
|
|
118
98
|
.map((line) => line.trim())
|
|
119
99
|
.filter((line) => line.length > 0);
|
|
120
|
-
const segments = [];
|
|
121
|
-
let current;
|
|
122
|
-
for (const line of lines) {
|
|
123
|
-
if (MODEL_LINE_RE.test(line)) {
|
|
124
|
-
current = { id: line, metadata: [] };
|
|
125
|
-
segments.push(current);
|
|
126
|
-
}
|
|
127
|
-
else if (current) {
|
|
128
|
-
current.metadata.push(line);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
100
|
const models = [];
|
|
132
|
-
const
|
|
133
|
-
for (const
|
|
134
|
-
|
|
135
|
-
const existingIndex = indexes.get(segment.id);
|
|
136
|
-
if (existingIndex !== undefined) {
|
|
137
|
-
const existing = models[existingIndex];
|
|
138
|
-
if (!existing.effortLevels && effortLevels) {
|
|
139
|
-
models[existingIndex] = { ...existing, effortLevels };
|
|
140
|
-
}
|
|
101
|
+
const ids = new Set();
|
|
102
|
+
for (const line of lines) {
|
|
103
|
+
if (!MODEL_LINE_RE.test(line) || ids.has(line))
|
|
141
104
|
continue;
|
|
142
|
-
}
|
|
143
105
|
if (models.length >= MAX_MODELS)
|
|
144
106
|
throw new Error('OpenCode model discovery exceeded the size limit');
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
models.push({
|
|
148
|
-
id: segment.id,
|
|
149
|
-
label: segment.id,
|
|
150
|
-
description: `via ${provider}`,
|
|
151
|
-
...(effortLevels ? { effortLevels } : {}),
|
|
152
|
-
});
|
|
107
|
+
ids.add(line);
|
|
108
|
+
const provider = line.slice(0, line.indexOf('/'));
|
|
109
|
+
models.push({ id: line, label: line, description: `via ${provider}` });
|
|
153
110
|
}
|
|
154
111
|
if (models.length === 0 && lines.length > 0) {
|
|
155
112
|
throw new Error('OpenCode model discovery returned unrecognized output');
|
|
156
113
|
}
|
|
157
114
|
return models;
|
|
158
115
|
}
|
|
159
|
-
function effortLevelsFromMetadata(lines) {
|
|
160
|
-
if (lines.length === 0)
|
|
161
|
-
return undefined;
|
|
162
|
-
let metadata;
|
|
163
|
-
try {
|
|
164
|
-
metadata = JSON.parse(lines.join('\n'));
|
|
165
|
-
}
|
|
166
|
-
catch {
|
|
167
|
-
return undefined;
|
|
168
|
-
}
|
|
169
|
-
if (!isRecord(metadata) || !isRecord(metadata.variants))
|
|
170
|
-
return undefined;
|
|
171
|
-
const levels = [];
|
|
172
|
-
for (const name of Object.keys(metadata.variants)) {
|
|
173
|
-
const parsed = effortLevelSchema.safeParse(name);
|
|
174
|
-
if (parsed.success && !levels.includes(parsed.data))
|
|
175
|
-
levels.push(parsed.data);
|
|
176
|
-
}
|
|
177
|
-
return levels.length > 0 ? levels : undefined;
|
|
178
|
-
}
|
|
179
|
-
function isRecord(value) {
|
|
180
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
181
|
-
}
|
|
182
116
|
function spawnOpencode(bin, args, cwd) {
|
|
183
|
-
|
|
117
|
+
const child = nodeSpawn(bin, [...args], {
|
|
184
118
|
cwd,
|
|
185
119
|
env: buildChildEnv({ backend: 'opencode' }),
|
|
186
120
|
});
|
|
121
|
+
// Nothing is ever written to it, and an open stdin is what makes a CLI that expects a TTY
|
|
122
|
+
// sit and wait instead of printing its list.
|
|
123
|
+
child.stdin.end();
|
|
124
|
+
return child;
|
|
187
125
|
}
|
|
188
126
|
/**
|
|
189
127
|
* Returns the probe's teardown: SIGTERM now, SIGKILL once the grace window elapses.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-model-catalog.js","sourceRoot":"","sources":["../../src/core/opencode-model-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAuC,MAAM,oBAAoB,CAAC;AAC7F,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"opencode-model-catalog.js","sourceRoot":"","sources":["../../src/core/opencode-model-catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type ChildProcessWithoutNullStreams } from 'node:child_process';
|
|
2
|
-
import { type EffortLevel } from '../contract/index.js';
|
|
3
2
|
import type { ModelOption } from './runner-model-catalog.ts';
|
|
4
3
|
export interface PiModelDiscoveryOptions {
|
|
5
4
|
cwd: string;
|
|
@@ -30,9 +29,3 @@ export declare function discoverPiModels(options: PiModelDiscoveryOptions): Prom
|
|
|
30
29
|
* like "you have no models".
|
|
31
30
|
*/
|
|
32
31
|
export declare function parsePiModels(stdout: string): ModelOption[];
|
|
33
|
-
/** Parse model-indexed Pi RPC responses without letting a failed model switch reuse prior state. */
|
|
34
|
-
export declare function parsePiEffortLevels(stdout: string, modelCount: number): Map<number, EffortLevel[]>;
|
|
35
|
-
export declare function spawnPi(bin: string, args: readonly string[], cwd: string, spawnImpl?: (bin: string, args: string[], options: {
|
|
36
|
-
cwd: string;
|
|
37
|
-
env: NodeJS.ProcessEnv;
|
|
38
|
-
}) => ChildProcessWithoutNullStreams): ChildProcessWithoutNullStreams;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { spawn as nodeSpawn } from 'node:child_process';
|
|
2
|
-
import { effortLevelSchema } from '../contract/index.js';
|
|
3
2
|
import { trackChildExit } from './agent-runner.js';
|
|
4
3
|
import { buildChildEnv } from './agent-env.js';
|
|
5
4
|
const DEFAULT_DISCOVERY_TIMEOUT_MS = 10_000;
|
|
@@ -8,14 +7,6 @@ export const KILL_GRACE_MS = 2_000;
|
|
|
8
7
|
const MAX_MODELS = 500;
|
|
9
8
|
/** Defensive cap on what we buffer from a misbehaving child (characters of stdout). */
|
|
10
9
|
const MAX_OUTPUT_CHARS = 512 * 1_024;
|
|
11
|
-
const RPC_ARGS = [
|
|
12
|
-
'--mode',
|
|
13
|
-
'rpc',
|
|
14
|
-
'--no-session',
|
|
15
|
-
'--no-tools',
|
|
16
|
-
'--no-skills',
|
|
17
|
-
'--no-prompt-templates',
|
|
18
|
-
];
|
|
19
10
|
/** SGR/CSI sequences — `pi --list-models` colorizes a TTY. */
|
|
20
11
|
const ANSI_RE = /\u001B\[[0-9;]*[A-Za-z]/g;
|
|
21
12
|
/** The host binary, resolved exactly like `PiRunner` and the backend probe. */
|
|
@@ -32,93 +23,53 @@ export function resolvePiExecutable(bin) {
|
|
|
32
23
|
* a model cap.
|
|
33
24
|
*/
|
|
34
25
|
export async function discoverPiModels(options) {
|
|
35
|
-
// `PiRunner` swaps in the bundled mock under CEZ_DRY_RUN=1
|
|
36
|
-
//
|
|
26
|
+
// `PiRunner` swaps in the bundled mock under CEZ_DRY_RUN=1; that mock speaks RPC, not
|
|
27
|
+
// `--list-models`. Without an explicit binary, skip the spawn so a dry-run cockpit never
|
|
28
|
+
// shells out to a real `pi` (AGENTS.md: dry-run keeps working with no real CLI).
|
|
37
29
|
if (options.bin === undefined && process.env.CEZ_PI_BIN === undefined && process.env.CEZ_DRY_RUN === '1') {
|
|
38
30
|
return [];
|
|
39
31
|
}
|
|
40
32
|
const bin = resolvePiExecutable(options.bin);
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
const listChild = spawn(bin, ['--list-models'], options.cwd);
|
|
44
|
-
const listOutputPromise = collectPiOutput(listChild, Math.max(1, deadline - Date.now()), 'Pi model discovery');
|
|
45
|
-
listChild.stdin.end();
|
|
46
|
-
const listOutput = await listOutputPromise;
|
|
47
|
-
const models = parsePiModels(listOutput);
|
|
48
|
-
if (models.length === 0 || Date.now() >= deadline)
|
|
49
|
-
return models;
|
|
50
|
-
try {
|
|
51
|
-
const rpcChild = spawn(bin, RPC_ARGS, options.cwd);
|
|
52
|
-
const outputPromise = collectPiOutput(rpcChild, Math.max(1, deadline - Date.now()), 'Pi effort discovery');
|
|
53
|
-
try {
|
|
54
|
-
models.forEach((model, index) => {
|
|
55
|
-
const slash = model.id.indexOf('/');
|
|
56
|
-
rpcChild.stdin.write(`${JSON.stringify({
|
|
57
|
-
id: `set:${index}`,
|
|
58
|
-
type: 'set_model',
|
|
59
|
-
provider: model.id.slice(0, slash),
|
|
60
|
-
modelId: model.id.slice(slash + 1),
|
|
61
|
-
})}\n`);
|
|
62
|
-
rpcChild.stdin.write(`${JSON.stringify({
|
|
63
|
-
id: `levels:${index}`,
|
|
64
|
-
type: 'get_available_thinking_levels',
|
|
65
|
-
})}\n`);
|
|
66
|
-
});
|
|
67
|
-
rpcChild.stdin.end();
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
rpcChild.stdin.destroy();
|
|
71
|
-
await outputPromise.catch(() => undefined);
|
|
72
|
-
throw error;
|
|
73
|
-
}
|
|
74
|
-
const output = await outputPromise;
|
|
75
|
-
const levels = parsePiEffortLevels(output, models.length);
|
|
76
|
-
return models.map((model, index) => {
|
|
77
|
-
const effortLevels = levels.get(index);
|
|
78
|
-
return effortLevels ? { ...model, effortLevels } : model;
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
// Effort metadata is enrichment. A missing/older RPC path must not discard a valid model list.
|
|
83
|
-
return models;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
async function collectPiOutput(child, timeoutMs, label) {
|
|
33
|
+
const args = ['--list-models'];
|
|
34
|
+
const child = (options.spawn ?? spawnPi)(bin, args, options.cwd);
|
|
87
35
|
const kill = teardown(child);
|
|
36
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_DISCOVERY_TIMEOUT_MS;
|
|
88
37
|
let timeout;
|
|
89
38
|
try {
|
|
90
39
|
return await new Promise((resolve, reject) => {
|
|
91
40
|
let stdout = '';
|
|
92
|
-
let
|
|
41
|
+
let overflowed = false;
|
|
93
42
|
const fail = (message) => {
|
|
94
|
-
if (settled)
|
|
95
|
-
return;
|
|
96
|
-
settled = true;
|
|
97
43
|
reject(new Error(message));
|
|
98
44
|
kill();
|
|
99
45
|
};
|
|
100
|
-
timeout = setTimeout(() => fail(
|
|
46
|
+
timeout = setTimeout(() => fail('Pi model discovery timed out'), timeoutMs);
|
|
101
47
|
timeout.unref?.();
|
|
102
48
|
child.stdout.setEncoding('utf8');
|
|
103
49
|
child.stdout.on('data', (chunk) => {
|
|
104
|
-
if (
|
|
50
|
+
if (overflowed)
|
|
105
51
|
return;
|
|
106
52
|
stdout += chunk;
|
|
107
|
-
if (stdout.length > MAX_OUTPUT_CHARS)
|
|
108
|
-
|
|
53
|
+
if (stdout.length > MAX_OUTPUT_CHARS) {
|
|
54
|
+
overflowed = true;
|
|
55
|
+
fail('Pi model discovery exceeded the output limit');
|
|
56
|
+
}
|
|
109
57
|
});
|
|
110
58
|
child.stderr.resume();
|
|
111
|
-
child.
|
|
112
|
-
child.once('error', () => fail(`${label} child failed`));
|
|
59
|
+
child.once('error', () => fail('Pi model discovery child failed'));
|
|
113
60
|
child.once('close', (code) => {
|
|
114
|
-
if (
|
|
61
|
+
if (overflowed)
|
|
115
62
|
return;
|
|
116
63
|
if (code !== 0) {
|
|
117
|
-
fail(
|
|
64
|
+
fail(`Pi model discovery child exited (${code ?? 'unknown'})`);
|
|
118
65
|
return;
|
|
119
66
|
}
|
|
120
|
-
|
|
121
|
-
|
|
67
|
+
try {
|
|
68
|
+
resolve(parsePiModels(stdout));
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
72
|
+
}
|
|
122
73
|
});
|
|
123
74
|
});
|
|
124
75
|
}
|
|
@@ -167,61 +118,13 @@ export function parsePiModels(stdout) {
|
|
|
167
118
|
}
|
|
168
119
|
return models;
|
|
169
120
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const successfulSets = new Set();
|
|
173
|
-
const candidates = new Map();
|
|
174
|
-
for (const line of stdout.split('\n')) {
|
|
175
|
-
if (!line.trim())
|
|
176
|
-
continue;
|
|
177
|
-
let record;
|
|
178
|
-
try {
|
|
179
|
-
record = JSON.parse(line);
|
|
180
|
-
}
|
|
181
|
-
catch {
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
if (!isRecord(record) || record.type !== 'response' || record.success !== true)
|
|
185
|
-
continue;
|
|
186
|
-
const id = typeof record.id === 'string' ? record.id : '';
|
|
187
|
-
const match = /^(set|levels):(\d+)$/.exec(id);
|
|
188
|
-
if (!match)
|
|
189
|
-
continue;
|
|
190
|
-
const index = Number(match[2]);
|
|
191
|
-
if (!Number.isInteger(index) || index < 0 || index >= modelCount)
|
|
192
|
-
continue;
|
|
193
|
-
if (match[1] === 'set' && record.command === 'set_model') {
|
|
194
|
-
successfulSets.add(index);
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
if (match[1] !== 'levels' || record.command !== 'get_available_thinking_levels')
|
|
198
|
-
continue;
|
|
199
|
-
if (!isRecord(record.data) || !Array.isArray(record.data.levels))
|
|
200
|
-
continue;
|
|
201
|
-
const levels = [];
|
|
202
|
-
for (const value of record.data.levels) {
|
|
203
|
-
const parsed = effortLevelSchema.safeParse(value);
|
|
204
|
-
if (parsed.success && !levels.includes(parsed.data))
|
|
205
|
-
levels.push(parsed.data);
|
|
206
|
-
}
|
|
207
|
-
if (levels.length > 0)
|
|
208
|
-
candidates.set(index, levels);
|
|
209
|
-
}
|
|
210
|
-
const result = new Map();
|
|
211
|
-
for (const [index, levels] of candidates) {
|
|
212
|
-
if (successfulSets.has(index))
|
|
213
|
-
result.set(index, levels);
|
|
214
|
-
}
|
|
215
|
-
return result;
|
|
216
|
-
}
|
|
217
|
-
function isRecord(value) {
|
|
218
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
219
|
-
}
|
|
220
|
-
export function spawnPi(bin, args, cwd, spawnImpl = nodeSpawn) {
|
|
221
|
-
return spawnImpl(bin, [...args], {
|
|
121
|
+
function spawnPi(bin, args, cwd) {
|
|
122
|
+
const child = nodeSpawn(bin, [...args], {
|
|
222
123
|
cwd,
|
|
223
124
|
env: buildChildEnv({ backend: 'pi' }),
|
|
224
125
|
});
|
|
126
|
+
child.stdin.end();
|
|
127
|
+
return child;
|
|
225
128
|
}
|
|
226
129
|
/**
|
|
227
130
|
* Returns the probe's teardown: SIGTERM now, SIGKILL once the grace window elapses.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pi-model-catalog.js","sourceRoot":"","sources":["../../src/core/pi-model-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAuC,MAAM,oBAAoB,CAAC;AAC7F,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"pi-model-catalog.js","sourceRoot":"","sources":["../../src/core/pi-model-catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,6 +23,26 @@ export function piTurnStarted(state) {
|
|
|
23
23
|
state: { ...state, turnSeq, turnId, stopReason: 'end_turn', textBlock: 0 },
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
+
/** Pi extensions may resume work after `agent_settled` without a new prompt or
|
|
27
|
+
* `turn_start`. Re-open the normalized turn before mapping that activity. */
|
|
28
|
+
function mapActivity(value, state, map) {
|
|
29
|
+
if (state.turnId)
|
|
30
|
+
return map(value, state);
|
|
31
|
+
const started = piTurnStarted(state);
|
|
32
|
+
const mapped = map(value, started.state);
|
|
33
|
+
return { events: [...started.events, ...mapped.events], state: mapped.state };
|
|
34
|
+
}
|
|
35
|
+
function isMessageUpdateActivity(value) {
|
|
36
|
+
const update = isRecord(value.assistantMessageEvent) ? value.assistantMessageEvent : undefined;
|
|
37
|
+
const type = update ? string(update.type) : undefined;
|
|
38
|
+
return type?.startsWith('text_') === true || type?.startsWith('thinking_') === true;
|
|
39
|
+
}
|
|
40
|
+
function isAssistantMessageEnd(value) {
|
|
41
|
+
return isRecord(value.message) && string(value.message.role) === 'assistant';
|
|
42
|
+
}
|
|
43
|
+
function isToolStart(value) {
|
|
44
|
+
return Boolean(string(value.toolCallId) && string(value.toolName));
|
|
45
|
+
}
|
|
26
46
|
export function mapPiRpcMessage(value, state) {
|
|
27
47
|
if (!isRecord(value) || typeof value.type !== 'string')
|
|
28
48
|
return { events: [], state };
|
|
@@ -47,11 +67,17 @@ export function mapPiRpcMessage(value, state) {
|
|
|
47
67
|
}
|
|
48
68
|
switch (value.type) {
|
|
49
69
|
case 'message_update':
|
|
50
|
-
return
|
|
70
|
+
return isMessageUpdateActivity(value)
|
|
71
|
+
? mapActivity(value, state, mapMessageUpdate)
|
|
72
|
+
: mapMessageUpdate(value, state);
|
|
51
73
|
case 'message_end':
|
|
52
|
-
return
|
|
74
|
+
return isAssistantMessageEnd(value)
|
|
75
|
+
? mapActivity(value, state, mapMessageEnd)
|
|
76
|
+
: mapMessageEnd(value, state);
|
|
53
77
|
case 'tool_execution_start':
|
|
54
|
-
return
|
|
78
|
+
return isToolStart(value)
|
|
79
|
+
? mapActivity(value, state, mapToolStart)
|
|
80
|
+
: mapToolStart(value, state);
|
|
55
81
|
case 'tool_execution_update':
|
|
56
82
|
return mapToolUpdate(value, state);
|
|
57
83
|
case 'tool_execution_end':
|