@polpo-ai/core 0.8.1 → 0.10.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 (65) hide show
  1. package/dist/approval-manager.d.ts +1 -0
  2. package/dist/approval-manager.d.ts.map +1 -1
  3. package/dist/approval-manager.js +7 -9
  4. package/dist/approval-manager.js.map +1 -1
  5. package/dist/index.d.ts +12 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +9 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/loop/contract.test.d.ts +2 -0
  10. package/dist/loop/contract.test.d.ts.map +1 -0
  11. package/dist/loop/contract.test.js +106 -0
  12. package/dist/loop/contract.test.js.map +1 -0
  13. package/dist/loop/expression.d.ts +29 -0
  14. package/dist/loop/expression.d.ts.map +1 -0
  15. package/dist/loop/expression.js +215 -0
  16. package/dist/loop/expression.js.map +1 -0
  17. package/dist/loop/expression.test.d.ts +2 -0
  18. package/dist/loop/expression.test.d.ts.map +1 -0
  19. package/dist/loop/expression.test.js +55 -0
  20. package/dist/loop/expression.test.js.map +1 -0
  21. package/dist/loop/hooks.d.ts +132 -0
  22. package/dist/loop/hooks.d.ts.map +1 -0
  23. package/dist/loop/hooks.js +85 -0
  24. package/dist/loop/hooks.js.map +1 -0
  25. package/dist/loop/normalize.d.ts +4 -0
  26. package/dist/loop/normalize.d.ts.map +1 -0
  27. package/dist/loop/normalize.js +88 -0
  28. package/dist/loop/normalize.js.map +1 -0
  29. package/dist/loop/pipeline.d.ts +45 -0
  30. package/dist/loop/pipeline.d.ts.map +1 -0
  31. package/dist/loop/pipeline.js +128 -0
  32. package/dist/loop/pipeline.js.map +1 -0
  33. package/dist/loop/pipeline.test.d.ts +2 -0
  34. package/dist/loop/pipeline.test.d.ts.map +1 -0
  35. package/dist/loop/pipeline.test.js +127 -0
  36. package/dist/loop/pipeline.test.js.map +1 -0
  37. package/dist/loop/runner.d.ts +44 -0
  38. package/dist/loop/runner.d.ts.map +1 -0
  39. package/dist/loop/runner.js +215 -0
  40. package/dist/loop/runner.js.map +1 -0
  41. package/dist/loop/runner.test.d.ts +2 -0
  42. package/dist/loop/runner.test.d.ts.map +1 -0
  43. package/dist/loop/runner.test.js +124 -0
  44. package/dist/loop/runner.test.js.map +1 -0
  45. package/dist/loop/selector.d.ts +13 -0
  46. package/dist/loop/selector.d.ts.map +1 -0
  47. package/dist/loop/selector.js +65 -0
  48. package/dist/loop/selector.js.map +1 -0
  49. package/dist/loop/selector.test.d.ts +2 -0
  50. package/dist/loop/selector.test.d.ts.map +1 -0
  51. package/dist/loop/selector.test.js +70 -0
  52. package/dist/loop/selector.test.js.map +1 -0
  53. package/dist/loop/types.d.ts +163 -0
  54. package/dist/loop/types.d.ts.map +1 -0
  55. package/dist/loop/types.js +14 -0
  56. package/dist/loop/types.js.map +1 -0
  57. package/dist/schemas.d.ts +204 -0
  58. package/dist/schemas.d.ts.map +1 -1
  59. package/dist/schemas.js +220 -0
  60. package/dist/schemas.js.map +1 -1
  61. package/dist/types.d.ts +13 -0
  62. package/dist/types.d.ts.map +1 -1
  63. package/dist/types.js +0 -1
  64. package/dist/types.js.map +1 -1
  65. package/package.json +1 -1
