@sourcepress/ai 0.1.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 (147) hide show
  1. package/.omc/state/last-tool-error.json +7 -0
  2. package/.turbo/turbo-build.log +4 -0
  3. package/.turbo/turbo-test.log +24 -0
  4. package/LICENSE +21 -0
  5. package/dist/__tests__/budget.test.d.ts +2 -0
  6. package/dist/__tests__/budget.test.d.ts.map +1 -0
  7. package/dist/__tests__/budget.test.js +96 -0
  8. package/dist/__tests__/budget.test.js.map +1 -0
  9. package/dist/__tests__/classify.test.d.ts +2 -0
  10. package/dist/__tests__/classify.test.d.ts.map +1 -0
  11. package/dist/__tests__/classify.test.js +72 -0
  12. package/dist/__tests__/classify.test.js.map +1 -0
  13. package/dist/__tests__/eval-runner.test.d.ts +2 -0
  14. package/dist/__tests__/eval-runner.test.d.ts.map +1 -0
  15. package/dist/__tests__/eval-runner.test.js +171 -0
  16. package/dist/__tests__/eval-runner.test.js.map +1 -0
  17. package/dist/__tests__/extract.test.d.ts +2 -0
  18. package/dist/__tests__/extract.test.d.ts.map +1 -0
  19. package/dist/__tests__/extract.test.js +79 -0
  20. package/dist/__tests__/extract.test.js.map +1 -0
  21. package/dist/__tests__/find-gaps.test.d.ts +2 -0
  22. package/dist/__tests__/find-gaps.test.d.ts.map +1 -0
  23. package/dist/__tests__/find-gaps.test.js +82 -0
  24. package/dist/__tests__/find-gaps.test.js.map +1 -0
  25. package/dist/__tests__/generate.test.d.ts +2 -0
  26. package/dist/__tests__/generate.test.d.ts.map +1 -0
  27. package/dist/__tests__/generate.test.js +68 -0
  28. package/dist/__tests__/generate.test.js.map +1 -0
  29. package/dist/__tests__/improve-prompt.test.d.ts +2 -0
  30. package/dist/__tests__/improve-prompt.test.d.ts.map +1 -0
  31. package/dist/__tests__/improve-prompt.test.js +32 -0
  32. package/dist/__tests__/improve-prompt.test.js.map +1 -0
  33. package/dist/__tests__/intent-impact.test.d.ts +2 -0
  34. package/dist/__tests__/intent-impact.test.d.ts.map +1 -0
  35. package/dist/__tests__/intent-impact.test.js +51 -0
  36. package/dist/__tests__/intent-impact.test.js.map +1 -0
  37. package/dist/__tests__/judge.test.d.ts +2 -0
  38. package/dist/__tests__/judge.test.d.ts.map +1 -0
  39. package/dist/__tests__/judge.test.js +61 -0
  40. package/dist/__tests__/judge.test.js.map +1 -0
  41. package/dist/__tests__/score.test.d.ts +2 -0
  42. package/dist/__tests__/score.test.d.ts.map +1 -0
  43. package/dist/__tests__/score.test.js +50 -0
  44. package/dist/__tests__/score.test.js.map +1 -0
  45. package/dist/__tests__/staleness.test.d.ts +2 -0
  46. package/dist/__tests__/staleness.test.d.ts.map +1 -0
  47. package/dist/__tests__/staleness.test.js +66 -0
  48. package/dist/__tests__/staleness.test.js.map +1 -0
  49. package/dist/budget.d.ts +13 -0
  50. package/dist/budget.d.ts.map +1 -0
  51. package/dist/budget.js +40 -0
  52. package/dist/budget.js.map +1 -0
  53. package/dist/eval/runner.d.ts +34 -0
  54. package/dist/eval/runner.d.ts.map +1 -0
  55. package/dist/eval/runner.js +128 -0
  56. package/dist/eval/runner.js.map +1 -0
  57. package/dist/functions/classify.d.ts +5 -0
  58. package/dist/functions/classify.d.ts.map +1 -0
  59. package/dist/functions/classify.js +43 -0
  60. package/dist/functions/classify.js.map +1 -0
  61. package/dist/functions/extract.d.ts +5 -0
  62. package/dist/functions/extract.d.ts.map +1 -0
  63. package/dist/functions/extract.js +57 -0
  64. package/dist/functions/extract.js.map +1 -0
  65. package/dist/functions/find-gaps.d.ts +5 -0
  66. package/dist/functions/find-gaps.d.ts.map +1 -0
  67. package/dist/functions/find-gaps.js +51 -0
  68. package/dist/functions/find-gaps.js.map +1 -0
  69. package/dist/functions/generate.d.ts +5 -0
  70. package/dist/functions/generate.d.ts.map +1 -0
  71. package/dist/functions/generate.js +39 -0
  72. package/dist/functions/generate.js.map +1 -0
  73. package/dist/functions/improve-prompt.d.ts +5 -0
  74. package/dist/functions/improve-prompt.d.ts.map +1 -0
  75. package/dist/functions/improve-prompt.js +38 -0
  76. package/dist/functions/improve-prompt.js.map +1 -0
  77. package/dist/functions/index.d.ts +11 -0
  78. package/dist/functions/index.d.ts.map +1 -0
  79. package/dist/functions/index.js +11 -0
  80. package/dist/functions/index.js.map +1 -0
  81. package/dist/functions/intent-impact.d.ts +5 -0
  82. package/dist/functions/intent-impact.d.ts.map +1 -0
  83. package/dist/functions/intent-impact.js +45 -0
  84. package/dist/functions/intent-impact.js.map +1 -0
  85. package/dist/functions/judge.d.ts +5 -0
  86. package/dist/functions/judge.d.ts.map +1 -0
  87. package/dist/functions/judge.js +32 -0
  88. package/dist/functions/judge.js.map +1 -0
  89. package/dist/functions/model-factory.d.ts +4 -0
  90. package/dist/functions/model-factory.d.ts.map +1 -0
  91. package/dist/functions/model-factory.js +52 -0
  92. package/dist/functions/model-factory.js.map +1 -0
  93. package/dist/functions/score.d.ts +5 -0
  94. package/dist/functions/score.d.ts.map +1 -0
  95. package/dist/functions/score.js +47 -0
  96. package/dist/functions/score.js.map +1 -0
  97. package/dist/functions/staleness.d.ts +5 -0
  98. package/dist/functions/staleness.d.ts.map +1 -0
  99. package/dist/functions/staleness.js +45 -0
  100. package/dist/functions/staleness.js.map +1 -0
  101. package/dist/functions/usage.d.ts +8 -0
  102. package/dist/functions/usage.d.ts.map +1 -0
  103. package/dist/functions/usage.js +13 -0
  104. package/dist/functions/usage.js.map +1 -0
  105. package/dist/index.d.ts +8 -0
  106. package/dist/index.d.ts.map +1 -0
  107. package/dist/index.js +6 -0
  108. package/dist/index.js.map +1 -0
  109. package/dist/provider.d.ts +10 -0
  110. package/dist/provider.d.ts.map +1 -0
  111. package/dist/provider.js +32 -0
  112. package/dist/provider.js.map +1 -0
  113. package/dist/types.d.ts +207 -0
  114. package/dist/types.d.ts.map +1 -0
  115. package/dist/types.js +2 -0
  116. package/dist/types.js.map +1 -0
  117. package/package.json +41 -0
  118. package/src/__tests__/budget.test.ts +103 -0
  119. package/src/__tests__/classify.test.ts +90 -0
  120. package/src/__tests__/eval-runner.test.ts +199 -0
  121. package/src/__tests__/extract.test.ts +92 -0
  122. package/src/__tests__/find-gaps.test.ts +93 -0
  123. package/src/__tests__/generate.test.ts +92 -0
  124. package/src/__tests__/improve-prompt.test.ts +42 -0
  125. package/src/__tests__/intent-impact.test.ts +62 -0
  126. package/src/__tests__/judge.test.ts +78 -0
  127. package/src/__tests__/score.test.ts +61 -0
  128. package/src/__tests__/staleness.test.ts +77 -0
  129. package/src/budget.ts +47 -0
  130. package/src/eval/runner.ts +163 -0
  131. package/src/functions/classify.ts +54 -0
  132. package/src/functions/extract.ts +72 -0
  133. package/src/functions/find-gaps.ts +65 -0
  134. package/src/functions/generate.ts +51 -0
  135. package/src/functions/improve-prompt.ts +48 -0
  136. package/src/functions/index.ts +10 -0
  137. package/src/functions/intent-impact.ts +56 -0
  138. package/src/functions/judge.ts +41 -0
  139. package/src/functions/model-factory.ts +60 -0
  140. package/src/functions/score.ts +56 -0
  141. package/src/functions/staleness.ts +54 -0
  142. package/src/functions/usage.ts +25 -0
  143. package/src/index.ts +47 -0
  144. package/src/provider.ts +41 -0
  145. package/src/types.ts +225 -0
  146. package/tsconfig.json +5 -0
  147. package/vitest.config.ts +2 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-gaps.test.js","sourceRoot":"","sources":["../../src/__tests__/find-gaps.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAGrD,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,IAAI,CAAC;AACpC,MAAM,YAAY,GAAqB;IACtC,QAAQ,EAAE,WAAW;IACrB,KAAK,EAAE,4BAA4B;CACnC,CAAC;AAEF,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QACnE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,qBAAqB,CAAC;YAC/C,MAAM,EAAE;gBACP,IAAI,EAAE;oBACL;wBACC,WAAW,EAAE,OAAO;wBACpB,WAAW,EAAE,YAAY;wBACzB,sBAAsB,EAAE,WAAW;wBACnC,QAAQ,EAAE,MAAM;wBAChB,MAAM,EAAE,iCAAiC;qBACzC;oBACD;wBACC,WAAW,EAAE,YAAY;wBACzB,WAAW,EAAE,YAAY;wBACzB,sBAAsB,EAAE,cAAc;wBACtC,QAAQ,EAAE,QAAQ;wBAClB,MAAM,EAAE,qCAAqC;qBAC7C;iBACD;aACD;YACD,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE;YACpD,yFAAyF;SAClF,CAAC,CAAC;QACV,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAC5B;YACC,QAAQ,EAAE;gBACT,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE;gBACrC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE;gBAC1C,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE;aACvC;YACD,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;YAC/D,gBAAgB,EAAE;gBACjB;oBACC,IAAI,EAAE,wBAAwB;oBAC9B,KAAK,EAAE,+BAA+B;oBACtC,OAAO,EAAE,0BAA0B;iBACnC;aACD;SACD,EACD,YAAY,EACZ,MAAM,CACN,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACzD,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,qBAAqB,CAAC;YAC/C,MAAM,EAAE;gBACP,IAAI,EAAE;oBACL;wBACC,WAAW,EAAE,aAAa;wBAC1B,WAAW,EAAE,SAAS;wBACtB,sBAAsB,EAAE,cAAc;wBACtC,QAAQ,EAAE,MAAM;wBAChB,MAAM,EAAE,yBAAyB;qBACjC;iBACD;aACD;YACD,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE;YACpD,yFAAyF;SAClF,CAAC,CAAC;QACV,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAC5B;YACC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;YACpD,SAAS,EAAE,EAAE;YACb,gBAAgB,EAAE,EAAE;YACpB,gBAAgB,EAAE,4DAA4D;SAC9E,EACD,YAAY,EACZ,MAAM,CACN,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=generate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/generate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,68 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { BudgetTracker } from "../budget.js";
