tiny-orchestrator 0.2.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.
- package/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/index.d.ts +106 -0
- package/dist/index.js +193 -0
- package/dist/index.js.map +1 -0
- package/dist/templates/index.d.ts +9 -0
- package/dist/templates/index.js +39 -0
- package/dist/templates/index.js.map +1 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dan Korotenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# tiny-orchestrator
|
|
2
|
+
|
|
3
|
+
A tiny TypeScript multi-agent runner with sane defaults, templates, and traces.
|
|
4
|
+
|
|
5
|
+
## Goals
|
|
6
|
+
|
|
7
|
+
- **Small surface area**: `new Orchestrator({ llm }).run({ goal })`
|
|
8
|
+
- **Code-driven orchestration**: budgets/policy live in code; the model is a worker.
|
|
9
|
+
- **Bring your own LLM**: minimal `LLM` interface (OpenAI/Anthropic/local).
|
|
10
|
+
- **Traces**: every run returns a trace you can persist.
|
|
11
|
+
|
|
12
|
+
## Install (core + provider)
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# npm (recommended)
|
|
16
|
+
npm i tiny-orchestrator @tiny-orchestrator/openrouter
|
|
17
|
+
|
|
18
|
+
# bun
|
|
19
|
+
bun add tiny-orchestrator @tiny-orchestrator/openrouter
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { Orchestrator } from "tiny-orchestrator";
|
|
26
|
+
import { OpenRouterChatLLM } from "@tiny-orchestrator/openrouter";
|
|
27
|
+
|
|
28
|
+
const llm = new OpenRouterChatLLM({
|
|
29
|
+
// Or just set OPENROUTER_API_KEY / OPENROUTER_MODEL in env.
|
|
30
|
+
apiKey: process.env.OPENROUTER_API_KEY,
|
|
31
|
+
model: process.env.OPENROUTER_MODEL ?? "openai/gpt-4o-mini",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const tools = [
|
|
35
|
+
{
|
|
36
|
+
name: "add",
|
|
37
|
+
description: "Add two numbers",
|
|
38
|
+
async run(args: { a: number; b: number }) {
|
|
39
|
+
return args.a + args.b;
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const orch = new Orchestrator({ llm, tools, budgets: { maxSteps: 10, timeMs: 30_000 } });
|
|
45
|
+
const out = await orch.run({ goal: "Use the add tool to compute 2 + 2, then explain." });
|
|
46
|
+
|
|
47
|
+
console.log(out.summary);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Tool calling protocol
|
|
51
|
+
|
|
52
|
+
The model must output **one JSON object** per step:
|
|
53
|
+
|
|
54
|
+
- Tool request:
|
|
55
|
+
- `{ "type": "tool", "name": "add", "args": { "a": 2, "b": 2 } }`
|
|
56
|
+
- Final answer:
|
|
57
|
+
- `{ "type": "final", "content": "..." }`
|
|
58
|
+
|
|
59
|
+
## Templates
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { researcher, reviewer, writer } from "tiny-orchestrator/templates";
|
|
63
|
+
|
|
64
|
+
console.log(researcher(), reviewer(), writer());
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Runtime
|
|
68
|
+
|
|
69
|
+
This package is **Node 18+** compatible. You can run scripts with **bun** or **node**.
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
type LLMMessage = {
|
|
2
|
+
role: "system" | "user" | "assistant";
|
|
3
|
+
content: string;
|
|
4
|
+
};
|
|
5
|
+
type LLMInput = {
|
|
6
|
+
system?: string;
|
|
7
|
+
messages: LLMMessage[];
|
|
8
|
+
signal?: AbortSignal;
|
|
9
|
+
};
|
|
10
|
+
type LLMResponse = {
|
|
11
|
+
content: string;
|
|
12
|
+
raw?: unknown;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Minimal interface: bring your own provider (OpenAI, Anthropic, local, etc.).
|
|
16
|
+
*/
|
|
17
|
+
interface LLM {
|
|
18
|
+
complete(input: LLMInput): Promise<LLMResponse>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type TraceEvent = {
|
|
22
|
+
t: "run.start";
|
|
23
|
+
runId: string;
|
|
24
|
+
goal: string;
|
|
25
|
+
at: number;
|
|
26
|
+
} | {
|
|
27
|
+
t: "run.end";
|
|
28
|
+
runId: string;
|
|
29
|
+
at: number;
|
|
30
|
+
summary: string;
|
|
31
|
+
} | {
|
|
32
|
+
t: "tool.call";
|
|
33
|
+
runId: string;
|
|
34
|
+
at: number;
|
|
35
|
+
tool: string;
|
|
36
|
+
args: unknown;
|
|
37
|
+
} | {
|
|
38
|
+
t: "tool.result";
|
|
39
|
+
runId: string;
|
|
40
|
+
at: number;
|
|
41
|
+
tool: string;
|
|
42
|
+
ok: boolean;
|
|
43
|
+
result?: unknown;
|
|
44
|
+
error?: string;
|
|
45
|
+
} | {
|
|
46
|
+
t: "agent.spawn";
|
|
47
|
+
runId: string;
|
|
48
|
+
at: number;
|
|
49
|
+
agent: string;
|
|
50
|
+
task: string;
|
|
51
|
+
} | {
|
|
52
|
+
t: "agent.result";
|
|
53
|
+
runId: string;
|
|
54
|
+
at: number;
|
|
55
|
+
agent: string;
|
|
56
|
+
output: string;
|
|
57
|
+
};
|
|
58
|
+
type ToolContext = {
|
|
59
|
+
runId: string;
|
|
60
|
+
signal: AbortSignal;
|
|
61
|
+
trace: (event: TraceEvent) => void;
|
|
62
|
+
};
|
|
63
|
+
type ToolResult<TResult = unknown> = {
|
|
64
|
+
ok: true;
|
|
65
|
+
result: TResult;
|
|
66
|
+
} | {
|
|
67
|
+
ok: false;
|
|
68
|
+
error: string;
|
|
69
|
+
};
|
|
70
|
+
type Tool<TArgs = unknown, TResult = unknown> = {
|
|
71
|
+
name: string;
|
|
72
|
+
description?: string;
|
|
73
|
+
/** Optional schema (zod/jsonschema/typebox). Treated as metadata by core. */
|
|
74
|
+
schema?: unknown;
|
|
75
|
+
run: (args: TArgs, ctx: ToolContext) => Promise<TResult>;
|
|
76
|
+
};
|
|
77
|
+
type OrchestratorOptions = {
|
|
78
|
+
llm: LLM;
|
|
79
|
+
tools?: Tool[];
|
|
80
|
+
budgets?: {
|
|
81
|
+
timeMs?: number;
|
|
82
|
+
/** Max LLM steps (each step may be a tool call or final response). */
|
|
83
|
+
maxSteps?: number;
|
|
84
|
+
maxSpawns?: number;
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
type RunInput = {
|
|
88
|
+
goal: string;
|
|
89
|
+
context?: Record<string, unknown>;
|
|
90
|
+
};
|
|
91
|
+
type RunResult = {
|
|
92
|
+
runId: string;
|
|
93
|
+
summary: string;
|
|
94
|
+
trace: TraceEvent[];
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
declare class Orchestrator {
|
|
98
|
+
private llm;
|
|
99
|
+
private tools;
|
|
100
|
+
private budgets;
|
|
101
|
+
private completeJSON;
|
|
102
|
+
constructor(opts: OrchestratorOptions);
|
|
103
|
+
run(input: RunInput): Promise<RunResult>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export { type LLM, type LLMInput, type LLMMessage, type LLMResponse, Orchestrator, type OrchestratorOptions, type RunInput, type RunResult, type Tool, type ToolContext, type ToolResult, type TraceEvent };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
|
|
3
|
+
// src/orchestrator.ts
|
|
4
|
+
|
|
5
|
+
// src/prompts.ts
|
|
6
|
+
function buildDefaultSystemPrompt(params) {
|
|
7
|
+
const toolList = params.tools.length ? params.tools.map((t) => `- ${t.name}${t.description ? `: ${t.description}` : ""}`).join("\n") : "- (no tools registered)";
|
|
8
|
+
return [
|
|
9
|
+
"You are Tiny Orchestrator.",
|
|
10
|
+
"You are allowed to call developer-provided tools.",
|
|
11
|
+
"",
|
|
12
|
+
"Rules:",
|
|
13
|
+
"- Be direct.",
|
|
14
|
+
"- Prefer concrete steps and checklists.",
|
|
15
|
+
"- If information is missing, call tools (if available) or ask exactly what you need.",
|
|
16
|
+
"",
|
|
17
|
+
"Tool calling protocol (IMPORTANT):",
|
|
18
|
+
"- You MUST respond with a single JSON object, and NOTHING else.",
|
|
19
|
+
"- Either request a tool:",
|
|
20
|
+
' { "type": "tool", "name": "toolName", "args": { ... } }',
|
|
21
|
+
"- Or finish with a final answer:",
|
|
22
|
+
' { "type": "final", "content": "..." }',
|
|
23
|
+
"- After you request a tool, you will receive a user message of the form:",
|
|
24
|
+
' { "type": "tool_result", "name": "toolName", "ok": true|false, "result": ..., "error": "..." }',
|
|
25
|
+
"- Do not wrap JSON in markdown. Do not include explanations outside JSON.",
|
|
26
|
+
"",
|
|
27
|
+
"Registered tools:",
|
|
28
|
+
toolList
|
|
29
|
+
].join("\n");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/orchestrator.ts
|
|
33
|
+
var Orchestrator = class {
|
|
34
|
+
llm;
|
|
35
|
+
tools;
|
|
36
|
+
budgets;
|
|
37
|
+
async completeJSON(input) {
|
|
38
|
+
const out1 = await this.llm.complete(input);
|
|
39
|
+
const t1 = out1.content.trim();
|
|
40
|
+
if (safeParseJSONLoose(t1)) return t1;
|
|
41
|
+
const retryMessages = [
|
|
42
|
+
...input.messages,
|
|
43
|
+
{
|
|
44
|
+
role: "user",
|
|
45
|
+
content: "Your previous response was not valid JSON. Reply again with ONLY a single JSON object that follows the protocol. No markdown. No extra text."
|
|
46
|
+
}
|
|
47
|
+
];
|
|
48
|
+
const out2 = await this.llm.complete({ ...input, messages: retryMessages });
|
|
49
|
+
return out2.content.trim();
|
|
50
|
+
}
|
|
51
|
+
constructor(opts) {
|
|
52
|
+
this.llm = opts.llm;
|
|
53
|
+
this.tools = opts.tools ?? [];
|
|
54
|
+
this.budgets = {
|
|
55
|
+
timeMs: opts.budgets?.timeMs ?? 6e4,
|
|
56
|
+
maxSteps: opts.budgets?.maxSteps ?? 20,
|
|
57
|
+
maxSpawns: opts.budgets?.maxSpawns ?? 4
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
async run(input) {
|
|
61
|
+
const runId = `to_${crypto.randomUUID()}`;
|
|
62
|
+
const trace = [];
|
|
63
|
+
const tracePush = (event) => trace.push(event);
|
|
64
|
+
const abort = new AbortController();
|
|
65
|
+
const timer = setTimeout(() => abort.abort(new Error("time budget exceeded")), this.budgets.timeMs);
|
|
66
|
+
const ctx = {
|
|
67
|
+
runId,
|
|
68
|
+
signal: abort.signal,
|
|
69
|
+
trace: tracePush
|
|
70
|
+
};
|
|
71
|
+
tracePush({ t: "run.start", runId, goal: input.goal, at: Date.now() });
|
|
72
|
+
const system = buildDefaultSystemPrompt({ tools: this.tools });
|
|
73
|
+
const toolMap = new Map(this.tools.map((t) => [t.name, t]));
|
|
74
|
+
const messages = [
|
|
75
|
+
{
|
|
76
|
+
role: "user",
|
|
77
|
+
content: JSON.stringify(
|
|
78
|
+
{
|
|
79
|
+
goal: input.goal,
|
|
80
|
+
context: input.context ?? {}
|
|
81
|
+
},
|
|
82
|
+
null,
|
|
83
|
+
2
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
];
|
|
87
|
+
for (let step = 0; step < this.budgets.maxSteps; step++) {
|
|
88
|
+
const text = await this.completeJSON({ system, messages, signal: abort.signal });
|
|
89
|
+
messages.push({ role: "assistant", content: text });
|
|
90
|
+
const parsed = safeParseJSONLoose(text);
|
|
91
|
+
if (!parsed || typeof parsed !== "object") {
|
|
92
|
+
clearTimeout(timer);
|
|
93
|
+
tracePush({ t: "run.end", runId, at: Date.now(), summary: text });
|
|
94
|
+
return { runId, summary: text, trace };
|
|
95
|
+
}
|
|
96
|
+
const type = parsed.type;
|
|
97
|
+
if (type === "final") {
|
|
98
|
+
const summary2 = String(parsed.content ?? "").trim();
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
tracePush({ t: "run.end", runId, at: Date.now(), summary: summary2 });
|
|
101
|
+
return { runId, summary: summary2, trace };
|
|
102
|
+
}
|
|
103
|
+
if (type !== "tool") {
|
|
104
|
+
clearTimeout(timer);
|
|
105
|
+
tracePush({ t: "run.end", runId, at: Date.now(), summary: text });
|
|
106
|
+
return { runId, summary: text, trace };
|
|
107
|
+
}
|
|
108
|
+
const toolName = String(parsed.name ?? "");
|
|
109
|
+
const args = parsed.args ?? {};
|
|
110
|
+
tracePush({ t: "tool.call", runId, at: Date.now(), tool: toolName, args });
|
|
111
|
+
const tool = toolMap.get(toolName);
|
|
112
|
+
if (!tool) {
|
|
113
|
+
const error = `unknown tool: ${toolName}`;
|
|
114
|
+
tracePush({ t: "tool.result", runId, at: Date.now(), tool: toolName, ok: false, error });
|
|
115
|
+
messages.push({
|
|
116
|
+
role: "user",
|
|
117
|
+
content: JSON.stringify({ type: "tool_result", name: toolName, ok: false, error }, null, 2)
|
|
118
|
+
});
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const result = await tool.run(args, ctx);
|
|
123
|
+
tracePush({ t: "tool.result", runId, at: Date.now(), tool: toolName, ok: true, result });
|
|
124
|
+
messages.push({
|
|
125
|
+
role: "user",
|
|
126
|
+
content: JSON.stringify({ type: "tool_result", name: toolName, ok: true, result }, null, 2)
|
|
127
|
+
});
|
|
128
|
+
} catch (e) {
|
|
129
|
+
const error = e instanceof Error ? e.message : String(e);
|
|
130
|
+
tracePush({ t: "tool.result", runId, at: Date.now(), tool: toolName, ok: false, error });
|
|
131
|
+
messages.push({
|
|
132
|
+
role: "user",
|
|
133
|
+
content: JSON.stringify({ type: "tool_result", name: toolName, ok: false, error }, null, 2)
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
clearTimeout(timer);
|
|
138
|
+
const summary = `maxSteps exceeded (${this.budgets.maxSteps})`;
|
|
139
|
+
tracePush({ t: "run.end", runId, at: Date.now(), summary });
|
|
140
|
+
return { runId, summary, trace };
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
function safeParseJSONLoose(text) {
|
|
144
|
+
try {
|
|
145
|
+
return JSON.parse(text);
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
const extracted = extractFirstJSONObject(text);
|
|
149
|
+
if (!extracted) return null;
|
|
150
|
+
try {
|
|
151
|
+
return JSON.parse(extracted);
|
|
152
|
+
} catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function extractFirstJSONObject(text) {
|
|
157
|
+
const start = text.indexOf("{");
|
|
158
|
+
if (start < 0) return null;
|
|
159
|
+
let depth = 0;
|
|
160
|
+
let inString = false;
|
|
161
|
+
let escape = false;
|
|
162
|
+
for (let i = start; i < text.length; i++) {
|
|
163
|
+
const ch = text[i];
|
|
164
|
+
if (inString) {
|
|
165
|
+
if (escape) {
|
|
166
|
+
escape = false;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (ch === "\\") {
|
|
170
|
+
escape = true;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (ch === '"') {
|
|
174
|
+
inString = false;
|
|
175
|
+
}
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (ch === '"') {
|
|
179
|
+
inString = true;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (ch === "{") depth++;
|
|
183
|
+
if (ch === "}") depth--;
|
|
184
|
+
if (depth === 0) {
|
|
185
|
+
return text.slice(start, i + 1);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export { Orchestrator };
|
|
192
|
+
//# sourceMappingURL=index.js.map
|
|
193
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/prompts.ts","../src/orchestrator.ts"],"names":["summary"],"mappings":"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","file":"index.js","sourcesContent":["import type { Tool } from \"./types\";\n\nexport function buildDefaultSystemPrompt(params: { tools: Tool[] }) {\n const toolList = params.tools.length\n ? params.tools.map((t) => `- ${t.name}${t.description ? `: ${t.description}` : \"\"}`).join(\"\\n\")\n : \"- (no tools registered)\";\n\n return [\n \"You are Tiny Orchestrator.\",\n \"You are allowed to call developer-provided tools.\",\n \"\",\n \"Rules:\",\n \"- Be direct.\",\n \"- Prefer concrete steps and checklists.\",\n \"- If information is missing, call tools (if available) or ask exactly what you need.\",\n \"\",\n \"Tool calling protocol (IMPORTANT):\",\n \"- You MUST respond with a single JSON object, and NOTHING else.\",\n \"- Either request a tool:\",\n \" { \\\"type\\\": \\\"tool\\\", \\\"name\\\": \\\"toolName\\\", \\\"args\\\": { ... } }\",\n \"- Or finish with a final answer:\",\n \" { \\\"type\\\": \\\"final\\\", \\\"content\\\": \\\"...\\\" }\",\n \"- After you request a tool, you will receive a user message of the form:\",\n \" { \\\"type\\\": \\\"tool_result\\\", \\\"name\\\": \\\"toolName\\\", \\\"ok\\\": true|false, \\\"result\\\": ..., \\\"error\\\": \\\"...\\\" }\",\n \"- Do not wrap JSON in markdown. Do not include explanations outside JSON.\",\n \"\",\n \"Registered tools:\",\n toolList,\n ].join(\"\\n\");\n}\n","import crypto from \"node:crypto\";\nimport { buildDefaultSystemPrompt } from \"./prompts\";\nimport type { LLMMessage } from \"./llm\";\nimport type { OrchestratorOptions, RunInput, RunResult, Tool, ToolContext, TraceEvent } from \"./types\";\n\nexport class Orchestrator {\n private llm: OrchestratorOptions[\"llm\"];\n private tools: Tool[];\n private budgets: Required<NonNullable<OrchestratorOptions[\"budgets\"]>>;\n\n private async completeJSON(input: Parameters<OrchestratorOptions[\"llm\"][\"complete\"]>[0]): Promise<string> {\n const out1 = await this.llm.complete(input);\n const t1 = out1.content.trim();\n if (safeParseJSONLoose(t1)) return t1;\n\n // One corrective retry. This is the common failure mode: the model adds prose.\n const retryMessages: LLMMessage[] = [\n ...input.messages,\n {\n role: \"user\",\n content:\n \"Your previous response was not valid JSON. Reply again with ONLY a single JSON object that follows the protocol. No markdown. No extra text.\",\n },\n ];\n\n const out2 = await this.llm.complete({ ...input, messages: retryMessages });\n return out2.content.trim();\n }\n\n constructor(opts: OrchestratorOptions) {\n this.llm = opts.llm;\n this.tools = opts.tools ?? [];\n this.budgets = {\n timeMs: opts.budgets?.timeMs ?? 60_000,\n maxSteps: opts.budgets?.maxSteps ?? 20,\n maxSpawns: opts.budgets?.maxSpawns ?? 4,\n };\n }\n\n async run(input: RunInput): Promise<RunResult> {\n const runId = `to_${crypto.randomUUID()}`;\n const trace: TraceEvent[] = [];\n const tracePush = (event: TraceEvent) => trace.push(event);\n\n const abort = new AbortController();\n const timer = setTimeout(() => abort.abort(new Error(\"time budget exceeded\")), this.budgets.timeMs);\n\n const ctx: ToolContext = {\n runId,\n signal: abort.signal,\n trace: tracePush,\n };\n\n tracePush({ t: \"run.start\", runId, goal: input.goal, at: Date.now() });\n\n const system = buildDefaultSystemPrompt({ tools: this.tools });\n\n const toolMap = new Map(this.tools.map((t) => [t.name, t] as const));\n\n const messages: LLMMessage[] = [\n {\n role: \"user\",\n content: JSON.stringify(\n {\n goal: input.goal,\n context: input.context ?? {},\n },\n null,\n 2,\n ),\n },\n ];\n\n for (let step = 0; step < this.budgets.maxSteps; step++) {\n const text = await this.completeJSON({ system, messages, signal: abort.signal });\n\n // Always record model output in the conversation.\n messages.push({ role: \"assistant\", content: text });\n\n const parsed = safeParseJSONLoose(text);\n if (!parsed || typeof parsed !== \"object\") {\n clearTimeout(timer);\n tracePush({ t: \"run.end\", runId, at: Date.now(), summary: text });\n return { runId, summary: text, trace };\n }\n\n const type = (parsed as any).type;\n if (type === \"final\") {\n const summary = String((parsed as any).content ?? \"\").trim();\n clearTimeout(timer);\n tracePush({ t: \"run.end\", runId, at: Date.now(), summary });\n return { runId, summary, trace };\n }\n\n if (type !== \"tool\") {\n // Unknown protocol → treat as final.\n clearTimeout(timer);\n tracePush({ t: \"run.end\", runId, at: Date.now(), summary: text });\n return { runId, summary: text, trace };\n }\n\n const toolName = String((parsed as any).name ?? \"\");\n const args = (parsed as any).args ?? {};\n tracePush({ t: \"tool.call\", runId, at: Date.now(), tool: toolName, args });\n\n const tool = toolMap.get(toolName);\n if (!tool) {\n const error = `unknown tool: ${toolName}`;\n tracePush({ t: \"tool.result\", runId, at: Date.now(), tool: toolName, ok: false, error });\n messages.push({\n role: \"user\",\n content: JSON.stringify({ type: \"tool_result\", name: toolName, ok: false, error }, null, 2),\n });\n continue;\n }\n\n try {\n const result = await tool.run(args, ctx);\n tracePush({ t: \"tool.result\", runId, at: Date.now(), tool: toolName, ok: true, result });\n messages.push({\n role: \"user\",\n content: JSON.stringify({ type: \"tool_result\", name: toolName, ok: true, result }, null, 2),\n });\n } catch (e) {\n const error = e instanceof Error ? e.message : String(e);\n tracePush({ t: \"tool.result\", runId, at: Date.now(), tool: toolName, ok: false, error });\n messages.push({\n role: \"user\",\n content: JSON.stringify({ type: \"tool_result\", name: toolName, ok: false, error }, null, 2),\n });\n }\n }\n\n clearTimeout(timer);\n const summary = `maxSteps exceeded (${this.budgets.maxSteps})`;\n tracePush({ t: \"run.end\", runId, at: Date.now(), summary });\n return { runId, summary, trace };\n }\n}\n\nfunction safeParseJSONLoose(text: string): unknown | null {\n // Strict first.\n try {\n return JSON.parse(text);\n } catch {\n // Fall through.\n }\n\n // Then try to extract the first JSON object from messy output.\n const extracted = extractFirstJSONObject(text);\n if (!extracted) return null;\n\n try {\n return JSON.parse(extracted);\n } catch {\n return null;\n }\n}\n\nfunction extractFirstJSONObject(text: string): string | null {\n const start = text.indexOf(\"{\");\n if (start < 0) return null;\n\n let depth = 0;\n let inString = false;\n let escape = false;\n\n for (let i = start; i < text.length; i++) {\n const ch = text[i];\n\n if (inString) {\n if (escape) {\n escape = false;\n continue;\n }\n if (ch === \"\\\\\") {\n escape = true;\n continue;\n }\n if (ch === \"\\\"\") {\n inString = false;\n }\n continue;\n }\n\n if (ch === \"\\\"\") {\n inString = true;\n continue;\n }\n\n if (ch === \"{\") depth++;\n if (ch === \"}\") depth--;\n\n if (depth === 0) {\n return text.slice(start, i + 1);\n }\n }\n\n return null;\n}\n\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type TemplateAgent = {
|
|
2
|
+
name: string;
|
|
3
|
+
system: string;
|
|
4
|
+
};
|
|
5
|
+
declare function researcher(): TemplateAgent;
|
|
6
|
+
declare function reviewer(): TemplateAgent;
|
|
7
|
+
declare function writer(): TemplateAgent;
|
|
8
|
+
|
|
9
|
+
export { type TemplateAgent, researcher, reviewer, writer };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// src/templates/index.ts
|
|
2
|
+
function researcher() {
|
|
3
|
+
return {
|
|
4
|
+
name: "researcher",
|
|
5
|
+
system: [
|
|
6
|
+
"You are a research agent.",
|
|
7
|
+
"Return:",
|
|
8
|
+
"- bullet findings",
|
|
9
|
+
"- sources (URLs) when available",
|
|
10
|
+
"- uncertainties"
|
|
11
|
+
].join("\n")
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function reviewer() {
|
|
15
|
+
return {
|
|
16
|
+
name: "reviewer",
|
|
17
|
+
system: [
|
|
18
|
+
"You are a code reviewer.",
|
|
19
|
+
"Return:",
|
|
20
|
+
"- summary",
|
|
21
|
+
"- risks",
|
|
22
|
+
"- suggested changes",
|
|
23
|
+
"- tests to add"
|
|
24
|
+
].join("\n")
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function writer() {
|
|
28
|
+
return {
|
|
29
|
+
name: "writer",
|
|
30
|
+
system: [
|
|
31
|
+
"You are a technical writer.",
|
|
32
|
+
"Write a clean, concise draft."
|
|
33
|
+
].join("\n")
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { researcher, reviewer, writer };
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
39
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/templates/index.ts"],"names":[],"mappings":";AAKO,SAAS,UAAA,GAA4B;AAC1C,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,YAAA;AAAA,IACN,MAAA,EAAQ;AAAA,MACN,2BAAA;AAAA,MACA,SAAA;AAAA,MACA,mBAAA;AAAA,MACA,iCAAA;AAAA,MACA;AAAA,KACF,CAAE,KAAK,IAAI;AAAA,GACb;AACF;AAEO,SAAS,QAAA,GAA0B;AACxC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,MAAA,EAAQ;AAAA,MACN,0BAAA;AAAA,MACA,SAAA;AAAA,MACA,WAAA;AAAA,MACA,SAAA;AAAA,MACA,qBAAA;AAAA,MACA;AAAA,KACF,CAAE,KAAK,IAAI;AAAA,GACb;AACF;AAEO,SAAS,MAAA,GAAwB;AACtC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA;AAAA,IACN,MAAA,EAAQ;AAAA,MACN,6BAAA;AAAA,MACA;AAAA,KACF,CAAE,KAAK,IAAI;AAAA,GACb;AACF","file":"index.js","sourcesContent":["export type TemplateAgent = {\n name: string;\n system: string;\n};\n\nexport function researcher(): TemplateAgent {\n return {\n name: \"researcher\",\n system: [\n \"You are a research agent.\",\n \"Return:\",\n \"- bullet findings\",\n \"- sources (URLs) when available\",\n \"- uncertainties\",\n ].join(\"\\n\"),\n };\n}\n\nexport function reviewer(): TemplateAgent {\n return {\n name: \"reviewer\",\n system: [\n \"You are a code reviewer.\",\n \"Return:\",\n \"- summary\",\n \"- risks\",\n \"- suggested changes\",\n \"- tests to add\",\n ].join(\"\\n\"),\n };\n}\n\nexport function writer(): TemplateAgent {\n return {\n name: \"writer\",\n system: [\n \"You are a technical writer.\",\n \"Write a clean, concise draft.\",\n ].join(\"\\n\"),\n };\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tiny-orchestrator",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "A tiny TypeScript multi-agent runner with sane defaults, templates, and traces.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./templates": {
|
|
13
|
+
"types": "./dist/templates/index.d.ts",
|
|
14
|
+
"import": "./dist/templates/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"test": "vitest",
|
|
28
|
+
"test:node": "npm run build && node ./scripts/node-smoke-test.mjs",
|
|
29
|
+
"lint": "tsc -p tsconfig.json --noEmit",
|
|
30
|
+
"prepublishOnly": "npm run build && npm run lint && npm test"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@esbuild/darwin-arm64": "0.27.3",
|
|
34
|
+
"@types/node": "^20.19.0",
|
|
35
|
+
"tsup": "^8.5.0",
|
|
36
|
+
"typescript": "^5.9.3",
|
|
37
|
+
"vitest": "^3.2.4"
|
|
38
|
+
}
|
|
39
|
+
}
|