orbitx 0.3.0 → 0.3.2

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 (83) hide show
  1. package/dist/core/ai-ask.d.ts +28 -0
  2. package/dist/core/ai-ask.d.ts.map +1 -0
  3. package/dist/core/ai-ask.js +80 -0
  4. package/dist/core/ai-ask.js.map +1 -0
  5. package/dist/core/mcp-auto-execution-policy.d.ts +22 -0
  6. package/dist/core/mcp-auto-execution-policy.d.ts.map +1 -0
  7. package/dist/core/mcp-auto-execution-policy.js +85 -0
  8. package/dist/core/mcp-auto-execution-policy.js.map +1 -0
  9. package/dist/core/stateless-agent.d.ts +30 -0
  10. package/dist/core/stateless-agent.d.ts.map +1 -0
  11. package/dist/core/stateless-agent.js +79 -0
  12. package/dist/core/stateless-agent.js.map +1 -0
  13. package/dist/index.d.ts +6 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +3 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/tests/core/ai-ask.test.d.ts +2 -0
  18. package/dist/tests/core/ai-ask.test.d.ts.map +1 -0
  19. package/dist/tests/core/ai-ask.test.js +101 -0
  20. package/dist/tests/core/ai-ask.test.js.map +1 -0
  21. package/dist/tests/core/mcp-auto-execution-policy.test.d.ts +2 -0
  22. package/dist/tests/core/mcp-auto-execution-policy.test.d.ts.map +1 -0
  23. package/dist/tests/core/mcp-auto-execution-policy.test.js +107 -0
  24. package/dist/tests/core/mcp-auto-execution-policy.test.js.map +1 -0
  25. package/dist/tests/core/stateless-agent.test.d.ts +2 -0
  26. package/dist/tests/core/stateless-agent.test.d.ts.map +1 -0
  27. package/dist/tests/core/stateless-agent.test.js +73 -0
  28. package/dist/tests/core/stateless-agent.test.js.map +1 -0
  29. package/dist/tests/index.d.ts +3 -0
  30. package/dist/tests/index.d.ts.map +1 -1
  31. package/dist/tests/index.js +3 -0
  32. package/dist/tests/index.js.map +1 -1
  33. package/docs/agents.md +77 -1
  34. package/docs/mcp-architecture.md +42 -0
  35. package/package.json +1 -1
  36. package/dist/core/image-describer.d.ts +0 -19
  37. package/dist/core/image-describer.d.ts.map +0 -1
  38. package/dist/core/image-describer.js +0 -37
  39. package/dist/core/image-describer.js.map +0 -1
  40. package/dist/core/worker-agent.d.ts +0 -43
  41. package/dist/core/worker-agent.d.ts.map +0 -1
  42. package/dist/core/worker-agent.js +0 -40
  43. package/dist/core/worker-agent.js.map +0 -1
  44. package/dist/skills/shopping.d.ts +0 -4
  45. package/dist/skills/shopping.d.ts.map +0 -1
  46. package/dist/skills/shopping.js +0 -71
  47. package/dist/skills/shopping.js.map +0 -1
  48. package/dist/tools/agent/interaction.d.ts +0 -25
  49. package/dist/tools/agent/interaction.d.ts.map +0 -1
  50. package/dist/tools/agent/interaction.js +0 -14
  51. package/dist/tools/agent/interaction.js.map +0 -1
  52. package/dist/tools/agent/list.d.ts +0 -5
  53. package/dist/tools/agent/list.d.ts.map +0 -1
  54. package/dist/tools/agent/list.js +0 -16
  55. package/dist/tools/agent/list.js.map +0 -1
  56. package/dist/tools/agent/report.d.ts +0 -12
  57. package/dist/tools/agent/report.d.ts.map +0 -1
  58. package/dist/tools/agent/report.js +0 -31
  59. package/dist/tools/agent/report.js.map +0 -1
  60. package/dist/tools/bash/interaction.d.ts +0 -29
  61. package/dist/tools/bash/interaction.d.ts.map +0 -1
  62. package/dist/tools/bash/interaction.js +0 -13
  63. package/dist/tools/bash/interaction.js.map +0 -1
  64. package/dist/tools/browser/interaction.d.ts +0 -49
  65. package/dist/tools/browser/interaction.d.ts.map +0 -1
  66. package/dist/tools/browser/interaction.js +0 -14
  67. package/dist/tools/browser/interaction.js.map +0 -1
  68. package/dist/tools/fs/interaction.d.ts +0 -37
  69. package/dist/tools/fs/interaction.d.ts.map +0 -1
  70. package/dist/tools/fs/interaction.js +0 -13
  71. package/dist/tools/fs/interaction.js.map +0 -1
  72. package/dist/tools/present/interaction.d.ts +0 -17
  73. package/dist/tools/present/interaction.d.ts.map +0 -1
  74. package/dist/tools/present/interaction.js +0 -15
  75. package/dist/tools/present/interaction.js.map +0 -1
  76. package/dist/tools/question-answer/interaction.d.ts +0 -14
  77. package/dist/tools/question-answer/interaction.d.ts.map +0 -1
  78. package/dist/tools/question-answer/interaction.js +0 -13
  79. package/dist/tools/question-answer/interaction.js.map +0 -1
  80. package/dist/tools/todo/interaction.d.ts +0 -30
  81. package/dist/tools/todo/interaction.d.ts.map +0 -1
  82. package/dist/tools/todo/interaction.js +0 -13
  83. package/dist/tools/todo/interaction.js.map +0 -1
