zidane 1.6.8 → 1.6.10

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 CHANGED
@@ -225,36 +225,37 @@ agent.hooks.hook('stream:thinking', (ctx) => {
225
225
 
226
226
  ### Tool execution
227
227
 
228
- ```ts
229
- agent.hooks.hook('tool:before', (ctx) => { /* ctx.name, ctx.input */ })
230
- agent.hooks.hook('tool:after', (ctx) => { /* ctx.name, ctx.input, ctx.result */ })
231
- agent.hooks.hook('tool:error', (ctx) => { /* ctx.name, ctx.input, ctx.error */ })
232
- ```
233
-
234
- ### Tool gate
235
-
236
- Block a tool from running:
228
+ All tool hooks include `turnId` and `callId` for correlation. Typed via `ToolHookContext`.
237
229
 
238
230
  ```ts
239
231
  agent.hooks.hook('tool:gate', (ctx) => {
232
+ // ctx.turnId, ctx.callId, ctx.name, ctx.input
240
233
  if (ctx.name === 'shell' && String(ctx.input.command).includes('rm -rf')) {
241
234
  ctx.block = true
242
235
  ctx.reason = 'dangerous command'
243
236
  }
244
237
  })
245
- ```
246
-
247
- ### Tool transform
248
-
249
- Modify tool output before it's sent back to the model:
250
238
 
251
- ```ts
239
+ agent.hooks.hook('tool:before', (ctx) => { /* ctx.turnId, ctx.callId, ctx.name, ctx.input */ })
240
+ agent.hooks.hook('tool:after', (ctx) => { /* + ctx.result */ })
241
+ agent.hooks.hook('tool:error', (ctx) => { /* + ctx.error */ })
252
242
  agent.hooks.hook('tool:transform', (ctx) => {
243
+ // + ctx.result, ctx.isError — mutate to modify output
253
244
  if (ctx.result.length > 5000)
254
245
  ctx.result = ctx.result.slice(0, 5000) + '\n... (truncated)'
255
246
  })
256
247
  ```
257
248
 
249
+ MCP tool hooks mirror the same pattern with `server` and `tool` fields. Typed via `McpToolHookContext`.
250
+
251
+ ```ts
252
+ agent.hooks.hook('mcp:tool:gate', (ctx) => { /* ctx.turnId, ctx.callId, ctx.server, ctx.tool, ctx.input, ctx.block, ctx.reason */ })
253
+ agent.hooks.hook('mcp:tool:before', (ctx) => { /* ctx.turnId, ctx.callId, ctx.server, ctx.tool, ctx.input */ })
254
+ agent.hooks.hook('mcp:tool:after', (ctx) => { /* + ctx.result */ })
255
+ agent.hooks.hook('mcp:tool:transform', (ctx) => { /* + ctx.result — mutate to modify */ })
256
+ agent.hooks.hook('mcp:tool:error', (ctx) => { /* + ctx.error */ })
257
+ ```
258
+
258
259
  ### Context transform
259
260
 
260
261
  Prune messages before each LLM call:
@@ -581,6 +582,9 @@ All types are available from `zidane/types`:
581
582
 
582
583
  ```ts
583
584
  import type { Agent, SessionTurn, TurnUsage, Provider, ToolDef } from 'zidane/types'
585
+
586
+ // Hook context types for typed event handlers
587
+ import type { ToolHookContext, McpToolHookContext, SessionHookContext, StreamHookContext } from 'zidane/types'
584
588
  ```
585
589
 
586
590
  ## Testing
@@ -589,7 +593,7 @@ import type { Agent, SessionTurn, TurnUsage, Provider, ToolDef } from 'zidane/ty
589
593
  bun test
590
594
  ```
591
595
 
592
- 484+ tests with mock provider and execution context. No API keys or Docker needed.
596
+ 489+ tests with mock provider and execution context. No API keys or Docker needed.
593
597
 
594
598
  ## License
595
599
 
@@ -777,13 +777,28 @@ ${skillsCatalog}`;
777
777
  hooks.callHook("session:turns", { sessionId: session.id, count: turns.length });
778
778
  }
779
779
  }) : void 0;