@@ -0,0 +1,127 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { LoopHookRegistry } from "./hooks.js";
3
+ import { PipelineExecutor } from "./pipeline.js";
4
+ describe("PipelineExecutor", () => {
5
+ it("runs sequential loop steps and accumulates context by loop name", async () => {
6
+ const executor = new PipelineExecutor();
7
+ const result = await executor.execute({
8
+ loops: { plan: {}, build: {} },
9
+ pipeline: { steps: [{ loop: "plan" }, { loop: "build", when: "plan.ready == true" }] },
10
+ runLoop: async (name) => ({ output: { ready: true, name } }),
11
+ });
12
+ expect(result.context).toMatchObject({
13
+ plan: { ready: true, name: "plan" },
14
+ build: { ready: true, name: "build" },
15
+ });
16
+ expect(result.trace.map(e => e.type)).toEqual(["loop", "loop"]);
17
+ });
18
+ it("routes switch branches deterministically from context", async () => {
19
+ const executor = new PipelineExecutor();
20
+ const result = await executor.execute({
21
+ loops: { review: {}, fix: {}, ship: {} },
22
+ context: { review: { passed: false } },
23
+ pipeline: {
24
+ steps: [{
25
+ switch: {
26
+ cases: [
27
+ { when: "review.passed == true", steps: [{ loop: "ship" }] },
28
+ { when: "review.passed == false", steps: [{ loop: "fix" }] },
29
+ ],
30
+ },
31
+ }],
32
+ },
33
+ runLoop: async (name) => ({ output: { ran: name } }),
34
+ });
35
+ expect(result.context.fix).toEqual({ ran: "fix" });
36
+ expect(result.context.ship).toBeUndefined();
37
+ });
38
+ it("runs parallel branches against a frozen snapshot and merges by branch output", async () => {
39
+ const executor = new PipelineExecutor();
40
+ const result = await executor.execute({
41
+ loops: { test: {}, typecheck: {} },
42
+ context: { build: { done: true } },
43
+ pipeline: { steps: [{ parallel: [{ loop: "test" }, { loop: "typecheck" }], join: "all" }] },
44
+ runLoop: async (name, _loop, context) => {
45
+ expect(() => (context.mutated = true)).toThrow();
46
+ return { output: { passed: name === "test" || name === "typecheck" } };
47
+ },
48
+ });
49
+ expect(result.context).toMatchObject({
50
+ test: { passed: true },
51
+ typecheck: { passed: true },
52
+ });
53
+ expect(result.context.mutated).toBeUndefined();
54
+ });
55
+ it("supports human nodes through an injected handler", async () => {
56
+ const executor = new PipelineExecutor();
57
+ const result = await executor.execute({
58
+ loops: {},
59
+ pipeline: { steps: [{ human: "underwriter" }] },
60
+ runLoop: async () => ({ output: {} }),
61
+ handleHuman: async () => ({ output: { decision: "approve" } }),
62
+ });
63
+ expect(result.context.underwriter).toEqual({ decision: "approve" });
64
+ });
65
+ it("runs deterministic tool steps and stores output at saveAs path", async () => {
66
+ const executor = new PipelineExecutor();
67
+ const result = await executor.execute({
68
+ loops: { plan: {} },
69
+ pipeline: {
70
+ steps: [
71
+ { tool: "clone_repository", input: { repoUrl: "https://github.com/acme/app.git" }, saveAs: "repo.clone" },
72
+ { loop: "plan", when: "repo.clone.ok == true" },
73
+ ],
74
+ },
75
+ runTool: async (name, input, context) => {
76
+ expect(name).toBe("clone_repository");
77
+ expect(input).toEqual({ repoUrl: "https://github.com/acme/app.git" });
78
+ expect(() => (context.mutated = true)).toThrow();
79
+ return { output: { ok: true, path: "workspace/app" } };
80
+ },
81
+ runLoop: async (name) => ({ output: { planned: name } }),
82
+ });
83
+ expect(result.context).toMatchObject({
84
+ repo: { clone: { ok: true, path: "workspace/app" } },
85
+ plan: { planned: "plan" },
86
+ });
87
+ expect(result.trace.map(e => e.type)).toEqual(["tool", "loop"]);
88
+ });
89
+ it("fires loop:transition hooks between sequential loop nodes", async () => {
90
+ const hooks = new LoopHookRegistry();
91
+ const transitions = [];
92
+ hooks.register({
93
+ hook: "loop:transition",
94
+ phase: "before",
95
+ handler: (ctx) => {
96
+ transitions.push(`${ctx.data.from}->${ctx.data.to}`);
97
+ },
98
+ });
99
+ const executor = new PipelineExecutor();
100
+ await executor.execute({
101
+ hooks,
102
+ loops: { plan: {}, build: {} },
103
+ pipeline: { steps: [{ loop: "plan" }, { loop: "build" }] },
104
+ runLoop: async (name) => ({ output: { name } }),
105
+ });
106
+ expect(transitions).toEqual(["plan->build"]);
107
+ });
108
+ it("blocks a transition when loop:transition is cancelled", async () => {
109
+ const hooks = new LoopHookRegistry();
110
+ hooks.register({
111
+ hook: "loop:transition",
112
+ phase: "before",
113
+ handler: (ctx) => {
114
+ if (ctx.data.from === "plan" && ctx.data.to === "build")
115
+ ctx.cancel("approval required");
116
+ },
117
+ });
118
+ const executor = new PipelineExecutor();
119
+ await expect(executor.execute({
120
+ hooks,
121
+ loops: { plan: {}, build: {} },
122
+ pipeline: { steps: [{ loop: "plan" }, { loop: "build" }] },
123
+ runLoop: async (name) => ({ output: { name } }),
124
+ })).rejects.toThrow('Loop transition from "plan" to "build" cancelled: approval required');
125
+ });
126
+ });
127
+ //# sourceMappingURL=pipeline.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.test.js","sourceRoot":"","sources":["../../src/loop/pipeline.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC;YACpC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YAC9B,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC,EAAE;YACtF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;SAC7D,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC;YACnC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;YACnC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;SACtC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC;YACpC,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;YACxC,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;YACtC,QAAQ,EAAE;gBACR,KAAK,EAAE,CAAC;wBACN,MAAM,EAAE;4BACN,KAAK,EAAE;gCACL,EAAE,IAAI,EAAE,uBAAuB,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE;gCAC5D,EAAE,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE;6BAC7D;yBACF;qBACF,CAAC;aACH;YACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC;SACrD,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8EAA8E,EAAE,KAAK,IAAI,EAAE;QAC5F,MAAM,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC;YACpC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;YAClC,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;YAClC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE;YAC3F,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;gBACtC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAE,OAAe,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;gBAC1D,OAAO,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,WAAW,EAAE,EAAE,CAAC;YACzE,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC;YACnC,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;YACtB,SAAS,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;SAC5B,CAAC,CAAC;QACH,MAAM,CAAE,MAAM,CAAC,OAAe,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC;YACpC,KAAK,EAAE,EAAE;YACT,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;YAC/C,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;YACrC,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC;SAC/D,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC;YACpC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;YACnB,QAAQ,EAAE;gBACR,KAAK,EAAE;oBACL,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,iCAAiC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE;oBACzG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,EAAE;iBAChD;aACF;YACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;gBACtC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;gBACtC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,iCAAiC,EAAE,CAAC,CAAC;gBACtE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAE,OAAe,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;gBAC1D,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,CAAC;YACzD,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;SACzD,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC;YACnC,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE;YACpD,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;SAC1B,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QACzE,MAAM,KAAK,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACrC,MAAM,WAAW,GAAa,EAAE,CAAC;QACjC,KAAK,CAAC,QAAQ,CAAC;YACb,IAAI,EAAE,iBAAiB;YACvB,KAAK,EAAE,QAAQ;YACf,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACf,WAAW,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YACvD,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACxC,MAAM,QAAQ,CAAC,OAAO,CAAC;YACrB,KAAK;YACL,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YAC9B,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE;YAC1D,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC;SAChD,CAAC,CAAC;QAEH,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,KAAK,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACrC,KAAK,CAAC,QAAQ,CAAC;YACb,IAAI,EAAE,iBAAiB;YACvB,KAAK,EAAE,QAAQ;YACf,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACf,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,OAAO;oBAAE,GAAG,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;YAC3F,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACxC,MAAM,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;YAC5B,KAAK;YACL,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YAC9B,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE;YAC1D,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC;SAChD,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,qEAAqE,CAAC,CAAC;IAC7F,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,44 @@
1
+ import type { AgentConfig } from "../types.js";
2
+ import type { ContextBag, LoopConfig } from "./types.js";
3
+ import { LoopHookRegistry, type LoopRuntimeConfig, type LoopRunStatus, type LoopStopReason, type LoopToolCall, type LoopToolResult } from "./hooks.js";
4
+ export interface LoopModelInput {
5
+ agent?: AgentConfig;
6
+ loop: LoopRuntimeConfig;
7
+ turn: number;
8
+ context: ContextBag;
9
+ activeTools?: string[];
10
+ toolChoice?: unknown;
11
+ }
12
+ export interface LoopModelResult {
13
+ text: string;
14
+ toolCalls?: LoopToolCall[];
15
+ usage?: unknown;
16
+ }
17
+ export interface LoopRunResult {
18
+ status: LoopRunStatus;
19
+ reason: LoopStopReason;
20
+ turns: number;
21
+ text: string;
22
+ context: ContextBag;
23
+ toolResults: LoopToolResult[];
24
+ }
25
+ export interface LoopRunnerOptions {
26
+ agent?: AgentConfig;
27
+ loop: LoopConfig & {
28
+ name?: string;
29
+ };
30
+ context?: ContextBag;
31
+ input?: unknown;
32
+ hooks?: LoopHookRegistry;
33
+ maxTurns?: number;
34
+ model: (input: LoopModelInput) => Promise<LoopModelResult>;
35
+ executeTool: (toolCall: LoopToolCall, input: LoopModelInput) => Promise<string>;
36
+ }
37
+ export declare class LoopRunner {
38
+ private readonly hooks;
39
+ private readonly evaluator;
40
+ constructor(hooks?: LoopHookRegistry);
41
+ run(options: LoopRunnerOptions): Promise<LoopRunResult>;
42
+ private finish;
43
+ }
44
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/loop/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EACL,gBAAgB,EAChB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,UAAU,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,UAAU,CAAC;IACpB,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,UAAU,GAAG;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3D,WAAW,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACjF;AA8BD,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiC;gBAE/C,KAAK,CAAC,EAAE,gBAAgB;IAI9B,GAAG,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC;YAiL/C,MAAM;CAuBrB"}
@@ -0,0 +1,215 @@
1
+ import { SafeExpressionEvaluator } from "./expression.js";
2
+ import { LoopHookRegistry, } from "./hooks.js";
3
+ const DEFAULT_MAX_TURNS = 20;
4
+ function normalizeLoop(loop) {
5
+ return {
6
+ ...loop,
7
+ name: loop.name ?? "default",
8
+ };
9
+ }
10
+ function shouldStopAfterTurn(loop, context, result, turn, maxTurns, evaluator) {
11
+ const reachedMaxTurns = turn + 1 >= maxTurns;
12
+ if (loop.stopWhen) {
13
+ const matched = evaluator.evaluate(loop.stopWhen.expression, context);
14
+ if (matched)
15
+ return { reason: "completed", shouldStop: true };
16
+ return reachedMaxTurns ? { reason: "max_turns", shouldStop: true } : { reason: "completed", shouldStop: false };
17
+ }
18
+ if ((result.toolCalls ?? []).length === 0)
19
+ return { reason: "completed", shouldStop: true };
20
+ if (reachedMaxTurns)
21
+ return { reason: "max_turns", shouldStop: true };
22
+ return { reason: "completed", shouldStop: false };
23
+ }
24
+ export class LoopRunner {
25
+ hooks;
26
+ evaluator = new SafeExpressionEvaluator();
27
+ constructor(hooks) {
28
+ this.hooks = hooks ?? new LoopHookRegistry();
29
+ }
30
+ async run(options) {
31
+ const hooks = options.hooks ?? this.hooks;
32
+ const loop = normalizeLoop(options.loop);
33
+ const context = options.context ?? {};
34
+ const maxTurns = options.maxTurns ?? loop.maxTurns ?? DEFAULT_MAX_TURNS;
35
+ let finalText = "";
36
+ let turns = 0;
37
+ const allToolResults = [];
38
+ const start = await hooks.runBefore("loop:start", {
39
+ agent: options.agent,
40
+ loop,
41
+ context,
42
+ input: options.input,
43
+ });
44
+ if (start.cancelled) {
45
+ return this.finish(hooks, {
46
+ agent: options.agent,
47
+ loop,
48
+ context,
49
+ status: "cancelled",
50
+ reason: "cancelled",
51
+ turns,
52
+ text: finalText,
53
+ toolResults: allToolResults,
54
+ });
55
+ }
56
+ for (let turn = 0; turn < maxTurns; turn++) {
57
+ turns = turn + 1;
58
+ const step = await hooks.runBefore("step:before", {
59
+ agent: options.agent,
60
+ loop,
61
+ turn,
62
+ context,
63
+ activeTools: loop.tools,
64
+ });
65
+ if (step.cancelled) {
66
+ return this.finish(hooks, {
67
+ agent: options.agent,
68
+ loop,
69
+ context,
70
+ status: "cancelled",
71
+ reason: "cancelled",
72
+ turns,
73
+ text: finalText,
74
+ toolResults: allToolResults,
75
+ });
76
+ }
77
+ const modelBefore = await hooks.runBefore("model:before", {
78
+ agent: options.agent,
79
+ loop,
80
+ turn,
81
+ context,
82
+ activeTools: step.data.activeTools,
83
+ toolChoice: step.data.toolChoice,
84
+ });
85
+ if (modelBefore.cancelled) {
86
+ return this.finish(hooks, {
87
+ agent: options.agent,
88
+ loop,
89
+ context,
90
+ status: "cancelled",
91
+ reason: "cancelled",
92
+ turns,
93
+ text: finalText,
94
+ toolResults: allToolResults,
95
+ });
96
+ }
97
+ const modelInput = {
98
+ agent: options.agent,
99
+ loop,
100
+ turn,
101
+ context,
102
+ activeTools: modelBefore.data.activeTools,
103
+ toolChoice: modelBefore.data.toolChoice,
104
+ };
105
+ const modelResult = await options.model(modelInput);
106
+ finalText += modelResult.text;
107
+ const toolResults = [];
108
+ for (const rawCall of modelResult.toolCalls ?? []) {
109
+ const before = await hooks.runBefore("tool:before", {
110
+ agent: options.agent,
111
+ loop,
112
+ turn,
113
+ context,
114
+ toolCall: { ...rawCall, args: { ...rawCall.args } },
115
+ });
116
+ const toolCall = before.data.toolCall;
117
+ const skipped = before.cancelled;
118
+ const result = skipped
119
+ ? before.data.result ?? `Error: Tool call "${toolCall.name}" denied${before.cancelReason ? `: ${before.cancelReason}` : ""}`
120
+ : await options.executeTool(toolCall, modelInput);
121
+ const toolResult = {
122
+ toolCall,
123
+ result,
124
+ isError: result.startsWith("Error:"),
125
+ skipped,
126
+ };
127
+ toolResults.push(toolResult);
128
+ allToolResults.push(toolResult);
129
+ await hooks.runAfter("tool:after", {
130
+ agent: options.agent,
131
+ loop,
132
+ turn,
133
+ context,
134
+ toolCall,
135
+ result,
136
+ isError: toolResult.isError,
137
+ skipped,
138
+ });
139
+ }
140
+ await hooks.runAfter("step:after", {
141
+ agent: options.agent,
142
+ loop,
143
+ turn,
144
+ context,
145
+ text: modelResult.text,
146
+ toolCalls: modelResult.toolCalls ?? [],
147
+ toolResults,
148
+ usage: modelResult.usage,
149
+ });
150
+ const stop = shouldStopAfterTurn(loop, context, modelResult, turn, maxTurns, this.evaluator);
151
+ const stopResult = await hooks.runBefore("loop:stop", {
152
+ agent: options.agent,
153
+ loop,
154
+ turn,
155
+ context,
156
+ reason: stop.reason,
157
+ shouldStop: stop.shouldStop,
158
+ });
159
+ if (stopResult.cancelled) {
160
+ return this.finish(hooks, {
161
+ agent: options.agent,
162
+ loop,
163
+ context,
164
+ status: "cancelled",
165
+ reason: "cancelled",
166
+ turns,
167
+ text: finalText,
168
+ toolResults: allToolResults,
169
+ });
170
+ }
171
+ if (stopResult.data.shouldStop) {
172
+ return this.finish(hooks, {
173
+ agent: options.agent,
174
+ loop,
175
+ context,
176
+ status: "completed",
177
+ reason: stopResult.data.reason,
178
+ turns,
179
+ text: finalText,
180
+ toolResults: allToolResults,
181
+ });
182
+ }
183
+ }
184
+ return this.finish(hooks, {
185
+ agent: options.agent,
186
+ loop,
187
+ context,
188
+ status: "completed",
189
+ reason: "max_turns",
190
+ turns,
191
+ text: finalText,
192
+ toolResults: allToolResults,
193
+ });
194
+ }
195
+ async finish(hooks, result) {
196
+ await hooks.runAfter("loop:end", {
197
+ agent: result.agent,
198
+ loop: result.loop,
199
+ context: result.context,
200
+ status: result.status,
201
+ reason: result.reason,
202
+ turns: result.turns,
203
+ text: result.text,
204
+ });
205
+ return {
206
+ status: result.status,
207
+ reason: result.reason,
208
+ turns: result.turns,
209
+ text: result.text,
210
+ context: result.context,
211
+ toolResults: result.toolResults,
212
+ };
213
+ }
214
+ }
215
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/loop/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=runner.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.test.d.ts","sourceRoot":"","sources":["../../src/loop/runner.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,124 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { LoopHookRegistry } from "./hooks.js";
3
+ import { LoopRunner } from "./runner.js";
4
+ describe("LoopRunner", () => {
5
+ it("runs the implicit loop with ordered lifecycle hooks", async () => {
6
+ const events = [];
7
+ const hooks = new LoopHookRegistry();
8
+ hooks.register({ hook: "loop:start", phase: "before", handler: () => { events.push("loop:start"); } });
9
+ hooks.register({ hook: "step:before", phase: "before", handler: () => { events.push("step:before"); } });
10
+ hooks.register({ hook: "model:before", phase: "before", handler: () => { events.push("model:before"); } });
11
+ hooks.register({ hook: "step:after", phase: "after", handler: () => { events.push("step:after"); } });
12
+ hooks.register({ hook: "loop:stop", phase: "before", handler: () => { events.push("loop:stop"); } });
13
+ hooks.register({ hook: "loop:end", phase: "after", handler: () => { events.push("loop:end"); } });
14
+ const runner = new LoopRunner(hooks);
15
+ const result = await runner.run({
16
+ loop: { name: "default" },
17
+ model: async () => ({ text: "done" }),
18
+ executeTool: async () => "unused",
19
+ });
20
+ expect(result).toMatchObject({ status: "completed", reason: "completed", turns: 1, text: "done" });
21
+ expect(events).toEqual(["loop:start", "step:before", "model:before", "step:after", "loop:stop", "loop:end"]);
22
+ });
23
+ it("lets step hooks constrain active tools before the model call", async () => {
24
+ const hooks = new LoopHookRegistry();
25
+ hooks.register({
26
+ hook: "step:before",
27
+ phase: "before",
28
+ handler: (ctx) => {
29
+ ctx.data.activeTools = ["read"];
30
+ },
31
+ });
32
+ const seenTools = [];
33
+ const runner = new LoopRunner(hooks);
34
+ await runner.run({
35
+ loop: { name: "plan", tools: ["read", "write"] },
36
+ model: async (input) => {
37
+ seenTools.push(input.activeTools);
38
+ return { text: "planned" };
39
+ },
40
+ executeTool: async () => "unused",
41
+ });
42
+ expect(seenTools).toEqual([["read"]]);
43
+ });
44
+ it("allows tool:before hooks to deny a tool call without invoking the executor", async () => {
45
+ const hooks = new LoopHookRegistry();
46
+ hooks.register({
47
+ hook: "tool:before",
48
+ phase: "before",
49
+ handler: (ctx) => {
50
+ if (ctx.data.toolCall.name === "write")
51
+ ctx.cancel("read-only loop");
52
+ },
53
+ });
54
+ let executed = false;
55
+ const runner = new LoopRunner(hooks);
56
+ const result = await runner.run({
57
+ loop: { name: "plan", tools: ["read"] },
58
+ maxTurns: 1,
59
+ model: async () => ({
60
+ text: "I will write.",
61
+ toolCalls: [{ id: "call-1", name: "write", args: { path: "x.txt" } }],
62
+ }),
63
+ executeTool: async () => {
64
+ executed = true;
65
+ return "should not run";
66
+ },
67
+ });
68
+ expect(executed).toBe(false);
69
+ expect(result.toolResults).toHaveLength(1);
70
+ expect(result.toolResults[0]).toMatchObject({
71
+ skipped: true,
72
+ isError: true,
73
+ result: 'Error: Tool call "write" denied: read-only loop',
74
+ });
75
+ });
76
+ it("continues when loop:stop mutates shouldStop to false", async () => {
77
+ const hooks = new LoopHookRegistry();
78
+ hooks.register({
79
+ hook: "loop:stop",
80
+ phase: "before",
81
+ handler: (ctx) => {
82
+ if (ctx.data.turn === 0)
83
+ ctx.data.shouldStop = false;
84
+ },
85
+ });
86
+ let calls = 0;
87
+ const runner = new LoopRunner(hooks);
88
+ const result = await runner.run({
89
+ loop: { name: "review" },
90
+ maxTurns: 2,
91
+ model: async () => {
92
+ calls++;
93
+ return { text: String(calls) };
94
+ },
95
+ executeTool: async () => "unused",
96
+ });
97
+ expect(result.text).toBe("12");
98
+ expect(result.turns).toBe(2);
99
+ expect(result.reason).toBe("completed");
100
+ });
101
+ it("uses stopWhen as the deterministic stop condition when configured", async () => {
102
+ const hooks = new LoopHookRegistry();
103
+ hooks.register({
104
+ hook: "step:after",
105
+ phase: "after",
106
+ handler: (ctx) => {
107
+ if (ctx.data.turn === 1)
108
+ ctx.data.context.done = true;
109
+ },
110
+ });
111
+ const runner = new LoopRunner(hooks);
112
+ const result = await runner.run({
113
+ loop: { name: "build", stopWhen: { expression: "done == true" } },
114
+ maxTurns: 3,
115
+ model: async () => ({ text: "tick" }),
116
+ executeTool: async () => "unused",
117
+ });
118
+ expect(result.text).toBe("ticktick");
119
+ expect(result.turns).toBe(2);
120
+ expect(result.reason).toBe("completed");
121
+ expect(result.context.done).toBe(true);
122
+ });
123
+ });
124
+ //# sourceMappingURL=runner.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.test.js","sourceRoot":"","sources":["../../src/loop/runner.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { AgentConfig } from "../types.js";
2
+ import type { LoopConfig } from "./types.js";
3
+ export interface LoopSelection {
4
+ name: string;
5
+ loop: LoopConfig & {
6
+ name: string;
7
+ };
8
+ agent: AgentConfig;
9
+ }
10
+ export declare function resolveActiveLoopTools(agent: AgentConfig, loop?: LoopConfig): string[] | undefined;
11
+ export declare function resolveActiveLoopSkills(agent: AgentConfig, loop?: LoopConfig): string[] | undefined;
12
+ export declare function resolveLoopSelection(agent: AgentConfig, requestedLoop?: string): LoopSelection;
13
+ //# sourceMappingURL=selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../../src/loop/selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,EAAE,GAAG,SAAS,CAElG;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,EAAE,GAAG,SAAS,CAEnG;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,aAAa,CAwC9F"}
@@ -0,0 +1,65 @@
1
+ export function resolveActiveLoopTools(agent, loop) {
2
+ return loop?.tools ?? agent.allowedTools;
3
+ }
4
+ export function resolveActiveLoopSkills(agent, loop) {
5
+ return loop?.skills ?? agent.skills;
6
+ }
7
+ export function resolveLoopSelection(agent, requestedLoop) {
8
+ if (!requestedLoop) {
9
+ if (agent.defaultLoop) {
10
+ return {
11
+ name: agent.defaultLoop,
12
+ loop: { name: agent.defaultLoop, tools: agent.allowedTools, model: agent.model, reasoning: agent.reasoning, maxTurns: agent.maxTurns },
13
+ agent,
14
+ };
15
+ }
16
+ const defaultLoop = agent.loops?.default;
17
+ if (!defaultLoop) {
18
+ return {
19
+ name: "default",
20
+ loop: { name: "default", tools: agent.allowedTools, model: agent.model, reasoning: agent.reasoning, maxTurns: agent.maxTurns },
21
+ agent,
22
+ };
23
+ }
24
+ return materializeLoopSelection(agent, "default", defaultLoop);
25
+ }
26
+ const loop = agent.loops?.[requestedLoop];
27
+ if (!loop) {
28
+ if (agent.assignedLoops?.includes(requestedLoop)) {
29
+ return {
30
+ name: requestedLoop,
31
+ loop: { name: requestedLoop, tools: agent.allowedTools, model: agent.model, reasoning: agent.reasoning, maxTurns: agent.maxTurns },
32
+ agent,
33
+ };
34
+ }
35
+ const available = Object.keys(agent.loops ?? {});
36
+ const assigned = agent.assignedLoops ?? [];
37
+ const allAvailable = [...available, ...assigned];
38
+ throw new Error(allAvailable.length > 0
39
+ ? `Unknown loop "${requestedLoop}". Available loops: ${allAvailable.join(", ")}`
40
+ : `Agent "${agent.name}" does not define configurable loops`);
41
+ }
42
+ return materializeLoopSelection(agent, requestedLoop, loop);
43
+ }
44
+ function materializeLoopSelection(agent, name, loop) {
45
+ const loopWithName = { ...loop, name: loop.name ?? name };
46
+ const loopPrompt = loop.systemPrompt?.trim();
47
+ const systemPrompt = loopPrompt
48
+ ? [agent.systemPrompt, `## Active loop: ${loopWithName.name}`, loopPrompt].filter(Boolean).join("\n\n")
49
+ : agent.systemPrompt;
50
+ return {
51
+ name: loopWithName.name,
52
+ loop: loopWithName,
53
+ agent: {
54
+ ...agent,
55
+ systemPrompt,
56
+ allowedTools: resolveActiveLoopTools(agent, loop),
57
+ skills: resolveActiveLoopSkills(agent, loop),
58
+ model: loop.model ?? agent.model,
59
+ reasoning: loop.reasoning ?? agent.reasoning,
60
+ maxTurns: loop.maxTurns ?? agent.maxTurns,
61
+ toolChoice: loop.toolChoice ?? agent.toolChoice,
62
+ },
63
+ };
64
+ }
65
+ //# sourceMappingURL=selector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.js","sourceRoot":"","sources":["../../src/loop/selector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=selector.test.d.ts.map