@@ -0,0 +1,107 @@
1
+ import { test, describe } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { MCPAutoExecutionPolicy } from "../../index.js";
4
+ import { ScriptedProvider } from "./scripted-provider.js";
5
+ const request = (overrides = {}) => ({
6
+ toolName: "bash-run",
7
+ inputs: { command: "rm -rf /" },
8
+ envID: "env",
9
+ toolCallId: "call-1",
10
+ ...overrides,
11
+ });
12
+ describe("core/mcp-auto-execution-policy", () => {
13
+ test("authorize(): an unwatched tool is authorized immediately, no model call, no verdict recorded", async () => {
14
+ const provider = new ScriptedProvider("p", () => ({ content: "should never be called" }));
15
+ const policy = new MCPAutoExecutionPolicy({ aiModel: provider });
16
+ const authorized = await policy.authorize(request({ toolName: "get-current-time", inputs: {}, toolCallId: "call-time" }));
17
+ assert.strictEqual(authorized, true);
18
+ assert.strictEqual(provider.getCallCount(), 0);
19
+ assert.strictEqual(policy.getVerdict("call-time"), undefined);
20
+ });
21
+ test("authorize(): bash-run always goes to the model — no path field to short-circuit on", async () => {
22
+ const provider = new ScriptedProvider("p", () => ({
23
+ toolCalls: [{ name: "submit_answer", inputs: { harmful: true, reason: "destroys the filesystem" } }],
24
+ }));
25
+ const policy = new MCPAutoExecutionPolicy({ aiModel: provider });
26
+ const authorized = await policy.authorize(request());
27
+ assert.strictEqual(authorized, false);
28
+ assert.strictEqual(provider.getCallCount(), 1);
29
+ });
30
+ test("authorize(): a watched fs call whose path resolves inside scope is authorized locally, no model call", async () => {
31
+ const provider = new ScriptedProvider("p", () => ({ content: "should never be called" }));
32
+ const policy = new MCPAutoExecutionPolicy({ aiModel: provider, scopeDir: process.cwd() });
33
+ const authorized = await policy.authorize(request({
34
+ toolName: "fs-write-file",
35
+ inputs: { path: "some/nested/file.txt", content: "hello" },
36
+ toolCallId: "call-write-in-scope",
37
+ }));
38
+ assert.strictEqual(authorized, true);
39
+ assert.strictEqual(provider.getCallCount(), 0);
40
+ assert.strictEqual(policy.getVerdict("call-write-in-scope").harmful, false);
41
+ assert.match(policy.getVerdict("call-write-in-scope").reason, /skipped model review/);
42
+ });
43
+ test("authorize(): a watched fs call whose path resolves outside scope escalates to the model", async () => {
44
+ const provider = new ScriptedProvider("p", () => ({
45
+ toolCalls: [{ name: "submit_answer", inputs: { harmful: true, reason: "writes outside the project" } }],
46
+ }));
47
+ const policy = new MCPAutoExecutionPolicy({ aiModel: provider, scopeDir: process.cwd() });
48
+ const authorized = await policy.authorize(request({
49
+ toolName: "fs-write-file",
50
+ inputs: { path: "../../outside.txt", content: "hello" },
51
+ }));
52
+ assert.strictEqual(authorized, false);
53
+ assert.strictEqual(provider.getCallCount(), 1);
54
+ });
55
+ test("authorize(): fs-move requires BOTH from and to inside scope to skip the model", async () => {
56
+ const provider = new ScriptedProvider("p", () => ({
57
+ toolCalls: [{ name: "submit_answer", inputs: { harmful: false, reason: "fine" } }],
58
+ }));
59
+ const policy = new MCPAutoExecutionPolicy({ aiModel: provider, scopeDir: process.cwd() });
60
+ await policy.authorize(request({
61
+ toolName: "fs-move",
62
+ inputs: { from: "in-scope.txt", to: "../outside.txt" },
63
+ }));
64
+ assert.strictEqual(provider.getCallCount(), 1, "one path outside scope forces a model review");
65
+ });
66
+ test("authorize(): file content is stripped before it ever reaches the model", async () => {
67
+ let seenPrompt = "";
68
+ const provider = new ScriptedProvider("p", ({ messages }) => {
69
+ seenPrompt = messages.at(-1)?.content ?? "";
70
+ return { toolCalls: [{ name: "submit_answer", inputs: { harmful: false, reason: "fine" } }] };
71
+ });
72
+ const policy = new MCPAutoExecutionPolicy({ aiModel: provider, scopeDir: "/some/other/scope" });
73
+ await policy.authorize(request({
74
+ toolName: "fs-write-file",
75
+ inputs: { path: "secrets.txt", content: "super-secret-password-do-not-leak-this" },
76
+ }));
77
+ assert.doesNotMatch(seenPrompt, /super-secret-password-do-not-leak-this/);
78
+ assert.match(seenPrompt, /omitted, \d+ bytes/);
79
+ });
80
+ test("getVerdict() / getLastVerdict() / onVerdict expose the reviewed verdict", async () => {
81
+ const provider = new ScriptedProvider("p", () => ({
82
+ toolCalls: [{ name: "submit_answer", inputs: { harmful: true, reason: "irreversible deletion" } }],
83
+ }));
84
+ const calls = [];
85
+ const policy = new MCPAutoExecutionPolicy({ aiModel: provider, onVerdict: (request, verdict) => calls.push({ request, verdict }) });
86
+ await policy.authorize(request({ toolCallId: "call-42" }));
87
+ assert.deepStrictEqual(policy.getVerdict("call-42"), { harmful: true, reason: "irreversible deletion" });
88
+ assert.deepStrictEqual(policy.getLastVerdict(), { harmful: true, reason: "irreversible deletion" });
89
+ assert.strictEqual(calls.length, 1);
90
+ });
91
+ test("authorize(): fails closed (denies) when the safety check itself can't produce a valid verdict", async () => {
92
+ const provider = new ScriptedProvider("p", () => ({ content: "I refuse to answer in JSON" }));
93
+ const policy = new MCPAutoExecutionPolicy({ aiModel: provider });
94
+ const authorized = await policy.authorize(request());
95
+ assert.strictEqual(authorized, false);
96
+ assert.strictEqual(policy.getVerdict("call-1").harmful, true);
97
+ });
98
+ test("watchedTools: a custom set overrides the default", async () => {
99
+ const provider = new ScriptedProvider("p", () => ({
100
+ toolCalls: [{ name: "submit_answer", inputs: { harmful: true, reason: "not allowed at all" } }],
101
+ }));
102
+ const policy = new MCPAutoExecutionPolicy({ aiModel: provider, watchedTools: ["todo-remove-list"] });
103
+ assert.strictEqual(await policy.authorize(request({ toolName: "bash-run" })), true, "bash-run isn't watched anymore");
104
+ assert.strictEqual(await policy.authorize(request({ toolName: "todo-remove-list", inputs: {} })), false);
105
+ });
106
+ });
107
+ //# sourceMappingURL=mcp-auto-execution-policy.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-auto-execution-policy.test.js","sourceRoot":"","sources":["../../../src/tests/core/mcp-auto-execution-policy.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=stateless-agent.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateless-agent.test.d.ts","sourceRoot":"","sources":["../../../src/tests/core/stateless-agent.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,73 @@
1
+ import { test, describe } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { StatelessAgent, GetCurrentTimeTool } from "../../index.js";
4
+ import { ScriptedProvider } from "./scripted-provider.js";
5
+ describe("core/stateless-agent", () => {
6
+ test("run(): a plain reply with no tool call is one chat() call", async () => {
7
+ const provider = new ScriptedProvider("p", () => ({ content: "42" }));
8
+ const agent = new StatelessAgent({ instruction: "answer with a number", aiProvider: provider });
9
+ const result = await agent.run("what is 6*7?");
10
+ assert.strictEqual(result.content, "42");
11
+ assert.deepStrictEqual(result.toolCalls, []);
12
+ assert.strictEqual(result.usage.length, 1);
13
+ assert.strictEqual(provider.getCallCount(), 1);
14
+ });
15
+ test("run(): a tool call is dispatched inline, still just one chat() call — no automatic follow-up", async () => {
16
+ const tool = GetCurrentTimeTool();
17
+ const mcpClient = {
18
+ getTools: async () => [{ name: tool.getOptions().name, description: tool.getOptions().description, inputs: tool.getOptions().inputs }],
19
+ callTool: async () => ({ output: { now: "2026-09-08T00:00:00Z" } }),
20
+ };
21
+ const provider = new ScriptedProvider("p", () => ({ toolCalls: [{ name: tool.getOptions().name, inputs: {} }] }));
22
+ const agent = new StatelessAgent({
23
+ instruction: "answer with the current time",
24
+ aiProvider: provider,
25
+ mcpClient,
26
+ allowedTools: [tool],
27
+ });
28
+ const result = await agent.run("what time is it?");
29
+ assert.strictEqual(result.toolCalls.length, 1);
30
+ assert.strictEqual(result.toolCalls[0].name, tool.getOptions().name);
31
+ assert.deepStrictEqual(JSON.parse(result.toolCalls[0].resultText), { now: "2026-09-08T00:00:00Z" });
32
+ assert.strictEqual(result.usage.length, 1);
33
+ assert.strictEqual(provider.getCallCount(), 1);
34
+ });
35
+ test("run(): messages returned include the tool result, ready to hand back in for a follow-up run()", async () => {
36
+ const tool = GetCurrentTimeTool();
37
+ const mcpClient = {
38
+ getTools: async () => [{ name: tool.getOptions().name, description: tool.getOptions().description, inputs: tool.getOptions().inputs }],
39
+ callTool: async () => ({ output: { now: "2026-09-08T00:00:00Z" } }),
40
+ };
41
+ const provider = new ScriptedProvider("p", [
42
+ () => ({ toolCalls: [{ name: tool.getOptions().name, inputs: {} }] }),
43
+ () => ({ content: "it is 2026-09-08" }),
44
+ ]);
45
+ const agent = new StatelessAgent({ instruction: "x", aiProvider: provider, mcpClient, allowedTools: [tool] });
46
+ const first = await agent.run("what time is it?");
47
+ assert.strictEqual(first.messages.at(-1)?.role, "tool");
48
+ const second = await agent.run("now answer in plain text", undefined, first.messages);
49
+ assert.strictEqual(second.content, "it is 2026-09-08");
50
+ assert.strictEqual(provider.getCallCount(), 2);
51
+ // second call's messages = first's full history + the new user turn + its own assistant turn
52
+ assert.strictEqual(second.messages.length, first.messages.length + 2);
53
+ });
54
+ test("run(): a tool the model calls that isn't allowed comes back as an error result, not a throw", async () => {
55
+ const mcpClient = { getTools: async () => [], callTool: async () => ({ output: {} }) };
56
+ const provider = new ScriptedProvider("p", () => ({ toolCalls: [{ name: "not-allowed", inputs: {} }] }));
57
+ const agent = new StatelessAgent({ instruction: "x", aiProvider: provider, mcpClient, allowedTools: [] });
58
+ const result = await agent.run("go");
59
+ assert.match(result.toolCalls[0].resultText, /not found or not allowed/);
60
+ });
61
+ test("constructor: allowedTools without mcpClient is rejected", () => {
62
+ const provider = new ScriptedProvider("p", () => ({ content: "x" }));
63
+ assert.throws(() => new StatelessAgent({ instruction: "x", aiProvider: provider, allowedTools: [GetCurrentTimeTool()] }), /mcpClient is required/);
64
+ });
65
+ test("run(): two fresh calls on the same instance are independent — no shared history", async () => {
66
+ const provider = new ScriptedProvider("p", ({ messages }) => ({ content: String(messages.length) }));
67
+ const agent = new StatelessAgent({ instruction: "x", aiProvider: provider });
68
+ const first = await agent.run("first");
69
+ const second = await agent.run("second");
70
+ assert.strictEqual(first.content, second.content);
71
+ });
72
+ });
73
+ //# sourceMappingURL=stateless-agent.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateless-agent.test.js","sourceRoot":"","sources":["../../../src/tests/core/stateless-agent.test.ts"],"names":[],"mappings":"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"}
@@ -36,5 +36,8 @@ import "./tools/browser/browser-tools.test.js";
36
36
  import "./tools/agent/agent-tools.test.js";
