@jellyos/agent 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.
- package/README.md +375 -0
- package/bin/jellyagent +31 -0
- package/dist/api/ExtensionAPI.d.ts +92 -0
- package/dist/api/ExtensionAPI.d.ts.map +1 -0
- package/dist/api/ExtensionAPI.js +15 -0
- package/dist/api/ExtensionAPI.js.map +1 -0
- package/dist/api/Registry.d.ts +54 -0
- package/dist/api/Registry.d.ts.map +1 -0
- package/dist/api/Registry.js +101 -0
- package/dist/api/Registry.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +134 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +23 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +84 -0
- package/dist/loader.js.map +1 -0
- package/dist/runner/AgentRunner.d.ts +66 -0
- package/dist/runner/AgentRunner.d.ts.map +1 -0
- package/dist/runner/AgentRunner.js +179 -0
- package/dist/runner/AgentRunner.js.map +1 -0
- package/dist/runner/ModelClient.d.ts +77 -0
- package/dist/runner/ModelClient.d.ts.map +1 -0
- package/dist/runner/ModelClient.js +224 -0
- package/dist/runner/ModelClient.js.map +1 -0
- package/dist/runner/SwarmRouter.d.ts +58 -0
- package/dist/runner/SwarmRouter.d.ts.map +1 -0
- package/dist/runner/SwarmRouter.js +153 -0
- package/dist/runner/SwarmRouter.js.map +1 -0
- package/dist/runner/ToolDispatcher.d.ts +19 -0
- package/dist/runner/ToolDispatcher.d.ts.map +1 -0
- package/dist/runner/ToolDispatcher.js +64 -0
- package/dist/runner/ToolDispatcher.js.map +1 -0
- package/dist/session/SessionManager.d.ts +23 -0
- package/dist/session/SessionManager.d.ts.map +1 -0
- package/dist/session/SessionManager.js +50 -0
- package/dist/session/SessionManager.js.map +1 -0
- package/dist/tui/App.d.ts +18 -0
- package/dist/tui/App.d.ts.map +1 -0
- package/dist/tui/App.js +188 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/REPL.d.ts +22 -0
- package/dist/tui/REPL.d.ts.map +1 -0
- package/dist/tui/REPL.js +46 -0
- package/dist/tui/REPL.js.map +1 -0
- package/dist/tui/StatusBar.d.ts +16 -0
- package/dist/tui/StatusBar.d.ts.map +1 -0
- package/dist/tui/StatusBar.js +15 -0
- package/dist/tui/StatusBar.js.map +1 -0
- package/dist/tui/theme.d.ts +30 -0
- package/dist/tui/theme.d.ts.map +1 -0
- package/dist/tui/theme.js +41 -0
- package/dist/tui/theme.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModelClient — sends messages to any OpenAI-compatible model API.
|
|
3
|
+
*
|
|
4
|
+
* Provider priority (auto-detected from env):
|
|
5
|
+
* OpenRouter > Anthropic compat > OpenAI > local (ollama/lm-studio)
|
|
6
|
+
*
|
|
7
|
+
* Model rotation: resolveModelChain() returns up to 5 configs — the AgentRunner
|
|
8
|
+
* walks the chain on 429 (rate limit) or 5xx errors, providing seamless fallback.
|
|
9
|
+
*
|
|
10
|
+
* All outbound, all local — no inbound ports, no server.
|
|
11
|
+
*/
|
|
12
|
+
export interface Message {
|
|
13
|
+
role: "system" | "user" | "assistant" | "tool";
|
|
14
|
+
content: string | null;
|
|
15
|
+
name?: string;
|
|
16
|
+
tool_calls?: ToolCall[];
|
|
17
|
+
tool_call_id?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ToolCall {
|
|
20
|
+
id: string;
|
|
21
|
+
type: "function";
|
|
22
|
+
function: {
|
|
23
|
+
name: string;
|
|
24
|
+
arguments: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export interface ChatChunk {
|
|
28
|
+
type: "delta" | "tool_call" | "done" | "error";
|
|
29
|
+
text?: string;
|
|
30
|
+
tool_calls?: ToolCall[];
|
|
31
|
+
error?: string;
|
|
32
|
+
finish_reason?: string;
|
|
33
|
+
/** HTTP status code — used by AgentRunner for rate-limit detection */
|
|
34
|
+
status?: number;
|
|
35
|
+
}
|
|
36
|
+
export interface ModelConfig {
|
|
37
|
+
baseUrl: string;
|
|
38
|
+
apiKey: string;
|
|
39
|
+
model: string;
|
|
40
|
+
maxTokens: number;
|
|
41
|
+
temperature: number;
|
|
42
|
+
siteUrl?: string;
|
|
43
|
+
siteName?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build the ordered model fallback chain.
|
|
47
|
+
*
|
|
48
|
+
* User-configurable pool: JELLY_MODEL_1 … JELLY_MODEL_5
|
|
49
|
+
* If any JELLY_MODEL_N vars are set they take priority; up to 5 are used in
|
|
50
|
+
* order. Unset slots are filled with provider-appropriate defaults.
|
|
51
|
+
*
|
|
52
|
+
* JELLY_MODEL_N format: just the model ID string, e.g.
|
|
53
|
+
* JELLY_MODEL_1=anthropic/claude-opus-4-5
|
|
54
|
+
* JELLY_MODEL_2=openai/gpt-4o
|
|
55
|
+
* JELLY_MODEL_3=google/gemini-2.5-pro
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveModelChain(): ModelConfig[];
|
|
58
|
+
/** Convenience: returns just the primary (first) model config */
|
|
59
|
+
export declare function resolveModelConfig(): ModelConfig;
|
|
60
|
+
export declare class ModelClient {
|
|
61
|
+
private cfg;
|
|
62
|
+
constructor(cfg: ModelConfig);
|
|
63
|
+
/**
|
|
64
|
+
* Stream a chat completion. Yields ChatChunk objects.
|
|
65
|
+
* On HTTP error the generator yields a single { type: "error", status, error }
|
|
66
|
+
* chunk and returns — the caller (AgentRunner) decides whether to rotate.
|
|
67
|
+
*/
|
|
68
|
+
stream(messages: Message[], tools?: Array<{
|
|
69
|
+
type: "function";
|
|
70
|
+
function: {
|
|
71
|
+
name: string;
|
|
72
|
+
description: string;
|
|
73
|
+
parameters: unknown;
|
|
74
|
+
};
|
|
75
|
+
}>): AsyncGenerator<ChatChunk>;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=ModelClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModelClient.d.ts","sourceRoot":"","sources":["../../src/runner/ModelClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAW,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IACxD,OAAO,EAAQ,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,CAAC,EAAU,MAAM,CAAC;IACtB,UAAU,CAAC,EAAI,QAAQ,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAQ,MAAM,CAAC;IACjB,IAAI,EAAM,UAAU,CAAC;IACrB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAY,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;IACzD,IAAI,CAAC,EAAW,MAAM,CAAC;IACvB,UAAU,CAAC,EAAK,QAAQ,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAU,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sEAAsE;IACtE,MAAM,CAAC,EAAS,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAM,MAAM,CAAC;IACpB,MAAM,EAAO,MAAM,CAAC;IACpB,KAAK,EAAQ,MAAM,CAAC;IACpB,SAAS,EAAI,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAK,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAI,MAAM,CAAC;CACrB;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,EAAE,CAgFjD;AAED,iEAAiE;AACjE,wBAAgB,kBAAkB,IAAI,WAAW,CAEhD;AAID,qBAAa,WAAW;IACV,OAAO,CAAC,GAAG;gBAAH,GAAG,EAAE,WAAW;IAEpC;;;;OAIG;IACI,MAAM,CACX,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE,CAAC,GACxG,cAAc,CAAC,SAAS,CAAC;CA2G7B"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModelClient — sends messages to any OpenAI-compatible model API.
|
|
3
|
+
*
|
|
4
|
+
* Provider priority (auto-detected from env):
|
|
5
|
+
* OpenRouter > Anthropic compat > OpenAI > local (ollama/lm-studio)
|
|
6
|
+
*
|
|
7
|
+
* Model rotation: resolveModelChain() returns up to 5 configs — the AgentRunner
|
|
8
|
+
* walks the chain on 429 (rate limit) or 5xx errors, providing seamless fallback.
|
|
9
|
+
*
|
|
10
|
+
* All outbound, all local — no inbound ports, no server.
|
|
11
|
+
*/
|
|
12
|
+
// ── Model rotation chain ──────────────────────────────────────────────────────
|
|
13
|
+
/**
|
|
14
|
+
* Build the ordered model fallback chain.
|
|
15
|
+
*
|
|
16
|
+
* User-configurable pool: JELLY_MODEL_1 … JELLY_MODEL_5
|
|
17
|
+
* If any JELLY_MODEL_N vars are set they take priority; up to 5 are used in
|
|
18
|
+
* order. Unset slots are filled with provider-appropriate defaults.
|
|
19
|
+
*
|
|
20
|
+
* JELLY_MODEL_N format: just the model ID string, e.g.
|
|
21
|
+
* JELLY_MODEL_1=anthropic/claude-opus-4-5
|
|
22
|
+
* JELLY_MODEL_2=openai/gpt-4o
|
|
23
|
+
* JELLY_MODEL_3=google/gemini-2.5-pro
|
|
24
|
+
*/
|
|
25
|
+
export function resolveModelChain() {
|
|
26
|
+
const env = process.env;
|
|
27
|
+
const tokens = parseInt(env.MAX_TOKENS ?? "8192");
|
|
28
|
+
const temp = parseFloat(env.TEMPERATURE ?? "0.7");
|
|
29
|
+
// ── Collect user-configured model IDs (JELLY_MODEL_1..5) ────────────────
|
|
30
|
+
const userModels = [];
|
|
31
|
+
for (let i = 1; i <= 5; i++) {
|
|
32
|
+
const m = env[`JELLY_MODEL_${i}`];
|
|
33
|
+
if (m?.trim())
|
|
34
|
+
userModels.push(m.trim());
|
|
35
|
+
}
|
|
36
|
+
// ── OpenRouter — supports all providers via a single key ─────────────────
|
|
37
|
+
if (env.OPENROUTER_API_KEY) {
|
|
38
|
+
const base = "https://openrouter.ai/api/v1";
|
|
39
|
+
const key = env.OPENROUTER_API_KEY;
|
|
40
|
+
const siteUrl = env.OPENROUTER_SITE_URL ?? "https://jellychain.fun";
|
|
41
|
+
const siteName = env.OPENROUTER_SITE_NAME ?? "JellyOS";
|
|
42
|
+
const mk = (model) => ({
|
|
43
|
+
baseUrl: base, apiKey: key, model, maxTokens: tokens, temperature: temp,
|
|
44
|
+
siteUrl, siteName,
|
|
45
|
+
});
|
|
46
|
+
const defaults = [
|
|
47
|
+
env.DEFAULT_MODEL ?? "anthropic/claude-sonnet-4-5",
|
|
48
|
+
"anthropic/claude-3-haiku",
|
|
49
|
+
"openai/gpt-4o-mini",
|
|
50
|
+
"google/gemini-flash-1.5",
|
|
51
|
+
"meta-llama/llama-3-8b-instruct:free",
|
|
52
|
+
];
|
|
53
|
+
// Merge: user-configured models first, then fill remaining slots with defaults
|
|
54
|
+
const merged = [...userModels, ...defaults.filter(d => !userModels.includes(d))].slice(0, 5);
|
|
55
|
+
return merged.map(mk);
|
|
56
|
+
}
|
|
57
|
+
// ── Anthropic direct (OpenAI-compat endpoint) ────────────────────────────
|
|
58
|
+
if (env.ANTHROPIC_API_KEY) {
|
|
59
|
+
const base = "https://api.anthropic.com/v1";
|
|
60
|
+
const key = env.ANTHROPIC_API_KEY;
|
|
61
|
+
const mk = (model) => ({
|
|
62
|
+
baseUrl: base, apiKey: key, model, maxTokens: tokens, temperature: temp,
|
|
63
|
+
});
|
|
64
|
+
const defaults = [
|
|
65
|
+
env.DEFAULT_MODEL ?? "claude-sonnet-4-5-20251101",
|
|
66
|
+
"claude-3-haiku-20240307",
|
|
67
|
+
"claude-3-5-haiku-20241022",
|
|
68
|
+
];
|
|
69
|
+
const merged = [...userModels, ...defaults.filter(d => !userModels.includes(d))].slice(0, 5);
|
|
70
|
+
return merged.map(mk);
|
|
71
|
+
}
|
|
72
|
+
// ── OpenAI direct ────────────────────────────────────────────────────────
|
|
73
|
+
if (env.OPENAI_API_KEY) {
|
|
74
|
+
const base = env.OPENAI_BASE_URL ?? "https://api.openai.com/v1";
|
|
75
|
+
const key = env.OPENAI_API_KEY;
|
|
76
|
+
const mk = (model) => ({
|
|
77
|
+
baseUrl: base, apiKey: key, model, maxTokens: tokens, temperature: temp,
|
|
78
|
+
});
|
|
79
|
+
const defaults = [
|
|
80
|
+
env.DEFAULT_MODEL ?? "gpt-4o",
|
|
81
|
+
"gpt-4o-mini",
|
|
82
|
+
"gpt-3.5-turbo",
|
|
83
|
+
];
|
|
84
|
+
const merged = [...userModels, ...defaults.filter(d => !userModels.includes(d))].slice(0, 5);
|
|
85
|
+
return merged.map(mk);
|
|
86
|
+
}
|
|
87
|
+
// ── Local model (ollama, lm-studio, etc.) — single entry, no rotation ───
|
|
88
|
+
if (env.OPENAI_BASE_URL) {
|
|
89
|
+
return [{
|
|
90
|
+
baseUrl: env.OPENAI_BASE_URL,
|
|
91
|
+
apiKey: env.OPENAI_API_KEY ?? "local",
|
|
92
|
+
model: userModels[0] ?? env.DEFAULT_MODEL ?? "llama3",
|
|
93
|
+
maxTokens: tokens,
|
|
94
|
+
temperature: temp,
|
|
95
|
+
}];
|
|
96
|
+
}
|
|
97
|
+
throw new Error("No API key found. Set OPENROUTER_API_KEY, ANTHROPIC_API_KEY, or OPENAI_API_KEY in ~/.jellyos/.env");
|
|
98
|
+
}
|
|
99
|
+
/** Convenience: returns just the primary (first) model config */
|
|
100
|
+
export function resolveModelConfig() {
|
|
101
|
+
return resolveModelChain()[0];
|
|
102
|
+
}
|
|
103
|
+
// ── ModelClient ───────────────────────────────────────────────────────────────
|
|
104
|
+
export class ModelClient {
|
|
105
|
+
cfg;
|
|
106
|
+
constructor(cfg) {
|
|
107
|
+
this.cfg = cfg;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Stream a chat completion. Yields ChatChunk objects.
|
|
111
|
+
* On HTTP error the generator yields a single { type: "error", status, error }
|
|
112
|
+
* chunk and returns — the caller (AgentRunner) decides whether to rotate.
|
|
113
|
+
*/
|
|
114
|
+
async *stream(messages, tools) {
|
|
115
|
+
const headers = {
|
|
116
|
+
"Content-Type": "application/json",
|
|
117
|
+
"Authorization": `Bearer ${this.cfg.apiKey}`,
|
|
118
|
+
"User-Agent": "JellyOS/1.0",
|
|
119
|
+
};
|
|
120
|
+
if (this.cfg.siteUrl)
|
|
121
|
+
headers["HTTP-Referer"] = this.cfg.siteUrl;
|
|
122
|
+
if (this.cfg.siteName)
|
|
123
|
+
headers["X-Title"] = this.cfg.siteName;
|
|
124
|
+
const body = {
|
|
125
|
+
model: this.cfg.model,
|
|
126
|
+
messages,
|
|
127
|
+
max_tokens: this.cfg.maxTokens,
|
|
128
|
+
temperature: this.cfg.temperature,
|
|
129
|
+
stream: true,
|
|
130
|
+
};
|
|
131
|
+
if (tools && tools.length > 0) {
|
|
132
|
+
body.tools = tools;
|
|
133
|
+
body.tool_choice = "auto";
|
|
134
|
+
}
|
|
135
|
+
let res;
|
|
136
|
+
try {
|
|
137
|
+
res = await fetch(`${this.cfg.baseUrl}/chat/completions`, {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers,
|
|
140
|
+
body: JSON.stringify(body),
|
|
141
|
+
signal: AbortSignal.timeout(120_000),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
catch (e) {
|
|
145
|
+
yield { type: "error", error: `Network error: ${e.message}`, status: 0 };
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (!res.ok) {
|
|
149
|
+
const err = await res.text().catch(() => res.statusText);
|
|
150
|
+
yield { type: "error", error: `Model API ${res.status}: ${err}`, status: res.status };
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
// Accumulate tool calls across chunks (they arrive fragmented)
|
|
154
|
+
const toolCallMap = new Map();
|
|
155
|
+
const reader = res.body.getReader();
|
|
156
|
+
const decoder = new TextDecoder();
|
|
157
|
+
let buf = "";
|
|
158
|
+
while (true) {
|
|
159
|
+
const { done, value } = await reader.read();
|
|
160
|
+
if (done)
|
|
161
|
+
break;
|
|
162
|
+
buf += decoder.decode(value, { stream: true });
|
|
163
|
+
const lines = buf.split("\n");
|
|
164
|
+
buf = lines.pop() ?? "";
|
|
165
|
+
for (const line of lines) {
|
|
166
|
+
const trimmed = line.trim();
|
|
167
|
+
if (!trimmed || trimmed === "data: [DONE]")
|
|
168
|
+
continue;
|
|
169
|
+
if (!trimmed.startsWith("data: "))
|
|
170
|
+
continue;
|
|
171
|
+
let chunk;
|
|
172
|
+
try {
|
|
173
|
+
chunk = JSON.parse(trimmed.slice(6));
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const delta = chunk.choices?.[0]?.delta;
|
|
179
|
+
if (!delta)
|
|
180
|
+
continue;
|
|
181
|
+
if (delta.content) {
|
|
182
|
+
yield { type: "delta", text: delta.content };
|
|
183
|
+
}
|
|
184
|
+
if (delta.tool_calls) {
|
|
185
|
+
for (const tc of delta.tool_calls) {
|
|
186
|
+
const idx = tc.index ?? 0;
|
|
187
|
+
const existing = toolCallMap.get(idx) ?? { id: "", name: "", args: "" };
|
|
188
|
+
if (tc.id)
|
|
189
|
+
existing.id += tc.id;
|
|
190
|
+
if (tc.function?.name)
|
|
191
|
+
existing.name += tc.function.name;
|
|
192
|
+
if (tc.function?.arguments)
|
|
193
|
+
existing.args += tc.function.arguments;
|
|
194
|
+
toolCallMap.set(idx, existing);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const finish = chunk.choices?.[0]?.finish_reason;
|
|
198
|
+
if (finish === "tool_calls" || finish === "stop") {
|
|
199
|
+
if (toolCallMap.size > 0) {
|
|
200
|
+
const tool_calls = [...toolCallMap.values()].map(tc => ({
|
|
201
|
+
id: tc.id || `call_${Date.now()}`,
|
|
202
|
+
type: "function",
|
|
203
|
+
function: { name: tc.name, arguments: tc.args },
|
|
204
|
+
}));
|
|
205
|
+
yield { type: "tool_call", tool_calls };
|
|
206
|
+
toolCallMap.clear();
|
|
207
|
+
}
|
|
208
|
+
yield { type: "done", finish_reason: finish };
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Flush any remaining tool calls if stream ended without finish_reason
|
|
213
|
+
if (toolCallMap.size > 0) {
|
|
214
|
+
const tool_calls = [...toolCallMap.values()].map(tc => ({
|
|
215
|
+
id: tc.id || `call_${Date.now()}`,
|
|
216
|
+
type: "function",
|
|
217
|
+
function: { name: tc.name, arguments: tc.args },
|
|
218
|
+
}));
|
|
219
|
+
yield { type: "tool_call", tool_calls };
|
|
220
|
+
}
|
|
221
|
+
yield { type: "done", finish_reason: "end" };
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=ModelClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModelClient.js","sourceRoot":"","sources":["../../src/runner/ModelClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SwarmRouter — complexity scoring and task decomposition.
|
|
3
|
+
*
|
|
4
|
+
* For complex prompts (score >= threshold) the runner decomposes the request
|
|
5
|
+
* into 2–5 sub-tasks, executes them with a capped worker pool, then feeds all
|
|
6
|
+
* results to a reviewer model that synthesises a final answer.
|
|
7
|
+
*
|
|
8
|
+
* Sub-task execution is sequential inside each worker slot to avoid hammering
|
|
9
|
+
* the provider; concurrency is capped at Math.min(maxAgents, os.cpus().length).
|
|
10
|
+
*/
|
|
11
|
+
export interface SwarmConfig {
|
|
12
|
+
/** Maximum parallel workers (hard cap: 5). Default: min(cpuCount, 3). */
|
|
13
|
+
maxAgents?: number;
|
|
14
|
+
/** Complexity score threshold above which swarm activates. Default: 40. */
|
|
15
|
+
complexityThreshold?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface SubTaskResult {
|
|
18
|
+
task: string;
|
|
19
|
+
result: string;
|
|
20
|
+
model: string;
|
|
21
|
+
ms: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Returns a score 0–100 reflecting prompt complexity.
|
|
25
|
+
* Tuned so "check ETH price" ≈ 10, "analyze ETH and BTC then predict" ≈ 55.
|
|
26
|
+
*/
|
|
27
|
+
export declare function scoreComplexity(prompt: string): number;
|
|
28
|
+
/**
|
|
29
|
+
* Splits a complex prompt into 2–5 focused sub-task strings.
|
|
30
|
+
* Uses simple heuristics so no extra model call is needed.
|
|
31
|
+
*/
|
|
32
|
+
export declare function decompose(prompt: string, maxTasks: number): string[];
|
|
33
|
+
export declare class SwarmRouter {
|
|
34
|
+
private maxAgents;
|
|
35
|
+
private complexityThreshold;
|
|
36
|
+
constructor(cfg?: SwarmConfig);
|
|
37
|
+
/** True when the prompt is complex enough to warrant swarm execution. */
|
|
38
|
+
shouldSwarm(prompt: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Decompose prompt into sub-tasks, execute them in groups of 3 (up to 5
|
|
41
|
+
* agents total), then synthesise with a reviewer model.
|
|
42
|
+
*
|
|
43
|
+
* Groups-of-3 planner:
|
|
44
|
+
* tasks = decompose(prompt, maxAgents) → 2–5 sub-tasks
|
|
45
|
+
* batches = chunk(tasks, 3) → [[t1,t2,t3],[t4,t5]] for 5 tasks
|
|
46
|
+
* each batch runs in parallel; batches run sequentially
|
|
47
|
+
* reviewer model synthesises all results into a unified answer
|
|
48
|
+
*
|
|
49
|
+
* @param prompt - Original user message
|
|
50
|
+
* @param systemPrompt - Current system prompt (passed to each sub-agent + reviewer)
|
|
51
|
+
* @param onProgress - Called as each sub-task completes
|
|
52
|
+
*/
|
|
53
|
+
run(prompt: string, systemPrompt: string, onProgress: (result: SubTaskResult, remaining: number) => void): Promise<{
|
|
54
|
+
synthesis: string;
|
|
55
|
+
subResults: SubTaskResult[];
|
|
56
|
+
}>;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=SwarmRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SwarmRouter.d.ts","sourceRoot":"","sources":["../../src/runner/SwarmRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAI,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAG,MAAM,CAAC;IACf,EAAE,EAAM,MAAM,CAAC;CAChB;AASD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAetD;AAID;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBpE;AAqCD,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,mBAAmB,CAAS;gBAExB,GAAG,GAAE,WAAgB;IAMjC,yEAAyE;IACzE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIpC;;;;;;;;;;;;;OAaG;IACG,GAAG,CACP,MAAM,EAAQ,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAI,CAAC,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,GAC/D,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,aAAa,EAAE,CAAA;KAAE,CAAC;CAoD/D"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SwarmRouter — complexity scoring and task decomposition.
|
|
3
|
+
*
|
|
4
|
+
* For complex prompts (score >= threshold) the runner decomposes the request
|
|
5
|
+
* into 2–5 sub-tasks, executes them with a capped worker pool, then feeds all
|
|
6
|
+
* results to a reviewer model that synthesises a final answer.
|
|
7
|
+
*
|
|
8
|
+
* Sub-task execution is sequential inside each worker slot to avoid hammering
|
|
9
|
+
* the provider; concurrency is capped at Math.min(maxAgents, os.cpus().length).
|
|
10
|
+
*/
|
|
11
|
+
import os from "os";
|
|
12
|
+
import { ModelClient, resolveModelChain } from "./ModelClient.js";
|
|
13
|
+
// ── Complexity scoring ───────────────────────────────────────────────────────
|
|
14
|
+
const CONJUNCTION_RE = /\b(and|also|then|additionally|plus|as well as|furthermore)\b/gi;
|
|
15
|
+
const MULTI_CHAIN_RE = /\b(eth|btc|sol|bnb|avax|matic|cosmos|atom|arb|op)\b/gi;
|
|
16
|
+
const ACTION_VERB_RE = /\b(analyze|compare|predict|scan|check|simulate|estimate|backtest|evaluate|assess)\b/gi;
|
|
17
|
+
const QUESTION_RE = /\?/g;
|
|
18
|
+
/**
|
|
19
|
+
* Returns a score 0–100 reflecting prompt complexity.
|
|
20
|
+
* Tuned so "check ETH price" ≈ 10, "analyze ETH and BTC then predict" ≈ 55.
|
|
21
|
+
*/
|
|
22
|
+
export function scoreComplexity(prompt) {
|
|
23
|
+
const conjunctions = (prompt.match(CONJUNCTION_RE) ?? []).length;
|
|
24
|
+
const chains = new Set((prompt.match(MULTI_CHAIN_RE) ?? []).map(s => s.toLowerCase())).size;
|
|
25
|
+
const actions = (prompt.match(ACTION_VERB_RE) ?? []).length;
|
|
26
|
+
const questions = (prompt.match(QUESTION_RE) ?? []).length;
|
|
27
|
+
const wordCount = prompt.trim().split(/\s+/).length;
|
|
28
|
+
return Math.min(100, conjunctions * 12 +
|
|
29
|
+
chains * 8 +
|
|
30
|
+
actions * 10 +
|
|
31
|
+
questions * 5 +
|
|
32
|
+
Math.floor(wordCount / 8));
|
|
33
|
+
}
|
|
34
|
+
// ── Task decomposition ───────────────────────────────────────────────────────
|
|
35
|
+
/**
|
|
36
|
+
* Splits a complex prompt into 2–5 focused sub-task strings.
|
|
37
|
+
* Uses simple heuristics so no extra model call is needed.
|
|
38
|
+
*/
|
|
39
|
+
export function decompose(prompt, maxTasks) {
|
|
40
|
+
const cap = Math.max(2, Math.min(maxTasks, 5));
|
|
41
|
+
// Split on explicit conjunctions / punctuation
|
|
42
|
+
const parts = prompt
|
|
43
|
+
.split(/,\s*| and | also | then | additionally | plus /i)
|
|
44
|
+
.map(s => s.trim())
|
|
45
|
+
.filter(s => s.length > 4);
|
|
46
|
+
if (parts.length >= 2) {
|
|
47
|
+
return parts.slice(0, cap);
|
|
48
|
+
}
|
|
49
|
+
// Fallback: split action verbs into separate sub-questions
|
|
50
|
+
const verbMatches = [...prompt.matchAll(/\b(analyze|compare|predict|scan|check|estimate|evaluate)\b[^,.?]*/gi)];
|
|
51
|
+
if (verbMatches.length >= 2) {
|
|
52
|
+
return verbMatches.slice(0, cap).map(m => m[0].trim());
|
|
53
|
+
}
|
|
54
|
+
// Cannot decompose meaningfully → return as-is (single task)
|
|
55
|
+
return [prompt];
|
|
56
|
+
}
|
|
57
|
+
// ── Reviewer synthesis ───────────────────────────────────────────────────────
|
|
58
|
+
async function reviewerSynthesize(originalPrompt, results, systemPrompt) {
|
|
59
|
+
const chain = resolveModelChain();
|
|
60
|
+
const cfg = chain[0];
|
|
61
|
+
const client = new ModelClient(cfg);
|
|
62
|
+
const context = results
|
|
63
|
+
.map((r, i) => `### Sub-task ${i + 1}: ${r.task}\n${r.result}`)
|
|
64
|
+
.join("\n\n");
|
|
65
|
+
const messages = [
|
|
66
|
+
{ role: "system", content: systemPrompt },
|
|
67
|
+
{
|
|
68
|
+
role: "user",
|
|
69
|
+
content: `You are a synthesis reviewer. The following sub-tasks were run in response to the user's original request.\n\n` +
|
|
70
|
+
`**Original request:** ${originalPrompt}\n\n${context}\n\n` +
|
|
71
|
+
`Write a concise, unified answer that directly addresses the original request using all the above findings.`,
|
|
72
|
+
},
|
|
73
|
+
];
|
|
74
|
+
let out = "";
|
|
75
|
+
for await (const chunk of client.stream(messages, [])) {
|
|
76
|
+
if (chunk.type === "delta" && chunk.text)
|
|
77
|
+
out += chunk.text;
|
|
78
|
+
}
|
|
79
|
+
return out || results.map(r => r.result).join("\n\n---\n\n");
|
|
80
|
+
}
|
|
81
|
+
// ── SwarmRouter class ────────────────────────────────────────────────────────
|
|
82
|
+
export class SwarmRouter {
|
|
83
|
+
maxAgents;
|
|
84
|
+
complexityThreshold;
|
|
85
|
+
constructor(cfg = {}) {
|
|
86
|
+
const cpus = os.cpus().length;
|
|
87
|
+
this.maxAgents = Math.min(cfg.maxAgents ?? Math.min(cpus, 3), 5);
|
|
88
|
+
this.complexityThreshold = cfg.complexityThreshold ?? 40;
|
|
89
|
+
}
|
|
90
|
+
/** True when the prompt is complex enough to warrant swarm execution. */
|
|
91
|
+
shouldSwarm(prompt) {
|
|
92
|
+
return scoreComplexity(prompt) >= this.complexityThreshold;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Decompose prompt into sub-tasks, execute them in groups of 3 (up to 5
|
|
96
|
+
* agents total), then synthesise with a reviewer model.
|
|
97
|
+
*
|
|
98
|
+
* Groups-of-3 planner:
|
|
99
|
+
* tasks = decompose(prompt, maxAgents) → 2–5 sub-tasks
|
|
100
|
+
* batches = chunk(tasks, 3) → [[t1,t2,t3],[t4,t5]] for 5 tasks
|
|
101
|
+
* each batch runs in parallel; batches run sequentially
|
|
102
|
+
* reviewer model synthesises all results into a unified answer
|
|
103
|
+
*
|
|
104
|
+
* @param prompt - Original user message
|
|
105
|
+
* @param systemPrompt - Current system prompt (passed to each sub-agent + reviewer)
|
|
106
|
+
* @param onProgress - Called as each sub-task completes
|
|
107
|
+
*/
|
|
108
|
+
async run(prompt, systemPrompt, onProgress) {
|
|
109
|
+
const tasks = decompose(prompt, this.maxAgents);
|
|
110
|
+
const chain = resolveModelChain();
|
|
111
|
+
const subResults = [];
|
|
112
|
+
// Split tasks into groups of 3 (the required "groups-of-3" planner)
|
|
113
|
+
const GROUP_SIZE = 3;
|
|
114
|
+
const batches = [];
|
|
115
|
+
for (let i = 0; i < tasks.length; i += GROUP_SIZE) {
|
|
116
|
+
batches.push(tasks.slice(i, i + GROUP_SIZE));
|
|
117
|
+
}
|
|
118
|
+
let modelIdx = 1; // reserve chain[0] for reviewer
|
|
119
|
+
const runOne = async (task, mIdx, remaining) => {
|
|
120
|
+
const cfg = chain[mIdx % chain.length] ?? chain[0];
|
|
121
|
+
const client = new ModelClient(cfg);
|
|
122
|
+
const msgs = [
|
|
123
|
+
{ role: "system", content: systemPrompt },
|
|
124
|
+
{ role: "user", content: task },
|
|
125
|
+
];
|
|
126
|
+
const t0 = Date.now();
|
|
127
|
+
let out = "";
|
|
128
|
+
for await (const chunk of client.stream(msgs, [])) {
|
|
129
|
+
if (chunk.type === "delta" && chunk.text)
|
|
130
|
+
out += chunk.text;
|
|
131
|
+
}
|
|
132
|
+
const r = {
|
|
133
|
+
task,
|
|
134
|
+
result: out || "(no output)",
|
|
135
|
+
model: cfg.model,
|
|
136
|
+
ms: Date.now() - t0,
|
|
137
|
+
};
|
|
138
|
+
subResults.push(r);
|
|
139
|
+
onProgress(r, remaining);
|
|
140
|
+
};
|
|
141
|
+
// Execute batches sequentially; within each batch run up to 3 in parallel
|
|
142
|
+
let remaining = tasks.length;
|
|
143
|
+
for (const batch of batches) {
|
|
144
|
+
await Promise.all(batch.map(task => {
|
|
145
|
+
remaining--;
|
|
146
|
+
return runOne(task, modelIdx++, remaining);
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
const synthesis = await reviewerSynthesize(prompt, subResults, systemPrompt);
|
|
150
|
+
return { synthesis, subResults };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=SwarmRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SwarmRouter.js","sourceRoot":"","sources":["../../src/runner/SwarmRouter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToolDispatcher — executes tool calls from the model response.
|
|
3
|
+
* Looks up tool by name in the Registry, validates params, runs execute().
|
|
4
|
+
*/
|
|
5
|
+
import type { Registry } from "../api/Registry.js";
|
|
6
|
+
import type { ToolCall } from "./ModelClient.js";
|
|
7
|
+
export interface ToolResult {
|
|
8
|
+
tool_call_id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
content: string;
|
|
11
|
+
isError: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare class ToolDispatcher {
|
|
14
|
+
private registry;
|
|
15
|
+
constructor(registry: Registry);
|
|
16
|
+
dispatch(calls: ToolCall[]): Promise<ToolResult[]>;
|
|
17
|
+
private execute;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=ToolDispatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolDispatcher.d.ts","sourceRoot":"","sources":["../../src/runner/ToolDispatcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAU,MAAM,CAAC;IACrB,OAAO,EAAO,MAAM,CAAC;IACrB,OAAO,EAAO,OAAO,CAAC;CACvB;AAED,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,QAAQ;IAEhC,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;YAI1C,OAAO;CAkDtB"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToolDispatcher — executes tool calls from the model response.
|
|
3
|
+
* Looks up tool by name in the Registry, validates params, runs execute().
|
|
4
|
+
*/
|
|
5
|
+
import { Value } from "@sinclair/typebox/value";
|
|
6
|
+
export class ToolDispatcher {
|
|
7
|
+
registry;
|
|
8
|
+
constructor(registry) {
|
|
9
|
+
this.registry = registry;
|
|
10
|
+
}
|
|
11
|
+
async dispatch(calls) {
|
|
12
|
+
return Promise.all(calls.map(tc => this.execute(tc)));
|
|
13
|
+
}
|
|
14
|
+
async execute(tc) {
|
|
15
|
+
const tool = this.registry.getTool(tc.function.name);
|
|
16
|
+
if (!tool) {
|
|
17
|
+
return {
|
|
18
|
+
tool_call_id: tc.id,
|
|
19
|
+
name: tc.function.name,
|
|
20
|
+
content: `Unknown tool: ${tc.function.name}`,
|
|
21
|
+
isError: true,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
let params;
|
|
25
|
+
try {
|
|
26
|
+
params = JSON.parse(tc.function.arguments || "{}");
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return {
|
|
30
|
+
tool_call_id: tc.id,
|
|
31
|
+
name: tc.function.name,
|
|
32
|
+
content: `Invalid JSON arguments: ${tc.function.arguments}`,
|
|
33
|
+
isError: true,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Validate params against the tool's TypeBox schema
|
|
37
|
+
if (!Value.Check(tool.parameters, params)) {
|
|
38
|
+
const errors = [...Value.Errors(tool.parameters, params)]
|
|
39
|
+
.slice(0, 3)
|
|
40
|
+
.map(e => `${e.path}: ${e.message}`)
|
|
41
|
+
.join("; ");
|
|
42
|
+
return {
|
|
43
|
+
tool_call_id: tc.id,
|
|
44
|
+
name: tc.function.name,
|
|
45
|
+
content: `Parameter validation failed: ${errors}`,
|
|
46
|
+
isError: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const result = await tool.execute(tc.id, params);
|
|
51
|
+
const content = result.content.map(c => c.text).join("\n");
|
|
52
|
+
return { tool_call_id: tc.id, name: tc.function.name, content, isError: false };
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
return {
|
|
56
|
+
tool_call_id: tc.id,
|
|
57
|
+
name: tc.function.name,
|
|
58
|
+
content: `Tool error: ${e?.message ?? String(e)}`,
|
|
59
|
+
isError: true,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=ToolDispatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolDispatcher.js","sourceRoot":"","sources":["../../src/runner/ToolDispatcher.ts"],"names":[],"mappings":"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"}
|