3
+ import { generate } from "../functions/generate.js";
4
+ vi.mock("ai", () => ({ generateObject: vi.fn() }));
5
+ import { generateObject } from "ai";
6
+ const mockProvider = {
7
+ provider: "anthropic",
8
+ model: "claude-sonnet-4-5-20250514",
9
+ };
10
+ describe("generate", () => {
11
+ it("generates content from knowledge context", async () => {
12
+ vi.mocked(generateObject).mockResolvedValueOnce({
13
+ object: {
14
+ frontmatter: { title: "Acme Corp Case Study", client: "acme-corp" },
15
+ body: "# Acme Corp\n\nWe migrated 12 services in 8 weeks.",
16
+ },
17
+ usage: { promptTokens: 3000, completionTokens: 500 },
18
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
19
+ });
20
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
21
+ const result = await generate({
22
+ content_type: "case-study",
23
+ generation_prompt: "Write a compelling case study with specific metrics.",
24
+ knowledge_context: "Acme Corp migrated 12 microservices to Next.js in 8 weeks. Load time improved by 40%.",
25
+ }, mockProvider, budget);
26
+ expect(result.content).toContain("Acme Corp");
27
+ expect(result.frontmatter.title).toBe("Acme Corp Case Study");
28
+ expect(result.usage.function_name).toBe("generate");
29
+ });
30
+ it("includes intent in generation when provided", async () => {
31
+ vi.mocked(generateObject).mockResolvedValueOnce({
32
+ object: {
33
+ frontmatter: { title: "Test" },
34
+ body: "Vi hjälpte kunden att migrera.",
35
+ },
36
+ usage: { promptTokens: 3500, completionTokens: 400 },
37
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
38
+ });
39
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
40
+ const result = await generate({
41
+ content_type: "case-study",
42
+ generation_prompt: "Write a case study.",
43
+ knowledge_context: "Acme Corp project data.",
44
+ intent: 'Always use "vi" form. No buzzwords.',
45
+ }, mockProvider, budget);
46
+ expect(result.content).toBeTruthy();
47
+ expect(result.usage.function_name).toBe("generate");
48
+ });
49
+ it("tracks budget usage", async () => {
50
+ vi.mocked(generateObject).mockResolvedValueOnce({
51
+ object: {
52
+ frontmatter: { title: "Test" },
53
+ body: "Content body.",
54
+ },
55
+ usage: { promptTokens: 2000, completionTokens: 300 },
56
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
57
+ });
58
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
59
+ await generate({
60
+ content_type: "blog-post",
61
+ generation_prompt: "Write a blog post.",
62
+ knowledge_context: "Blog knowledge.",
63
+ }, mockProvider, budget);
64
+ const status = budget.getStatus();
65
+ expect(status.spent_today_usd).toBeGreaterThan(0);
66
+ });
67
+ });
68
+ //# sourceMappingURL=generate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.test.js","sourceRoot":"","sources":["../../src/__tests__/generate.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=improve-prompt.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"improve-prompt.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/improve-prompt.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,32 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { BudgetTracker } from "../budget.js";
3
+ import { improvePrompt } from "../functions/improve-prompt.js";
4
+ vi.mock("ai", () => ({ generateObject: vi.fn() }));
5
+ import { generateObject } from "ai";
6
+ const mockProvider = {
7
+ provider: "anthropic",
8
+ model: "claude-sonnet-4-5-20250514",
9
+ };
10
+ describe("improvePrompt", () => {
11
+ it("improves a generation prompt based on judge feedback", async () => {
12
+ vi.mocked(generateObject).mockResolvedValueOnce({
13
+ object: {
14
+ improved_prompt: "Write a case study with specific metrics, client quotes, and a clear before/after comparison.",
15
+ changes_summary: "Added requirements for metrics and quotes based on judge feedback.",
16
+ },
17
+ usage: { promptTokens: 1500, completionTokens: 300 },
18
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
19
+ });
20
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
21
+ const result = await improvePrompt({
22
+ current_prompt: "Write a case study.",
23
+ judge_reasoning: "Draft is generic, lacks specific metrics and client quotes.",
24
+ judge_score: 45,
25
+ content_type: "case-study",
26
+ }, mockProvider, budget);
27
+ expect(result.improved_prompt).toContain("metrics");
28
+ expect(result.changes_summary).toBeTruthy();
29
+ expect(result.usage.function_name).toBe("improvePrompt");
30
+ });
31
+ });
32
+ //# sourceMappingURL=improve-prompt.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"improve-prompt.test.js","sourceRoot":"","sources":["../../src/__tests__/improve-prompt.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAG/D,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,IAAI,CAAC;AAEpC,MAAM,YAAY,GAAqB;IACtC,QAAQ,EAAE,WAAW;IACrB,KAAK,EAAE,4BAA4B;CACnC,CAAC;AAEF,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACrE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,qBAAqB,CAAC;YAC/C,MAAM,EAAE;gBACP,eAAe,EACd,+FAA+F;gBAChG,eAAe,EAAE,oEAAoE;aACrF;YACD,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE;YACpD,yFAAyF;SAClF,CAAC,CAAC;QAEV,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,aAAa,CACjC;YACC,cAAc,EAAE,qBAAqB;YACrC,eAAe,EAAE,6DAA6D;YAC9E,WAAW,EAAE,EAAE;YACf,YAAY,EAAE,YAAY;SAC1B,EACD,YAAY,EACZ,MAAM,CACN,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACpD,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,UAAU,EAAE,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=intent-impact.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent-impact.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/intent-impact.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,51 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { BudgetTracker } from "../budget.js";
3
+ import { analyzeIntentImpact } from "../functions/intent-impact.js";
4
+ vi.mock("ai", () => ({ generateObject: vi.fn() }));
5
+ import { generateObject } from "ai";
6
+ const mockProvider = {
7
+ provider: "anthropic",
8
+ model: "claude-sonnet-4-5-20250514",
9
+ };
10
+ describe("analyzeIntentImpact", () => {
11
+ it("identifies pages affected by intent change", async () => {
12
+ vi.mocked(generateObject).mockResolvedValueOnce({
13
+ object: {
14
+ affected_pages: [
15
+ { path: "content/cases/acme.mdx", impact: "high", reason: "Uses forbidden word" },
16
+ { path: "content/posts/tech-update.mdx", impact: "low", reason: "Minor tone adjustment" },
17
+ ],
18
+ summary: "2 pages affected",
19
+ },
20
+ usage: { promptTokens: 3000, completionTokens: 200 },
21
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
22
+ });
23
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
24
+ const result = await analyzeIntentImpact({
25
+ changed_intent: 'Forbidden words: "revolutionerande", "synergier"',
26
+ previous_intent: 'Forbidden words: "synergier"',
27
+ content_pages: [
28
+ { path: "content/cases/acme.mdx", text: "En revolutionerande migration till Next.js." },
29
+ { path: "content/posts/tech-update.mdx", text: "Vi uppdaterade vår tech-stack." },
30
+ ],
31
+ }, mockProvider, budget);
32
+ expect(result.affected_pages).toHaveLength(2);
33
+ expect(result.affected_pages[0].impact).toBe("high");
34
+ expect(result.usage.function_name).toBe("analyzeIntentImpact");
35
+ });
36
+ it("returns empty when no pages affected", async () => {
37
+ vi.mocked(generateObject).mockResolvedValueOnce({
38
+ object: { affected_pages: [], summary: "No pages affected." },
39
+ usage: { promptTokens: 2000, completionTokens: 80 },
40
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
41
+ });
42
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
43
+ const result = await analyzeIntentImpact({
44
+ changed_intent: "Use we-form.",
45
+ previous_intent: "Use we-form.",
46
+ content_pages: [{ path: "content/about.mdx", text: "Vi hjälper företag att växa." }],
47
+ }, mockProvider, budget);
48
+ expect(result.affected_pages).toHaveLength(0);
49
+ });
50
+ });
51
+ //# sourceMappingURL=intent-impact.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent-impact.test.js","sourceRoot":"","sources":["../../src/__tests__/intent-impact.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAGpE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,IAAI,CAAC;AACpC,MAAM,YAAY,GAAqB;IACtC,QAAQ,EAAE,WAAW;IACrB,KAAK,EAAE,4BAA4B;CACnC,CAAC;AAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC3D,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,qBAAqB,CAAC;YAC/C,MAAM,EAAE;gBACP,cAAc,EAAE;oBACf,EAAE,IAAI,EAAE,wBAAwB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,EAAE;oBACjF,EAAE,IAAI,EAAE,+BAA+B,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE;iBACzF;gBACD,OAAO,EAAE,kBAAkB;aAC3B;YACD,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE;YACpD,yFAAyF;SAClF,CAAC,CAAC;QACV,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,mBAAmB,CACvC;YACC,cAAc,EAAE,kDAAkD;YAClE,eAAe,EAAE,8BAA8B;YAC/C,aAAa,EAAE;gBACd,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI,EAAE,6CAA6C,EAAE;gBACvF,EAAE,IAAI,EAAE,+BAA+B,EAAE,IAAI,EAAE,gCAAgC,EAAE;aACjF;SACD,EACD,YAAY,EACZ,MAAM,CACN,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACrD,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,qBAAqB,CAAC;YAC/C,MAAM,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,OAAO,EAAE,oBAAoB,EAAE;YAC7D,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,EAAE;YACnD,yFAAyF;SAClF,CAAC,CAAC;QACV,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,mBAAmB,CACvC;YACC,cAAc,EAAE,cAAc;YAC9B,eAAe,EAAE,cAAc;YAC/B,aAAa,EAAE,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,8BAA8B,EAAE,CAAC;SACpF,EACD,YAAY,EACZ,MAAM,CACN,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=judge.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"judge.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/judge.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,61 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { BudgetTracker } from "../budget.js";
3
+ import { judge } from "../functions/judge.js";
4
+ vi.mock("ai", () => ({ generateObject: vi.fn() }));
5
+ import { generateObject } from "ai";
6
+ const mockProvider = {
7
+ provider: "anthropic",
8
+ model: "claude-sonnet-4-5-20250514",
9
+ };
10
+ describe("judge", () => {
11
+ it("judges a draft against gold standard", async () => {
12
+ vi.mocked(generateObject).mockResolvedValueOnce({
13
+ object: {
14
+ score: 82,
15
+ reasoning: "Draft matches gold standard structure. Tone is correct. Missing one metric.",
16
+ },
17
+ usage: { promptTokens: 2000, completionTokens: 200 },
18
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
19
+ });
20
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
21
+ const result = await judge({
22
+ draft: "# Acme Case Study\n\nWe helped Acme migrate.",
23
+ gold_standard: "# Perfect Case Study\n\nWe migrated 12 services in 8 weeks, reducing load time by 40%.",
24
+ judge_prompt: "Score 0-100.",
25
+ }, mockProvider, budget);
26
+ expect(result.score).toBe(82);
27
+ expect(result.reasoning).toBeTruthy();
28
+ expect(result.usage.function_name).toBe("judge");
29
+ });
30
+ it("gives low score for poor match", async () => {
31
+ vi.mocked(generateObject).mockResolvedValueOnce({
32
+ object: { score: 35, reasoning: "Draft is generic, lacks specifics, wrong tone." },
33
+ usage: { promptTokens: 1500, completionTokens: 100 },
34
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
35
+ });
36
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
37
+ const result = await judge({
38
+ draft: "We are a great company.",
39
+ gold_standard: "# Perfect Case Study\n\nDetailed metrics.",
40
+ judge_prompt: "Score 0-100.",
41
+ }, mockProvider, budget);
42
+ expect(result.score).toBeLessThan(50);
43
+ });
44
+ it("includes intent in judgment when provided", async () => {
45
+ vi.mocked(generateObject).mockResolvedValueOnce({
46
+ object: { score: 70, reasoning: "Matches intent tone but not all structural requirements." },
47
+ usage: { promptTokens: 2500, completionTokens: 180 },
48
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
49
+ });
50
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
51
+ const result = await judge({
52
+ draft: "Case study draft.",
53
+ gold_standard: "Perfect case study.",
54
+ judge_prompt: "Score 0-100.",
55
+ intent: 'Always use "we" form. No buzzwords.',
56
+ }, mockProvider, budget);
57
+ expect(result.score).toBe(70);
58
+ expect(result.usage.function_name).toBe("judge");
59
+ });
60
+ });
61
+ //# sourceMappingURL=judge.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"judge.test.js","sourceRoot":"","sources":["../../src/__tests__/judge.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=score.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/score.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,50 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { BudgetTracker } from "../budget.js";
3
+ import { score } from "../functions/score.js";
4
+ vi.mock("ai", () => ({ generateObject: vi.fn() }));
5
+ import { generateObject } from "ai";
6
+ const mockProvider = {
7
+ provider: "anthropic",
8
+ model: "claude-sonnet-4-5-20250514",
9
+ };
10
+ describe("score", () => {
11
+ it("scores content against intent", async () => {
12
+ vi.mocked(generateObject).mockResolvedValueOnce({
13
+ object: {
14
+ score: 74,
15
+ issues: ["Generic heading", "Missing specific results"],
16
+ strengths: ["Correct tone of voice", "Good structure"],
17
+ },
18
+ usage: { promptTokens: 1000, completionTokens: 150 },
19
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
20
+ });
21
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
22
+ const result = await score({
23
+ content: "# Acme Corp Case Study\n\nWe helped Acme Corp modernize their tech stack.",
24
+ intent: "Use concrete results with numbers.",
25
+ }, mockProvider, budget);
26
+ expect(result.score).toBe(74);
27
+ expect(result.issues).toContain("Generic heading");
28
+ expect(result.strengths.length).toBeGreaterThan(0);
29
+ expect(result.usage.function_name).toBe("score");
30
+ });
31
+ it("returns high score for well-matched content", async () => {
32
+ vi.mocked(generateObject).mockResolvedValueOnce({
33
+ object: {
34
+ score: 92,
35
+ issues: [],
36
+ strengths: ["Specific metrics", "Perfect tone", "Clear CTA"],
37
+ },
38
+ usage: { promptTokens: 800, completionTokens: 100 },
39
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
40
+ });
41
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
42
+ const result = await score({
43
+ content: "# Acme Corp: 40% Faster with Next.js\n\nWe migrated 12 services in 8 weeks.",
44
+ intent: "Use concrete results with numbers.",
45
+ }, mockProvider, budget);
46
+ expect(result.score).toBeGreaterThanOrEqual(90);
47
+ expect(result.issues).toHaveLength(0);
48
+ });
49
+ });
50
+ //# sourceMappingURL=score.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.test.js","sourceRoot":"","sources":["../../src/__tests__/score.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAG9C,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,IAAI,CAAC;AACpC,MAAM,YAAY,GAAqB;IACtC,QAAQ,EAAE,WAAW;IACrB,KAAK,EAAE,4BAA4B;CACnC,CAAC;AAEF,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACtB,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC9C,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,qBAAqB,CAAC;YAC/C,MAAM,EAAE;gBACP,KAAK,EAAE,EAAE;gBACT,MAAM,EAAE,CAAC,iBAAiB,EAAE,0BAA0B,CAAC;gBACvD,SAAS,EAAE,CAAC,uBAAuB,EAAE,gBAAgB,CAAC;aACtD;YACD,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE;YACpD,yFAAyF;SAClF,CAAC,CAAC;QACV,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,KAAK,CACzB;YACC,OAAO,EAAE,2EAA2E;YACpF,MAAM,EAAE,oCAAoC;SAC5C,EACD,YAAY,EACZ,MAAM,CACN,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC5D,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,qBAAqB,CAAC;YAC/C,MAAM,EAAE;gBACP,KAAK,EAAE,EAAE;gBACT,MAAM,EAAE,EAAE;gBACV,SAAS,EAAE,CAAC,kBAAkB,EAAE,cAAc,EAAE,WAAW,CAAC;aAC5D;YACD,KAAK,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE;YACnD,yFAAyF;SAClF,CAAC,CAAC;QACV,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,KAAK,CACzB;YACC,OAAO,EAAE,6EAA6E;YACtF,MAAM,EAAE,oCAAoC;SAC5C,EACD,YAAY,EACZ,MAAM,CACN,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=staleness.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staleness.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/staleness.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,66 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { BudgetTracker } from "../budget.js";
3
+ import { detectStaleness } from "../functions/staleness.js";
4
+ vi.mock("ai", () => ({ generateObject: vi.fn() }));
5
+ import { generateObject } from "ai";
6
+ const mockProvider = {
7
+ provider: "anthropic",
8
+ model: "claude-sonnet-4-5-20250514",
9
+ };
10
+ describe("detectStaleness", () => {
11
+ it("detects stale content when sources have changed", async () => {
12
+ vi.mocked(generateObject).mockResolvedValueOnce({
13
+ object: {
14
+ stale: true,
15
+ reason: "Source file has new information about project completion.",
16
+ stale_sources: ["knowledge/clients/acme.md"],
17
+ confidence: 0.92,
18
+ },
19
+ usage: { promptTokens: 3000, completionTokens: 150 },
20
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
21
+ });
22
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
23
+ const result = await detectStaleness({
24
+ content: "Acme Corp is currently migrating to Next.js.",
25
+ content_generated_at: "2026-03-01T10:00:00Z",
26
+ source_texts: [
27
+ {
28
+ path: "knowledge/clients/acme.md",
29
+ text: "Acme Corp completed their Next.js migration on 2026-03-15.",
30
+ updated_at: "2026-03-16T10:00:00Z",
31
+ },
32
+ ],
33
+ }, mockProvider, budget);
34
+ expect(result.stale).toBe(true);
35
+ expect(result.stale_sources).toContain("knowledge/clients/acme.md");
36
+ expect(result.confidence).toBeGreaterThan(0.8);
37
+ expect(result.usage.function_name).toBe("detectStaleness");
38
+ });
39
+ it("reports fresh content when no meaningful changes", async () => {
40
+ vi.mocked(generateObject).mockResolvedValueOnce({
41
+ object: {
42
+ stale: false,
43
+ reason: "Source changes are minor formatting edits.",
44
+ stale_sources: [],
45
+ confidence: 0.88,
46
+ },
47
+ usage: { promptTokens: 2500, completionTokens: 100 },
48
+ // biome-ignore lint/suspicious/noExplicitAny: partial mock of generateObject return type
49
+ });
50
+ const budget = new BudgetTracker({ daily_limit_usd: 5.0 });
51
+ const result = await detectStaleness({
52
+ content: "Acme Corp case study content.",
53
+ content_generated_at: "2026-04-01T10:00:00Z",
54
+ source_texts: [
55
+ {
56
+ path: "knowledge/clients/acme.md",
57
+ text: "Acme Corp case study notes (reformatted).",
58
+ updated_at: "2026-04-02T10:00:00Z",
59
+ },
60
+ ],
61
+ }, mockProvider, budget);
62
+ expect(result.stale).toBe(false);
63
+ expect(result.stale_sources).toHaveLength(0);
64
+ });
65
+ });
66
+ //# sourceMappingURL=staleness.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staleness.test.js","sourceRoot":"","sources":["../../src/__tests__/staleness.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5D,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,IAAI,CAAC;AACpC,MAAM,YAAY,GAAqB;IACtC,QAAQ,EAAE,WAAW;IACrB,KAAK,EAAE,4BAA4B;CACnC,CAAC;AAEF,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAChE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,qBAAqB,CAAC;YAC/C,MAAM,EAAE;gBACP,KAAK,EAAE,IAAI;gBACX,MAAM,EAAE,2DAA2D;gBACnE,aAAa,EAAE,CAAC,2BAA2B,CAAC;gBAC5C,UAAU,EAAE,IAAI;aAChB;YACD,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE;YACpD,yFAAyF;SAClF,CAAC,CAAC;QACV,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,eAAe,CACnC;YACC,OAAO,EAAE,8CAA8C;YACvD,oBAAoB,EAAE,sBAAsB;YAC5C,YAAY,EAAE;gBACb;oBACC,IAAI,EAAE,2BAA2B;oBACjC,IAAI,EAAE,4DAA4D;oBAClE,UAAU,EAAE,sBAAsB;iBAClC;aACD;SACD,EACD,YAAY,EACZ,MAAM,CACN,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC;QACpE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QACjE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,qBAAqB,CAAC;YAC/C,MAAM,EAAE;gBACP,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,4CAA4C;gBACpD,aAAa,EAAE,EAAE;gBACjB,UAAU,EAAE,IAAI;aAChB;YACD,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE;YACpD,yFAAyF;SAClF,CAAC,CAAC;QACV,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,eAAe,CACnC;YACC,OAAO,EAAE,+BAA+B;YACxC,oBAAoB,EAAE,sBAAsB;YAC5C,YAAY,EAAE;gBACb;oBACC,IAAI,EAAE,2BAA2B;oBACjC,IAAI,EAAE,2CAA2C;oBACjD,UAAU,EAAE,sBAAsB;iBAClC;aACD;SACD,EACD,YAAY,EACZ,MAAM,CACN,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { BudgetConfig, BudgetStatus, TokenUsage } from "./types.js";
2
+ export declare class BudgetTracker {
3
+ private config;
4
+ private usage;
5
+ private dailySpent;
6
+ constructor(config: BudgetConfig);
7
+ record(usage: TokenUsage): void;
8
+ getStatus(): BudgetStatus;
9
+ canSpend(estimated_cost_usd: number): boolean;
10
+ getHistory(): TokenUsage[];
11
+ resetDaily(): void;
12
+ }
13
+ //# sourceMappingURL=budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../src/budget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEzE,qBAAa,aAAa;IACzB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,UAAU,CAAK;gBAEX,MAAM,EAAE,YAAY;IAIhC,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAK/B,SAAS,IAAI,YAAY;IAkBzB,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO;IAI7C,UAAU,IAAI,UAAU,EAAE;IAI1B,UAAU,IAAI,IAAI;CAIlB"}
package/dist/budget.js ADDED
@@ -0,0 +1,40 @@
1
+ export class BudgetTracker {
2
+ config;
3
+ usage = [];
4
+ dailySpent = 0;
5
+ constructor(config) {
6
+ this.config = config;
7
+ }
8
+ record(usage) {
9
+ this.usage.push(usage);
10
+ this.dailySpent += usage.estimated_cost_usd;
11
+ }
12
+ getStatus() {
13
+ const remaining = Math.max(0, this.config.daily_limit_usd - this.dailySpent);
14
+ const warnAt = this.config.warn_at_usd ?? this.config.daily_limit_usd * 0.8;
15
+ const now = new Date();
16
+ const resetAt = new Date(now);
17
+ resetAt.setUTCDate(resetAt.getUTCDate() + 1);
18
+ resetAt.setUTCHours(0, 0, 0, 0);
19
+ return {
20
+ spent_today_usd: Math.round(this.dailySpent * 1000) / 1000,
21
+ limit_usd: this.config.daily_limit_usd,
22
+ warn_at_usd: warnAt,
23
+ remaining_usd: Math.round(remaining * 1000) / 1000,
24
+ is_over_limit: this.dailySpent >= this.config.daily_limit_usd,
25
+ is_warned: this.dailySpent >= warnAt,
26
+ reset_at: resetAt.toISOString(),
27
+ };
28
+ }
29
+ canSpend(estimated_cost_usd) {
30
+ return this.dailySpent + estimated_cost_usd <= this.config.daily_limit_usd;
31
+ }
32
+ getHistory() {
33
+ return [...this.usage];
34
+ }
35
+ resetDaily() {
36
+ this.usage = [];
37
+ this.dailySpent = 0;
38
+ }
39
+ }
40
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../src/budget.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,aAAa;IACjB,MAAM,CAAe;IACrB,KAAK,GAAiB,EAAE,CAAC;IACzB,UAAU,GAAG,CAAC,CAAC;IAEvB,YAAY,MAAoB;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAED,MAAM,CAAC,KAAiB;QACvB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC,kBAAkB,CAAC;IAC7C,CAAC;IAED,SAAS;QACR,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7E,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,GAAG,GAAG,CAAC;QAC5E,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAChC,OAAO;YACN,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,IAAI;YAC1D,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe;YACtC,WAAW,EAAE,MAAM;YACnB,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,IAAI;YAClD,aAAa,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe;YAC7D,SAAS,EAAE,IAAI,CAAC,UAAU,IAAI,MAAM;YACpC,QAAQ,EAAE,OAAO,CAAC,WAAW,EAAE;SAC/B,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,kBAA0B;QAClC,OAAO,IAAI,CAAC,UAAU,GAAG,kBAAkB,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;IAC5E,CAAC;IAED,UAAU;QACT,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,UAAU;QACT,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;IACrB,CAAC;CACD"}
@@ -0,0 +1,34 @@
1
+ import type { BudgetTracker } from "../budget.js";
2
+ import type { ResolvedProvider } from "../provider.js";
3
+ import type { EvalRunConfig, EvalRunResult, TokenUsage } from "../types.js";
4
+ export declare class EvalRunner {
5
+ private provider;
6
+ private budget;
7
+ constructor(provider: ResolvedProvider, budget: BudgetTracker);
8
+ /**
9
+ * Run the generate-judge-decide-improve loop.
10
+ *
11
+ * 1. GENERATE — AI creates content with current prompt
12
+ * 2. JUDGE — Locked judge-prompt scores 0-100
13
+ * 3. DECIDE — Score >= threshold? Keep. Otherwise discard.
14
+ * 4. IMPROVE — If discard: agent adjusts generation prompt
15
+ * 5. LOG — Result recorded
16
+ * 6. REPEAT — Until threshold met or max iterations
17
+ */
18
+ run(config: EvalRunConfig): Promise<EvalRunResult>;
19
+ /**
20
+ * Single judge pass — score existing content without the improve loop.
21
+ * Used for quality scoring of already-published content.
22
+ */
23
+ judgeOnly(input: {
24
+ draft: string;
25
+ gold_standard: string;
26
+ judge_prompt: string;
27
+ intent?: string;
28
+ }): Promise<{
29
+ score: number;
30
+ reasoning: string;
31
+ usage: TokenUsage;
32
+ }>;
33
+ }
34
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/eval/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAIlD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAc,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAsBxF,qBAAa,UAAU;IACtB,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,MAAM,CAAgB;gBAElB,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,aAAa;IAK7D;;;;;;;;;OASG;IACG,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAmGxD;;;OAGG;IACG,SAAS,CAAC,KAAK,EAAE;QACtB,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;CAQpE"}