37
37
  import "./core/agent-definition.test.js";
38
38
  import "./core/swarm-base.test.js";
39
+ import "./core/stateless-agent.test.js";
40
+ import "./core/ai-ask.test.js";
41
+ import "./core/mcp-auto-execution-policy.test.js";
39
42
  import "./agents/default-agents.test.js";
40
43
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tests/index.ts"],"names":[],"mappings":"AAAA,OAAO,6BAA6B,CAAC;AACrC,OAAO,+BAA+B,CAAC;AACvC,OAAO,mCAAmC,CAAC;AAC3C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,qCAAqC,CAAC;AAG7C,OAAO,6BAA6B,CAAC;AACrC,OAAO,wCAAwC,CAAC;AAChD,OAAO,kCAAkC,CAAC;AAE1C,OAAO,8BAA8B,CAAC;AACtC,OAAO,+BAA+B,CAAC;AACvC,OAAO,8BAA8B,CAAC;AACtC,OAAO,6BAA6B,CAAC;AACrC,OAAO,+BAA+B,CAAC;AACvC,OAAO,2BAA2B,CAAC;AACnC,OAAO,yBAAyB,CAAC;AACjC,OAAO,yBAAyB,CAAC;AAEjC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AACxC,OAAO,+BAA+B,CAAC;AACvC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,iCAAiC,CAAC;AAEzC,OAAO,6BAA6B,CAAC;AACrC,OAAO,+BAA+B,CAAC;AACvC,OAAO,kCAAkC,CAAC;AAE1C,OAAO,0BAA0B,CAAC;AAClC,OAAO,2BAA2B,CAAC;AACnC,OAAO,2BAA2B,CAAC;AACnC,OAAO,2BAA2B,CAAC;AACnC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAExC,OAAO,iDAAiD,CAAC;AAEzD,OAAO,uCAAuC,CAAC;AAE/C,OAAO,mCAAmC,CAAC;AAE3C,OAAO,iCAAiC,CAAC;AACzC,OAAO,2BAA2B,CAAC;AAEnC,OAAO,iCAAiC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tests/index.ts"],"names":[],"mappings":"AAAA,OAAO,6BAA6B,CAAC;AACrC,OAAO,+BAA+B,CAAC;AACvC,OAAO,mCAAmC,CAAC;AAC3C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,qCAAqC,CAAC;AAG7C,OAAO,6BAA6B,CAAC;AACrC,OAAO,wCAAwC,CAAC;AAChD,OAAO,kCAAkC,CAAC;AAE1C,OAAO,8BAA8B,CAAC;AACtC,OAAO,+BAA+B,CAAC;AACvC,OAAO,8BAA8B,CAAC;AACtC,OAAO,6BAA6B,CAAC;AACrC,OAAO,+BAA+B,CAAC;AACvC,OAAO,2BAA2B,CAAC;AACnC,OAAO,yBAAyB,CAAC;AACjC,OAAO,yBAAyB,CAAC;AAEjC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AACxC,OAAO,+BAA+B,CAAC;AACvC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,iCAAiC,CAAC;AAEzC,OAAO,6BAA6B,CAAC;AACrC,OAAO,+BAA+B,CAAC;AACvC,OAAO,kCAAkC,CAAC;AAE1C,OAAO,0BAA0B,CAAC;AAClC,OAAO,2BAA2B,CAAC;AACnC,OAAO,2BAA2B,CAAC;AACnC,OAAO,2BAA2B,CAAC;AACnC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAExC,OAAO,iDAAiD,CAAC;AAEzD,OAAO,uCAAuC,CAAC;AAE/C,OAAO,mCAAmC,CAAC;AAE3C,OAAO,iCAAiC,CAAC;AACzC,OAAO,2BAA2B,CAAC;AACnC,OAAO,gCAAgC,CAAC;AACxC,OAAO,uBAAuB,CAAC;AAC/B,OAAO,0CAA0C,CAAC;AAElD,OAAO,iCAAiC,CAAC"}
@@ -36,5 +36,8 @@ import "./tools/browser/browser-tools.test.js";
36
36
  import "./tools/agent/agent-tools.test.js";
