@hmharness/agent 0.8.0 → 0.8.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/dist/i18n.d.ts +16 -0
- package/dist/i18n.js +32 -2
- package/dist/roles.d.ts +20 -0
- package/dist/roles.js +39 -0
- package/dist/runner.d.ts +3 -0
- package/dist/runner.js +4 -1
- package/dist/spawn.js +3 -2
- package/package.json +3 -3
package/dist/i18n.d.ts
CHANGED
|
@@ -74,6 +74,22 @@ export interface Strings {
|
|
|
74
74
|
cmdResumeNone: string;
|
|
75
75
|
cmdResumeNotFound: (p: string) => string;
|
|
76
76
|
cmdResumeLoaded: (n: number) => string;
|
|
77
|
+
/** Codex-style resume picker (v0.8.2 transplant) */
|
|
78
|
+
pickerTitle: string;
|
|
79
|
+
pickerHint1: string;
|
|
80
|
+
pickerHint2: string;
|
|
81
|
+
pickerEmpty: string;
|
|
82
|
+
pickerNoMatch: string;
|
|
83
|
+
pickerLoading: string;
|
|
84
|
+
pickerMore: string;
|
|
85
|
+
pickerPreviewNone: string;
|
|
86
|
+
pickerLabelFilter: string;
|
|
87
|
+
pickerLabelSort: string;
|
|
88
|
+
pickerValCwd: string;
|
|
89
|
+
pickerValAll: string;
|
|
90
|
+
pickerValUpdated: string;
|
|
91
|
+
pickerValCreated: string;
|
|
92
|
+
pickerPos: (pos: number, total: number, pct: string) => string;
|
|
77
93
|
tuiRadarScanning: string;
|
|
78
94
|
tuiEvolveDone: (proposals: number, insights: number, notes: number) => string;
|
|
79
95
|
tuiPassRate: (pct: string) => string;
|
package/dist/i18n.js
CHANGED
|
@@ -56,10 +56,25 @@ const zh = {
|
|
|
56
56
|
tuiScrolled: '↑ 已上滚 · PgDn/End/滚轮 回底',
|
|
57
57
|
tuiWebHint: '浏览器界面: 在另一个终端运行 hmh web --port=7788',
|
|
58
58
|
updateHint: (latest) => `新版本 ${latest} 可用: npm i -g @hmharness/cli 更新`,
|
|
59
|
-
cmdResume: '恢复历史会话(/resume 打开选择器,↑↓ 选择,Enter
|
|
59
|
+
cmdResume: '恢复历史会话(/resume 打开选择器,↑↓ 选择,Enter 载入;输入即过滤)',
|
|
60
60
|
cmdResumeNone: '还没有历史会话',
|
|
61
61
|
cmdResumeNotFound: (p) => `没有匹配 "${p}" 的会话`,
|
|
62
62
|
cmdResumeLoaded: (n) => `已恢复会话(${n} 条消息),直接输入内容继续对话`,
|
|
63
|
+
pickerTitle: '恢复会话',
|
|
64
|
+
pickerHint1: 'Enter 恢复 · ↑↓ 浏览 · Tab 切筛选/排序 · ←→ 调整',
|
|
65
|
+
pickerHint2: 'Esc 关闭 · 输入即过滤(标题/id/目录/分支)',
|
|
66
|
+
pickerEmpty: '还没有会话',
|
|
67
|
+
pickerNoMatch: '没有匹配的会话',
|
|
68
|
+
pickerLoading: '正在加载会话…',
|
|
69
|
+
pickerMore: '↓ 加载更多…',
|
|
70
|
+
pickerPreviewNone: '(无消息)',
|
|
71
|
+
pickerLabelFilter: '筛选',
|
|
72
|
+
pickerLabelSort: '排序',
|
|
73
|
+
pickerValCwd: '当前目录',
|
|
74
|
+
pickerValAll: '全部',
|
|
75
|
+
pickerValUpdated: '最近更新',
|
|
76
|
+
pickerValCreated: '创建时间',
|
|
77
|
+
pickerPos: (pos, total, pct) => ` ${pos} / ${total} · ${pct}% `,
|
|
63
78
|
tuiRadarScanning: '雷达扫描中…',
|
|
64
79
|
tuiEvolveDone: (p, i, n) => `evolve 完成: ${p} 提案 · 洞察 ${i} · 记忆 ${n}`,
|
|
65
80
|
tuiPassRate: (pct) => `pass rate: ${pct}`,
|
|
@@ -151,10 +166,25 @@ const en = {
|
|
|
151
166
|
tuiScrolled: '↑ scrolled up · PgDn/End/wheel back to bottom',
|
|
152
167
|
tuiWebHint: 'web UI: run hmh web --port=7788 in another terminal',
|
|
153
168
|
updateHint: (latest) => `version ${latest} available - update with: npm i -g @hmharness/cli`,
|
|
154
|
-
cmdResume: 'resume a past session (/resume opens the picker; arrows + Enter, type
|
|
169
|
+
cmdResume: 'resume a past session (/resume opens the picker; arrows + Enter, type to filter)',
|
|
155
170
|
cmdResumeNone: 'no past sessions yet',
|
|
156
171
|
cmdResumeNotFound: (p) => `no session matches "${p}"`,
|
|
157
172
|
cmdResumeLoaded: (n) => `session resumed (${n} messages) - just type to continue`,
|
|
173
|
+
pickerTitle: 'Resume session',
|
|
174
|
+
pickerHint1: 'Enter resume · ↑↓ browse · Tab filter/sort · ←→ change',
|
|
175
|
+
pickerHint2: 'Esc close · type to filter (title/id/dir/branch)',
|
|
176
|
+
pickerEmpty: 'no sessions yet',
|
|
177
|
+
pickerNoMatch: 'no results for your search',
|
|
178
|
+
pickerLoading: 'Loading sessions…',
|
|
179
|
+
pickerMore: '↓ loading more…',
|
|
180
|
+
pickerPreviewNone: '(no message yet)',
|
|
181
|
+
pickerLabelFilter: 'Filter',
|
|
182
|
+
pickerLabelSort: 'Sort',
|
|
183
|
+
pickerValCwd: 'Cwd',
|
|
184
|
+
pickerValAll: 'All',
|
|
185
|
+
pickerValUpdated: 'Updated',
|
|
186
|
+
pickerValCreated: 'Created',
|
|
187
|
+
pickerPos: (pos, total, pct) => ` ${pos} / ${total} · ${pct}% `,
|
|
158
188
|
tuiRadarScanning: 'scanning radar…',
|
|
159
189
|
tuiEvolveDone: (p, i, n) => `evolve done: ${p} proposals · ${i} insights · ${n} notes`,
|
|
160
190
|
tuiPassRate: (pct) => `pass rate: ${pct}`,
|
package/dist/roles.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hmharness/agent - team roles (V2 blueprint M7).
|
|
3
|
+
*
|
|
4
|
+
* spawn_agent already accepts a free-text role label with a success-rate
|
|
5
|
+
* leaderboard; this adds the canonical engineering-team CHARTERS. When a
|
|
6
|
+
* spawn names a canonical role, the child's system prompt carries that
|
|
7
|
+
* role's discipline text (what it always does / never does), turning
|
|
8
|
+
* "role: a word" into "role: a contract".
|
|
9
|
+
*/
|
|
10
|
+
export interface TeamRole {
|
|
11
|
+
name: string;
|
|
12
|
+
charter: string;
|
|
13
|
+
/** typical delegation phrasing hints, for docs only */
|
|
14
|
+
goodFor: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const TEAM_ROLES: Record<string, TeamRole>;
|
|
17
|
+
/** Resolve a role label to its charter (canonical names only); '' when free-form. */
|
|
18
|
+
export declare function roleCharter(role: string): string;
|
|
19
|
+
/** The known-role list for tool descriptions. */
|
|
20
|
+
export declare const TEAM_ROLE_NAMES: string[];
|
package/dist/roles.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const TEAM_ROLES = {
|
|
2
|
+
planner: {
|
|
3
|
+
name: 'planner',
|
|
4
|
+
charter: 'PLANNER duty: decompose the goal into ordered, verifiable steps. Output a numbered plan where every step names its verification (command/check). Never execute the steps yourself - plan only. Flag risks and unknowns explicitly.',
|
|
5
|
+
goodFor: 'task decomposition before implementation',
|
|
6
|
+
},
|
|
7
|
+
coder: {
|
|
8
|
+
name: 'coder',
|
|
9
|
+
charter: 'CODER duty: implement exactly the agreed step. Prefer surgical edits (edit_file) inside the workspace. Keep changes minimal and consistent with surrounding code. Run the cheapest verification that proves the change (build/lint/test) before answering.',
|
|
10
|
+
goodFor: 'focused implementation steps',
|
|
11
|
+
},
|
|
12
|
+
tester: {
|
|
13
|
+
name: 'tester',
|
|
14
|
+
charter: 'TESTER duty: try to BREAK the thing under test. Probe edge cases, empty inputs, wrong types, boundary values. Report each probe as input -> actual vs expected. A run with zero failures must say what WAS covered, never "all good".',
|
|
15
|
+
goodFor: 'adversarial verification',
|
|
16
|
+
},
|
|
17
|
+
reviewer: {
|
|
18
|
+
name: 'reviewer',
|
|
19
|
+
charter: 'REVIEWER duty: findings first, ordered by severity, each with file:line evidence. Prioritize bugs, regressions, and missing tests over style. No fixes - report only. If nothing significant, say so explicitly rather than inventing nits.',
|
|
20
|
+
goodFor: 'code review passes',
|
|
21
|
+
},
|
|
22
|
+
judge: {
|
|
23
|
+
name: 'judge',
|
|
24
|
+
charter: 'JUDGE duty: verdict from EVIDENCE, not from the executor\'s self-report. Cite what you actually observed (command outputs, file contents). Hard evidence (exit codes, tests) outranks your opinion; label opinion as opinion. End with VERDICT: PASS or VERDICT: FAIL plus one line why.',
|
|
25
|
+
goodFor: 'independent evaluation of a finished step',
|
|
26
|
+
},
|
|
27
|
+
repairer: {
|
|
28
|
+
name: 'repairer',
|
|
29
|
+
charter: 'REPAIRER duty: reproduce the failure first, state the root cause in one sentence, then apply the smallest fix that removes it, then re-run the reproduction to prove it is gone. Report before/after outputs.',
|
|
30
|
+
goodFor: 'fixing broken builds/tests',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
/** Resolve a role label to its charter (canonical names only); '' when free-form. */
|
|
34
|
+
export function roleCharter(role) {
|
|
35
|
+
const r = TEAM_ROLES[String(role ?? '').trim().toLowerCase()];
|
|
36
|
+
return r ? r.charter : '';
|
|
37
|
+
}
|
|
38
|
+
/** The known-role list for tool descriptions. */
|
|
39
|
+
export const TEAM_ROLE_NAMES = Object.keys(TEAM_ROLES);
|
package/dist/runner.d.ts
CHANGED
|
@@ -93,6 +93,9 @@ export interface AgentTaskOptions {
|
|
|
93
93
|
/** Overrides the terminal gate (web supplies a remote one). */
|
|
94
94
|
approvalAsk?: LoopApproval['ask'];
|
|
95
95
|
resumeMessages?: ChatMessage[];
|
|
96
|
+
/** Continue THIS session's rollout (append) instead of starting a new one -
|
|
97
|
+
* codex Resume semantics: one thread, one JSONL, appended across turns. */
|
|
98
|
+
sessionId?: string;
|
|
96
99
|
events?: RunnerEvents;
|
|
97
100
|
/** AbortSignal: cancels the agent loop at the next turn boundary. */
|
|
98
101
|
signal?: AbortSignal;
|
package/dist/runner.js
CHANGED
|
@@ -229,7 +229,10 @@ export async function runAgentTask(opts) {
|
|
|
229
229
|
const cfg = opts.cfg ?? (await loadConfig());
|
|
230
230
|
const ctx = opts.ctx ?? { cwd: process.cwd(), home: homeDir() };
|
|
231
231
|
const events = opts.events ?? {};
|
|
232
|
-
|
|
232
|
+
// resume = append to the same rollout; a missing/unreadable id falls back
|
|
233
|
+
// to a fresh session so a renamed-away file never breaks the conversation
|
|
234
|
+
const session = (opts.sessionId ? await Session.resume(ctx.home, opts.sessionId) : null)
|
|
235
|
+
?? Session.create(ctx.home, ctx.cwd, cfg.provider.model);
|
|
233
236
|
// V2 M1 flight recorder: every run leaves a typed, replayable trajectory
|
|
234
237
|
// under <home>/runs/<run-id>/. Best-effort by contract - storage failures
|
|
235
238
|
// are swallowed inside the recorder and can never fail the task itself.
|
package/dist/spawn.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { appendFile, mkdir, readFile } from 'node:fs/promises';
|
|
17
17
|
import { join } from 'node:path';
|
|
18
18
|
import { runLoop } from '@hmharness/kernel';
|
|
19
|
+
import { roleCharter } from "./roles.js";
|
|
19
20
|
export const MAX_SPAWN_DEPTH = 2;
|
|
20
21
|
export async function recordRole(home, role, ok) {
|
|
21
22
|
try {
|
|
@@ -62,7 +63,7 @@ export function makeSpawnTool(deps) {
|
|
|
62
63
|
type: 'object',
|
|
63
64
|
properties: {
|
|
64
65
|
task: { type: 'string', description: 'complete, self-contained instructions for the sub-agent' },
|
|
65
|
-
role: { type: 'string', description: 'optional label
|
|
66
|
+
role: { type: 'string', description: 'optional role label; canonical roles carry a duty charter: planner / coder / tester / reviewer / judge / repairer (plus any custom label - roles accumulate success rates you will see next time)' },
|
|
66
67
|
max_turns: { type: 'number', description: 'turn budget for the sub-agent (default 8, max 12)' },
|
|
67
68
|
},
|
|
68
69
|
required: ['task'],
|
|
@@ -92,7 +93,7 @@ export function makeSpawnTool(deps) {
|
|
|
92
93
|
}
|
|
93
94
|
const system = [
|
|
94
95
|
`You are a hmh sub-agent (depth ${childDepth}${role ? `, role: ${role}` : ''}). You have no conversation history beyond this task.`,
|
|
95
|
-
role ? `Perform the ${role} duty with that specialty's discipline.` : '',
|
|
96
|
+
role ? roleCharter(role) || `Perform the ${role} duty with that specialty's discipline.` : '',
|
|
96
97
|
'Do exactly what the task asks, use tools as needed, verify before answering, and reply with a concise result (the caller only sees your final answer).',
|
|
97
98
|
].filter(Boolean).join('\n');
|
|
98
99
|
base.onLine?.(`[${tag}] start: ${task.slice(0, 80)}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hmharness/agent",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "hmharness agent execution layer: base tools, system prompt, sub-agent spawn, and the shared task runner that frontends (cli, web) drive.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"build": "tsc -p tsconfig.build.json"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@hmharness/kernel": "0.8.
|
|
18
|
+
"@hmharness/kernel": "0.8.2",
|
|
19
19
|
"@hmharness/observability": "0.7.0",
|
|
20
|
-
"@hmharness/evolution": "0.8.
|
|
20
|
+
"@hmharness/evolution": "0.8.3",
|
|
21
21
|
"@hmharness/domain-harmony": "0.8.0",
|
|
22
22
|
"@hmharness/domain-ops": "0.8.0"
|
|
23
23
|
},
|