fourmis-agents-sdk 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 (105) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +309 -0
  3. package/dist/agent-loop.d.ts +36 -0
  4. package/dist/agent-loop.d.ts.map +1 -0
  5. package/dist/agent-loop.js +387 -0
  6. package/dist/agents/index.d.ts +8 -0
  7. package/dist/agents/index.d.ts.map +1 -0
  8. package/dist/agents/index.js +2309 -0
  9. package/dist/agents/task-manager.d.ts +14 -0
  10. package/dist/agents/task-manager.d.ts.map +1 -0
  11. package/dist/agents/task-manager.js +67 -0
  12. package/dist/agents/tools.d.ts +24 -0
  13. package/dist/agents/tools.d.ts.map +1 -0
  14. package/dist/agents/tools.js +2257 -0
  15. package/dist/agents/types.d.ts +22 -0
  16. package/dist/agents/types.d.ts.map +1 -0
  17. package/dist/agents/types.js +1 -0
  18. package/dist/api.d.ts +35 -0
  19. package/dist/api.d.ts.map +1 -0
  20. package/dist/api.js +2983 -0
  21. package/dist/auth/login-openai.d.ts +10 -0
  22. package/dist/auth/login-openai.d.ts.map +1 -0
  23. package/dist/auth/login-openai.js +316 -0
  24. package/dist/auth/openai-oauth.d.ts +45 -0
  25. package/dist/auth/openai-oauth.d.ts.map +1 -0
  26. package/dist/auth/openai-oauth.js +308 -0
  27. package/dist/hooks.d.ts +71 -0
  28. package/dist/hooks.d.ts.map +1 -0
  29. package/dist/hooks.js +87 -0
  30. package/dist/index.d.ts +27 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +3025 -0
  33. package/dist/mcp/client.d.ts +24 -0
  34. package/dist/mcp/client.d.ts.map +1 -0
  35. package/dist/mcp/client.js +176 -0
  36. package/dist/mcp/index.d.ts +8 -0
  37. package/dist/mcp/index.d.ts.map +1 -0
  38. package/dist/mcp/index.js +203 -0
  39. package/dist/mcp/server.d.ts +25 -0
  40. package/dist/mcp/server.d.ts.map +1 -0
  41. package/dist/mcp/server.js +42 -0
  42. package/dist/mcp/types.d.ts +47 -0
  43. package/dist/mcp/types.d.ts.map +1 -0
  44. package/dist/mcp/types.js +1 -0
  45. package/dist/permissions.d.ts +29 -0
  46. package/dist/permissions.d.ts.map +1 -0
  47. package/dist/permissions.js +157 -0
  48. package/dist/providers/anthropic.d.ts +26 -0
  49. package/dist/providers/anthropic.d.ts.map +1 -0
  50. package/dist/providers/anthropic.js +382 -0
  51. package/dist/providers/openai.d.ts +42 -0
  52. package/dist/providers/openai.d.ts.map +1 -0
  53. package/dist/providers/openai.js +871 -0
  54. package/dist/providers/registry.d.ts +11 -0
  55. package/dist/providers/registry.d.ts.map +1 -0
  56. package/dist/providers/registry.js +1118 -0
  57. package/dist/providers/types.d.ts +79 -0
  58. package/dist/providers/types.d.ts.map +1 -0
  59. package/dist/providers/types.js +1 -0
  60. package/dist/query.d.ts +9 -0
  61. package/dist/query.d.ts.map +1 -0
  62. package/dist/query.js +36 -0
  63. package/dist/settings.d.ts +28 -0
  64. package/dist/settings.d.ts.map +1 -0
  65. package/dist/settings.js +143 -0
  66. package/dist/tools/bash.d.ts +6 -0
  67. package/dist/tools/bash.d.ts.map +1 -0
  68. package/dist/tools/bash.js +88 -0
  69. package/dist/tools/edit.d.ts +6 -0
  70. package/dist/tools/edit.d.ts.map +1 -0
  71. package/dist/tools/edit.js +108 -0
  72. package/dist/tools/glob.d.ts +6 -0
  73. package/dist/tools/glob.d.ts.map +1 -0
  74. package/dist/tools/glob.js +70 -0
  75. package/dist/tools/grep.d.ts +7 -0
  76. package/dist/tools/grep.d.ts.map +1 -0
  77. package/dist/tools/grep.js +183 -0
  78. package/dist/tools/index.d.ts +18 -0
  79. package/dist/tools/index.d.ts.map +1 -0
  80. package/dist/tools/index.js +595 -0
  81. package/dist/tools/mcp-resources.d.ts +8 -0
  82. package/dist/tools/mcp-resources.d.ts.map +1 -0
  83. package/dist/tools/mcp-resources.js +87 -0
  84. package/dist/tools/presets.d.ts +6 -0
  85. package/dist/tools/presets.d.ts.map +1 -0
  86. package/dist/tools/presets.js +32 -0
  87. package/dist/tools/read.d.ts +6 -0
  88. package/dist/tools/read.d.ts.map +1 -0
  89. package/dist/tools/read.js +81 -0
  90. package/dist/tools/registry.d.ts +31 -0
  91. package/dist/tools/registry.d.ts.map +1 -0
  92. package/dist/tools/registry.js +52 -0
  93. package/dist/tools/write.d.ts +6 -0
  94. package/dist/tools/write.d.ts.map +1 -0
  95. package/dist/tools/write.js +62 -0
  96. package/dist/types.d.ts +201 -0
  97. package/dist/types.d.ts.map +1 -0
  98. package/dist/types.js +39 -0
  99. package/dist/utils/cost.d.ts +35 -0
  100. package/dist/utils/cost.d.ts.map +1 -0
  101. package/dist/utils/cost.js +176 -0
  102. package/dist/utils/system-prompt.d.ts +11 -0
  103. package/dist/utils/system-prompt.d.ts.map +1 -0
  104. package/dist/utils/system-prompt.js +89 -0
  105. package/package.json +66 -0