37
37
  import "./core/agent-definition.test.js";
38
38
  import "./core/swarm-base.test.js";
39
+ import "./core/stateless-agent.test.js";
40
+ import "./core/ai-ask.test.js";
41
+ import "./core/mcp-auto-execution-policy.test.js";
39
42
  import "./agents/default-agents.test.js";
40
43
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tests/index.ts"],"names":[],"mappings":"AAAA,OAAO,6BAA6B,CAAC;AACrC,OAAO,+BAA+B,CAAC;AACvC,OAAO,mCAAmC,CAAC;AAC3C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,qCAAqC,CAAC;AAG7C,OAAO,6BAA6B,CAAC;AACrC,OAAO,wCAAwC,CAAC;AAChD,OAAO,kCAAkC,CAAC;AAE1C,OAAO,8BAA8B,CAAC;AACtC,OAAO,+BAA+B,CAAC;AACvC,OAAO,8BAA8B,CAAC;AACtC,OAAO,6BAA6B,CAAC;AACrC,OAAO,+BAA+B,CAAC;AACvC,OAAO,2BAA2B,CAAC;AACnC,OAAO,yBAAyB,CAAC;AACjC,OAAO,yBAAyB,CAAC;AAEjC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AACxC,OAAO,+BAA+B,CAAC;AACvC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,iCAAiC,CAAC;AAEzC,OAAO,6BAA6B,CAAC;AACrC,OAAO,+BAA+B,CAAC;AACvC,OAAO,kCAAkC,CAAC;AAE1C,OAAO,0BAA0B,CAAC;AAClC,OAAO,2BAA2B,CAAC;AACnC,OAAO,2BAA2B,CAAC;AACnC,OAAO,2BAA2B,CAAC;AACnC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAExC,OAAO,iDAAiD,CAAC;AAEzD,OAAO,uCAAuC,CAAC;AAE/C,OAAO,mCAAmC,CAAC;AAE3C,OAAO,iCAAiC,CAAC;AACzC,OAAO,2BAA2B,CAAC;AAEnC,OAAO,iCAAiC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tests/index.ts"],"names":[],"mappings":"AAAA,OAAO,6BAA6B,CAAC;AACrC,OAAO,+BAA+B,CAAC;AACvC,OAAO,mCAAmC,CAAC;AAC3C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,qCAAqC,CAAC;AAG7C,OAAO,6BAA6B,CAAC;AACrC,OAAO,wCAAwC,CAAC;AAChD,OAAO,kCAAkC,CAAC;AAE1C,OAAO,8BAA8B,CAAC;AACtC,OAAO,+BAA+B,CAAC;AACvC,OAAO,8BAA8B,CAAC;AACtC,OAAO,6BAA6B,CAAC;AACrC,OAAO,+BAA+B,CAAC;AACvC,OAAO,2BAA2B,CAAC;AACnC,OAAO,yBAAyB,CAAC;AACjC,OAAO,yBAAyB,CAAC;AAEjC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AACxC,OAAO,+BAA+B,CAAC;AACvC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,kCAAkC,CAAC;AAC1C,OAAO,iCAAiC,CAAC;AAEzC,OAAO,6BAA6B,CAAC;AACrC,OAAO,+BAA+B,CAAC;AACvC,OAAO,kCAAkC,CAAC;AAE1C,OAAO,0BAA0B,CAAC;AAClC,OAAO,2BAA2B,CAAC;AACnC,OAAO,2BAA2B,CAAC;AACnC,OAAO,2BAA2B,CAAC;AACnC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAExC,OAAO,iDAAiD,CAAC;AAEzD,OAAO,uCAAuC,CAAC;AAE/C,OAAO,mCAAmC,CAAC;AAE3C,OAAO,iCAAiC,CAAC;AACzC,OAAO,2BAA2B,CAAC;AACnC,OAAO,gCAAgC,CAAC;AACxC,OAAO,uBAAuB,CAAC;AAC/B,OAAO,0CAA0C,CAAC;AAElD,OAAO,iCAAiC,CAAC"}
package/docs/agents.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # Agents
2
2
 
