@hmharness/agent 0.3.0 → 0.4.0
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/runner.d.ts +5 -1
- package/dist/runner.js +28 -7
- package/dist/tools.js +6 -4
- package/package.json +5 -5
package/dist/runner.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* approval gate construction.
|
|
7
7
|
*/
|
|
8
8
|
import { Registry, type ChatMessage, type DeltaKind, type HmhConfig, type LoopApproval, type LoopResult, type McpClient, type McpServerConfig, type McpServerImport, type ToolContext } from '@hmharness/kernel';
|
|
9
|
+
import { type EmbeddingProvider } from '@hmharness/evolution';
|
|
9
10
|
import * as readline from 'node:readline/promises';
|
|
10
11
|
import { type SpawnBase } from './spawn.ts';
|
|
11
12
|
/** Flatten the config.json shape into the runtime discriminated union. */
|
|
@@ -29,7 +30,10 @@ export declare function buildRegistry(opts?: {
|
|
|
29
30
|
* P0 canary: ~20% of sessions (deterministic by session id) also receive
|
|
30
31
|
* the canary skill block, watermarked as experimental references - the
|
|
31
32
|
* impact loop compares these sessions against the rest. */
|
|
32
|
-
export declare function contextPack(task: string, sessionId?: string
|
|
33
|
+
export declare function contextPack(task: string, sessionId?: string, opts?: {
|
|
34
|
+
workspace?: string | null;
|
|
35
|
+
embedding?: EmbeddingProvider;
|
|
36
|
+
}): Promise<{
|
|
33
37
|
memory: string;
|
|
34
38
|
skills: string;
|
|
35
39
|
insights: string;
|
package/dist/runner.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* approval gate construction.
|
|
7
7
|
*/
|
|
8
8
|
import { homeDir, loadConfig, resolveProvider, mcpServerTools, Registry, runLoop, Session, } from '@hmharness/kernel';
|
|
9
|
-
import { appendMemory, listSkills, readInsights, readNotes, recentInsights, recordInsight, retrieveMemory, skillsToPrompt, sessionGetsCanary, canaryWatermark, listCanary } from '@hmharness/evolution';
|
|
9
|
+
import { appendMemory, listSkills, readInsights, readNotes, recentInsights, recordInsight, retrieveMemory, skillsToPrompt, sessionGetsCanary, canaryWatermark, listCanary, workspaceForCwd } from '@hmharness/evolution';
|
|
10
10
|
import { harmonyTools } from '@hmharness/domain-harmony';
|
|
11
11
|
import { opsTools } from '@hmharness/domain-ops';
|
|
12
12
|
import * as readline from 'node:readline/promises';
|
|
@@ -76,10 +76,10 @@ export async function buildRegistry(opts = {}) {
|
|
|
76
76
|
* P0 canary: ~20% of sessions (deterministic by session id) also receive
|
|
77
77
|
* the canary skill block, watermarked as experimental references - the
|
|
78
78
|
* impact loop compares these sessions against the rest. */
|
|
79
|
-
export async function contextPack(task, sessionId) {
|
|
79
|
+
export async function contextPack(task, sessionId, opts = {}) {
|
|
80
80
|
const home = homeDir();
|
|
81
81
|
const [memory, skills, insights] = await Promise.all([
|
|
82
|
-
retrieveMemory(home, task),
|
|
82
|
+
retrieveMemory(home, task, { workspace: opts.workspace ?? undefined, embedding: opts.embedding }),
|
|
83
83
|
listSkills(home),
|
|
84
84
|
recentInsights(home),
|
|
85
85
|
]);
|
|
@@ -129,9 +129,17 @@ export async function runAgentTask(opts) {
|
|
|
129
129
|
const ctx = opts.ctx ?? { cwd: process.cwd(), home: homeDir() };
|
|
130
130
|
const events = opts.events ?? {};
|
|
131
131
|
const session = new Session(ctx.home, ctx.cwd, cfg.provider.model);
|
|
132
|
+
// workspace scoping + optional embedding hybrid for memory retrieval.
|
|
133
|
+
// Embeddings only when routing.embedding is EXPLICITLY set - an inherited
|
|
134
|
+
// chat route would 404 on /embeddings once per task for nothing.
|
|
135
|
+
const workspace = await workspaceForCwd(ctx.home, ctx.cwd);
|
|
136
|
+
const embeddingRoute = cfg.routing?.['embedding'];
|
|
137
|
+
const embedding = embeddingRoute && cfg.providers?.[embeddingRoute]
|
|
138
|
+
? cfg.providers[embeddingRoute]
|
|
139
|
+
: undefined;
|
|
132
140
|
// contextPack needs the session id: canary injection is deterministic
|
|
133
141
|
// per-session (stable attribution), decided before the prompt is built
|
|
134
|
-
const pack = await contextPack(opts.task, session.id);
|
|
142
|
+
const pack = await contextPack(opts.task, session.id, { workspace, embedding });
|
|
135
143
|
const system = buildSystemPrompt({
|
|
136
144
|
cwd: ctx.cwd,
|
|
137
145
|
home: ctx.home,
|
|
@@ -160,13 +168,26 @@ export async function runAgentTask(opts) {
|
|
|
160
168
|
// note, so the NEXT session starts knowing what broke this one (the
|
|
161
169
|
// self-evolution loop's missing per-session feedback channel)
|
|
162
170
|
const toolErrors = new Map();
|
|
171
|
+
// rolling digest hook: compaction-evicted tool output is distilled into a
|
|
172
|
+
// persistent summary note by the chat model instead of being dropped
|
|
173
|
+
// (failures degrade silently to the deterministic prune inside the kernel)
|
|
174
|
+
const chatProvider = resolveProvider(cfg, 'chat');
|
|
175
|
+
const { chat: chatFn } = await import('@hmharness/kernel');
|
|
176
|
+
const summarizeContext = async (input) => {
|
|
177
|
+
const r = await chatFn(chatProvider, [
|
|
178
|
+
{ role: 'system', content: 'You compress evicted agent transcript content into a dense factual digest. Keep: what was done, key results, paths, versions, decisions, errors and their fixes. Drop: raw listings, repetition, fluff. Max 120 words. Plain text bullets, no preamble.' },
|
|
179
|
+
{ role: 'user', content: (input.previousDigest ? `PREVIOUS DIGEST (merge, keep still-relevant facts):\n${input.previousDigest}\n\n` : '') + `NEWLY EVICTED CONTENT:\n${input.evicted.join('\n---\n').slice(0, 24_000)}` },
|
|
180
|
+
]);
|
|
181
|
+
return r.message.content ?? '';
|
|
182
|
+
};
|
|
163
183
|
const result = await runLoop({
|
|
164
|
-
provider:
|
|
184
|
+
provider: chatProvider,
|
|
165
185
|
registry: opts.registry,
|
|
166
186
|
messages,
|
|
167
187
|
ctx,
|
|
168
188
|
maxTurns: cfg.maxTurns,
|
|
169
189
|
maxContextChars: cfg.maxContextChars,
|
|
190
|
+
summarizeContext,
|
|
170
191
|
approval: spawnBase.current.approval,
|
|
171
192
|
events: {
|
|
172
193
|
onDelta: (kind, chunk) => events.onDelta?.(kind, chunk),
|
|
@@ -207,7 +228,7 @@ export async function runAgentTask(opts) {
|
|
|
207
228
|
const last = notes.slice(-40).map((n) => n.text).join('\n');
|
|
208
229
|
if (last.includes(`[self-note] tool ${name}`))
|
|
209
230
|
continue;
|
|
210
|
-
await appendMemory(ctx.home, `[self-note] tool ${name} failed ${errs.length}x in one session; samples: ${[...new Set(errs)].slice(0, 2).join(' | ')}
|
|
231
|
+
await appendMemory(ctx.home, `[self-note] tool ${name} failed ${errs.length}x in one session; samples: ${[...new Set(errs)].slice(0, 2).join(' | ')}`, workspace ?? undefined);
|
|
211
232
|
}
|
|
212
233
|
}
|
|
213
234
|
catch {
|
|
@@ -232,7 +253,7 @@ export async function runAgentTask(opts) {
|
|
|
232
253
|
]);
|
|
233
254
|
const lesson = (r.message.content ?? '').trim();
|
|
234
255
|
if (lesson && lesson.toUpperCase() !== 'NONE' && lesson.length < 300) {
|
|
235
|
-
await appendMemory(ctx.home, `[lesson] ${lesson}
|
|
256
|
+
await appendMemory(ctx.home, `[lesson] ${lesson}`, workspace ?? undefined);
|
|
236
257
|
}
|
|
237
258
|
}
|
|
238
259
|
catch {
|
package/dist/tools.js
CHANGED
|
@@ -528,11 +528,13 @@ export const rememberTool = {
|
|
|
528
528
|
properties: { note: { type: 'string', description: 'the fact/lesson to remember, one line preferred' } },
|
|
529
529
|
required: ['note'],
|
|
530
530
|
},
|
|
531
|
-
async execute(args) {
|
|
531
|
+
async execute(args, ctx) {
|
|
532
532
|
try {
|
|
533
|
-
const { appendMemory } = await import('@hmharness/evolution');
|
|
534
|
-
|
|
535
|
-
|
|
533
|
+
const { appendMemory, workspaceForCwd } = await import('@hmharness/evolution');
|
|
534
|
+
const home = ctx?.home ?? homeDir();
|
|
535
|
+
const ws = await workspaceForCwd(home, ctx?.cwd ?? process.cwd());
|
|
536
|
+
await appendMemory(home, String(args.note ?? ''), ws ?? undefined);
|
|
537
|
+
return { output: ws ? `remembered (workspace: ${ws}).` : 'remembered.' };
|
|
536
538
|
}
|
|
537
539
|
catch (err) {
|
|
538
540
|
return { output: String(err), isError: true };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hmharness/agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
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,10 +15,10 @@
|
|
|
15
15
|
"build": "tsc -p tsconfig.build.json"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@hmharness/kernel": "0.
|
|
19
|
-
"@hmharness/evolution": "0.
|
|
20
|
-
"@hmharness/domain-harmony": "0.
|
|
21
|
-
"@hmharness/domain-ops": "0.
|
|
18
|
+
"@hmharness/kernel": "0.4.0",
|
|
19
|
+
"@hmharness/evolution": "0.4.0",
|
|
20
|
+
"@hmharness/domain-harmony": "0.4.0",
|
|
21
|
+
"@hmharness/domain-ops": "0.4.0"
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"dist"
|