@@ -0,0 +1,387 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
+ var __require = import.meta.require;
14
+
15
+ // src/tools/mcp-resources.ts
16
+ var exports_mcp_resources = {};
17
+ __export(exports_mcp_resources, {
18
+ createReadMcpResourceTool: () => createReadMcpResourceTool,
19
+ createListMcpResourcesTool: () => createListMcpResourcesTool
20
+ });
21
+ function createListMcpResourcesTool(mcpClient) {
22
+ return {
23
+ name: "mcp__list_resources",
24
+ description: "List available resources from MCP servers.",
25
+ inputSchema: {
26
+ type: "object",
27
+ properties: {
28
+ server: {
29
+ type: "string",
30
+ description: "Optional server name to filter by. If omitted, lists resources from all servers."
31
+ }
32
+ }
33
+ },
34
+ async execute(input) {
35
+ const { server } = input ?? {};
36
+ try {
37
+ const resources = await mcpClient.listResources(server);
38
+ if (resources.length === 0) {
39
+ return { content: "No resources available." };
40
+ }
41
+ const lines = resources.map((r) => `[${r.server}] ${r.uri} - ${r.name}${r.description ? `: ${r.description}` : ""}`);
42
+ return { content: lines.join(`
43
+ `) };
44
+ } catch (err) {
45
+ const message = err instanceof Error ? err.message : String(err);
46
+ return { content: `Error listing resources: ${message}`, isError: true };
47
+ }
48
+ }
49
+ };
50
+ }
51
+ function createReadMcpResourceTool(mcpClient) {
52
+ return {
53
+ name: "mcp__read_resource",
54
+ description: "Read a specific resource from an MCP server by URI.",
55
+ inputSchema: {
56
+ type: "object",
57
+ properties: {
58
+ server: {
59
+ type: "string",
60
+ description: "The MCP server name that hosts the resource."
61
+ },
62
+ uri: {
63
+ type: "string",
64
+ description: "The resource URI to read."
65
+ }
66
+ },
67
+ required: ["server", "uri"]
68
+ },
69
+ async execute(input) {
70
+ const { server, uri } = input;
71
+ if (!server || !uri) {
72
+ return { content: "Both 'server' and 'uri' are required.", isError: true };
73
+ }
74
+ try {
75
+ const content = await mcpClient.readResource(server, uri);
76
+ return { content };
77
+ } catch (err) {
78
+ const message = err instanceof Error ? err.message : String(err);
79
+ return { content: `Error reading resource: ${message}`, isError: true };
80
+ }
81
+ }
82
+ };
83
+ }
84
+
85
+ // src/types.ts
86
+ function uuid() {
87
+ return crypto.randomUUID();
88
+ }
89
+ function emptyTokenUsage() {
90
+ return {
91
+ inputTokens: 0,
92
+ outputTokens: 0,
93
+ cacheReadInputTokens: 0,
94
+ cacheCreationInputTokens: 0
95
+ };
96
+ }
97
+ function mergeUsage(a, b) {
98
+ return {
99
+ inputTokens: a.inputTokens + b.inputTokens,
100
+ outputTokens: a.outputTokens + b.outputTokens,
101
+ cacheReadInputTokens: a.cacheReadInputTokens + b.cacheReadInputTokens,
102
+ cacheCreationInputTokens: a.cacheCreationInputTokens + b.cacheCreationInputTokens
103
+ };
104
+ }
105
+
106
+ // src/agent-loop.ts
107
+ async function* agentLoop(prompt, options) {
108
+ const {
109
+ provider,
110
+ model,
111
+ systemPrompt,
112
+ tools,
113
+ permissions,
114
+ cwd,
115
+ sessionId,
116
+ maxTurns,
117
+ maxBudgetUsd,
118
+ includeStreamEvents,
119
+ signal,
120
+ env,
121
+ debug,
122
+ hooks,
123
+ mcpClient
124
+ } = options;
125
+ const startTime = Date.now();
126
+ let apiTimeMs = 0;
127
+ let turns = 0;
128
+ let totalUsage = emptyTokenUsage();
129
+ let costUsd = 0;
130
+ const modelUsage = {};
131
+ if (mcpClient) {
132
+ await mcpClient.connectAll();
133
+ for (const tool of mcpClient.getTools()) {
134
+ tools.register(tool);
135
+ }
136
+ const { createListMcpResourcesTool: createListMcpResourcesTool2, createReadMcpResourceTool: createReadMcpResourceTool2 } = await Promise.resolve().then(() => exports_mcp_resources);
137
+ tools.register(createListMcpResourcesTool2(mcpClient));
138
+ tools.register(createReadMcpResourceTool2(mcpClient));
139
+ }
140
+ const messages = [
141
+ { role: "user", content: prompt }
142
+ ];
143
+ yield {
144
+ type: "init",
145
+ sessionId,
146
+ model,
147
+ provider: provider.name,
148
+ tools: tools.list(),
149
+ cwd,
150
+ uuid: uuid()
151
+ };
152
+ if (hooks) {
153
+ await hooks.fire("SessionStart", { event: "SessionStart", session_id: sessionId }, undefined, { signal });
154
+ }
155
+ while (true) {
156
+ if (signal.aborted) {
157
+ yield makeError("error_execution", ["Aborted"], turns, costUsd, sessionId, startTime);
158
+ return;
159
+ }
160
+ if (turns >= maxTurns) {
161
+ yield makeError("error_max_turns", [`Reached maximum turns (${maxTurns})`], turns, costUsd, sessionId, startTime);
162
+ return;
163
+ }
164
+ if (maxBudgetUsd > 0 && costUsd >= maxBudgetUsd) {
165
+ yield makeError("error_max_budget", [`Reached budget limit ($${maxBudgetUsd})`], turns, costUsd, sessionId, startTime);
166
+ return;
167
+ }
168
+ const toolDefs = tools.getDefinitions();
169
+ const apiStart = Date.now();
170
+ let assistantTextParts = [];
171
+ let toolCalls = [];
172
+ let turnUsage = emptyTokenUsage();
173
+ try {
174
+ const chunks = provider.chat({
175
+ model,
176
+ messages,
177
+ tools: toolDefs.length > 0 ? toolDefs : undefined,
178
+ systemPrompt,
179
+ signal
180
+ });
181
+ for await (const chunk of chunks) {
182
+ switch (chunk.type) {
183
+ case "text_delta":
184
+ assistantTextParts.push(chunk.text);
185
+ if (includeStreamEvents) {
186
+ yield { type: "stream", subtype: "text_delta", text: chunk.text, uuid: uuid() };
187
+ }
188
+ break;
189
+ case "thinking_delta":
190
+ if (includeStreamEvents) {
191
+ yield { type: "stream", subtype: "thinking_delta", text: chunk.text, uuid: uuid() };
192
+ }
193
+ break;
194
+ case "tool_call":
195
+ toolCalls.push({ id: chunk.id, name: chunk.name, input: chunk.input });
196
+ break;
197
+ case "usage":
198
+ turnUsage = mergeUsage(turnUsage, chunk.usage);
199
+ break;
200
+ case "done":
201
+ break;
202
+ }
203
+ }
204
+ } catch (err) {
205
+ const message = err instanceof Error ? err.message : String(err);
206
+ yield makeError("error_execution", [`API error: ${message}`], turns, costUsd, sessionId, startTime);
207
+ return;
208
+ }
209
+ apiTimeMs += Date.now() - apiStart;
210
+ turns++;
211
+ totalUsage = mergeUsage(totalUsage, turnUsage);
212
+ const turnCost = provider.calculateCost(model, turnUsage);
213
+ costUsd += turnCost;
214
+ if (!modelUsage[model]) {
215
+ modelUsage[model] = {
216
+ inputTokens: 0,
217
+ outputTokens: 0,
218
+ cacheReadInputTokens: 0,
219
+ cacheCreationInputTokens: 0,
220
+ totalCostUsd: 0
221
+ };
222
+ }
223
+ modelUsage[model].inputTokens += turnUsage.inputTokens;
224
+ modelUsage[model].outputTokens += turnUsage.outputTokens;
225
+ modelUsage[model].cacheReadInputTokens += turnUsage.cacheReadInputTokens;
226
+ modelUsage[model].cacheCreationInputTokens += turnUsage.cacheCreationInputTokens;
227
+ modelUsage[model].totalCostUsd += turnCost;
228
+ const assistantText = assistantTextParts.join("");
229
+ const assistantContent = [];
230
+ if (assistantText) {
231
+ assistantContent.push({ type: "text", text: assistantText });
232
+ }
233
+ for (const call of toolCalls) {
234
+ assistantContent.push({
235
+ type: "tool_use",
236
+ id: call.id,
237
+ name: call.name,
238
+ input: call.input
239
+ });
240
+ }
241
+ messages.push({ role: "assistant", content: assistantContent });
242
+ if (assistantText) {
243
+ yield { type: "text", text: assistantText, uuid: uuid() };
244
+ }
245
+ if (toolCalls.length === 0) {
246
+ if (hooks) {
247
+ await hooks.fire("Stop", { event: "Stop", session_id: sessionId, text: assistantText || undefined }, undefined, { signal });
248
+ }
249
+ if (hooks) {
250
+ await hooks.fire("SessionEnd", { event: "SessionEnd", session_id: sessionId }, undefined, { signal });
251
+ }
252
+ yield {
253
+ type: "result",
254
+ subtype: "success",
255
+ text: assistantText || null,
256
+ turns,
257
+ costUsd,
258
+ durationMs: Date.now() - startTime,
259
+ durationApiMs: apiTimeMs,
260
+ sessionId,
261
+ usage: totalUsage,
262
+ modelUsage,
263
+ uuid: uuid()
264
+ };
265
+ return;
266
+ }
267
+ const toolResults = [];
268
+ for (const call of toolCalls) {
269
+ let hookDenied = false;
270
+ let hookUpdatedInput;
271
+ if (hooks) {
272
+ const hookResult = await hooks.fire("PreToolUse", { event: "PreToolUse", tool_name: call.name, tool_input: call.input, session_id: sessionId }, call.id, { signal });
273
+ if (hookResult) {
274
+ if (hookResult.permissionDecision === "deny") {
275
+ hookDenied = true;
276
+ }
277
+ if (hookResult.updatedInput !== undefined) {
278
+ hookUpdatedInput = hookResult.updatedInput;
279
+ }
280
+ }
281
+ }
282
+ if (hookDenied) {
283
+ const denyContent = "Denied by hook";
284
+ yield {
285
+ type: "tool_result",
286
+ id: call.id,
287
+ name: call.name,
288
+ content: denyContent,
289
+ isError: true,
290
+ uuid: uuid()
291
+ };
292
+ toolResults.push({
293
+ type: "tool_result",
294
+ tool_use_id: call.id,
295
+ content: denyContent,
296
+ is_error: true
297
+ });
298
+ if (hooks) {
299
+ await hooks.fire("PostToolUseFailure", { event: "PostToolUseFailure", tool_name: call.name, tool_result: denyContent, tool_error: true, session_id: sessionId }, call.id, { signal });
300
+ }
301
+ continue;
302
+ }
303
+ const inputAfterHook = hookUpdatedInput !== undefined ? hookUpdatedInput : call.input;
304
+ const permResult = await permissions.check(call.name, inputAfterHook ?? {}, { signal, toolUseId: call.id });
305
+ if (permResult.behavior === "deny") {
306
+ const denyContent = `Permission denied: ${permResult.message}`;
307
+ yield {
308
+ type: "tool_result",
309
+ id: call.id,
310
+ name: call.name,
311
+ content: denyContent,
312
+ isError: true,
313
+ uuid: uuid()
314
+ };
315
+ toolResults.push({
316
+ type: "tool_result",
317
+ tool_use_id: call.id,
318
+ content: denyContent,
319
+ is_error: true
320
+ });
321
+ if (hooks) {
322
+ await hooks.fire("PostToolUseFailure", { event: "PostToolUseFailure", tool_name: call.name, tool_result: denyContent, tool_error: true, session_id: sessionId }, call.id, { signal });
323
+ }
324
+ continue;
325
+ }
326
+ const toolInput = permResult.behavior === "allow" && permResult.updatedInput ? permResult.updatedInput : inputAfterHook;
327
+ yield {
328
+ type: "tool_use",
329
+ id: call.id,
330
+ name: call.name,
331
+ input: toolInput,
332
+ uuid: uuid()
333
+ };
334
+ const toolCtx = {
335
+ cwd,
336
+ signal,
337
+ sessionId,
338
+ env
339
+ };
340
+ const result = await tools.execute(call.name, toolInput, toolCtx);
341
+ if (debug) {
342
+ console.error(`[debug] Tool ${call.name}: ${result.isError ? "ERROR" : "OK"} (${result.content.length} chars)`);
343
+ }
344
+ if (hooks) {
345
+ if (result.isError) {
346
+ await hooks.fire("PostToolUseFailure", { event: "PostToolUseFailure", tool_name: call.name, tool_result: result.content, tool_error: true, session_id: sessionId }, call.id, { signal });
347
+ } else {
348
+ const postResult = await hooks.fire("PostToolUse", { event: "PostToolUse", tool_name: call.name, tool_result: result.content, session_id: sessionId }, call.id, { signal });
349
+ if (postResult?.additionalContext) {
350
+ result.content += `
351
+ ${postResult.additionalContext}`;
352
+ }
353
+ }
354
+ }
355
+ yield {
356
+ type: "tool_result",
357
+ id: call.id,
358
+ name: call.name,
359
+ content: result.content,
360
+ isError: result.isError,
361
+ uuid: uuid()
362
+ };
363
+ toolResults.push({
364
+ type: "tool_result",
365
+ tool_use_id: call.id,
366
+ content: result.content,
367
+ is_error: result.isError
368
+ });
369
+ }
370
+ messages.push({ role: "user", content: toolResults });
371
+ }
372
+ }
373
+ function makeError(subtype, errors, turns, costUsd, sessionId, startTime) {
374
+ return {
375
+ type: "result",
376
+ subtype,
377
+ errors,
378
+ turns,
379
+ costUsd,
380
+ durationMs: Date.now() - startTime,
381
+ sessionId,
382
+ uuid: uuid()
383
+ };
384
+ }
385
+ export {
386
+ agentLoop
387
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Agents module — re-exports.
3
+ */
4
+ export type { AgentDefinition, BackgroundTask } from "./types.js";
5
+ export { TaskManager } from "./task-manager.js";
6
+ export { createTaskTool, createTaskOutputTool, createTaskStopTool } from "./tools.js";
7
+ export type { AgentContext } from "./tools.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACtF,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}