3
- ## `BaseAgent` vs `SimpleAgent`
3
+ ## `BaseAgent` vs `SimpleAgent` vs `StatelessAgent`
4
4
 
5
5
  - **`BaseAgent`** (`src/core/base-agent.ts`) is the real engine — the run loop, memory compaction, tool dispatch, token accounting. It requires you to bring your own `MCPClient` (and therefore your own `MCPServer`/connection), which is what gives you the choice of in-process, IPC, or WebSocket execution (see [MCP Architecture](./mcp-architecture.md)).
6
6
  - **`SimpleAgent`** (`src/templates/simple.ts`) is a thin subclass that wires up an in-process `MCPConnection` + `MCPServer` + `MCPClient` for you from a flat `tools`/`skills` list. Use this unless you specifically need a different transport.
7
+ - **`StatelessAgent`** (`src/core/stateless-agent.ts`) is not a loop at all — one `input` in, one `chat()` call out (see [`StatelessAgent`](#statelessagent) below). Use this for input checking, classification, or validation, where `BaseAgent`'s multi-turn loop and memory compaction are unnecessary overhead.
7
8
  - **`AgentDefinition`** (`src/core/agent-definition.ts`) isn't an agent at all — it's a reusable *description* of one kind of agent (persona, skills, tools) with no runtime wiring, which `SwarmBase` instantiates as many plain `BaseAgent`s as it needs. See [Multi-agent](#multi-agent) below.
8
9
 
9
10
  ## `BaseAgent` constructor
@@ -164,6 +165,81 @@ Every other `type` entry comes from a tool calling `mcp.executeProvider(toolCall
164
165
 
165
166
  The system prompt is built lazily on first use and cached — a stable prefix between compactions, which matters for provider-side prompt caching. It's assembled from: a fixed "you have tools" preamble, each skill's name/description/instructions (see [Skills](./skills.md)), the current `MEMORY:` block (sourced from `compactMemory`), and your `instruction` string, in that order. Each `compact_memory` call invalidates the cache (see [Memory compaction](#memory-compaction)), so the next turn's system prompt is rebuilt with the fresh `MEMORY:` block instead of the one that was current when the prompt was first built.
166
167
 
168
+ ## `StatelessAgent`
169
+
170
+ ```ts
171
+ new StatelessAgent({
172
+ instruction: string;
173
+ safetyPolicies?: string; // default: "" — sent as its own leading system message, same convention as BaseAgent
174
+ aiProvider: AIProvider | AgentProviderEntry[];
175
+ mcpClient?: MCPClient; // required only if allowedTools is non-empty — bring your own, same as BaseAgent
176
+ allowedTools?: MCPTool<any>[]; // default: []
177
+ });
178
+ ```
179
+
180
+ Unlike `BaseAgent`, there is no `run` loop, no `messagesCompact`/`retiredMessages`, no `compact_memory` tool, and no `getCurrentAgentStates()` — an instance holds only its fixed configuration (instruction, provider, allowed tools), never conversation state. Because of that, one instance is meant to be constructed once and reused: `run()` can be called any number of times, including concurrently, and calls never see each other's input or output — each builds its own message array from scratch (or continues one you hand back in — see below).
181
+
182
+ ```ts
183
+ const result = await agent.run(input: string, streamCallback?: StreamCallback, previousMessages?: Message[]): Promise<StatelessAgentResult>;
184
+ // { content: string; toolCalls: DispatchedToolCall[]; usage: MessageUsage[]; messages: Message[] }
185
+ ```
186
+
187
+ `run()` makes exactly **one** `chat()` call — never a second, even when the model requests tool calls:
188
+
189
+ 1. `previousMessages` omitted (the default): the message array is built fresh as `[system(safetyPolicies), system(instruction), user(input)]`. Given instead, `input` is appended as one more `user` message onto it — this is how you continue an exchange without StatelessAgent retaining any state of its own; see `result.messages` below.
190
+ 2. That one `chat()` call is made. If the model requested tool calls, every one of them is dispatched right away (via the `MCPClient`/`allowedTools` this agent was built with — same dispatch semantics as `BaseAgent#dispatchTool`: an error from a tool, or a tool name that isn't allowed, comes back as an `Error: ...` result string rather than throwing), and their `role: "tool"` result messages are appended to `messages`. `run()` then returns immediately — there is no automatic follow-up `chat()` call to fold those results into a final answer.
191
+
192
+ If the model's first turn requests no tools, `run()` still resolves after that one call, with `toolCalls: []`.
193
+
194
+ ### Continuing an exchange: `result.messages` / `previousMessages`
195
+
196
+ Since `run()` never makes a second `chat()` call on its own, `result.messages` is how you pick up where it left off: it's the complete array built for that call — the two leading system messages, the `user` turn, the resulting `assistant` turn, and any `tool` result messages — in the order the provider needs them replayed. Call `run()` again with it as `previousMessages` (and whatever `input` makes sense next — often just a nudge like `"continue"`, or nothing new to add beyond letting the model see the tool results) to get the model's next turn, e.g. its synthesized answer after seeing what a tool returned. Each such call is still exactly one `chat()` call; a caller that wants BaseAgent-style looping-until-no-more-tool-calls behavior builds that loop itself by chaining `run()` calls this way, rather than getting it for free.
197
+
198
+ ### Token accounting
199
+
200
+ `result.usage` is exactly one `MessageUsage` entry per `run()` call — there's no running total to query since there's no persisted state between calls; sum `usage` yourself across calls (e.g. across a chain of `previousMessages`-linked calls) if you need a lifetime total.
201
+
202
+ ## `AIASK`
203
+
204
+ `AIASK` (`src/core/ai-ask.ts`) asks the model for exactly one answer in a validated JSON shape. It's built on `StatelessAgent`, not a replacement for it — internally it registers a single `submit_answer` tool (built from `outputStructure`) on its own private, in-process `MCPClient` (same `MCPConnection` + `MCPServer` wiring `SimpleAgent` uses) and drives a `StatelessAgent` with it. There's nothing to wire up from outside:
205
+
206
+ ```ts
207
+ new AIASK({
208
+ instruction: string;
209
+ aiModel: AIProvider | AgentProviderEntry[];
210
+ outputStructure: { name: string; type: "number" | "string" | "boolean" | "object" | "array"; description: string; required?: boolean }[];
211
+ });
212
+ ```
213
+
214
+ No `mcpClient`, no `allowedTools`, and deliberately no `safetyPolicies` field — for a single narrow structured-answer call, `instruction` *is* the whole system prompt (fold any guardrail text straight into it) rather than a separate cache-stable prefix, which only earns its keep across many turns.
215
+
216
+ ```ts
217
+ const result = await ask.run(input: string): Promise<AIAskResult>;
218
+ // { output: Record<string, any>; valid: boolean; errors?: string[]; attempts: number; usage: MessageUsage[] }
219
+ ```
220
+
221
+ Each field in `outputStructure` becomes one input on the `submit_answer` tool (`required` defaults to `true`). After the model calls it (or fails to), the returned fields are validated against `outputStructure` — every `required` field present, and each field's JS type (`typeof`, with `Array.isArray` for `"array"` and a plain-object check for `"object"`) matching what was declared. Replying in plain text instead of calling the tool at all counts as a failed attempt too.
222
+
223
+ A failed attempt (validation errors, or no tool call) triggers a retry: `run()` calls the underlying `StatelessAgent` again, up to **3 attempts total**, with the validation errors folded into the next prompt so the model can see exactly what was wrong and self-correct. The first attempt that validates returns immediately with `valid: true` and `errors` unset. If all 3 attempts fail, `run()` returns rather than throwing — `valid: false`, `errors` from the last attempt, `attempts: 3`, and `output` holding whatever fields the last attempt did manage to submit (possibly `{}` if it never called the tool at all).
224
+
225
+ ```ts
226
+ const ask = new AIASK({
227
+ instruction: "Classify the input as spam or not.",
228
+ aiModel,
229
+ outputStructure: [
230
+ { name: "spam", type: "boolean", description: "true if this is spam" },
231
+ { name: "reason", type: "string", description: "one-sentence justification" },
232
+ ],
233
+ });
234
+
235
+ const { output, valid, attempts } = await ask.run(userMessage);
236
+ if (valid) {
237
+ // output is { spam: boolean, reason: string }
238
+ }
239
+ ```
240
+
241
+ `result.usage` accumulates every `chat()` call across every attempt (up to 3, one per `StatelessAgent.run()` call), not just the winning one.
242
+
167
243
  ## Multi-agent
168
244
 
169
245
  Multiple agents that hire, task, and report to each other live in [Swarm](./swarm.md) — `SwarmBase`, `getAgentTools()`, and `AgentDefinition`.
@@ -158,6 +158,48 @@ class AllowlistPolicy extends MCPExecutionPolicy {
158
158
  const mcpClient = new MCPClient(envID, connection, storage, rng, undefined, new AllowlistPolicy(["get_current_time"]));
159
159
  ```
160
160
 
161
+ ### `MCPAutoExecutionPolicy` — an AI-judged policy
162
+
163
+ `MCPAutoExecutionPolicy` (`src/core/mcp-auto-execution-policy.ts`) is a built-in `MCPExecutionPolicy` that asks a model, via [`AIASK`](./agents.md#aiask), whether each call is safe — an alternative to a hand-written allowlist/denylist for cases where "safe" isn't a fixed rule. It's built to keep the expensive part (an actual model call) as rare as possible rather than reviewing every single tool call:
164
+
165
+ ```ts
166
+ new MCPAutoExecutionPolicy({
167
+ aiModel: AIProvider | AgentProviderEntry[];
168
+ instruction?: string; // extra context appended after the built-in default instruction — e.g. what the user actually asked the agent to do
169
+ onVerdict?: (request: MCPToolCallRequest, verdict: { harmful: boolean; reason: string }) => void;
170
+ watchedTools?: string[]; // default: ["bash-run", "fs-write-file", "fs-edit-file", "fs-delete", "fs-move"]
171
+ scopeDir?: string; // default: process.cwd() at construction time
172
+ });
173
+ ```
174
+
175
+ Three cost-cutting layers, checked in order inside `authorize(request)`:
176
+
177
+ 1. **Not in `watchedTools`?** Authorized immediately — no model call, no verdict recorded at all. Most tools (`get-current-time`, `todo-*`, `fs-read-file`, ...) have nothing dangerous to weigh, so the default watch list is only the destructive/execution tools: `bash-run` and the fs tools that write, edit, delete, or move something. Pass your own `watchedTools` to widen or narrow that set.
178
+ 2. **A watched *fs* call whose path(s) all resolve inside `scopeDir`?** Also authorized immediately, no model call — a write/edit/delete confined to the expected working directory doesn't need judgment. Paths are resolved the same way the fs tools themselves resolve them (relative to `process.cwd()`); `fs-move` needs *both* `from` and `to` inside scope to skip the model — one path escaping scope is enough to escalate. `bash-run` has no path field to check here, so it always falls through to the model.
179
+ 3. **Otherwise, ask the model** — via `AIASK`, on `{ toolName, inputs }`. `authorize()` denies whenever the verdict comes back `harmful: true`, or whenever `AIASK` itself couldn't reach a valid verdict after its own retries (fails closed, not open).
180
+
181
+ Whenever a call *does* reach the model, file content is stripped out first — `fs-write-file`/`fs-edit-file`'s `content` field is replaced with `<omitted, N bytes>` before it's ever sent, since the file's contents aren't relevant to judging whether the *call* is safe, and including it would make every write/edit review needlessly expensive. The model judges those calls by path and other inputs alone.
182
+
183
+ `authorize()`'s boolean return only tells `MCPClient` whether to proceed — it doesn't surface *why* a call was judged (or skipped as) harmful/safe, which callers usually want (to log it, or show the user what got blocked). Three ways to get that — all populated for both a model-reviewed call and one that was authorized locally via the path-scope check, but never for a call outside `watchedTools`, which is never reviewed at all:
184
+
185
+ - `policy.getVerdict(toolCallId)` — the verdict recorded for one specific call, if it carried a `toolCallId`.
186
+ - `policy.getLastVerdict()` — the most recent verdict of any reviewed call, useful when only one policy instance is ever in flight at a time.
187
+ - `onVerdict` — called synchronously right after every reviewed `authorize()` decision, with both the request and the verdict.
188
+
189
+ ```ts
190
+ const policy = new MCPAutoExecutionPolicy({
191
+ aiModel,
192
+ scopeDir: "/home/me/project", // writes/edits/deletes/moves confined here skip the model entirely
193
+ onVerdict: (request, verdict) => {
194
+ if (verdict.harmful) console.warn(`blocked ${request.toolName}: ${verdict.reason}`);
195
+ },
196
+ });
197
+
198
+ const mcpClient = new MCPClient(envID, connection, storage, rng, undefined, policy);
199
+ ```
200
+
201
+ Even with those shortcuts, a call that does reach the model costs at least one real call (more if `AIASK`'s own retry loop kicks in — see [`AIASK`](./agents.md#aiask)) — this still trades latency/cost for judgment a fixed rule can't express, just as rarely as the watch list and scope check allow. Reach for a plain `MCPExecutionPolicy` subclass first when a simple allowlist/denylist actually covers the case.
202
+
161
203
  ## Custom `MCP` subclasses
162
204
 
163
205
  Both `MCPServer` and `MCPClient` extend the abstract `MCP` class — `getStorage()`, `getRNG()`, and `executeProvider(toolCallId, type, input)`. Tool `execute` functions receive the calling `MCP` instance directly, as their 4th argument (after a `toolCallId` — see [Tools](./tools.md#the-mcptool-shape)), so a tool can reach storage/RNG scoped to whichever client dispatched the call.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orbitx",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "An AI SDK providing agents, swarms, planners, skills, MCP tools, workflows, and multi-provider AI integrations.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,19 +0,0 @@
1
- import type { AIProvider } from "./ai-provider.js";
2
- /** Usage for one `describe()` call. */
3
- export interface ImageDescription {
4
- description: string;
5
- inputTokens: number;
6
- outputTokens: number;
7
- }
8
- export declare class ImageDescriber {
9
- #private;
10
- constructor(provider: AIProvider);
11
- /**
12
- * @param image base64-encoded image bytes (no data: prefix)
13
- * @param mimeType e.g. "image/png"
14
- * @param focusHint what the calling agent wants the description to pay attention to
15
- */
16
- describe(image: string, mimeType?: string, focusHint?: string): Promise<ImageDescription>;
17
- }
18
- export default ImageDescriber;
19
- //# sourceMappingURL=image-describer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"image-describer.d.ts","sourceRoot":"","sources":["../../src/core/image-describer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAsB,MAAM,kBAAkB,CAAC;AAEvE,uCAAuC;AACvC,MAAM,WAAW,gBAAgB;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,cAAc;;gBAGX,QAAQ,EAAE,UAAU;IAIhC;;;;OAIG;IACG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAoB,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;CA6B/G;AAED,eAAe,cAAc,CAAC"}
@@ -1,37 +0,0 @@
1
- export class ImageDescriber {
2
- #provider;
3
- constructor(provider) {
4
- this.#provider = provider;
5
- }
6
- /**
7
- * @param image base64-encoded image bytes (no data: prefix)
8
- * @param mimeType e.g. "image/png"
9
- * @param focusHint what the calling agent wants the description to pay attention to
10
- */
11
- async describe(image, mimeType = "image/png", focusHint) {
12
- const caps = this.#provider.getCapabilities();
13
- if (!caps.supportsImages) {
14
- throw new Error("ImageDescriber's provider does not support image input (getCapabilities().supportsImages is false) — " +
15
- "configure ImageDescriber with a vision-capable provider.");
16
- }
17
- const parts = [
18
- {
19
- type: "text",
20
- text: focusHint
21
- ? `Describe this image concisely for another AI agent that cannot see it. Focus specifically on: ${focusHint}`
22
- : "Describe this image concisely for another AI agent that cannot see it. Mention layout, visible text, colors, and anything that looks unusual or broken.",
23
- },
24
- { type: "image", image, mimeType },
25
- ];
26
- const response = await this.#provider.chat([
27
- { role: "user", parts },
28
- ]);
29
- return {
30
- description: response.content,
31
- inputTokens: response.inputTokens,
32
- outputTokens: response.outputTokens,
33
- };
34
- }
35
- }
36
- export default ImageDescriber;
37
- //# sourceMappingURL=image-describer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"image-describer.js","sourceRoot":"","sources":["../../src/core/image-describer.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,cAAc;IACvB,SAAS,CAAa;IAEtB,YAAY,QAAoB;QAC5B,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC9B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CAAC,KAAa,EAAE,WAAmB,WAAW,EAAE,SAAkB;QAC5E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,CAAC;QAC9C,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CACX,uGAAuG;gBACvG,0DAA0D,CAC7D,CAAC;QACN,CAAC;QAED,MAAM,KAAK,GAAyB;YAChC;gBACI,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,SAAS;oBACX,CAAC,CAAC,iGAAiG,SAAS,EAAE;oBAC9G,CAAC,CAAC,yJAAyJ;aAClK;YACD,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE;SACrC,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YACvC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE;SAC1B,CAAC,CAAC;QAEH,OAAO;YACH,WAAW,EAAE,QAAQ,CAAC,OAAO;YAC7B,WAAW,EAAE,QAAQ,CAAC,WAAW;YACjC,YAAY,EAAE,QAAQ,CAAC,YAAY;SACtC,CAAC;IACN,CAAC;CACJ;AAED,eAAe,cAAc,CAAC"}
@@ -1,43 +0,0 @@
1
- import BaseAgent from "./base-agent.js";
2
- /**
3
- * Per-task-type fit score for a WorkerAgent, e.g. `{ backend: 9, frontend: 4,
4
- * "3d-web": 10 }`. Keys are free-form task-type labels chosen by whoever
5
- * builds the roster; there's no fixed enum since "what counts as a task
6
- * type" is app-specific. Convention (not enforced): 0-10, higher is a
7
- * better fit. AgentListTool hands this straight to the hiring agent so it
8
- * can judge which worker fits a given task.
9
- */
10
- export type WorkerAgentRating = Record<string, number>;
11
- /**
12
- * EXPERIMENTAL: this class, and the agent-management tools built on it
13
- * (src/tools/agent/), are new and still settling — names and behavior may
14
- * change in a future release.
15
- *
16
- * A BaseAgent with an identity a *hiring* agent can reason about — name,
17
- * description (persona/specialty), and a rating per task type — so it can
18
- * be listed, compared against other workers, and hired via the tools in
19
- * `src/tools/agent/` (see AgentTools()). Everything about running it (tool
20
- * dispatch, memory, streaming) is unchanged from BaseAgent; WorkerAgent only
21
- * adds metadata on top.
22
- *
23
- * Like BaseAgent, this is a raw building block: you still bring your own
24
- * `mcpClient`/`allowedTools`. If you want this worker to be able to report
25
- * back to whoever hired it, include AgentReportTool() (from
26
- * `src/tools/agent/`) in its own tools, same as any other tool.
27
- */
28
- export declare class WorkerAgent extends BaseAgent {
29
- #private;
30
- constructor({ name, description, rating, ...baseAgentOptions }: {
31
- /** Unique identifier used by AgentTools() to hire/prompt this worker — must be unique across whatever roster it's included in. */
32
- name: string;
33
- /** Persona/specialty shown to the hiring agent via agent-list — what this worker is good at, written for the model to judge fit from, not just a human label. */
34
- description: string;
35
- /** Per-task-type fit score — see WorkerAgentRating. Defaults to empty (no stated specialty). */
36
- rating?: WorkerAgentRating;
37
- } & ConstructorParameters<typeof BaseAgent>[0]);
38
- getName(): string;
39
- getDescription(): string;
40
- getRating(): WorkerAgentRating;
41
- }
42
- export default WorkerAgent;
43
- //# sourceMappingURL=worker-agent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"worker-agent.d.ts","sourceRoot":"","sources":["../../src/core/worker-agent.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,iBAAiB,CAAC;AAExC;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEvD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,WAAY,SAAQ,SAAS;;gBAK1B,EACR,IAAI,EACJ,WAAW,EACX,MAAW,EACX,GAAG,gBAAgB,EACtB,EAAE;QACC,kIAAkI;QAClI,IAAI,EAAE,MAAM,CAAC;QACb,iKAAiK;QACjK,WAAW,EAAE,MAAM,CAAC;QACpB,gGAAgG;QAChG,MAAM,CAAC,EAAE,iBAAiB,CAAC;KAC9B,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;IAO9C,OAAO,IAAI,MAAM;IAIjB,cAAc,IAAI,MAAM;IAIxB,SAAS,IAAI,iBAAiB;CAGjC;AAED,eAAe,WAAW,CAAC"}
@@ -1,40 +0,0 @@
1
- import BaseAgent from "./base-agent.js";
2
- /**
3
- * EXPERIMENTAL: this class, and the agent-management tools built on it
4
- * (src/tools/agent/), are new and still settling — names and behavior may
5
- * change in a future release.
6
- *
7
- * A BaseAgent with an identity a *hiring* agent can reason about — name,
8
- * description (persona/specialty), and a rating per task type — so it can
9
- * be listed, compared against other workers, and hired via the tools in
10
- * `src/tools/agent/` (see AgentTools()). Everything about running it (tool
11
- * dispatch, memory, streaming) is unchanged from BaseAgent; WorkerAgent only
12
- * adds metadata on top.
13
- *
14
- * Like BaseAgent, this is a raw building block: you still bring your own
15
- * `mcpClient`/`allowedTools`. If you want this worker to be able to report
16
- * back to whoever hired it, include AgentReportTool() (from
17
- * `src/tools/agent/`) in its own tools, same as any other tool.
18
- */
19
- export class WorkerAgent extends BaseAgent {
20
- #name;
21
- #description;
22
- #rating;
23
- constructor({ name, description, rating = {}, ...baseAgentOptions }) {
24
- super(baseAgentOptions);
25
- this.#name = name;
26
- this.#description = description;
27
- this.#rating = rating;
28
- }
29
- getName() {
30
- return this.#name;
31
- }
32
- getDescription() {
33
- return this.#description;
34
- }
35
- getRating() {
36
- return this.#rating;
37
- }
38
- }
39
- export default WorkerAgent;
40
- //# sourceMappingURL=worker-agent.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"worker-agent.js","sourceRoot":"","sources":["../../src/core/worker-agent.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,iBAAiB,CAAC;AAYxC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,WAAY,SAAQ,SAAS;IACtC,KAAK,CAAS;IACd,YAAY,CAAS;IACrB,OAAO,CAAoB;IAE3B,YAAY,EACR,IAAI,EACJ,WAAW,EACX,MAAM,GAAG,EAAE,EACX,GAAG,gBAAgB,EAQuB;QAC1C,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IAC1B,CAAC;IAED,OAAO;QACH,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,cAAc;QACV,OAAO,IAAI,CAAC,YAAY,CAAC;IAC7B,CAAC;IAED,SAAS;QACL,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;CACJ;AAED,eAAe,WAAW,CAAC"}
@@ -1,4 +0,0 @@
1
- import Skill from "../core/skill.js";
2
- export declare const ShoppingSkill: () => Skill;
3
- export default ShoppingSkill;
4
- //# sourceMappingURL=shopping.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"shopping.d.ts","sourceRoot":"","sources":["../../src/skills/shopping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,kBAAkB,CAAC;AAIrC,eAAO,MAAM,aAAa,aAiExB,CAAC;AAEH,eAAe,aAAa,CAAC"}