@zenera/cli 1.1.24 → 1.1.26
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/README.md +65 -0
- package/dist/ask.js +28 -5
- package/dist/banner.js +2 -2
- package/dist/batch.d.ts +6 -0
- package/dist/batch.js +76 -1
- package/dist/catalog.d.ts +31 -1
- package/dist/catalog.js +140 -7
- package/dist/commands/index.js +2 -0
- package/dist/commands/inspect.d.ts +52 -2
- package/dist/commands/inspect.js +220 -31
- package/dist/commands/memory.js +156 -32
- package/dist/commands/meta.js +333 -24
- package/dist/commands/models.js +97 -12
- package/dist/commands/open.js +4 -4
- package/dist/commands/run.js +38 -4
- package/dist/commands/sandbox.js +148 -16
- package/dist/commands/view.d.ts +8 -0
- package/dist/commands/view.js +114 -0
- package/dist/engine.d.ts +8 -1
- package/dist/engine.js +7 -0
- package/dist/eventlog.d.ts +64 -0
- package/dist/eventlog.js +170 -0
- package/dist/liveness.d.ts +7 -0
- package/dist/liveness.js +35 -3
- package/dist/main.js +0 -0
- package/dist/meta/editor.d.ts +9 -0
- package/dist/meta/editor.js +43 -0
- package/dist/meta/finetune/analyze-brief.d.ts +26 -0
- package/dist/meta/finetune/analyze-brief.js +131 -0
- package/dist/meta/finetune/apply-brief.d.ts +23 -0
- package/dist/meta/finetune/apply-brief.js +247 -0
- package/dist/meta/finetune/brief.d.ts +45 -0
- package/dist/meta/finetune/brief.js +158 -0
- package/dist/meta/finetune/children.d.ts +8 -0
- package/dist/meta/finetune/children.js +76 -0
- package/dist/meta/finetune/command.d.ts +30 -0
- package/dist/meta/finetune/command.js +516 -0
- package/dist/meta/finetune/cost.d.ts +46 -0
- package/dist/meta/finetune/cost.js +105 -0
- package/dist/meta/finetune/dataset/anchors.d.ts +41 -0
- package/dist/meta/finetune/dataset/anchors.js +239 -0
- package/dist/meta/finetune/dataset/changes.d.ts +36 -0
- package/dist/meta/finetune/dataset/changes.js +319 -0
- package/dist/meta/finetune/dataset/command.d.ts +17 -0
- package/dist/meta/finetune/dataset/command.js +1011 -0
- package/dist/meta/finetune/dataset/drift.d.ts +33 -0
- package/dist/meta/finetune/dataset/drift.js +71 -0
- package/dist/meta/finetune/dataset/export.d.ts +26 -0
- package/dist/meta/finetune/dataset/export.js +51 -0
- package/dist/meta/finetune/dataset/index.d.ts +2 -0
- package/dist/meta/finetune/dataset/index.js +2 -0
- package/dist/meta/finetune/dataset/sample.d.ts +50 -0
- package/dist/meta/finetune/dataset/sample.js +197 -0
- package/dist/meta/finetune/dataset/schema.d.ts +33 -0
- package/dist/meta/finetune/dataset/schema.js +216 -0
- package/dist/meta/finetune/dataset/store.d.ts +35 -0
- package/dist/meta/finetune/dataset/store.js +177 -0
- package/dist/meta/finetune/dataset/types.d.ts +127 -0
- package/dist/meta/finetune/dataset/types.js +39 -0
- package/dist/meta/finetune/failure.d.ts +15 -0
- package/dist/meta/finetune/failure.js +26 -0
- package/dist/meta/finetune/feedback.d.ts +57 -0
- package/dist/meta/finetune/feedback.js +104 -0
- package/dist/meta/finetune/guard.d.ts +29 -0
- package/dist/meta/finetune/guard.js +104 -0
- package/dist/meta/finetune/improvements.d.ts +98 -0
- package/dist/meta/finetune/improvements.js +501 -0
- package/dist/meta/finetune/index.d.ts +2 -0
- package/dist/meta/finetune/index.js +2 -0
- package/dist/meta/finetune/journal.d.ts +35 -0
- package/dist/meta/finetune/journal.js +135 -0
- package/dist/meta/finetune/live.d.ts +84 -0
- package/dist/meta/finetune/live.js +272 -0
- package/dist/meta/finetune/loop.d.ts +3 -0
- package/dist/meta/finetune/loop.js +163 -0
- package/dist/meta/finetune/memories.d.ts +47 -0
- package/dist/meta/finetune/memories.js +154 -0
- package/dist/meta/finetune/recheck.d.ts +58 -0
- package/dist/meta/finetune/recheck.js +311 -0
- package/dist/meta/finetune/report.d.ts +40 -0
- package/dist/meta/finetune/report.js +1397 -0
- package/dist/meta/finetune/retry.d.ts +24 -0
- package/dist/meta/finetune/retry.js +96 -0
- package/dist/meta/finetune/sampler.d.ts +18 -0
- package/dist/meta/finetune/sampler.js +47 -0
- package/dist/meta/finetune/system.d.ts +27 -0
- package/dist/meta/finetune/system.js +132 -0
- package/dist/meta/finetune/train.d.ts +43 -0
- package/dist/meta/finetune/train.js +425 -0
- package/dist/meta/finetune/tui.d.ts +16 -0
- package/dist/meta/finetune/tui.js +316 -0
- package/dist/meta/finetune/tuning.d.ts +193 -0
- package/dist/meta/finetune/tuning.js +308 -0
- package/dist/meta/finetune/usage.d.ts +66 -0
- package/dist/meta/finetune/usage.js +260 -0
- package/dist/meta/finetune/view.d.ts +9 -0
- package/dist/meta/finetune/view.js +27 -0
- package/dist/meta/host.d.ts +15 -0
- package/dist/meta/host.js +21 -0
- package/dist/meta/index.d.ts +11 -0
- package/dist/meta/index.js +11 -0
- package/dist/meta/launch.d.ts +81 -0
- package/dist/meta/launch.js +286 -0
- package/dist/meta/model.d.ts +44 -0
- package/dist/meta/model.js +119 -0
- package/dist/meta/prompts.d.ts +18 -0
- package/dist/meta/prompts.js +61 -0
- package/dist/meta/relay.d.ts +20 -0
- package/dist/meta/relay.js +123 -0
- package/dist/meta/tokens.d.ts +52 -0
- package/dist/meta/tokens.js +226 -0
- package/dist/meta/window.d.ts +61 -0
- package/dist/meta/window.js +198 -0
- package/dist/meta/wire.d.ts +42 -0
- package/dist/meta/wire.js +129 -0
- package/dist/meta.d.ts +71 -1
- package/dist/meta.js +303 -6
- package/dist/modelref.d.ts +16 -0
- package/dist/modelref.js +41 -0
- package/dist/narrate.js +5 -2
- package/dist/podman.d.ts +26 -0
- package/dist/podman.js +83 -3
- package/dist/projects.d.ts +0 -5
- package/dist/projects.js +2 -15
- package/dist/resources.d.ts +215 -0
- package/dist/resources.js +856 -0
- package/dist/sandbox.d.ts +2 -0
- package/dist/sandbox.js +10 -3
- package/dist/scaffold.d.ts +15 -7
- package/dist/scaffold.js +24 -67
- package/dist/session.js +4 -29
- package/dist/term.d.ts +2 -0
- package/dist/term.js +11 -2
- package/dist/trace.d.ts +5 -0
- package/dist/trace.js +107 -7
- package/dist/tui/app.js +19 -5
- package/dist/tui/links.d.ts +27 -0
- package/dist/tui/links.js +142 -0
- package/dist/tui/models.d.ts +35 -0
- package/dist/tui/models.js +447 -0
- package/dist/tui/sandbox.d.ts +10 -0
- package/dist/tui/sandbox.js +131 -0
- package/dist/tui/wrap.d.ts +5 -0
- package/dist/tui/wrap.js +12 -0
- package/dist/usage.d.ts +78 -0
- package/dist/usage.js +51 -0
- package/package.json +4 -2
- package/templates/editor/.github/copilot-instructions.md +60 -145
- package/templates/editor/.github/prompts/analyze.prompt.md +33 -0
- package/templates/editor/.github/prompts/dataset.prompt.md +108 -0
- package/templates/editor/.github/prompts/finetune-apply.prompt.md +270 -0
- package/templates/editor/.github/prompts/finetune.prompt.md +691 -198
- package/templates/editor/.github/prompts/new-agent.prompt.md +3 -1
- package/templates/editor/.github/prompts/new-skill.prompt.md +2 -0
- package/templates/editor/.github/prompts/project-review.prompt.md +5 -4
- package/templates/editor/.github/skills/zen-analyze-run/SKILL.md +588 -0
- package/templates/editor/.github/skills/zen-cli/SKILL.md +9 -1
- package/templates/editor/.github/skills/zen-cli/references/dataset.md +34 -0
- package/templates/editor/.github/skills/zen-cli/references/finetune.md +137 -0
- package/templates/editor/.github/skills/zen-cli/references/inspect.md +63 -11
- package/templates/editor/.github/skills/zen-cli/references/memory.md +33 -10
- package/templates/editor/.github/skills/zen-cli/references/meta.md +61 -0
- package/templates/editor/.github/skills/zen-cli/references/models.md +5 -1
- package/templates/editor/.github/skills/zen-cli/references/projects.md +4 -6
- package/templates/editor/.github/skills/zen-cli/references/rag.md +24 -6
- package/templates/editor/.github/skills/zen-cli/references/sandbox.md +35 -14
- package/templates/editor/.github/skills/zen-code-python/SKILL.md +123 -0
- package/templates/editor/.github/skills/zen-code-python/references/code_python.md +48 -0
- package/templates/editor/.github/skills/zen-dataset/SKILL.md +253 -0
- package/templates/editor/.github/skills/zen-finetune/SKILL.md +1492 -660
- package/templates/editor/.github/skills/zen-finetune/references/readme-template.md +268 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/batch.mjs +390 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/difficult.mjs +243 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/memory.mjs +280 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/next.mjs +398 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/report.mjs +797 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/select.mjs +354 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/usage.mjs +722 -0
- package/templates/editor/.github/skills/zen-inspect/SKILL.md +74 -26
- package/templates/editor/.github/skills/zen-inspect-ask/SKILL.md +271 -0
- package/templates/editor/.github/skills/zen-instructions/SKILL.md +4 -12
- package/templates/editor/.github/skills/zen-memory/SKILL.md +82 -53
- package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +20 -8
- package/templates/editor/.github/skills/zen-review/SKILL.md +8 -31
- package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +5 -5
- package/templates/editor/.github/skills/zen-review/scripts/review.sh +3 -12
- package/templates/editor/.github/skills/zen-sandbox/SKILL.md +9 -4
- package/templates/editor/.github/skills/zen-sandbox-capacity/SKILL.md +2 -2
- package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +2 -4
- package/templates/editor/.github/skills/zen-topology/SKILL.md +283 -0
- package/templates/editor/.vscode/settings.json +1 -0
- package/templates/project/agents/files-instructions.md +29 -20
- package/templates/project/agents/fork-instructions.md +78 -28
- package/templates/project/agents/memory-instructions.md +222 -494
- package/templates/project/agents/tools-instructions.md +14 -4
- package/templates/project/gitignore +2 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/collect.sh +0 -432
- package/templates/editor/.github/skills/zen-finetune/scripts/sample.sh +0 -199
- package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +0 -116
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { existsSync, statSync } from 'node:fs';
|
|
2
|
+
import { basename, dirname, relative, resolve, sep } from 'node:path';
|
|
3
|
+
import { parse } from "../args.js";
|
|
4
|
+
import { dim, json, note, usageError, write } from "../term.js";
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// zen view - a folder in the browser, redrawn as its files change
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
const USAGE = 'zen view [path] [--port <n>] [--throttle <ms>] [--open] [--hidden]';
|
|
9
|
+
const OPTIONS = {
|
|
10
|
+
port: { type: 'string' },
|
|
11
|
+
throttle: { type: 'string' },
|
|
12
|
+
open: { type: 'boolean' },
|
|
13
|
+
hidden: { type: 'boolean' },
|
|
14
|
+
};
|
|
15
|
+
/** Resolves when one of the signals arrives, and stops listening for them. */
|
|
16
|
+
function until(signals) {
|
|
17
|
+
return new Promise((settle) => {
|
|
18
|
+
const done = () => {
|
|
19
|
+
for (const s of signals) {
|
|
20
|
+
process.off(s, done);
|
|
21
|
+
}
|
|
22
|
+
settle();
|
|
23
|
+
};
|
|
24
|
+
for (const s of signals) {
|
|
25
|
+
process.once(s, done);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/** A file inside the cwd is served from the cwd, so its links up the tree still resolve. */
|
|
30
|
+
export function placeOf(cwd, target) {
|
|
31
|
+
if (statSync(target).isDirectory()) {
|
|
32
|
+
return { root: target, start: '/' };
|
|
33
|
+
}
|
|
34
|
+
const rel = relative(cwd, target);
|
|
35
|
+
const parts = rel.split(sep);
|
|
36
|
+
// A dot-folder on the way would be refused as hidden, so serve from the file's own folder.
|
|
37
|
+
const within = rel !== '' &&
|
|
38
|
+
rel !== '..' &&
|
|
39
|
+
!rel.startsWith(`..${sep}`) &&
|
|
40
|
+
!parts.slice(0, -1).some((p) => p.startsWith('.'));
|
|
41
|
+
const root = within ? cwd : dirname(target);
|
|
42
|
+
const path = within ? parts : [basename(target)];
|
|
43
|
+
return { root, start: `/${path.join('/')}` };
|
|
44
|
+
}
|
|
45
|
+
export const view = {
|
|
46
|
+
summary: 'Show a folder in the browser: markdown, diagrams and code, redrawn as files change.',
|
|
47
|
+
usage: USAGE,
|
|
48
|
+
details: [
|
|
49
|
+
'Serves [path] (default: here) on 127.0.0.1 until Ctrl-C and prints its address.',
|
|
50
|
+
'Markdown is drawn with its tables and mermaid diagrams; json, jsonl, python and',
|
|
51
|
+
'other code is highlighted; a directory is a listing. An open page follows its',
|
|
52
|
+
'file: when the file changes, only what changed is redrawn. Images, html and pdf',
|
|
53
|
+
'are handed to the browser as they are. Dotfiles are not served without --hidden,',
|
|
54
|
+
'and .env and .git never are.',
|
|
55
|
+
'',
|
|
56
|
+
'Options:',
|
|
57
|
+
' --port <n> This port. Default: one derived from the folder, so a page left',
|
|
58
|
+
' open reconnects after a restart; any free one if it is taken.',
|
|
59
|
+
' --throttle <ms> Least time between two redraws of one page. Default 1000.',
|
|
60
|
+
' --open Open the page in the browser.',
|
|
61
|
+
' --hidden Serve dotfiles too.',
|
|
62
|
+
'',
|
|
63
|
+
'Examples:',
|
|
64
|
+
' zen view',
|
|
65
|
+
' zen view finetune/STATUS.md --open',
|
|
66
|
+
],
|
|
67
|
+
banner: { head: 'Zenera', accent: 'View', subtitle: 'Live File Viewer', hue: 'pink' },
|
|
68
|
+
run: async (ctx) => {
|
|
69
|
+
const { values, positionals } = parse(ctx.args, OPTIONS, USAGE);
|
|
70
|
+
if (positionals.length > 1) {
|
|
71
|
+
throw usageError('zen view takes one path', USAGE);
|
|
72
|
+
}
|
|
73
|
+
const target = resolve(ctx.cwd, positionals[0] ?? '.');
|
|
74
|
+
if (!existsSync(target)) {
|
|
75
|
+
throw usageError(`no such file or directory: ${target}`);
|
|
76
|
+
}
|
|
77
|
+
let port;
|
|
78
|
+
if (values.port !== undefined) {
|
|
79
|
+
port = Number(values.port);
|
|
80
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
81
|
+
throw usageError('--port takes a port number', `got "${values.port}"`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
let throttleMs;
|
|
85
|
+
if (values.throttle !== undefined) {
|
|
86
|
+
throttleMs = Number(values.throttle);
|
|
87
|
+
if (!Number.isInteger(throttleMs) || throttleMs < 0) {
|
|
88
|
+
throw usageError('--throttle takes milliseconds', `got "${values.throttle}"`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const { root, start } = placeOf(ctx.cwd, target);
|
|
92
|
+
const { openBrowser, serveView } = await import('@zenera/view');
|
|
93
|
+
const server = await serveView({
|
|
94
|
+
root,
|
|
95
|
+
start,
|
|
96
|
+
hidden: values.hidden ?? false,
|
|
97
|
+
...(port !== undefined ? { port } : {}),
|
|
98
|
+
...(throttleMs !== undefined ? { throttleMs } : {}),
|
|
99
|
+
});
|
|
100
|
+
if (ctx.json) {
|
|
101
|
+
json({ url: server.url, root: server.root, port: server.port });
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
write(server.url);
|
|
105
|
+
note(dim(`serving ${server.root} · Ctrl-C stops it`));
|
|
106
|
+
}
|
|
107
|
+
if (values.open) {
|
|
108
|
+
openBrowser(server.url);
|
|
109
|
+
}
|
|
110
|
+
await until(['SIGINT', 'SIGTERM']);
|
|
111
|
+
await server.close();
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=view.js.map
|
package/dist/engine.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AgentRunner, type AgentEvent, type AgentProject, type AgentState, type Input, type RunResult } from '@zenera/neo';
|
|
1
|
+
import { AgentRunner, Workspace, type AgentEvent, type AgentProject, type AgentState, type Input, type RunResult } from '@zenera/neo';
|
|
2
2
|
import { type Project } from './projects.ts';
|
|
3
3
|
import { type SandboxSetup } from './sandbox.ts';
|
|
4
4
|
import { type Held, type RunPaths, type SessionPaths } from './session.ts';
|
|
@@ -24,6 +24,11 @@ export interface EngineOptions {
|
|
|
24
24
|
* complaint is a worse report than one.
|
|
25
25
|
*/
|
|
26
26
|
quiet?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* The session will never be resumed, so its containers are removed on close
|
|
29
|
+
* whatever `persist:` says. A stopped one would only hold an engine lock.
|
|
30
|
+
*/
|
|
31
|
+
disposable?: boolean;
|
|
27
32
|
}
|
|
28
33
|
export interface Engine {
|
|
29
34
|
project: AgentProject;
|
|
@@ -32,6 +37,8 @@ export interface Engine {
|
|
|
32
37
|
workspace: string;
|
|
33
38
|
/** where the workspace appears inside the container */
|
|
34
39
|
workspaceMount: string;
|
|
40
|
+
/** every tree the file tools reach, and the names they reach them by */
|
|
41
|
+
files: Workspace;
|
|
35
42
|
/** whether the agent was denied every writing tool */
|
|
36
43
|
readOnly: boolean;
|
|
37
44
|
session: SessionPaths;
|
package/dist/engine.js
CHANGED
|
@@ -2,6 +2,7 @@ import { AgentRunner, FilePayloadStore, SANDBOX_MOUNT, SKILLS_MOUNT, Workspace,
|
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import { writeFile } from 'node:fs/promises';
|
|
4
4
|
import { resolve } from 'node:path';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
5
6
|
import { auditModels, describeIssue } from "./audit.js";
|
|
6
7
|
import { loadProjectEnv } from "./env.js";
|
|
7
8
|
import { readJson, writeJson } from "./home.js";
|
|
@@ -64,6 +65,7 @@ export async function open(opts) {
|
|
|
64
65
|
keys: opts.keys,
|
|
65
66
|
env: env?.names,
|
|
66
67
|
mounts,
|
|
68
|
+
...(opts.disposable ? { persist: false } : {}),
|
|
67
69
|
});
|
|
68
70
|
const workspaceOptions = {
|
|
69
71
|
root: workspace,
|
|
@@ -122,6 +124,7 @@ export async function open(opts) {
|
|
|
122
124
|
name: opts.project.name,
|
|
123
125
|
workspace,
|
|
124
126
|
workspaceMount: sandbox.spec.workdir ?? SANDBOX_MOUNT,
|
|
127
|
+
files,
|
|
125
128
|
readOnly: Boolean(opts.readOnly),
|
|
126
129
|
session: opts.session,
|
|
127
130
|
memory,
|
|
@@ -232,6 +235,10 @@ async function record(engine, input, result, startedAt, durationMs) {
|
|
|
232
235
|
title: `${engine.name} · ${run.id}`,
|
|
233
236
|
architecture: await engine.runner.describe(),
|
|
234
237
|
memory: engine.runner.services.memory?.store,
|
|
238
|
+
mounts: [
|
|
239
|
+
{ at: engine.workspaceMount, href: pathToFileURL(engine.files.root).href },
|
|
240
|
+
...engine.files.mounts.map((m) => ({ at: m.at, href: pathToFileURL(m.host).href })),
|
|
241
|
+
],
|
|
235
242
|
});
|
|
236
243
|
await writeFile(run.report, renderReportHtml(built), 'utf8');
|
|
237
244
|
report = run.report;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type AgentEvent } from '@zenera/neo';
|
|
2
|
+
export type EventBody = {
|
|
3
|
+
type: 'llm';
|
|
4
|
+
model: string;
|
|
5
|
+
in: number;
|
|
6
|
+
cached: number;
|
|
7
|
+
out: number;
|
|
8
|
+
reasoning: number;
|
|
9
|
+
ms?: number;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'tool';
|
|
12
|
+
phase: 'start';
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
subject: string;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'tool';
|
|
18
|
+
phase: 'end';
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
ok: boolean;
|
|
22
|
+
ms?: number;
|
|
23
|
+
} | {
|
|
24
|
+
type: 'say';
|
|
25
|
+
text: string;
|
|
26
|
+
} | {
|
|
27
|
+
type: 'think';
|
|
28
|
+
text: string;
|
|
29
|
+
};
|
|
30
|
+
export type EventLine = EventBody & {
|
|
31
|
+
t: string;
|
|
32
|
+
};
|
|
33
|
+
/** A thought summary's last `**heading**`, else its first sentence. */
|
|
34
|
+
export declare function heading(thinking: string): string;
|
|
35
|
+
/** A line that cannot be written is dropped: watching a run must not break it. */
|
|
36
|
+
export declare function eventLog(path: string): (body: EventBody) => void;
|
|
37
|
+
/** For `zen run`: the runtime's own events, folded to the shared lines. */
|
|
38
|
+
export declare function agentEventLog(path: string): (event: AgentEvent) => void;
|
|
39
|
+
/** One line of copilot's JSONL, as much of it as is read here. */
|
|
40
|
+
export interface CopilotEvent {
|
|
41
|
+
type: string;
|
|
42
|
+
data?: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
/** A model call read off copilot's span file - see `meta/tokens.ts`. */
|
|
45
|
+
export interface CopilotCall {
|
|
46
|
+
model: string;
|
|
47
|
+
usage: {
|
|
48
|
+
inputTokens: number;
|
|
49
|
+
cachedInputTokens: number;
|
|
50
|
+
outputTokens: number;
|
|
51
|
+
reasoningTokens: number;
|
|
52
|
+
};
|
|
53
|
+
durationMs: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* For `zen meta run`: copilot's events and spans, folded to the same lines.
|
|
57
|
+
* Its JSONL has no token counts, so `llm` lines come from the spans instead,
|
|
58
|
+
* about a second after each call.
|
|
59
|
+
*/
|
|
60
|
+
export declare function copilotEventLog(path: string): {
|
|
61
|
+
event: (event: CopilotEvent) => void;
|
|
62
|
+
call: (call: CopilotCall) => void;
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=eventlog.d.ts.map
|
package/dist/eventlog.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { isCheckpoint } from '@zenera/neo';
|
|
2
|
+
import { appendFileSync, mkdirSync } from 'node:fs';
|
|
3
|
+
import { dirname } from 'node:path';
|
|
4
|
+
const MAX_TEXT = 400;
|
|
5
|
+
const clip = (text) => {
|
|
6
|
+
const one = text.replace(/\s+/g, ' ').trim();
|
|
7
|
+
return one.length > MAX_TEXT ? `${one.slice(0, MAX_TEXT - 1)}…` : one;
|
|
8
|
+
};
|
|
9
|
+
/** A thought summary's last `**heading**`, else its first sentence. */
|
|
10
|
+
export function heading(thinking) {
|
|
11
|
+
const bold = [...thinking.matchAll(/\*\*([^*\n]+)\*\*/g)].at(-1)?.[1];
|
|
12
|
+
if (bold) {
|
|
13
|
+
return clip(bold);
|
|
14
|
+
}
|
|
15
|
+
const one = clip(thinking);
|
|
16
|
+
return one.match(/^.+?[.!?](?=\s|$)/)?.[0] ?? one;
|
|
17
|
+
}
|
|
18
|
+
/** A line that cannot be written is dropped: watching a run must not break it. */
|
|
19
|
+
export function eventLog(path) {
|
|
20
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
21
|
+
return (body) => {
|
|
22
|
+
try {
|
|
23
|
+
appendFileSync(path, `${JSON.stringify({ t: new Date().toISOString(), ...body })}\n`);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// See above.
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** For `zen run`: the runtime's own events, folded to the shared lines. */
|
|
31
|
+
export function agentEventLog(path) {
|
|
32
|
+
const write = eventLog(path);
|
|
33
|
+
// Keyed by branch, since a fork has several model calls open at once.
|
|
34
|
+
const began = new Map();
|
|
35
|
+
const said = new Map();
|
|
36
|
+
const thought = new Map();
|
|
37
|
+
return (event) => {
|
|
38
|
+
const key = event.branch?.name ?? '';
|
|
39
|
+
if (!isCheckpoint(event)) {
|
|
40
|
+
if (event.type === 'text_delta') {
|
|
41
|
+
said.set(key, (said.get(key) ?? '') + event.delta);
|
|
42
|
+
}
|
|
43
|
+
else if (event.type === 'thinking_delta') {
|
|
44
|
+
thought.set(key, (thought.get(key) ?? '') + event.delta);
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
switch (event.type) {
|
|
49
|
+
case 'before_llm_call':
|
|
50
|
+
began.set(key, Date.now());
|
|
51
|
+
said.delete(key);
|
|
52
|
+
thought.delete(key);
|
|
53
|
+
break;
|
|
54
|
+
case 'after_llm_call': {
|
|
55
|
+
const u = event.node.usage;
|
|
56
|
+
const at = began.get(key);
|
|
57
|
+
write({
|
|
58
|
+
type: 'llm',
|
|
59
|
+
model: event.node.model,
|
|
60
|
+
in: u.inputTokens,
|
|
61
|
+
cached: u.cachedInputTokens ?? 0,
|
|
62
|
+
out: u.outputTokens,
|
|
63
|
+
reasoning: u.reasoningTokens ?? 0,
|
|
64
|
+
...(at !== undefined ? { ms: Date.now() - at } : {}),
|
|
65
|
+
});
|
|
66
|
+
const thinking = thought.get(key)?.trim();
|
|
67
|
+
thought.delete(key);
|
|
68
|
+
if (thinking) {
|
|
69
|
+
write({ type: 'think', text: heading(thinking) });
|
|
70
|
+
}
|
|
71
|
+
const text = said.get(key)?.trim();
|
|
72
|
+
said.delete(key);
|
|
73
|
+
if (text) {
|
|
74
|
+
write({ type: 'say', text: clip(text) });
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
case 'before_tool_call':
|
|
79
|
+
write({
|
|
80
|
+
type: 'tool',
|
|
81
|
+
phase: 'start',
|
|
82
|
+
id: event.call.callId,
|
|
83
|
+
name: event.call.name,
|
|
84
|
+
subject: clip(event.call.args.preview ?? ''),
|
|
85
|
+
});
|
|
86
|
+
break;
|
|
87
|
+
case 'after_tool_call':
|
|
88
|
+
write({
|
|
89
|
+
type: 'tool',
|
|
90
|
+
phase: 'end',
|
|
91
|
+
id: event.node.callId,
|
|
92
|
+
name: event.node.name,
|
|
93
|
+
ok: !event.node.isError,
|
|
94
|
+
...(event.node.durationMs !== undefined ? { ms: event.node.durationMs } : {}),
|
|
95
|
+
});
|
|
96
|
+
break;
|
|
97
|
+
default:
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* For `zen meta run`: copilot's events and spans, folded to the same lines.
|
|
104
|
+
* Its JSONL has no token counts, so `llm` lines come from the spans instead,
|
|
105
|
+
* about a second after each call.
|
|
106
|
+
*/
|
|
107
|
+
export function copilotEventLog(path) {
|
|
108
|
+
const write = eventLog(path);
|
|
109
|
+
// Its completion names no tool, so the start is remembered by call id.
|
|
110
|
+
const began = new Map();
|
|
111
|
+
return {
|
|
112
|
+
event: (event) => {
|
|
113
|
+
const data = event.data ?? {};
|
|
114
|
+
const id = String(data.toolCallId ?? '');
|
|
115
|
+
switch (event.type) {
|
|
116
|
+
case 'assistant.message': {
|
|
117
|
+
const text = String(data.content ?? '').trim();
|
|
118
|
+
if (text) {
|
|
119
|
+
write({ type: 'say', text: clip(text) });
|
|
120
|
+
}
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
case 'tool.execution_start': {
|
|
124
|
+
const args = (data.arguments ?? {});
|
|
125
|
+
const subject = args.command ??
|
|
126
|
+
args.description ??
|
|
127
|
+
args.path ??
|
|
128
|
+
args.skill ??
|
|
129
|
+
args.pattern ??
|
|
130
|
+
'';
|
|
131
|
+
const name = String(data.toolName ?? 'tool');
|
|
132
|
+
began.set(id, { at: Date.now(), name });
|
|
133
|
+
write({
|
|
134
|
+
type: 'tool',
|
|
135
|
+
phase: 'start',
|
|
136
|
+
id,
|
|
137
|
+
name,
|
|
138
|
+
subject: clip(typeof subject === 'string' ? subject : JSON.stringify(subject)),
|
|
139
|
+
});
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
case 'tool.execution_complete': {
|
|
143
|
+
const start = began.get(id);
|
|
144
|
+
began.delete(id);
|
|
145
|
+
write({
|
|
146
|
+
type: 'tool',
|
|
147
|
+
phase: 'end',
|
|
148
|
+
id,
|
|
149
|
+
name: start?.name ?? String(data.toolName ?? 'tool'),
|
|
150
|
+
ok: data.success !== false,
|
|
151
|
+
...(start ? { ms: Date.now() - start.at } : {}),
|
|
152
|
+
});
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
default:
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
call: (call) => write({
|
|
160
|
+
type: 'llm',
|
|
161
|
+
model: call.model,
|
|
162
|
+
in: call.usage.inputTokens,
|
|
163
|
+
cached: call.usage.cachedInputTokens,
|
|
164
|
+
out: call.usage.outputTokens,
|
|
165
|
+
reasoning: call.usage.reasoningTokens,
|
|
166
|
+
ms: call.durationMs,
|
|
167
|
+
}),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=eventlog.js.map
|
package/dist/liveness.d.ts
CHANGED
|
@@ -54,6 +54,13 @@ export interface ModelProbe {
|
|
|
54
54
|
/** embeddings only: the width the model actually returned */
|
|
55
55
|
dimensions?: number;
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* A chat model sized for a probe: 16 output tokens is enough for "ok", and
|
|
59
|
+
* Anthropic requires a cap at all. Only the adapters that read `maxTokens` are
|
|
60
|
+
* given one — the registry refuses a knob its adapter would never send, and the
|
|
61
|
+
* OpenAI adapters have no such knob.
|
|
62
|
+
*/
|
|
63
|
+
export declare function probeChat(provider: string, id: string): Model;
|
|
57
64
|
export declare function probeModel(target: ModelTarget): Promise<ModelProbe>;
|
|
58
65
|
/**
|
|
59
66
|
* One round trip per model, run together — they are independent questions, and
|
package/dist/liveness.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EXA_BASE_URL, isUnfunded, ModelRegistry, text, } from '@zenera/neo';
|
|
1
|
+
import { createModel, EXA_BASE_URL, isUnfunded, ModelRegistry, text, vertexRoute, } from '@zenera/neo';
|
|
2
2
|
import { envOf, SHAPES, } from "./keys.js";
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
// Liveness
|
|
@@ -389,6 +389,17 @@ const UNSERVED = [
|
|
|
389
389
|
'no access',
|
|
390
390
|
];
|
|
391
391
|
const targetId = (target) => target.kind === 'model' ? target.model.id : target.embedder.id;
|
|
392
|
+
/**
|
|
393
|
+
* A chat model sized for a probe: 16 output tokens is enough for "ok", and
|
|
394
|
+
* Anthropic requires a cap at all. Only the adapters that read `maxTokens` are
|
|
395
|
+
* given one — the registry refuses a knob its adapter would never send, and the
|
|
396
|
+
* OpenAI adapters have no such knob.
|
|
397
|
+
*/
|
|
398
|
+
export function probeChat(provider, id) {
|
|
399
|
+
const capped = { provider, model: id, maxTokens: 16 };
|
|
400
|
+
const unread = new ModelRegistry().knobs(capped).some((k) => k.knob === 'maxTokens');
|
|
401
|
+
return createModel(unread ? { provider, model: id } : capped);
|
|
402
|
+
}
|
|
392
403
|
/**
|
|
393
404
|
* Refused by the provider, unreachable, or served.
|
|
394
405
|
*
|
|
@@ -396,7 +407,7 @@ const targetId = (target) => target.kind === 'model' ? target.model.id : target.
|
|
|
396
407
|
* accepted and the id was the thing refused, so the fix is another model rather
|
|
397
408
|
* than another key. `dead` is left to mean the credential itself was rejected.
|
|
398
409
|
*/
|
|
399
|
-
function classifyModel(err, target) {
|
|
410
|
+
function classifyModel(err, target, ms) {
|
|
400
411
|
const at = new Date().toISOString();
|
|
401
412
|
const message = err instanceof Error ? err.message : String(err);
|
|
402
413
|
const e = err;
|
|
@@ -408,11 +419,31 @@ function classifyModel(err, target) {
|
|
|
408
419
|
return { state: 'blocked', at, detail: firstLine(message), fix: instead(target) };
|
|
409
420
|
}
|
|
410
421
|
const check = classify(err);
|
|
422
|
+
// classify() calls a 429 a live key; for a model it means nothing answered.
|
|
423
|
+
if (check.state === 'live') {
|
|
424
|
+
const said = err.detail;
|
|
425
|
+
return {
|
|
426
|
+
state: 'unknown',
|
|
427
|
+
at,
|
|
428
|
+
detail: `rate limited after ${(ms / 1000).toFixed(1)}s of retries: ${typeof said === 'string' ? said : firstLine(message)}`,
|
|
429
|
+
fix: limited(target),
|
|
430
|
+
};
|
|
431
|
+
}
|
|
411
432
|
return check.state === 'blocked' && !check.fix ? { ...check, fix: instead(target) } : check;
|
|
412
433
|
}
|
|
434
|
+
function limited(target) {
|
|
435
|
+
const blame = "the key and the model id are fine, the provider's rate limit is not";
|
|
436
|
+
if (target.ref.endsWith(':free')) {
|
|
437
|
+
return `${blame} — free models share a small upstream quota; retry later, or test the paid id: zen models test ${target.ref.slice(0, -':free'.length)}`;
|
|
438
|
+
}
|
|
439
|
+
return `${blame} — retry later`;
|
|
440
|
+
}
|
|
413
441
|
/** The command that finds something this account can actually use. */
|
|
414
442
|
function instead(target) {
|
|
415
443
|
const provider = target.ref.includes(':') ? target.ref.split(':')[0] : undefined;
|
|
444
|
+
if (provider === 'vertex' && vertexRoute(targetId(target)) !== 'gemini') {
|
|
445
|
+
return 'enable it for this project in Model Garden: https://console.cloud.google.com/vertex-ai/model-garden';
|
|
446
|
+
}
|
|
416
447
|
return provider
|
|
417
448
|
? `zen models ls ${provider}`
|
|
418
449
|
: `zen models pick --${target.kind === 'embedding' ? 'embedding' : 'chat'}`;
|
|
@@ -455,7 +486,8 @@ export async function probeModel(target) {
|
|
|
455
486
|
};
|
|
456
487
|
}
|
|
457
488
|
catch (err) {
|
|
458
|
-
|
|
489
|
+
const ms = Date.now() - started;
|
|
490
|
+
return { ...common, check: classifyModel(err, target, ms), ms };
|
|
459
491
|
}
|
|
460
492
|
}
|
|
461
493
|
/**
|
package/dist/main.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writes the editor's files under `dir`, replacing what is there. They are
|
|
3
|
+
* ours: they say how the editor is to treat a directory the agents write into,
|
|
4
|
+
* and they describe the file formats of the version of `zen` in hand, so the
|
|
5
|
+
* current answer is the only one worth having and a stale one is worse than
|
|
6
|
+
* none. Returns the relative paths that actually changed.
|
|
7
|
+
*/
|
|
8
|
+
export declare function editorFiles(dir: string): string[];
|
|
9
|
+
//# sourceMappingURL=editor.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { copyTree, TEMPLATES } from "./host.js";
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Telling the editor which instructions are not for it
|
|
5
|
+
//
|
|
6
|
+
// The project's house rules are `agents/instructions.md`, deliberately not
|
|
7
|
+
// `AGENTS.md`: every coding assistant now reads that name out of an open
|
|
8
|
+
// folder and feeds it to itself as always-on instructions, and `zen open`
|
|
9
|
+
// opens exactly this directory. A name nobody else claims means the two are
|
|
10
|
+
// never confused, and `chat.useAgentsMdFile` no longer has to be switched off
|
|
11
|
+
// to keep them apart.
|
|
12
|
+
//
|
|
13
|
+
// They sit under `agents/` because there is rarely only one of them. Anything
|
|
14
|
+
// named `agents/<topic>-instructions.md` is read too, in filename order, so a
|
|
15
|
+
// subject that is true for every agent but is about one capability — memory,
|
|
16
|
+
// say — gets its own document instead of another section in a file that keeps
|
|
17
|
+
// growing.
|
|
18
|
+
//
|
|
19
|
+
// `chat.useNestedAgentsMdFiles` is still written. It is already false by
|
|
20
|
+
// default, but it is opt-in globally, and this is a directory the agent itself
|
|
21
|
+
// writes into — someone who turned it on would otherwise have the editor pick
|
|
22
|
+
// up whatever `AGENTS.md` a run happened to leave behind. It is a *restricted*
|
|
23
|
+
// setting, so it applies only in a trusted workspace; that is the right way
|
|
24
|
+
// round, since an untrusted folder is not one to run agents in either.
|
|
25
|
+
//
|
|
26
|
+
// `agents/instructions.md` addresses the *project's* agents. The editor's
|
|
27
|
+
// assistant still needs a brief of its own, and what it needs to know is how
|
|
28
|
+
// this kind of project is put together — the file formats, how a prompt is
|
|
29
|
+
// written, when to add a skill rather than an agent. That is what the
|
|
30
|
+
// `.github/` tree is: the standing brief, plus the prompt files and skills the
|
|
31
|
+
// editor picks up from the same place.
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
/**
|
|
34
|
+
* Writes the editor's files under `dir`, replacing what is there. They are
|
|
35
|
+
* ours: they say how the editor is to treat a directory the agents write into,
|
|
36
|
+
* and they describe the file formats of the version of `zen` in hand, so the
|
|
37
|
+
* current answer is the only one worth having and a stale one is worse than
|
|
38
|
+
* none. Returns the relative paths that actually changed.
|
|
39
|
+
*/
|
|
40
|
+
export function editorFiles(dir) {
|
|
41
|
+
return copyTree(join(TEMPLATES, 'editor'), dir, '', {});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=editor.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Brief, type Step } from './brief.ts';
|
|
2
|
+
import type { Case } from './dataset/types.ts';
|
|
3
|
+
import { type Phase } from './feedback.ts';
|
|
4
|
+
import { type Attempt } from './report.ts';
|
|
5
|
+
import type { Run } from './train.ts';
|
|
6
|
+
import type { Tuning } from './tuning.ts';
|
|
7
|
+
export interface AnalyzeBrief extends Brief {
|
|
8
|
+
run: Run;
|
|
9
|
+
case: Case;
|
|
10
|
+
phase: Phase;
|
|
11
|
+
attempt: number;
|
|
12
|
+
/** earlier tries of this case revision, oldest first */
|
|
13
|
+
earlier: Attempt[];
|
|
14
|
+
/** the patch a recheck checks */
|
|
15
|
+
recheck?: string;
|
|
16
|
+
/** skills an apply made for this case that the run never loaded */
|
|
17
|
+
missed?: string[];
|
|
18
|
+
/** the try's folder: brief.md, feedback.json and ask/ live here */
|
|
19
|
+
dir: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const ANALYZE_BRIEF: Step<AnalyzeBrief>[];
|
|
22
|
+
/** The analysis brief as markdown. */
|
|
23
|
+
export declare function renderAnalyzeBrief(b: AnalyzeBrief, log: string, steps?: Step<AnalyzeBrief>[]): Promise<string>;
|
|
24
|
+
/** Writes `brief.md` into the try's folder; the path is what `--prompt-file` takes. */
|
|
25
|
+
export declare function writeAnalyzeBrief(t: Tuning, dir: string, at: Omit<AnalyzeBrief, 't' | 'systemDir' | 'project' | 'dir'>): Promise<string>;
|
|
26
|
+
//# sourceMappingURL=analyze-brief.d.ts.map
|