@agntk/agent-harness 0.1.1

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 (212) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +41 -0
  3. package/README.md +445 -0
  4. package/defaults/agents/summarizer.md +49 -0
  5. package/defaults/instincts/lead-with-answer.md +24 -0
  6. package/defaults/instincts/qualify-before-recommending.md +40 -0
  7. package/defaults/instincts/read-before-edit.md +23 -0
  8. package/defaults/instincts/search-before-create.md +23 -0
  9. package/defaults/playbooks/ship-feature.md +31 -0
  10. package/defaults/rules/ask-before-assuming.md +35 -0
  11. package/defaults/rules/operations.md +35 -0
  12. package/defaults/rules/respect-the-user.md +39 -0
  13. package/defaults/skills/business-analyst.md +181 -0
  14. package/defaults/skills/content-marketer.md +184 -0
  15. package/defaults/skills/research.md +34 -0
  16. package/defaults/tools/example-web-search.md +60 -0
  17. package/defaults/workflows/daily-reflection.md +54 -0
  18. package/dist/agent-framework-K4GUIICH.js +344 -0
  19. package/dist/agent-framework-K4GUIICH.js.map +1 -0
  20. package/dist/analytics-RPT73WNM.js +12 -0
  21. package/dist/analytics-RPT73WNM.js.map +1 -0
  22. package/dist/auto-processor-OLE45UI3.js +13 -0
  23. package/dist/auto-processor-OLE45UI3.js.map +1 -0
  24. package/dist/chunk-274RV3YO.js +162 -0
  25. package/dist/chunk-274RV3YO.js.map +1 -0
  26. package/dist/chunk-4CWAGBNS.js +168 -0
  27. package/dist/chunk-4CWAGBNS.js.map +1 -0
  28. package/dist/chunk-4FDUOGSZ.js +69 -0
  29. package/dist/chunk-4FDUOGSZ.js.map +1 -0
  30. package/dist/chunk-5H34JPMB.js +199 -0
  31. package/dist/chunk-5H34JPMB.js.map +1 -0
  32. package/dist/chunk-6EMOEYGU.js +102 -0
  33. package/dist/chunk-6EMOEYGU.js.map +1 -0
  34. package/dist/chunk-A7BJPQQ6.js +236 -0
  35. package/dist/chunk-A7BJPQQ6.js.map +1 -0
  36. package/dist/chunk-AGAAFJEO.js +76 -0
  37. package/dist/chunk-AGAAFJEO.js.map +1 -0
  38. package/dist/chunk-BSKDOFRT.js +65 -0
  39. package/dist/chunk-BSKDOFRT.js.map +1 -0
  40. package/dist/chunk-CHJ5GNZC.js +100 -0
  41. package/dist/chunk-CHJ5GNZC.js.map +1 -0
  42. package/dist/chunk-CSL3ERUI.js +307 -0
  43. package/dist/chunk-CSL3ERUI.js.map +1 -0
  44. package/dist/chunk-DA7IKHC4.js +229 -0
  45. package/dist/chunk-DA7IKHC4.js.map +1 -0
  46. package/dist/chunk-DGUM43GV.js +11 -0
  47. package/dist/chunk-DGUM43GV.js.map +1 -0
  48. package/dist/chunk-DTTXPHFW.js +211 -0
  49. package/dist/chunk-DTTXPHFW.js.map +1 -0
  50. package/dist/chunk-FD55B3IO.js +204 -0
  51. package/dist/chunk-FD55B3IO.js.map +1 -0
  52. package/dist/chunk-FLZU44SV.js +230 -0
  53. package/dist/chunk-FLZU44SV.js.map +1 -0
  54. package/dist/chunk-GJNNR2RA.js +200 -0
  55. package/dist/chunk-GJNNR2RA.js.map +1 -0
  56. package/dist/chunk-GNUSHD2Y.js +111 -0
  57. package/dist/chunk-GNUSHD2Y.js.map +1 -0
  58. package/dist/chunk-GUJTBGVS.js +2212 -0
  59. package/dist/chunk-GUJTBGVS.js.map +1 -0
  60. package/dist/chunk-IZ6UZ3ZL.js +207 -0
  61. package/dist/chunk-IZ6UZ3ZL.js.map +1 -0
  62. package/dist/chunk-JKMGYWXB.js +197 -0
  63. package/dist/chunk-JKMGYWXB.js.map +1 -0
  64. package/dist/chunk-KFX54TQM.js +165 -0
  65. package/dist/chunk-KFX54TQM.js.map +1 -0
  66. package/dist/chunk-M7NXUK55.js +199 -0
  67. package/dist/chunk-M7NXUK55.js.map +1 -0
  68. package/dist/chunk-MPZ3BPUI.js +374 -0
  69. package/dist/chunk-MPZ3BPUI.js.map +1 -0
  70. package/dist/chunk-OC6YSTDX.js +119 -0
  71. package/dist/chunk-OC6YSTDX.js.map +1 -0
  72. package/dist/chunk-RC6MEZB6.js +469 -0
  73. package/dist/chunk-RC6MEZB6.js.map +1 -0
  74. package/dist/chunk-RY3ZFII7.js +3440 -0
  75. package/dist/chunk-RY3ZFII7.js.map +1 -0
  76. package/dist/chunk-TAT6JU3X.js +167 -0
  77. package/dist/chunk-TAT6JU3X.js.map +1 -0
  78. package/dist/chunk-UDZIS2AQ.js +79 -0
  79. package/dist/chunk-UDZIS2AQ.js.map +1 -0
  80. package/dist/chunk-UPLBF4RZ.js +115 -0
  81. package/dist/chunk-UPLBF4RZ.js.map +1 -0
  82. package/dist/chunk-UWQTZMNI.js +154 -0
  83. package/dist/chunk-UWQTZMNI.js.map +1 -0
  84. package/dist/chunk-W4T7PGI2.js +346 -0
  85. package/dist/chunk-W4T7PGI2.js.map +1 -0
  86. package/dist/chunk-XTBKL5BI.js +111 -0
  87. package/dist/chunk-XTBKL5BI.js.map +1 -0
  88. package/dist/chunk-YIJY5DBV.js +399 -0
  89. package/dist/chunk-YIJY5DBV.js.map +1 -0
  90. package/dist/chunk-YUFNYN2H.js +242 -0
  91. package/dist/chunk-YUFNYN2H.js.map +1 -0
  92. package/dist/chunk-Z2PUCXTZ.js +94 -0
  93. package/dist/chunk-Z2PUCXTZ.js.map +1 -0
  94. package/dist/chunk-ZZJOFKAT.js +13 -0
  95. package/dist/chunk-ZZJOFKAT.js.map +1 -0
  96. package/dist/cli/index.js +3661 -0
  97. package/dist/cli/index.js.map +1 -0
  98. package/dist/config-WVMRUOCA.js +13 -0
  99. package/dist/config-WVMRUOCA.js.map +1 -0
  100. package/dist/context-loader-3ORBPMHJ.js +13 -0
  101. package/dist/context-loader-3ORBPMHJ.js.map +1 -0
  102. package/dist/conversation-QDEIDQPH.js +22 -0
  103. package/dist/conversation-QDEIDQPH.js.map +1 -0
  104. package/dist/cost-tracker-RS3W7SVY.js +24 -0
  105. package/dist/cost-tracker-RS3W7SVY.js.map +1 -0
  106. package/dist/delegate-VJCJLYEK.js +29 -0
  107. package/dist/delegate-VJCJLYEK.js.map +1 -0
  108. package/dist/emotional-state-VQVRA6ED.js +206 -0
  109. package/dist/emotional-state-VQVRA6ED.js.map +1 -0
  110. package/dist/env-discovery-2BLVMAIM.js +251 -0
  111. package/dist/env-discovery-2BLVMAIM.js.map +1 -0
  112. package/dist/export-6GCYHEHQ.js +165 -0
  113. package/dist/export-6GCYHEHQ.js.map +1 -0
  114. package/dist/graph-YUIPOSOO.js +14 -0
  115. package/dist/graph-YUIPOSOO.js.map +1 -0
  116. package/dist/harness-LCHA3DWP.js +10 -0
  117. package/dist/harness-LCHA3DWP.js.map +1 -0
  118. package/dist/harness-WE4SLCML.js +26 -0
  119. package/dist/harness-WE4SLCML.js.map +1 -0
  120. package/dist/health-NZ6WNIMV.js +23 -0
  121. package/dist/health-NZ6WNIMV.js.map +1 -0
  122. package/dist/index.d.ts +3612 -0
  123. package/dist/index.js +13501 -0
  124. package/dist/index.js.map +1 -0
  125. package/dist/indexer-LONANRRM.js +16 -0
  126. package/dist/indexer-LONANRRM.js.map +1 -0
  127. package/dist/instinct-learner-SRM72DHF.js +20 -0
  128. package/dist/instinct-learner-SRM72DHF.js.map +1 -0
  129. package/dist/intake-4M3HNU43.js +21 -0
  130. package/dist/intake-4M3HNU43.js.map +1 -0
  131. package/dist/intelligence-HJOCA4SJ.js +1081 -0
  132. package/dist/intelligence-HJOCA4SJ.js.map +1 -0
  133. package/dist/journal-WANJL3MI.js +24 -0
  134. package/dist/journal-WANJL3MI.js.map +1 -0
  135. package/dist/loader-C3TKIKZR.js +23 -0
  136. package/dist/loader-C3TKIKZR.js.map +1 -0
  137. package/dist/mcp-WTQJJZAO.js +15 -0
  138. package/dist/mcp-WTQJJZAO.js.map +1 -0
  139. package/dist/mcp-discovery-WPAQFL6S.js +377 -0
  140. package/dist/mcp-discovery-WPAQFL6S.js.map +1 -0
  141. package/dist/mcp-installer-6O2XXD3V.js +394 -0
  142. package/dist/mcp-installer-6O2XXD3V.js.map +1 -0
  143. package/dist/metrics-KXGNFAAB.js +20 -0
  144. package/dist/metrics-KXGNFAAB.js.map +1 -0
  145. package/dist/primitive-registry-I6VTIR4W.js +512 -0
  146. package/dist/primitive-registry-I6VTIR4W.js.map +1 -0
  147. package/dist/project-discovery-C4UMD7JI.js +246 -0
  148. package/dist/project-discovery-C4UMD7JI.js.map +1 -0
  149. package/dist/provider-LQHQX7Z7.js +26 -0
  150. package/dist/provider-LQHQX7Z7.js.map +1 -0
  151. package/dist/provider-SXPQZ74H.js +28 -0
  152. package/dist/provider-SXPQZ74H.js.map +1 -0
  153. package/dist/rate-limiter-RLRVM325.js +22 -0
  154. package/dist/rate-limiter-RLRVM325.js.map +1 -0
  155. package/dist/rule-engine-YGQ3RYZM.js +182 -0
  156. package/dist/rule-engine-YGQ3RYZM.js.map +1 -0
  157. package/dist/scaffold-A3VRRCBV.js +347 -0
  158. package/dist/scaffold-A3VRRCBV.js.map +1 -0
  159. package/dist/scheduler-XHHIVHRI.js +397 -0
  160. package/dist/scheduler-XHHIVHRI.js.map +1 -0
  161. package/dist/search-V3W5JMJG.js +75 -0
  162. package/dist/search-V3W5JMJG.js.map +1 -0
  163. package/dist/semantic-search-2DTOO5UX.js +241 -0
  164. package/dist/semantic-search-2DTOO5UX.js.map +1 -0
  165. package/dist/serve-DTQ3HENY.js +291 -0
  166. package/dist/serve-DTQ3HENY.js.map +1 -0
  167. package/dist/sessions-CZGVXKQE.js +21 -0
  168. package/dist/sessions-CZGVXKQE.js.map +1 -0
  169. package/dist/sources-RW5DT56F.js +32 -0
  170. package/dist/sources-RW5DT56F.js.map +1 -0
  171. package/dist/starter-packs-76YUVHEU.js +893 -0
  172. package/dist/starter-packs-76YUVHEU.js.map +1 -0
  173. package/dist/state-GMXILIHW.js +13 -0
  174. package/dist/state-GMXILIHW.js.map +1 -0
  175. package/dist/state-merge-NKO5FRBA.js +174 -0
  176. package/dist/state-merge-NKO5FRBA.js.map +1 -0
  177. package/dist/telemetry-UC6PBXC7.js +22 -0
  178. package/dist/telemetry-UC6PBXC7.js.map +1 -0
  179. package/dist/tool-executor-MJ7IG7PQ.js +28 -0
  180. package/dist/tool-executor-MJ7IG7PQ.js.map +1 -0
  181. package/dist/tools-DZ4KETET.js +20 -0
  182. package/dist/tools-DZ4KETET.js.map +1 -0
  183. package/dist/types-EW7AIB3R.js +18 -0
  184. package/dist/types-EW7AIB3R.js.map +1 -0
  185. package/dist/types-WGDLSPO6.js +16 -0
  186. package/dist/types-WGDLSPO6.js.map +1 -0
  187. package/dist/universal-installer-QGS4SJGX.js +578 -0
  188. package/dist/universal-installer-QGS4SJGX.js.map +1 -0
  189. package/dist/validator-7WXMDIHH.js +22 -0
  190. package/dist/validator-7WXMDIHH.js.map +1 -0
  191. package/dist/verification-gate-FYXUX6LH.js +246 -0
  192. package/dist/verification-gate-FYXUX6LH.js.map +1 -0
  193. package/dist/versioning-Z3XNE2Q2.js +271 -0
  194. package/dist/versioning-Z3XNE2Q2.js.map +1 -0
  195. package/dist/watcher-ISJC7YKL.js +109 -0
  196. package/dist/watcher-ISJC7YKL.js.map +1 -0
  197. package/dist/web-server-DD7ZOP46.js +28 -0
  198. package/dist/web-server-DD7ZOP46.js.map +1 -0
  199. package/package.json +76 -0
  200. package/sources.yaml +121 -0
  201. package/templates/assistant/CORE.md +24 -0
  202. package/templates/assistant/SYSTEM.md +24 -0
  203. package/templates/assistant/config.yaml +51 -0
  204. package/templates/base/CORE.md +17 -0
  205. package/templates/base/SYSTEM.md +24 -0
  206. package/templates/base/config.yaml +51 -0
  207. package/templates/claude-opus/config.yaml +51 -0
  208. package/templates/code-reviewer/CORE.md +25 -0
  209. package/templates/code-reviewer/SYSTEM.md +30 -0
  210. package/templates/code-reviewer/config.yaml +51 -0
  211. package/templates/gpt4/config.yaml +51 -0
  212. package/templates/local/config.yaml +51 -0
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {
4
+ withFileLockSync
5
+ } from "./chunk-Z2PUCXTZ.js";
6
+
7
+ // src/runtime/sessions.ts
8
+ import { writeFileSync, mkdirSync, existsSync, readdirSync, unlinkSync, copyFileSync } from "fs";
9
+ import { join } from "path";
10
+ import { randomUUID } from "crypto";
11
+ function createSessionId() {
12
+ const now = /* @__PURE__ */ new Date();
13
+ const date = now.toISOString().split("T")[0];
14
+ const short = randomUUID().slice(0, 8);
15
+ return `${date}-${short}`;
16
+ }
17
+ function formatToolCalls(toolCalls) {
18
+ if (!toolCalls || toolCalls.length === 0) return "";
19
+ const lines = ["\n## Tools Used\n"];
20
+ for (const tc of toolCalls) {
21
+ lines.push(`### ${tc.toolName}`);
22
+ const argsStr = JSON.stringify(tc.args, null, 2);
23
+ lines.push(`**Args:** \`${argsStr.length > 200 ? argsStr.slice(0, 200) + "..." : argsStr}\``);
24
+ if (tc.result !== null && tc.result !== void 0) {
25
+ const resultStr = typeof tc.result === "string" ? tc.result : JSON.stringify(tc.result);
26
+ lines.push(`**Result:** ${resultStr.length > 300 ? resultStr.slice(0, 300) + "..." : resultStr}`);
27
+ }
28
+ lines.push("");
29
+ }
30
+ return lines.join("\n");
31
+ }
32
+ function writeSession(harnessDir, session) {
33
+ const sessionsDir = join(harnessDir, "memory", "sessions");
34
+ if (!existsSync(sessionsDir)) {
35
+ mkdirSync(sessionsDir, { recursive: true });
36
+ }
37
+ const filePath = join(sessionsDir, `${session.id}.md`);
38
+ const tags = session.delegated_to ? `[session, delegation, ${session.delegated_to}]` : "[session]";
39
+ const modelLine = session.model_id ? `
40
+ **Model:** ${session.model_id}` : "";
41
+ const delegateLine = session.delegated_to ? `
42
+ **Delegated to:** ${session.delegated_to}` : "";
43
+ const toolSection = formatToolCalls(session.tool_calls);
44
+ const content = `---
45
+ id: ${session.id}
46
+ tags: ${tags}
47
+ created: ${session.started}
48
+ updated: ${session.ended}
49
+ author: agent
50
+ status: active
51
+ duration_minutes: ${Math.round((new Date(session.ended).getTime() - new Date(session.started).getTime()) / 6e4)}
52
+ ---
53
+
54
+ <!-- L0: Session ${session.id} \u2014 ${session.summary.slice(0, 60)} -->
55
+ <!-- L1: ${session.summary} -->
56
+
57
+ # Session: ${session.id}
58
+
59
+ **Started:** ${session.started}
60
+ **Ended:** ${session.ended}
61
+ **Tokens:** ${session.tokens_used}
62
+ **Steps:** ${session.steps}${modelLine}${delegateLine}
63
+
64
+ ## Prompt
65
+ ${session.prompt}
66
+
67
+ ## Summary
68
+ ${session.summary}
69
+ ${toolSection}`;
70
+ withFileLockSync(harnessDir, filePath, () => {
71
+ writeFileSync(filePath, content, "utf-8");
72
+ });
73
+ return filePath;
74
+ }
75
+ function archiveOldFiles(harnessDir, sessionRetentionDays, journalRetentionDays) {
76
+ const result = {
77
+ sessionsArchived: 0,
78
+ journalsArchived: 0,
79
+ sessionFiles: [],
80
+ journalFiles: []
81
+ };
82
+ const now = Date.now();
83
+ const sessionsDir = join(harnessDir, "memory", "sessions");
84
+ if (existsSync(sessionsDir)) {
85
+ const cutoff = now - sessionRetentionDays * 24 * 60 * 60 * 1e3;
86
+ const files = readdirSync(sessionsDir).filter(
87
+ (f) => f.endsWith(".md") && !f.startsWith(".") && !f.startsWith("_")
88
+ );
89
+ for (const file of files) {
90
+ const dateStr = extractDateFromFilename(file);
91
+ if (dateStr && new Date(dateStr).getTime() < cutoff) {
92
+ const yearMonth = dateStr.slice(0, 7);
93
+ const archiveDir = join(sessionsDir, "archive", yearMonth);
94
+ mkdirSync(archiveDir, { recursive: true });
95
+ copyFileSync(join(sessionsDir, file), join(archiveDir, file));
96
+ unlinkSync(join(sessionsDir, file));
97
+ result.sessionsArchived++;
98
+ result.sessionFiles.push(file);
99
+ }
100
+ }
101
+ }
102
+ const journalDir = join(harnessDir, "memory", "journal");
103
+ if (existsSync(journalDir)) {
104
+ const cutoff = now - journalRetentionDays * 24 * 60 * 60 * 1e3;
105
+ const files = readdirSync(journalDir).filter(
106
+ (f) => f.endsWith(".md") && !f.startsWith(".") && !f.startsWith("_")
107
+ );
108
+ for (const file of files) {
109
+ const dateStr = extractDateFromFilename(file);
110
+ if (dateStr && new Date(dateStr).getTime() < cutoff) {
111
+ const yearMonth = dateStr.slice(0, 7);
112
+ const archiveDir = join(journalDir, "archive", yearMonth);
113
+ mkdirSync(archiveDir, { recursive: true });
114
+ copyFileSync(join(journalDir, file), join(archiveDir, file));
115
+ unlinkSync(join(journalDir, file));
116
+ result.journalsArchived++;
117
+ result.journalFiles.push(file);
118
+ }
119
+ }
120
+ }
121
+ return result;
122
+ }
123
+ function cleanupOldFiles(harnessDir, sessionRetentionDays, journalRetentionDays) {
124
+ const result = {
125
+ sessionsRemoved: 0,
126
+ journalsRemoved: 0,
127
+ sessionFiles: [],
128
+ journalFiles: []
129
+ };
130
+ const now = Date.now();
131
+ const sessionsDir = join(harnessDir, "memory", "sessions");
132
+ if (existsSync(sessionsDir)) {
133
+ const cutoff = now - sessionRetentionDays * 24 * 60 * 60 * 1e3;
134
+ const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".md") && !f.startsWith("."));
135
+ for (const file of files) {
136
+ const dateStr = extractDateFromFilename(file);
137
+ if (dateStr && new Date(dateStr).getTime() < cutoff) {
138
+ unlinkSync(join(sessionsDir, file));
139
+ result.sessionsRemoved++;
140
+ result.sessionFiles.push(file);
141
+ }
142
+ }
143
+ }
144
+ const journalDir = join(harnessDir, "memory", "journal");
145
+ if (existsSync(journalDir)) {
146
+ const cutoff = now - journalRetentionDays * 24 * 60 * 60 * 1e3;
147
+ const files = readdirSync(journalDir).filter((f) => f.endsWith(".md") && !f.startsWith("."));
148
+ for (const file of files) {
149
+ const dateStr = extractDateFromFilename(file);
150
+ if (dateStr && new Date(dateStr).getTime() < cutoff) {
151
+ unlinkSync(join(journalDir, file));
152
+ result.journalsRemoved++;
153
+ result.journalFiles.push(file);
154
+ }
155
+ }
156
+ }
157
+ return result;
158
+ }
159
+ function extractDateFromFilename(filename) {
160
+ const match = filename.match(/^(\d{4}-\d{2}-\d{2})/);
161
+ if (!match) return null;
162
+ const date = new Date(match[1]);
163
+ return isNaN(date.getTime()) ? null : match[1];
164
+ }
165
+ function listSessions(harnessDir) {
166
+ const sessionsDir = join(harnessDir, "memory", "sessions");
167
+ if (!existsSync(sessionsDir)) return [];
168
+ return readdirSync(sessionsDir).filter((f) => f.endsWith(".md") && !f.startsWith(".")).sort().reverse().map((f) => ({
169
+ id: f.replace(".md", ""),
170
+ date: extractDateFromFilename(f) || "unknown",
171
+ path: join(sessionsDir, f)
172
+ }));
173
+ }
174
+ function listExpiredFiles(harnessDir, sessionRetentionDays, journalRetentionDays) {
175
+ const now = Date.now();
176
+ const sessionFiles = [];
177
+ const journalFiles = [];
178
+ const sessionsDir = join(harnessDir, "memory", "sessions");
179
+ if (existsSync(sessionsDir)) {
180
+ const cutoff = now - sessionRetentionDays * 24 * 60 * 60 * 1e3;
181
+ const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".md") && !f.startsWith("."));
182
+ for (const file of files) {
183
+ const dateStr = extractDateFromFilename(file);
184
+ if (dateStr && new Date(dateStr).getTime() < cutoff) {
185
+ sessionFiles.push(file);
186
+ }
187
+ }
188
+ }
189
+ const journalDir = join(harnessDir, "memory", "journal");
190
+ if (existsSync(journalDir)) {
191
+ const cutoff = now - journalRetentionDays * 24 * 60 * 60 * 1e3;
192
+ const files = readdirSync(journalDir).filter((f) => f.endsWith(".md") && !f.startsWith("."));
193
+ for (const file of files) {
194
+ const dateStr = extractDateFromFilename(file);
195
+ if (dateStr && new Date(dateStr).getTime() < cutoff) {
196
+ journalFiles.push(file);
197
+ }
198
+ }
199
+ }
200
+ return { sessionFiles, journalFiles };
201
+ }
202
+
203
+ export {
204
+ createSessionId,
205
+ writeSession,
206
+ archiveOldFiles,
207
+ cleanupOldFiles,
208
+ listSessions,
209
+ listExpiredFiles
210
+ };
211
+ //# sourceMappingURL=chunk-DTTXPHFW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/sessions.ts"],"sourcesContent":["import { writeFileSync, mkdirSync, existsSync, readdirSync, unlinkSync, copyFileSync } from 'fs';\nimport { join } from 'path';\nimport { randomUUID } from 'crypto';\nimport { withFileLockSync } from './file-lock.js';\nimport type { ToolCallInfo } from '../core/types.js';\n\nexport interface SessionRecord {\n id: string;\n started: string;\n ended: string;\n prompt: string;\n summary: string;\n tokens_used: number;\n steps: number;\n model_id?: string;\n delegated_to?: string;\n /** Tool calls executed during this session */\n tool_calls?: ToolCallInfo[];\n}\n\nexport function createSessionId(): string {\n const now = new Date();\n const date = now.toISOString().split('T')[0];\n const short = randomUUID().slice(0, 8);\n return `${date}-${short}`;\n}\n\n/** Format tool calls as markdown for session files */\nfunction formatToolCalls(toolCalls?: ToolCallInfo[]): string {\n if (!toolCalls || toolCalls.length === 0) return '';\n\n const lines = ['\\n## Tools Used\\n'];\n for (const tc of toolCalls) {\n lines.push(`### ${tc.toolName}`);\n const argsStr = JSON.stringify(tc.args, null, 2);\n lines.push(`**Args:** \\`${argsStr.length > 200 ? argsStr.slice(0, 200) + '...' : argsStr}\\``);\n if (tc.result !== null && tc.result !== undefined) {\n const resultStr = typeof tc.result === 'string' ? tc.result : JSON.stringify(tc.result);\n lines.push(`**Result:** ${resultStr.length > 300 ? resultStr.slice(0, 300) + '...' : resultStr}`);\n }\n lines.push('');\n }\n return lines.join('\\n');\n}\n\nexport function writeSession(harnessDir: string, session: SessionRecord): string {\n const sessionsDir = join(harnessDir, 'memory', 'sessions');\n if (!existsSync(sessionsDir)) {\n mkdirSync(sessionsDir, { recursive: true });\n }\n\n const filePath = join(sessionsDir, `${session.id}.md`);\n const tags = session.delegated_to\n ? `[session, delegation, ${session.delegated_to}]`\n : '[session]';\n const modelLine = session.model_id ? `\\n**Model:** ${session.model_id}` : '';\n const delegateLine = session.delegated_to ? `\\n**Delegated to:** ${session.delegated_to}` : '';\n const toolSection = formatToolCalls(session.tool_calls);\n\n const content = `---\nid: ${session.id}\ntags: ${tags}\ncreated: ${session.started}\nupdated: ${session.ended}\nauthor: agent\nstatus: active\nduration_minutes: ${Math.round((new Date(session.ended).getTime() - new Date(session.started).getTime()) / 60000)}\n---\n\n<!-- L0: Session ${session.id} — ${session.summary.slice(0, 60)} -->\n<!-- L1: ${session.summary} -->\n\n# Session: ${session.id}\n\n**Started:** ${session.started}\n**Ended:** ${session.ended}\n**Tokens:** ${session.tokens_used}\n**Steps:** ${session.steps}${modelLine}${delegateLine}\n\n## Prompt\n${session.prompt}\n\n## Summary\n${session.summary}\n${toolSection}`;\n\n withFileLockSync(harnessDir, filePath, () => {\n writeFileSync(filePath, content, 'utf-8');\n });\n return filePath;\n}\n\nexport interface CleanupResult {\n sessionsRemoved: number;\n journalsRemoved: number;\n sessionFiles: string[];\n journalFiles: string[];\n}\n\nexport interface ArchiveResult {\n sessionsArchived: number;\n journalsArchived: number;\n sessionFiles: string[];\n journalFiles: string[];\n}\n\n/**\n * Archive sessions and journals older than their configured retention periods.\n * Moves files to archive/YYYY-MM/ subdirectories instead of deleting them.\n * Archived files remain on disk for audit/query but aren't loaded by default.\n */\nexport function archiveOldFiles(\n harnessDir: string,\n sessionRetentionDays: number,\n journalRetentionDays: number,\n): ArchiveResult {\n const result: ArchiveResult = {\n sessionsArchived: 0,\n journalsArchived: 0,\n sessionFiles: [],\n journalFiles: [],\n };\n\n const now = Date.now();\n\n // Archive sessions\n const sessionsDir = join(harnessDir, 'memory', 'sessions');\n if (existsSync(sessionsDir)) {\n const cutoff = now - sessionRetentionDays * 24 * 60 * 60 * 1000;\n const files = readdirSync(sessionsDir).filter(\n (f) => f.endsWith('.md') && !f.startsWith('.') && !f.startsWith('_'),\n );\n\n for (const file of files) {\n const dateStr = extractDateFromFilename(file);\n if (dateStr && new Date(dateStr).getTime() < cutoff) {\n const yearMonth = dateStr.slice(0, 7); // YYYY-MM\n const archiveDir = join(sessionsDir, 'archive', yearMonth);\n mkdirSync(archiveDir, { recursive: true });\n copyFileSync(join(sessionsDir, file), join(archiveDir, file));\n unlinkSync(join(sessionsDir, file));\n result.sessionsArchived++;\n result.sessionFiles.push(file);\n }\n }\n }\n\n // Archive journals\n const journalDir = join(harnessDir, 'memory', 'journal');\n if (existsSync(journalDir)) {\n const cutoff = now - journalRetentionDays * 24 * 60 * 60 * 1000;\n const files = readdirSync(journalDir).filter(\n (f) => f.endsWith('.md') && !f.startsWith('.') && !f.startsWith('_'),\n );\n\n for (const file of files) {\n const dateStr = extractDateFromFilename(file);\n if (dateStr && new Date(dateStr).getTime() < cutoff) {\n const yearMonth = dateStr.slice(0, 7);\n const archiveDir = join(journalDir, 'archive', yearMonth);\n mkdirSync(archiveDir, { recursive: true });\n copyFileSync(join(journalDir, file), join(archiveDir, file));\n unlinkSync(join(journalDir, file));\n result.journalsArchived++;\n result.journalFiles.push(file);\n }\n }\n }\n\n return result;\n}\n\n/**\n * Remove sessions and journals older than their configured retention periods.\n * @deprecated Use archiveOldFiles() instead — it preserves files in archive/.\n * This function deletes files permanently.\n */\nexport function cleanupOldFiles(\n harnessDir: string,\n sessionRetentionDays: number,\n journalRetentionDays: number,\n): CleanupResult {\n const result: CleanupResult = {\n sessionsRemoved: 0,\n journalsRemoved: 0,\n sessionFiles: [],\n journalFiles: [],\n };\n\n const now = Date.now();\n\n // Clean sessions\n const sessionsDir = join(harnessDir, 'memory', 'sessions');\n if (existsSync(sessionsDir)) {\n const cutoff = now - sessionRetentionDays * 24 * 60 * 60 * 1000;\n const files = readdirSync(sessionsDir).filter((f) => f.endsWith('.md') && !f.startsWith('.'));\n\n for (const file of files) {\n const dateStr = extractDateFromFilename(file);\n if (dateStr && new Date(dateStr).getTime() < cutoff) {\n unlinkSync(join(sessionsDir, file));\n result.sessionsRemoved++;\n result.sessionFiles.push(file);\n }\n }\n }\n\n // Clean journals\n const journalDir = join(harnessDir, 'memory', 'journal');\n if (existsSync(journalDir)) {\n const cutoff = now - journalRetentionDays * 24 * 60 * 60 * 1000;\n const files = readdirSync(journalDir).filter((f) => f.endsWith('.md') && !f.startsWith('.'));\n\n for (const file of files) {\n const dateStr = extractDateFromFilename(file);\n if (dateStr && new Date(dateStr).getTime() < cutoff) {\n unlinkSync(join(journalDir, file));\n result.journalsRemoved++;\n result.journalFiles.push(file);\n }\n }\n }\n\n return result;\n}\n\n/** Extract YYYY-MM-DD from filename like \"2026-04-06-abcdef12.md\" or \"2026-04-06.md\" */\nfunction extractDateFromFilename(filename: string): string | null {\n const match = filename.match(/^(\\d{4}-\\d{2}-\\d{2})/);\n if (!match) return null;\n const date = new Date(match[1]);\n return isNaN(date.getTime()) ? null : match[1];\n}\n\n/** List all session files with their dates */\nexport function listSessions(harnessDir: string): Array<{ id: string; date: string; path: string }> {\n const sessionsDir = join(harnessDir, 'memory', 'sessions');\n if (!existsSync(sessionsDir)) return [];\n\n return readdirSync(sessionsDir)\n .filter((f) => f.endsWith('.md') && !f.startsWith('.'))\n .sort()\n .reverse()\n .map((f) => ({\n id: f.replace('.md', ''),\n date: extractDateFromFilename(f) || 'unknown',\n path: join(sessionsDir, f),\n }));\n}\n\n/** List files that would be removed by cleanup (dry run — doesn't delete) */\nexport function listExpiredFiles(\n harnessDir: string,\n sessionRetentionDays: number,\n journalRetentionDays: number,\n): { sessionFiles: string[]; journalFiles: string[] } {\n const now = Date.now();\n const sessionFiles: string[] = [];\n const journalFiles: string[] = [];\n\n const sessionsDir = join(harnessDir, 'memory', 'sessions');\n if (existsSync(sessionsDir)) {\n const cutoff = now - sessionRetentionDays * 24 * 60 * 60 * 1000;\n const files = readdirSync(sessionsDir).filter((f) => f.endsWith('.md') && !f.startsWith('.'));\n for (const file of files) {\n const dateStr = extractDateFromFilename(file);\n if (dateStr && new Date(dateStr).getTime() < cutoff) {\n sessionFiles.push(file);\n }\n }\n }\n\n const journalDir = join(harnessDir, 'memory', 'journal');\n if (existsSync(journalDir)) {\n const cutoff = now - journalRetentionDays * 24 * 60 * 60 * 1000;\n const files = readdirSync(journalDir).filter((f) => f.endsWith('.md') && !f.startsWith('.'));\n for (const file of files) {\n const dateStr = extractDateFromFilename(file);\n if (dateStr && new Date(dateStr).getTime() < cutoff) {\n journalFiles.push(file);\n }\n }\n }\n\n return { sessionFiles, journalFiles };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,204 @@
1
+ // src/llm/provider.ts
2
+ import { createOpenRouter } from "@openrouter/ai-sdk-provider";
3
+ import { createAnthropic } from "@ai-sdk/anthropic";
4
+ import { createOpenAI } from "@ai-sdk/openai";
5
+ import { generateText, streamText, stepCountIs } from "ai";
6
+ var ENV_KEYS = {
7
+ openrouter: "OPENROUTER_API_KEY",
8
+ anthropic: "ANTHROPIC_API_KEY",
9
+ openai: "OPENAI_API_KEY"
10
+ };
11
+ var _providers = /* @__PURE__ */ new Map();
12
+ function getOrCreateFactory(providerName, apiKey) {
13
+ const cacheKey = `${providerName}:${apiKey ?? "env"}`;
14
+ const cached = _providers.get(cacheKey);
15
+ if (cached) return cached;
16
+ const envKey = ENV_KEYS[providerName];
17
+ const key = apiKey ?? process.env[envKey];
18
+ let factory;
19
+ switch (providerName) {
20
+ case "openrouter": {
21
+ if (!key) {
22
+ throw new Error(
23
+ `No API key found for provider "${providerName}". Set ${envKey} environment variable or pass apiKey option.`
24
+ );
25
+ }
26
+ const provider = createOpenRouter({ apiKey: key });
27
+ factory = (modelId) => provider(modelId);
28
+ break;
29
+ }
30
+ case "anthropic": {
31
+ const provider = createAnthropic(key ? { apiKey: key } : void 0);
32
+ factory = (modelId) => provider(modelId);
33
+ break;
34
+ }
35
+ case "openai": {
36
+ const provider = createOpenAI(key ? { apiKey: key } : void 0);
37
+ factory = (modelId) => provider(modelId);
38
+ break;
39
+ }
40
+ default:
41
+ throw new Error(
42
+ `Unknown provider "${providerName}". Supported providers: ${Object.keys(ENV_KEYS).join(", ")}`
43
+ );
44
+ }
45
+ _providers.set(cacheKey, factory);
46
+ return factory;
47
+ }
48
+ function getProvider(apiKey) {
49
+ const key = apiKey ?? process.env.OPENROUTER_API_KEY;
50
+ if (!key) {
51
+ throw new Error(
52
+ "No OpenRouter API key found. Set OPENROUTER_API_KEY environment variable or pass apiKey option."
53
+ );
54
+ }
55
+ return createOpenRouter({ apiKey: key });
56
+ }
57
+ function resetProvider() {
58
+ _providers.clear();
59
+ }
60
+ function getModel(config, apiKey) {
61
+ const providerName = config.model.provider ?? "openrouter";
62
+ const factory = getOrCreateFactory(providerName, apiKey);
63
+ return factory(config.model.id);
64
+ }
65
+ function getSummaryModel(config, apiKey) {
66
+ const modelId = config.model.summary_model ?? config.model.id;
67
+ const providerName = config.model.provider ?? "openrouter";
68
+ const factory = getOrCreateFactory(providerName, apiKey);
69
+ return factory(modelId);
70
+ }
71
+ function getFastModel(config, apiKey) {
72
+ const modelId = config.model.fast_model ?? config.model.summary_model ?? config.model.id;
73
+ const providerName = config.model.provider ?? "openrouter";
74
+ const factory = getOrCreateFactory(providerName, apiKey);
75
+ return factory(modelId);
76
+ }
77
+ function extractUsage(usage) {
78
+ return {
79
+ inputTokens: usage?.inputTokens ?? 0,
80
+ outputTokens: usage?.outputTokens ?? 0,
81
+ totalTokens: (usage?.inputTokens ?? 0) + (usage?.outputTokens ?? 0)
82
+ };
83
+ }
84
+ function buildCallSettings(opts) {
85
+ const hasTools = opts.tools && Object.keys(opts.tools).length > 0;
86
+ return {
87
+ ...opts.maxRetries !== void 0 ? { maxRetries: opts.maxRetries } : {},
88
+ ...opts.timeoutMs !== void 0 ? { timeout: opts.timeoutMs } : {},
89
+ ...opts.abortSignal ? { abortSignal: opts.abortSignal } : {},
90
+ ...hasTools ? { tools: opts.tools } : {},
91
+ ...hasTools ? { stopWhen: stepCountIs(opts.maxToolSteps ?? 5) } : {}
92
+ };
93
+ }
94
+ function extractToolCalls(result) {
95
+ const calls = [];
96
+ if (!result.steps) return calls;
97
+ for (const step of result.steps) {
98
+ if (!step.toolCalls) continue;
99
+ for (let i = 0; i < step.toolCalls.length; i++) {
100
+ const tc = step.toolCalls[i];
101
+ const tr = step.toolResults?.[i];
102
+ calls.push({
103
+ toolName: tc.toolName,
104
+ args: tc.input ?? {},
105
+ result: tr?.output ?? null
106
+ });
107
+ }
108
+ }
109
+ return calls;
110
+ }
111
+ async function generate(opts) {
112
+ const result = await generateText({
113
+ model: opts.model,
114
+ system: opts.system,
115
+ prompt: opts.prompt,
116
+ maxOutputTokens: opts.maxOutputTokens,
117
+ ...buildCallSettings(opts)
118
+ });
119
+ const usage = result.totalUsage ?? result.usage;
120
+ return {
121
+ text: result.text,
122
+ usage: extractUsage(usage),
123
+ toolCalls: extractToolCalls(result),
124
+ steps: result.steps?.length ?? 1
125
+ };
126
+ }
127
+ async function generateWithMessages(opts) {
128
+ const result = await generateText({
129
+ model: opts.model,
130
+ system: opts.system,
131
+ messages: opts.messages,
132
+ maxOutputTokens: opts.maxOutputTokens,
133
+ ...buildCallSettings(opts)
134
+ });
135
+ const usage = result.totalUsage ?? result.usage;
136
+ return {
137
+ text: result.text,
138
+ usage: extractUsage(usage),
139
+ toolCalls: extractToolCalls(result),
140
+ steps: result.steps?.length ?? 1
141
+ };
142
+ }
143
+ async function* streamGenerate(opts) {
144
+ const result = streamText({
145
+ model: opts.model,
146
+ system: opts.system,
147
+ prompt: opts.prompt,
148
+ maxOutputTokens: opts.maxOutputTokens,
149
+ ...buildCallSettings(opts)
150
+ });
151
+ for await (const chunk of result.textStream) {
152
+ yield chunk;
153
+ }
154
+ }
155
+ function streamWithMessages(opts) {
156
+ const result = streamText({
157
+ model: opts.model,
158
+ system: opts.system,
159
+ messages: opts.messages,
160
+ maxOutputTokens: opts.maxOutputTokens,
161
+ ...buildCallSettings(opts)
162
+ });
163
+ const totalUsage = Promise.resolve(result.totalUsage ?? result.usage).then((u) => extractUsage(u));
164
+ const toolCalls = Promise.resolve(result.steps).then((s) => extractToolCalls({ steps: s }));
165
+ const steps = Promise.resolve(result.steps).then((s) => s?.length ?? 1);
166
+ return {
167
+ textStream: result.textStream,
168
+ usage: totalUsage,
169
+ toolCalls,
170
+ steps
171
+ };
172
+ }
173
+ function streamGenerateWithDetails(opts) {
174
+ const result = streamText({
175
+ model: opts.model,
176
+ system: opts.system,
177
+ prompt: opts.prompt,
178
+ maxOutputTokens: opts.maxOutputTokens,
179
+ ...buildCallSettings(opts)
180
+ });
181
+ const totalUsage = Promise.resolve(result.totalUsage ?? result.usage).then((u) => extractUsage(u));
182
+ const toolCalls = Promise.resolve(result.steps).then((s) => extractToolCalls({ steps: s }));
183
+ const steps = Promise.resolve(result.steps).then((s) => s?.length ?? 1);
184
+ return {
185
+ textStream: result.textStream,
186
+ usage: totalUsage,
187
+ toolCalls,
188
+ steps
189
+ };
190
+ }
191
+
192
+ export {
193
+ getProvider,
194
+ resetProvider,
195
+ getModel,
196
+ getSummaryModel,
197
+ getFastModel,
198
+ generate,
199
+ generateWithMessages,
200
+ streamGenerate,
201
+ streamWithMessages,
202
+ streamGenerateWithDetails
203
+ };
204
+ //# sourceMappingURL=chunk-FD55B3IO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/llm/provider.ts"],"sourcesContent":["import { createOpenRouter } from '@openrouter/ai-sdk-provider';\nimport { createAnthropic } from '@ai-sdk/anthropic';\nimport { createOpenAI } from '@ai-sdk/openai';\nimport { generateText, streamText, stepCountIs, type LanguageModel } from 'ai';\nimport type { ModelMessage } from '@ai-sdk/provider-utils';\nimport type { HarnessConfig, ToolCallInfo } from '../core/types.js';\nimport type { AIToolSet } from '../runtime/tool-executor.js';\n\n/** Supported provider names for config.model.provider */\nexport type ProviderName = 'openrouter' | 'anthropic' | 'openai';\n\n/** Provider factory — maps provider names to (apiKey) => LanguageModel functions */\ntype ProviderFactory = (modelId: string, apiKey?: string) => LanguageModel;\n\nconst ENV_KEYS: Record<ProviderName, string> = {\n openrouter: 'OPENROUTER_API_KEY',\n anthropic: 'ANTHROPIC_API_KEY',\n openai: 'OPENAI_API_KEY',\n};\n\n/** Cached provider instances keyed by provider name */\nconst _providers: Map<string, ProviderFactory> = new Map();\n\nfunction getOrCreateFactory(providerName: ProviderName, apiKey?: string): ProviderFactory {\n const cacheKey = `${providerName}:${apiKey ?? 'env'}`;\n const cached = _providers.get(cacheKey);\n if (cached) return cached;\n\n const envKey = ENV_KEYS[providerName];\n const key = apiKey ?? process.env[envKey];\n\n let factory: ProviderFactory;\n\n switch (providerName) {\n case 'openrouter': {\n if (!key) {\n throw new Error(\n `No API key found for provider \"${providerName}\". ` +\n `Set ${envKey} environment variable or pass apiKey option.`\n );\n }\n const provider = createOpenRouter({ apiKey: key });\n factory = (modelId) => provider(modelId);\n break;\n }\n case 'anthropic': {\n // createAnthropic reads ANTHROPIC_API_KEY from env by default\n const provider = createAnthropic(key ? { apiKey: key } : undefined);\n factory = (modelId) => provider(modelId);\n break;\n }\n case 'openai': {\n // createOpenAI reads OPENAI_API_KEY from env by default\n const provider = createOpenAI(key ? { apiKey: key } : undefined);\n factory = (modelId) => provider(modelId);\n break;\n }\n default:\n throw new Error(\n `Unknown provider \"${providerName}\". ` +\n `Supported providers: ${Object.keys(ENV_KEYS).join(', ')}`\n );\n }\n\n _providers.set(cacheKey, factory);\n return factory;\n}\n\n/**\n * Get the OpenRouter provider (backward-compatible).\n * @deprecated Use getModel() with config.model.provider instead.\n */\nexport function getProvider(apiKey?: string): ReturnType<typeof createOpenRouter> {\n const key = apiKey ?? process.env.OPENROUTER_API_KEY;\n if (!key) {\n throw new Error(\n 'No OpenRouter API key found. Set OPENROUTER_API_KEY environment variable or pass apiKey option.'\n );\n }\n return createOpenRouter({ apiKey: key });\n}\n\nexport function resetProvider(): void {\n _providers.clear();\n}\n\n/**\n * Get a LanguageModel from config. Supports openrouter, anthropic, and openai providers.\n *\n * Provider is selected from config.model.provider (defaults to 'openrouter').\n * Model ID format depends on provider:\n * - openrouter: \"anthropic/claude-sonnet-4\" (vendor/model)\n * - anthropic: \"claude-sonnet-4-20250514\" (native model ID)\n * - openai: \"gpt-4o\" (native model ID)\n */\nexport function getModel(config: HarnessConfig, apiKey?: string): LanguageModel {\n const providerName = (config.model.provider ?? 'openrouter') as ProviderName;\n const factory = getOrCreateFactory(providerName, apiKey);\n return factory(config.model.id);\n}\n\n/**\n * Get the summary model for cheap auto-generation tasks (L0/L1 summaries, tags, frontmatter).\n * Falls back to the primary model if summary_model is not configured.\n *\n * Usage: set `model.summary_model` in config.yaml, e.g.:\n * summary_model: \"google/gemini-flash-1.5\"\n */\nexport function getSummaryModel(config: HarnessConfig, apiKey?: string): LanguageModel {\n const modelId = config.model.summary_model ?? config.model.id;\n const providerName = (config.model.provider ?? 'openrouter') as ProviderName;\n const factory = getOrCreateFactory(providerName, apiKey);\n return factory(modelId);\n}\n\n/**\n * Get the fast model for validation, checks, and quick decisions.\n * Falls back to summary_model, then primary model.\n *\n * Usage: set `model.fast_model` in config.yaml, e.g.:\n * fast_model: \"google/gemini-flash-1.5\"\n */\nexport function getFastModel(config: HarnessConfig, apiKey?: string): LanguageModel {\n const modelId = config.model.fast_model ?? config.model.summary_model ?? config.model.id;\n const providerName = (config.model.provider ?? 'openrouter') as ProviderName;\n const factory = getOrCreateFactory(providerName, apiKey);\n return factory(modelId);\n}\n\nexport interface CallOptions {\n maxRetries?: number;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n}\n\nexport interface GenerateOptions extends CallOptions {\n model: LanguageModel;\n system: string;\n prompt: string;\n maxOutputTokens?: number;\n /** AI SDK tools to make available for the LLM */\n tools?: AIToolSet;\n /** Max tool-use roundtrips (default: 1 if tools provided, 0 otherwise) */\n maxToolSteps?: number;\n}\n\nexport interface GenerateWithMessagesOptions extends CallOptions {\n model: LanguageModel;\n system: string;\n messages: ModelMessage[];\n maxOutputTokens?: number;\n /** AI SDK tools to make available for the LLM */\n tools?: AIToolSet;\n /** Max tool-use roundtrips (default: 1 if tools provided, 0 otherwise) */\n maxToolSteps?: number;\n}\n\nexport interface GenerateResult {\n text: string;\n usage: { inputTokens: number; outputTokens: number; totalTokens: number };\n /** Tool calls made during generation (empty if no tools used) */\n toolCalls: ToolCallInfo[];\n /** Number of steps taken (1 = no tool calls, >1 = tool roundtrips) */\n steps: number;\n}\n\nfunction extractUsage(usage: { inputTokens?: number; outputTokens?: number } | undefined) {\n return {\n inputTokens: usage?.inputTokens ?? 0,\n outputTokens: usage?.outputTokens ?? 0,\n totalTokens: (usage?.inputTokens ?? 0) + (usage?.outputTokens ?? 0),\n };\n}\n\nfunction buildCallSettings(opts: CallOptions & { tools?: AIToolSet; maxToolSteps?: number }) {\n const hasTools = opts.tools && Object.keys(opts.tools).length > 0;\n return {\n ...(opts.maxRetries !== undefined ? { maxRetries: opts.maxRetries } : {}),\n ...(opts.timeoutMs !== undefined ? { timeout: opts.timeoutMs } : {}),\n ...(opts.abortSignal ? { abortSignal: opts.abortSignal } : {}),\n ...(hasTools ? { tools: opts.tools } : {}),\n ...(hasTools ? { stopWhen: stepCountIs(opts.maxToolSteps ?? 5) } : {}),\n };\n}\n\n/** Extract tool call info from AI SDK step results */\nfunction extractToolCalls(result: { steps?: Array<{ toolCalls?: Array<{ toolName: string; input: unknown }>; toolResults?: Array<{ toolName: string; output: unknown }> }> }): ToolCallInfo[] {\n const calls: ToolCallInfo[] = [];\n if (!result.steps) return calls;\n\n for (const step of result.steps) {\n if (!step.toolCalls) continue;\n for (let i = 0; i < step.toolCalls.length; i++) {\n const tc = step.toolCalls[i];\n const tr = step.toolResults?.[i];\n calls.push({\n toolName: tc.toolName,\n args: (tc.input ?? {}) as Record<string, unknown>,\n result: tr?.output ?? null,\n });\n }\n }\n return calls;\n}\n\nexport async function generate(opts: GenerateOptions): Promise<GenerateResult> {\n const result = await generateText({\n model: opts.model,\n system: opts.system,\n prompt: opts.prompt,\n maxOutputTokens: opts.maxOutputTokens,\n ...buildCallSettings(opts),\n });\n\n // Use totalUsage when available (multi-step) otherwise fall back to usage\n const usage = result.totalUsage ?? result.usage;\n\n return {\n text: result.text,\n usage: extractUsage(usage),\n toolCalls: extractToolCalls(result),\n steps: result.steps?.length ?? 1,\n };\n}\n\nexport async function generateWithMessages(opts: GenerateWithMessagesOptions): Promise<GenerateResult> {\n const result = await generateText({\n model: opts.model,\n system: opts.system,\n messages: opts.messages,\n maxOutputTokens: opts.maxOutputTokens,\n ...buildCallSettings(opts),\n });\n\n const usage = result.totalUsage ?? result.usage;\n\n return {\n text: result.text,\n usage: extractUsage(usage),\n toolCalls: extractToolCalls(result),\n steps: result.steps?.length ?? 1,\n };\n}\n\n/**\n * @deprecated Use `streamGenerateWithDetails()` instead — returns metadata (usage, toolCalls, steps).\n */\nexport async function* streamGenerate(opts: GenerateOptions): AsyncIterable<string> {\n const result = streamText({\n model: opts.model,\n system: opts.system,\n prompt: opts.prompt,\n maxOutputTokens: opts.maxOutputTokens,\n ...buildCallSettings(opts),\n });\n\n for await (const chunk of result.textStream) {\n yield chunk;\n }\n}\n\nexport interface StreamWithMessagesResult {\n textStream: AsyncIterable<string>;\n usage: Promise<GenerateResult['usage']>;\n /** Tool calls made across all steps (resolves after stream completes) */\n toolCalls: Promise<ToolCallInfo[]>;\n /** Number of steps (resolves after stream completes) */\n steps: Promise<number>;\n}\n\nexport function streamWithMessages(opts: GenerateWithMessagesOptions): StreamWithMessagesResult {\n const result = streamText({\n model: opts.model,\n system: opts.system,\n messages: opts.messages,\n maxOutputTokens: opts.maxOutputTokens,\n ...buildCallSettings(opts),\n });\n\n const totalUsage = Promise.resolve(result.totalUsage ?? result.usage).then((u) => extractUsage(u));\n const toolCalls = Promise.resolve(result.steps).then((s) => extractToolCalls({ steps: s }));\n const steps = Promise.resolve(result.steps).then((s) => s?.length ?? 1);\n\n return {\n textStream: result.textStream,\n usage: totalUsage,\n toolCalls,\n steps,\n };\n}\n\nexport interface StreamGenerateResult {\n textStream: AsyncIterable<string>;\n usage: Promise<GenerateResult['usage']>;\n toolCalls: Promise<ToolCallInfo[]>;\n steps: Promise<number>;\n}\n\nexport function streamGenerateWithDetails(opts: GenerateOptions): StreamGenerateResult {\n const result = streamText({\n model: opts.model,\n system: opts.system,\n prompt: opts.prompt,\n maxOutputTokens: opts.maxOutputTokens,\n ...buildCallSettings(opts),\n });\n\n const totalUsage = Promise.resolve(result.totalUsage ?? result.usage).then((u) => extractUsage(u));\n const toolCalls = Promise.resolve(result.steps).then((s) => extractToolCalls({ steps: s }));\n const steps = Promise.resolve(result.steps).then((s) => s?.length ?? 1);\n\n return {\n textStream: result.textStream,\n usage: totalUsage,\n toolCalls,\n steps,\n };\n}\n"],"mappings":";AAAA,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,cAAc,YAAY,mBAAuC;AAW1E,IAAM,WAAyC;AAAA,EAC7C,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,QAAQ;AACV;AAGA,IAAM,aAA2C,oBAAI,IAAI;AAEzD,SAAS,mBAAmB,cAA4B,QAAkC;AACxF,QAAM,WAAW,GAAG,YAAY,IAAI,UAAU,KAAK;AACnD,QAAM,SAAS,WAAW,IAAI,QAAQ;AACtC,MAAI,OAAQ,QAAO;AAEnB,QAAM,SAAS,SAAS,YAAY;AACpC,QAAM,MAAM,UAAU,QAAQ,IAAI,MAAM;AAExC,MAAI;AAEJ,UAAQ,cAAc;AAAA,IACpB,KAAK,cAAc;AACjB,UAAI,CAAC,KAAK;AACR,cAAM,IAAI;AAAA,UACR,kCAAkC,YAAY,UACvC,MAAM;AAAA,QACf;AAAA,MACF;AACA,YAAM,WAAW,iBAAiB,EAAE,QAAQ,IAAI,CAAC;AACjD,gBAAU,CAAC,YAAY,SAAS,OAAO;AACvC;AAAA,IACF;AAAA,IACA,KAAK,aAAa;AAEhB,YAAM,WAAW,gBAAgB,MAAM,EAAE,QAAQ,IAAI,IAAI,MAAS;AAClE,gBAAU,CAAC,YAAY,SAAS,OAAO;AACvC;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AAEb,YAAM,WAAW,aAAa,MAAM,EAAE,QAAQ,IAAI,IAAI,MAAS;AAC/D,gBAAU,CAAC,YAAY,SAAS,OAAO;AACvC;AAAA,IACF;AAAA,IACA;AACE,YAAM,IAAI;AAAA,QACR,qBAAqB,YAAY,2BACT,OAAO,KAAK,QAAQ,EAAE,KAAK,IAAI,CAAC;AAAA,MAC1D;AAAA,EACJ;AAEA,aAAW,IAAI,UAAU,OAAO;AAChC,SAAO;AACT;AAMO,SAAS,YAAY,QAAsD;AAChF,QAAM,MAAM,UAAU,QAAQ,IAAI;AAClC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO,iBAAiB,EAAE,QAAQ,IAAI,CAAC;AACzC;AAEO,SAAS,gBAAsB;AACpC,aAAW,MAAM;AACnB;AAWO,SAAS,SAAS,QAAuB,QAAgC;AAC9E,QAAM,eAAgB,OAAO,MAAM,YAAY;AAC/C,QAAM,UAAU,mBAAmB,cAAc,MAAM;AACvD,SAAO,QAAQ,OAAO,MAAM,EAAE;AAChC;AASO,SAAS,gBAAgB,QAAuB,QAAgC;AACrF,QAAM,UAAU,OAAO,MAAM,iBAAiB,OAAO,MAAM;AAC3D,QAAM,eAAgB,OAAO,MAAM,YAAY;AAC/C,QAAM,UAAU,mBAAmB,cAAc,MAAM;AACvD,SAAO,QAAQ,OAAO;AACxB;AASO,SAAS,aAAa,QAAuB,QAAgC;AAClF,QAAM,UAAU,OAAO,MAAM,cAAc,OAAO,MAAM,iBAAiB,OAAO,MAAM;AACtF,QAAM,eAAgB,OAAO,MAAM,YAAY;AAC/C,QAAM,UAAU,mBAAmB,cAAc,MAAM;AACvD,SAAO,QAAQ,OAAO;AACxB;AAuCA,SAAS,aAAa,OAAoE;AACxF,SAAO;AAAA,IACL,aAAa,OAAO,eAAe;AAAA,IACnC,cAAc,OAAO,gBAAgB;AAAA,IACrC,cAAc,OAAO,eAAe,MAAM,OAAO,gBAAgB;AAAA,EACnE;AACF;AAEA,SAAS,kBAAkB,MAAkE;AAC3F,QAAM,WAAW,KAAK,SAAS,OAAO,KAAK,KAAK,KAAK,EAAE,SAAS;AAChE,SAAO;AAAA,IACL,GAAI,KAAK,eAAe,SAAY,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;AAAA,IACvE,GAAI,KAAK,cAAc,SAAY,EAAE,SAAS,KAAK,UAAU,IAAI,CAAC;AAAA,IAClE,GAAI,KAAK,cAAc,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;AAAA,IAC5D,GAAI,WAAW,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,IACxC,GAAI,WAAW,EAAE,UAAU,YAAY,KAAK,gBAAgB,CAAC,EAAE,IAAI,CAAC;AAAA,EACtE;AACF;AAGA,SAAS,iBAAiB,QAAoK;AAC5L,QAAM,QAAwB,CAAC;AAC/B,MAAI,CAAC,OAAO,MAAO,QAAO;AAE1B,aAAW,QAAQ,OAAO,OAAO;AAC/B,QAAI,CAAC,KAAK,UAAW;AACrB,aAAS,IAAI,GAAG,IAAI,KAAK,UAAU,QAAQ,KAAK;AAC9C,YAAM,KAAK,KAAK,UAAU,CAAC;AAC3B,YAAM,KAAK,KAAK,cAAc,CAAC;AAC/B,YAAM,KAAK;AAAA,QACT,UAAU,GAAG;AAAA,QACb,MAAO,GAAG,SAAS,CAAC;AAAA,QACpB,QAAQ,IAAI,UAAU;AAAA,MACxB,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,SAAS,MAAgD;AAC7E,QAAM,SAAS,MAAM,aAAa;AAAA,IAChC,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,QAAQ,KAAK;AAAA,IACb,iBAAiB,KAAK;AAAA,IACtB,GAAG,kBAAkB,IAAI;AAAA,EAC3B,CAAC;AAGD,QAAM,QAAQ,OAAO,cAAc,OAAO;AAE1C,SAAO;AAAA,IACL,MAAM,OAAO;AAAA,IACb,OAAO,aAAa,KAAK;AAAA,IACzB,WAAW,iBAAiB,MAAM;AAAA,IAClC,OAAO,OAAO,OAAO,UAAU;AAAA,EACjC;AACF;AAEA,eAAsB,qBAAqB,MAA4D;AACrG,QAAM,SAAS,MAAM,aAAa;AAAA,IAChC,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,UAAU,KAAK;AAAA,IACf,iBAAiB,KAAK;AAAA,IACtB,GAAG,kBAAkB,IAAI;AAAA,EAC3B,CAAC;AAED,QAAM,QAAQ,OAAO,cAAc,OAAO;AAE1C,SAAO;AAAA,IACL,MAAM,OAAO;AAAA,IACb,OAAO,aAAa,KAAK;AAAA,IACzB,WAAW,iBAAiB,MAAM;AAAA,IAClC,OAAO,OAAO,OAAO,UAAU;AAAA,EACjC;AACF;AAKA,gBAAuB,eAAe,MAA8C;AAClF,QAAM,SAAS,WAAW;AAAA,IACxB,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,QAAQ,KAAK;AAAA,IACb,iBAAiB,KAAK;AAAA,IACtB,GAAG,kBAAkB,IAAI;AAAA,EAC3B,CAAC;AAED,mBAAiB,SAAS,OAAO,YAAY;AAC3C,UAAM;AAAA,EACR;AACF;AAWO,SAAS,mBAAmB,MAA6D;AAC9F,QAAM,SAAS,WAAW;AAAA,IACxB,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,UAAU,KAAK;AAAA,IACf,iBAAiB,KAAK;AAAA,IACtB,GAAG,kBAAkB,IAAI;AAAA,EAC3B,CAAC;AAED,QAAM,aAAa,QAAQ,QAAQ,OAAO,cAAc,OAAO,KAAK,EAAE,KAAK,CAAC,MAAM,aAAa,CAAC,CAAC;AACjG,QAAM,YAAY,QAAQ,QAAQ,OAAO,KAAK,EAAE,KAAK,CAAC,MAAM,iBAAiB,EAAE,OAAO,EAAE,CAAC,CAAC;AAC1F,QAAM,QAAQ,QAAQ,QAAQ,OAAO,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC;AAEtE,SAAO;AAAA,IACL,YAAY,OAAO;AAAA,IACnB,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EACF;AACF;AASO,SAAS,0BAA0B,MAA6C;AACrF,QAAM,SAAS,WAAW;AAAA,IACxB,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,QAAQ,KAAK;AAAA,IACb,iBAAiB,KAAK;AAAA,IACtB,GAAG,kBAAkB,IAAI;AAAA,EAC3B,CAAC;AAED,QAAM,aAAa,QAAQ,QAAQ,OAAO,cAAc,OAAO,KAAK,EAAE,KAAK,CAAC,MAAM,aAAa,CAAC,CAAC;AACjG,QAAM,YAAY,QAAQ,QAAQ,OAAO,KAAK,EAAE,KAAK,CAAC,MAAM,iBAAiB,EAAE,OAAO,EAAE,CAAC,CAAC;AAC1F,QAAM,QAAQ,QAAQ,QAAQ,OAAO,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC;AAEtE,SAAO;AAAA,IACL,YAAY,OAAO;AAAA,IACnB,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EACF;AACF;","names":[]}