@hmharness/agent 0.6.8 → 0.7.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.
Files changed (2) hide show
  1. package/dist/runner.js +26 -0
  2. package/package.json +6 -5
package/dist/runner.js CHANGED
@@ -6,6 +6,7 @@
6
6
  * approval gate construction.
7
7
  */
8
8
  import { homeDir, loadConfig, resolveProvider, mcpServerTools, Registry, runLoop, Session, } from '@hmharness/kernel';
9
+ import { brief, createTrajectoryRecorder } from '@hmharness/observability';
9
10
  import { readFile } from 'node:fs/promises';
10
11
  import { readFileSync, writeFileSync } from 'node:fs';
11
12
  import { join, dirname } from 'node:path';
@@ -229,6 +230,11 @@ export async function runAgentTask(opts) {
229
230
  const ctx = opts.ctx ?? { cwd: process.cwd(), home: homeDir() };
230
231
  const events = opts.events ?? {};
231
232
  const session = new Session(ctx.home, ctx.cwd, cfg.provider.model);
233
+ // V2 M1 flight recorder: every run leaves a typed, replayable trajectory
234
+ // under <home>/runs/<run-id>/. Best-effort by contract - storage failures
235
+ // are swallowed inside the recorder and can never fail the task itself.
236
+ const traj = createTrajectoryRecorder(ctx.home, { task: opts.task, model: cfg.provider.model, cwd: ctx.cwd });
237
+ traj.emit('run.started', 'user', { task: brief(opts.task, 400) });
232
238
  // workspace scoping + optional embedding hybrid for memory retrieval.
233
239
  // Embeddings only when routing.embedding is EXPLICITLY set - an inherited
234
240
  // chat route would 404 on /embeddings once per task for nothing.
@@ -256,6 +262,14 @@ export async function runAgentTask(opts) {
256
262
  // watches IT - this makes the size visible every run (review finding #5)
257
263
  const systemTokens = Math.ceil(system.length / 4);
258
264
  events.onLine?.(` [prompt] system: ${system.length} chars (~${systemTokens} tokens) · ${agentsMd ? 'AGENTS.md: yes' : 'no AGENTS.md'}`);
265
+ traj.emit('context.assembled', 'system', {
266
+ systemChars: system.length,
267
+ systemTokens,
268
+ agentsMd: Boolean(agentsMd),
269
+ memoryChars: pack.memory.length,
270
+ skills: pack.skills.length,
271
+ insights: pack.insights.length,
272
+ });
259
273
  await session.user(opts.task);
260
274
  // YOLO fix: when yes=true the caller's approvalAsk (TUI dialog, web remote
261
275
  // gate) must NOT override the auto-approve gate - it used to take
@@ -306,6 +320,7 @@ export async function runAgentTask(opts) {
306
320
  onDelta: (kind, chunk) => events.onDelta?.(kind, chunk),
307
321
  onToolCall: (name, args) => {
308
322
  toolsUsed.push(name);
323
+ traj.emit('tool.requested', 'tool', { name, args: brief(args, 120) });
309
324
  events.onToolCall?.(name, args);
310
325
  },
311
326
  onToolResult: (name, output, isError) => {
@@ -313,19 +328,30 @@ export async function runAgentTask(opts) {
313
328
  const list = toolErrors.get(name) ?? [];
314
329
  list.push(output.split('\n')[0].slice(0, 120));
315
330
  toolErrors.set(name, list);
331
+ traj.emit('error.observed', 'tool', { name, preview: brief(output, 160) });
316
332
  }
317
333
  void session.tool(name, output, isError);
334
+ traj.emit('tool.completed', 'tool', { name, isError, preview: brief(output, 120) });
318
335
  events.onToolResult?.(name, output, isError);
319
336
  },
320
337
  onApproval: (name, args, granted) => {
321
338
  void session.approval(name, granted);
339
+ traj.emit(granted ? 'tool.approved' : 'tool.denied', 'system', { name });
322
340
  events.onApproval?.(name, args, granted);
323
341
  },
324
342
  onAssistant: async (m) => {
343
+ // stamp the event when the message lands, not after the session
344
+ // write drains - awaiting first made model.responded land AFTER
345
+ // run.completed in the timeline
346
+ traj.emit('model.responded', 'agent', { contentChars: m.content?.length ?? 0, toolCalls: m.tool_calls?.length ?? 0 });
325
347
  await session.assistant(m.content ?? null, m.tool_calls);
326
348
  },
327
349
  },
350
+ }).catch((err) => {
351
+ traj.finish({ success: false, reason: 'error', error: brief(String(err), 200) }, { toolUses: toolsUsed.length });
352
+ throw err;
328
353
  });
354
+ traj.finish({ success: result.reason === 'final', reason: result.reason }, { turns: result.turns, toolUses: result.toolUses, promptTokens: result.usage.promptTokens, completionTokens: result.usage.completionTokens });
329
355
  // ---- instant feedback: learn from THIS task's mistakes, not 8 tasks later ----
330
356
  // Tier 1 (always, zero cost): raw error pattern → memory self-note. Lowered
331
357
  // to 1 failure for system-level patterns (shell incompat, auth, missing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hmharness/agent",
3
- "version": "0.6.8",
3
+ "version": "0.7.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,11 @@
15
15
  "build": "tsc -p tsconfig.build.json"
16
16
  },
17
17
  "dependencies": {
18
- "@hmharness/kernel": "0.6.8",
19
- "@hmharness/evolution": "0.6.8",
20
- "@hmharness/domain-harmony": "0.6.8",
21
- "@hmharness/domain-ops": "0.6.8"
18
+ "@hmharness/kernel": "0.7.0",
19
+ "@hmharness/observability": "0.7.0",
20
+ "@hmharness/evolution": "0.7.0",
21
+ "@hmharness/domain-harmony": "0.7.0",
22
+ "@hmharness/domain-ops": "0.7.0"
22
23
  },
23
24
  "files": [
24
25
  "dist"