780
+ async function flushTurns() {
781
+ if (!session) return;
782
+ const remaining = turns.slice(lastPersistedTurnCount);
783
+ if (remaining.length > 0) {
784
+ await session.appendTurns(remaining);
785
+ lastPersistedTurnCount = turns.length;
786
+ }
787
+ }
788
+ async function finalizeSession(status) {
789
+ if (!session) return;
790
+ const run2 = session.runs.find((r) => r.id === runId);
791
+ if (run2)
792
+ await session.updateRun(run2);
793
+ await session.updateStatus(status === "aborted" ? "idle" : status);
794
+ await hooks.callHook("session:end", { sessionId: session.id, runId, status, turnRange: [runTurnStart, turns.length - 1] });
795
+ }
780
796
  try {
781
797
  const stats = await runLoop({
782
798
  provider,
783
799
  hooks,
784
800
  harness,
785
801
  tools,
786
- toolSpecs,
787
802
  formattedTools,
788
803
  model,
789
804
  system,
@@ -806,26 +821,16 @@ ${skillsCatalog}`;
806
821
  ...stats,
807
822
  children: childrenStats.length > 0 ? childrenStats : void 0
808
823
  };
824
+ await flushTurns();
809
825
  if (abortController.signal.aborted) {
810
826
  session?.abortRun(runId);
811
- if (session) {
812
- const run2 = session.runs.find((r) => r.id === runId);
813
- if (run2)
814
- await session.updateRun(run2);
815
- await session.updateStatus("idle");
816
- await hooks.callHook("session:end", { sessionId: session.id, runId, status: "aborted", turnRange: [runTurnStart, turns.length - 1] });
817
- }
827
+ await finalizeSession("aborted");
818
828
  await hooks.callHook("agent:done", finalStats);
819
829
  return finalStats;
820
830
  }
821
831
  const totalCost = finalStats.turnUsage?.reduce((sum, t) => sum + (t.cost ?? 0), 0);
822
832
  if (totalCost)
823
833
  finalStats.cost = totalCost;
824
- const finalNewTurns = turns.slice(lastPersistedTurnCount);
825
- if (session && finalNewTurns.length > 0) {
826
- await session.appendTurns(finalNewTurns);
827
- lastPersistedTurnCount = turns.length;
828
- }
829
834
  session?.completeRun(runId, {
830
835
  turns: finalStats.turns,
831
836
  tokensIn: finalStats.totalIn,
@@ -833,37 +838,20 @@ ${skillsCatalog}`;
833
838
  turnUsage: finalStats.turnUsage,
834
839
  cost: totalCost
835
840
  });
836
- if (session) {
837
- const run2 = session.runs.find((r) => r.id === runId);
838
- if (run2)
839
- await session.updateRun(run2);
840
- await session.updateStatus("completed");
841
- await hooks.callHook("session:end", { sessionId: session.id, runId, status: "completed", turnRange: [runTurnStart, turns.length - 1] });
842
- }
841
+ await finalizeSession("completed");
843
842
  await hooks.callHook("agent:done", finalStats);
844
843
  return finalStats;
845
844
  } catch (err) {
845
+ await flushTurns();
846
846
  if (abortController.signal.aborted) {
847
847
  session?.abortRun(runId);
848
- if (session) {
849
- const run2 = session.runs.find((r) => r.id === runId);
850
- if (run2)
851
- await session.updateRun(run2);
852
- await session.updateStatus("idle");
853
- await hooks.callHook("session:end", { sessionId: session.id, runId, status: "aborted", turnRange: [runTurnStart, turns.length - 1] });
854
- }
848
+ await finalizeSession("aborted");
855
849
  const stats = { totalIn: 0, totalOut: 0, turns: 0, elapsed: 0 };
856
850
  await hooks.callHook("agent:done", stats);
857
851
  return stats;
858
852
  }
859
853
  session?.errorRun(runId, err.message);
860
- if (session) {
861
- const run2 = session.runs.find((r) => r.id === runId);
862
- if (run2)
863
- await session.updateRun(run2);
864
- await session.updateStatus("error");
865
- await hooks.callHook("session:end", { sessionId: session.id, runId, status: "error", turnRange: [runTurnStart, turns.length - 1] });
866
- }
854
+ await finalizeSession("error");
867
855
  throw err;
868
856
  } finally {
869
857
  unregisterSpawnHook();
@@ -4,7 +4,7 @@ import {
4
4
  shell,
5
5
  spawn,
6
6
  writeFile
7
- } from "./chunk-GCALAOLD.js";
7
+ } from "./chunk-GGPBK22K.js";
8
8
 
9
9
  // src/harnesses/basic.ts
10
10
  var basicTools = { shell, readFile, writeFile, listFiles };
package/dist/harnesses.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  basic_default,
4
4
  defineHarness,
5
5
  noTools
6
- } from "./chunk-Z2NZSEBZ.js";
7
- import "./chunk-GCALAOLD.js";
6
+ } from "./chunk-NPXSTO6S.js";
7
+ import "./chunk-GGPBK22K.js";
8
8
  import "./chunk-5LOHDFK3.js";
9
9
  import "./chunk-4C6Y56CC.js";
10
10
  export {
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  defineHarness,
3
3
  noTools
4
- } from "./chunk-Z2NZSEBZ.js";
4
+ } from "./chunk-NPXSTO6S.js";
5
5
  import {
6
6
  createAgent,
7
7
  createDockerContext,
@@ -10,7 +10,7 @@ import {
10
10
  createSandboxContext,
11
11
  createSpawnTool,
12
12
  spawn
13
- } from "./chunk-GCALAOLD.js";
13
+ } from "./chunk-GGPBK22K.js";
14
14
  import {
15
15
  connectMcpServers
16
16
  } from "./chunk-5LOHDFK3.js";
package/dist/tools.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  spawn,
8
8
  validateToolArgs,
9
9
  writeFile
10
- } from "./chunk-GCALAOLD.js";
10
+ } from "./chunk-GGPBK22K.js";
11
11
  import "./chunk-5LOHDFK3.js";
12
12
  import "./chunk-4C6Y56CC.js";
13
13
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zidane",
3
- "version": "1.6.8",
3
+ "version": "1.6.10",
4
4
  "description": "an agent that goes straight to the goal",
5
5
  "type": "module",
6
6
  "private": false,