roboport 0.0.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 +25 -0
- package/core/agent.d.ts +35 -0
- package/core/index.d.ts +9 -0
- package/core/mcp.d.ts +6 -0
- package/core/message.d.ts +36 -0
- package/core/model.d.ts +10 -0
- package/core/session.d.ts +75 -0
- package/core/skill.d.ts +11 -0
- package/core/stream.d.ts +33 -0
- package/core/tool.d.ts +77 -0
- package/env.d.ts +8 -0
- package/harness/claudeCode.d.ts +3 -0
- package/harness/codex.d.ts +3 -0
- package/harness/core.d.ts +7 -0
- package/harness/index.d.ts +5 -0
- package/harness/index.js +1512 -0
- package/harness/pi.d.ts +3 -0
- package/harness/shared.d.ts +33 -0
- package/harness/tools.d.ts +33 -0
- package/index.d.ts +2 -0
- package/index.js +537 -0
- package/mcp/auth.d.ts +40 -0
- package/mcp/clients/grafana.d.ts +17 -0
- package/mcp/clients/linear.d.ts +9 -0
- package/mcp/clients/tenderly.d.ts +11 -0
- package/mcp/core.d.ts +30 -0
- package/mcp/index.d.ts +4 -0
- package/mcp/index.js +1356 -0
- package/mcp/oauth.d.ts +36 -0
- package/mcp/servers/calculator.d.ts +1 -0
- package/mcp/storage.d.ts +29 -0
- package/models/anthropic.d.ts +15 -0
- package/models/google.d.ts +14 -0
- package/models/index.d.ts +6 -0
- package/models/index.js +2039 -0
- package/models/moonshot.d.ts +16 -0
- package/models/openai-codex-auth.d.ts +17 -0
- package/models/openai-compatible.d.ts +41 -0
- package/models/openai.d.ts +29 -0
- package/package.json +60 -0
- package/skills/index.d.ts +7 -0
- package/skills/index.js +1007 -0
- package/triggers/bus.d.ts +8 -0
- package/triggers/core.d.ts +14 -0
- package/triggers/index.d.ts +7 -0
- package/triggers/index.js +588 -0
- package/triggers/sources/cron.d.ts +29 -0
- package/triggers/sources/github.d.ts +148 -0
- package/triggers/sources/grafana.d.ts +37 -0
- package/triggers/sources/linear.d.ts +39 -0
- package/triggers/sources/telegram.d.ts +85 -0
package/harness/pi.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Tool, type SearchHit, type ToolContext } from '../core';
|
|
2
|
+
declare function notImplemented(name: string): () => Promise<never>;
|
|
3
|
+
declare function runWebSearch(ctx: ToolContext, args: {
|
|
4
|
+
query: string;
|
|
5
|
+
allowed_domains?: string[];
|
|
6
|
+
blocked_domains?: string[];
|
|
7
|
+
}): Promise<SearchHit[]>;
|
|
8
|
+
declare function runWebFetch(ctx: ToolContext, args: {
|
|
9
|
+
url: string;
|
|
10
|
+
prompt: string;
|
|
11
|
+
}): Promise<string>;
|
|
12
|
+
declare function serializeShellResult(stdout: string, stderr: string, exitCode: number): string;
|
|
13
|
+
declare function runShell({ cmd, timeout, workdir, shell, login, }: {
|
|
14
|
+
cmd: string;
|
|
15
|
+
timeout?: number;
|
|
16
|
+
workdir?: string;
|
|
17
|
+
shell?: string;
|
|
18
|
+
login?: boolean;
|
|
19
|
+
}): Promise<string>;
|
|
20
|
+
declare function readFile(filePath: string, opts?: {
|
|
21
|
+
offset?: number;
|
|
22
|
+
limit?: number;
|
|
23
|
+
}): Promise<string>;
|
|
24
|
+
type ExactReplacement = {
|
|
25
|
+
oldString: string;
|
|
26
|
+
newString: string;
|
|
27
|
+
};
|
|
28
|
+
declare function applyExactReplacements(filePath: string, replacements: ExactReplacement[]): Promise<number>;
|
|
29
|
+
declare function applyPatchText(patch: string, opts?: {
|
|
30
|
+
cwd?: string;
|
|
31
|
+
}): Promise<string>;
|
|
32
|
+
declare function createToolSearch(): Tool;
|
|
33
|
+
export { applyExactReplacements, applyPatchText, createToolSearch, notImplemented, readFile, runShell, runWebFetch, runWebSearch, serializeShellResult, };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { Tool } from '../core';
|
|
3
|
+
declare const webSearch: Tool<z.ZodObject<{
|
|
4
|
+
query: z.ZodString;
|
|
5
|
+
allowed_domains: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
6
|
+
blocked_domains: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
7
|
+
}, z.core.$strip>, import("../core").SearchHit[]>;
|
|
8
|
+
declare const webFetch: Tool<z.ZodObject<{
|
|
9
|
+
url: z.ZodURL;
|
|
10
|
+
prompt: z.ZodString;
|
|
11
|
+
}, z.core.$strip>, string>;
|
|
12
|
+
declare const readFile: Tool<z.ZodObject<{
|
|
13
|
+
path: z.ZodString;
|
|
14
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
15
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
}, z.core.$strip>, string>;
|
|
17
|
+
declare const writeFile: Tool<z.ZodObject<{
|
|
18
|
+
path: z.ZodString;
|
|
19
|
+
content: z.ZodString;
|
|
20
|
+
}, z.core.$strip>, string>;
|
|
21
|
+
declare const editFile: Tool<z.ZodObject<{
|
|
22
|
+
path: z.ZodString;
|
|
23
|
+
edits: z.ZodArray<z.ZodObject<{
|
|
24
|
+
old_text: z.ZodString;
|
|
25
|
+
new_text: z.ZodString;
|
|
26
|
+
}, z.core.$strip>>;
|
|
27
|
+
}, z.core.$strip>, string>;
|
|
28
|
+
declare const bash: Tool<z.ZodObject<{
|
|
29
|
+
command: z.ZodString;
|
|
30
|
+
timeout: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
workdir: z.ZodOptional<z.ZodString>;
|
|
32
|
+
}, z.core.$strip>, string>;
|
|
33
|
+
export { bash, editFile, readFile, webFetch, webSearch, writeFile };
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Agent, Model, Session, Skill, Tool, Turn, type CreateMessageParams, type CreateMessageResponse, type Message, type ModelStreamEvent, type SearchHit, type SearchOptions, type SessionState, type StopReason, type TextPart, type ThinkingLevel, type ThinkingPart, type ToolCallPart, type ToolContext, type ToolRegistry, type ToolResultPart, type TurnEvent } from './core';
|
|
2
|
+
export { Agent, Model, Session, Skill, Tool, Turn, type CreateMessageParams, type CreateMessageResponse, type Message, type ModelStreamEvent, type SearchHit, type SearchOptions, type SessionState, type StopReason, type TextPart, type ThinkingLevel, type ThinkingPart, type ToolCallPart, type ToolContext, type ToolRegistry, type ToolResultPart, type TurnEvent, };
|
package/index.js
ADDED
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/core/agent.ts
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
// src/core/session.ts
|
|
6
|
+
class Turn {
|
|
7
|
+
queue = [];
|
|
8
|
+
waiters = [];
|
|
9
|
+
ended = false;
|
|
10
|
+
iterated = false;
|
|
11
|
+
resultPromise;
|
|
12
|
+
abortController = new AbortController;
|
|
13
|
+
constructor(runner) {
|
|
14
|
+
this.resultPromise = runner({
|
|
15
|
+
emit: (event) => this.emit(event),
|
|
16
|
+
signal: this.abortController.signal
|
|
17
|
+
}).then((messages) => {
|
|
18
|
+
this.close();
|
|
19
|
+
return messages;
|
|
20
|
+
}, (error) => {
|
|
21
|
+
this.close();
|
|
22
|
+
throw error;
|
|
23
|
+
});
|
|
24
|
+
this.resultPromise.catch(() => {});
|
|
25
|
+
}
|
|
26
|
+
emit(event) {
|
|
27
|
+
const waiter = this.waiters.shift();
|
|
28
|
+
if (waiter) {
|
|
29
|
+
waiter({ value: event, done: false });
|
|
30
|
+
} else {
|
|
31
|
+
this.queue.push(event);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
close() {
|
|
35
|
+
this.ended = true;
|
|
36
|
+
while (this.waiters.length > 0) {
|
|
37
|
+
const waiter = this.waiters.shift();
|
|
38
|
+
waiter?.({ value: undefined, done: true });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
abort(reason) {
|
|
42
|
+
this.abortController.abort(reason);
|
|
43
|
+
}
|
|
44
|
+
[Symbol.asyncIterator]() {
|
|
45
|
+
if (this.iterated) {
|
|
46
|
+
throw new Error("Turn can only be iterated once.");
|
|
47
|
+
}
|
|
48
|
+
this.iterated = true;
|
|
49
|
+
return {
|
|
50
|
+
next: () => {
|
|
51
|
+
if (this.queue.length > 0) {
|
|
52
|
+
const value = this.queue.shift();
|
|
53
|
+
return Promise.resolve({ value, done: false });
|
|
54
|
+
}
|
|
55
|
+
if (this.ended) {
|
|
56
|
+
return Promise.resolve({
|
|
57
|
+
value: undefined,
|
|
58
|
+
done: true
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return new Promise((resolve) => this.waiters.push(resolve));
|
|
62
|
+
},
|
|
63
|
+
return: async () => {
|
|
64
|
+
this.abort("iteration ended");
|
|
65
|
+
await this.resultPromise.catch(() => {});
|
|
66
|
+
return {
|
|
67
|
+
value: undefined,
|
|
68
|
+
done: true
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
then(onfulfilled, onrejected) {
|
|
74
|
+
return this.resultPromise.then(onfulfilled, onrejected);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
class Session {
|
|
79
|
+
internals;
|
|
80
|
+
state;
|
|
81
|
+
constructor(internals, state) {
|
|
82
|
+
this.internals = internals;
|
|
83
|
+
this.state = state;
|
|
84
|
+
}
|
|
85
|
+
get messages() {
|
|
86
|
+
return this.state.messages;
|
|
87
|
+
}
|
|
88
|
+
send(prompt) {
|
|
89
|
+
return this.internals.send(prompt);
|
|
90
|
+
}
|
|
91
|
+
async close() {
|
|
92
|
+
await this.internals.close();
|
|
93
|
+
}
|
|
94
|
+
async[Symbol.asyncDispose]() {
|
|
95
|
+
await this.close();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/core/tool.ts
|
|
100
|
+
import * as z4 from "zod/v4/core";
|
|
101
|
+
function hasParseMethod(schema) {
|
|
102
|
+
return typeof schema === "object" && schema !== null && "parse" in schema && typeof schema.parse === "function";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
class Tool {
|
|
106
|
+
name;
|
|
107
|
+
description;
|
|
108
|
+
inputSchema;
|
|
109
|
+
jsonSchema;
|
|
110
|
+
execute;
|
|
111
|
+
deferred;
|
|
112
|
+
constructor(init) {
|
|
113
|
+
this.name = init.name;
|
|
114
|
+
this.description = init.description;
|
|
115
|
+
this.deferred = init.deferred ?? false;
|
|
116
|
+
if ("inputSchema" in init) {
|
|
117
|
+
this.inputSchema = init.inputSchema;
|
|
118
|
+
this.execute = init.execute;
|
|
119
|
+
} else {
|
|
120
|
+
this.jsonSchema = init.jsonSchema;
|
|
121
|
+
this.execute = init.execute;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
toJsonSchema() {
|
|
125
|
+
if (this.jsonSchema !== undefined)
|
|
126
|
+
return this.jsonSchema;
|
|
127
|
+
if (this.inputSchema === undefined) {
|
|
128
|
+
throw new Error(`Tool "${this.name}" has neither inputSchema nor jsonSchema.`);
|
|
129
|
+
}
|
|
130
|
+
return z4.toJSONSchema(this.inputSchema);
|
|
131
|
+
}
|
|
132
|
+
parse(input) {
|
|
133
|
+
const schema = this.inputSchema;
|
|
134
|
+
if (!schema)
|
|
135
|
+
return input;
|
|
136
|
+
if (hasParseMethod(schema))
|
|
137
|
+
return schema.parse(input);
|
|
138
|
+
return z4.parse(schema, input);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function createRegistry(tools) {
|
|
142
|
+
const byName = new Map(tools.map((tool) => [tool.name, tool]));
|
|
143
|
+
const loadedNames = new Set(tools.filter((tool) => !tool.deferred).map((tool) => tool.name));
|
|
144
|
+
return {
|
|
145
|
+
loaded: () => tools.filter((tool) => loadedNames.has(tool.name)),
|
|
146
|
+
deferred: () => tools.filter((tool) => tool.deferred && !loadedNames.has(tool.name)),
|
|
147
|
+
load: (names) => {
|
|
148
|
+
const loaded = [];
|
|
149
|
+
const missing = [];
|
|
150
|
+
for (const name of names) {
|
|
151
|
+
const tool = byName.get(name);
|
|
152
|
+
if (!tool) {
|
|
153
|
+
missing.push(name);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
loadedNames.add(name);
|
|
157
|
+
loaded.push(tool);
|
|
158
|
+
}
|
|
159
|
+
return { loaded, missing };
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/core/agent.ts
|
|
165
|
+
class Agent {
|
|
166
|
+
model;
|
|
167
|
+
system;
|
|
168
|
+
tools;
|
|
169
|
+
skills;
|
|
170
|
+
mcp;
|
|
171
|
+
cwd;
|
|
172
|
+
registrations = [];
|
|
173
|
+
unsubs = [];
|
|
174
|
+
constructor({
|
|
175
|
+
model,
|
|
176
|
+
system,
|
|
177
|
+
tools,
|
|
178
|
+
skills,
|
|
179
|
+
mcp,
|
|
180
|
+
cwd
|
|
181
|
+
}) {
|
|
182
|
+
this.model = model;
|
|
183
|
+
this.system = system;
|
|
184
|
+
this.tools = tools;
|
|
185
|
+
this.skills = skills;
|
|
186
|
+
this.mcp = mcp ?? [];
|
|
187
|
+
this.cwd = cwd;
|
|
188
|
+
}
|
|
189
|
+
on(trigger, handler) {
|
|
190
|
+
this.registrations.push({ trigger, handler });
|
|
191
|
+
}
|
|
192
|
+
async start() {
|
|
193
|
+
for (const { trigger, handler } of this.registrations) {
|
|
194
|
+
const unsub = await trigger.start((event) => {
|
|
195
|
+
Promise.resolve().then(() => handler(event)).catch((error) => {
|
|
196
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
197
|
+
console.error(`[roboport] trigger "${trigger.name}" handler failed: ${message}`);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
this.unsubs.push(unsub);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async stop() {
|
|
204
|
+
const unsubs = this.unsubs;
|
|
205
|
+
this.unsubs = [];
|
|
206
|
+
await Promise.all(unsubs.map((u) => u()));
|
|
207
|
+
}
|
|
208
|
+
buildSystem(allTools) {
|
|
209
|
+
let system = this.system;
|
|
210
|
+
if (this.skills.length > 0) {
|
|
211
|
+
const skillsList = this.skills.map((skill) => `- ${skill.name}: ${skill.description}`).join(`
|
|
212
|
+
`);
|
|
213
|
+
system = `${system}
|
|
214
|
+
|
|
215
|
+
# Skills
|
|
216
|
+
The following skills are available. When a task matches one, call the \`Skill\` tool with that skill's name to load its full content before proceeding.
|
|
217
|
+
|
|
218
|
+
${skillsList}`;
|
|
219
|
+
}
|
|
220
|
+
const deferred = allTools.filter((tool) => tool.deferred);
|
|
221
|
+
if (deferred.length > 0) {
|
|
222
|
+
const list = deferred.map((tool) => `- ${tool.name}`).join(`
|
|
223
|
+
`);
|
|
224
|
+
system = `${system}
|
|
225
|
+
|
|
226
|
+
# Deferred tools
|
|
227
|
+
These tools are available but their schemas are not loaded. Use ToolSearch to load them before calling.
|
|
228
|
+
${list}`;
|
|
229
|
+
}
|
|
230
|
+
return system;
|
|
231
|
+
}
|
|
232
|
+
buildSkillTool() {
|
|
233
|
+
const byName = new Map(this.skills.map((skill) => [skill.name, skill]));
|
|
234
|
+
return new Tool({
|
|
235
|
+
name: "Skill",
|
|
236
|
+
description: 'Load the full content of a skill listed under "# Skills" in the system prompt. Call this when you decide a listed skill applies to the current task; the returned content extends your instructions for the rest of the session.',
|
|
237
|
+
inputSchema: z.object({
|
|
238
|
+
skill: z.string().describe("Name of the skill to load (must match a listed skill).")
|
|
239
|
+
}),
|
|
240
|
+
execute: ({ skill }) => {
|
|
241
|
+
const found = byName.get(skill);
|
|
242
|
+
if (!found) {
|
|
243
|
+
const available = [...byName.keys()].join(", ");
|
|
244
|
+
throw new Error(`Skill "${skill}" not found. Available: ${available}`);
|
|
245
|
+
}
|
|
246
|
+
return `<skill name="${found.name}">
|
|
247
|
+
${found.content}
|
|
248
|
+
</skill>`;
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
session(init) {
|
|
253
|
+
const initialMessages = init?.messages ? [...init.messages] : [];
|
|
254
|
+
const sessionCwd = init?.cwd ?? this.cwd ?? process.cwd();
|
|
255
|
+
const state = {
|
|
256
|
+
messages: initialMessages,
|
|
257
|
+
store: new Map
|
|
258
|
+
};
|
|
259
|
+
let activeTurn = null;
|
|
260
|
+
let mcpConnected = false;
|
|
261
|
+
let allTools = null;
|
|
262
|
+
let registry = null;
|
|
263
|
+
let ctx = null;
|
|
264
|
+
const ensureReady = async () => {
|
|
265
|
+
if (!allTools || !registry || !ctx) {
|
|
266
|
+
const mcpToolGroups = await Promise.all(this.mcp.map((mcp) => mcp.connect()));
|
|
267
|
+
mcpConnected = true;
|
|
268
|
+
allTools = [
|
|
269
|
+
...this.tools,
|
|
270
|
+
...mcpToolGroups.flat(),
|
|
271
|
+
...this.skills.length > 0 ? [this.buildSkillTool()] : []
|
|
272
|
+
];
|
|
273
|
+
registry = createRegistry(allTools);
|
|
274
|
+
ctx = {
|
|
275
|
+
complete: async (p) => {
|
|
276
|
+
const response = await this.model.createMessage({
|
|
277
|
+
messages: [{ role: "user", content: p }]
|
|
278
|
+
});
|
|
279
|
+
return response.content.filter((block) => block.type === "text").map((block) => block.text).join(`
|
|
280
|
+
`);
|
|
281
|
+
},
|
|
282
|
+
searchWeb: (query, opts) => this.model.searchWeb(query, opts),
|
|
283
|
+
session: state,
|
|
284
|
+
tools: registry,
|
|
285
|
+
cwd: sessionCwd
|
|
286
|
+
};
|
|
287
|
+
if (state.messages.length === 0 || state.messages[0]?.role !== "system") {
|
|
288
|
+
state.messages.unshift({
|
|
289
|
+
role: "system",
|
|
290
|
+
content: this.buildSystem(allTools)
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return { tools: allTools, registry, ctx };
|
|
295
|
+
};
|
|
296
|
+
const internals = {
|
|
297
|
+
send: (prompt) => {
|
|
298
|
+
if (activeTurn !== null) {
|
|
299
|
+
throw new Error("Session.send() called while another turn is in flight.");
|
|
300
|
+
}
|
|
301
|
+
const turn = new Turn(async (turnCtx) => {
|
|
302
|
+
try {
|
|
303
|
+
const ready = await ensureReady();
|
|
304
|
+
state.messages.push(toUserMessage(prompt));
|
|
305
|
+
await runAgentLoop({
|
|
306
|
+
model: this.model,
|
|
307
|
+
state,
|
|
308
|
+
registry: ready.registry,
|
|
309
|
+
ctx: ready.ctx,
|
|
310
|
+
emit: turnCtx.emit,
|
|
311
|
+
signal: turnCtx.signal
|
|
312
|
+
});
|
|
313
|
+
return [...state.messages];
|
|
314
|
+
} finally {
|
|
315
|
+
activeTurn = null;
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
activeTurn = turn;
|
|
319
|
+
return turn;
|
|
320
|
+
},
|
|
321
|
+
close: async () => {
|
|
322
|
+
const pending = activeTurn;
|
|
323
|
+
if (pending) {
|
|
324
|
+
pending.abort("session closed");
|
|
325
|
+
await Promise.resolve(pending).catch(() => {});
|
|
326
|
+
}
|
|
327
|
+
if (mcpConnected) {
|
|
328
|
+
await Promise.all(this.mcp.map((mcp) => mcp.disconnect()));
|
|
329
|
+
mcpConnected = false;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
return new Session(internals, state);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
function toUserMessage(prompt) {
|
|
337
|
+
if (typeof prompt === "string")
|
|
338
|
+
return { role: "user", content: prompt };
|
|
339
|
+
return { role: "user", content: prompt };
|
|
340
|
+
}
|
|
341
|
+
async function runAgentLoop({
|
|
342
|
+
model,
|
|
343
|
+
state,
|
|
344
|
+
registry,
|
|
345
|
+
ctx,
|
|
346
|
+
emit,
|
|
347
|
+
signal
|
|
348
|
+
}) {
|
|
349
|
+
while (true) {
|
|
350
|
+
if (signal.aborted)
|
|
351
|
+
break;
|
|
352
|
+
const active = registry.loaded();
|
|
353
|
+
const toolByName = new Map(active.map((tool) => [tool.name, tool]));
|
|
354
|
+
emit({ type: "message-start" });
|
|
355
|
+
const assistantContent = [];
|
|
356
|
+
let stopReason = "end_turn";
|
|
357
|
+
let usage = { inputTokens: 0, outputTokens: 0 };
|
|
358
|
+
try {
|
|
359
|
+
for await (const event of model.streamMessage({
|
|
360
|
+
messages: state.messages,
|
|
361
|
+
tools: active,
|
|
362
|
+
signal
|
|
363
|
+
})) {
|
|
364
|
+
switch (event.type) {
|
|
365
|
+
case "text-delta":
|
|
366
|
+
emit({ type: "text-delta", text: event.text });
|
|
367
|
+
break;
|
|
368
|
+
case "text-end":
|
|
369
|
+
assistantContent.push({ type: "text", text: event.text });
|
|
370
|
+
emit({ type: "text", text: event.text });
|
|
371
|
+
break;
|
|
372
|
+
case "thinking-delta":
|
|
373
|
+
emit({ type: "thinking-delta", text: event.text });
|
|
374
|
+
break;
|
|
375
|
+
case "thinking-end":
|
|
376
|
+
assistantContent.push({
|
|
377
|
+
type: "thinking",
|
|
378
|
+
text: event.text,
|
|
379
|
+
...event.signature !== undefined ? { signature: event.signature } : {},
|
|
380
|
+
...event.redactedData !== undefined ? { redactedData: event.redactedData } : {}
|
|
381
|
+
});
|
|
382
|
+
emit({
|
|
383
|
+
type: "thinking",
|
|
384
|
+
text: event.text,
|
|
385
|
+
...event.signature !== undefined ? { signature: event.signature } : {}
|
|
386
|
+
});
|
|
387
|
+
break;
|
|
388
|
+
case "tool-call":
|
|
389
|
+
assistantContent.push({
|
|
390
|
+
type: "tool-call",
|
|
391
|
+
toolCallId: event.toolCallId,
|
|
392
|
+
toolName: event.toolName,
|
|
393
|
+
input: event.input
|
|
394
|
+
});
|
|
395
|
+
emit({
|
|
396
|
+
type: "tool-call",
|
|
397
|
+
toolCallId: event.toolCallId,
|
|
398
|
+
toolName: event.toolName,
|
|
399
|
+
input: event.input
|
|
400
|
+
});
|
|
401
|
+
break;
|
|
402
|
+
case "message-end":
|
|
403
|
+
stopReason = event.stopReason;
|
|
404
|
+
usage = event.usage;
|
|
405
|
+
break;
|
|
406
|
+
default:
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
} catch (error) {
|
|
411
|
+
if (signal.aborted) {
|
|
412
|
+
state.messages.push({ role: "assistant", content: assistantContent });
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
416
|
+
emit({ type: "error", error: err });
|
|
417
|
+
throw err;
|
|
418
|
+
}
|
|
419
|
+
state.messages.push({ role: "assistant", content: assistantContent });
|
|
420
|
+
emit({ type: "message-end", usage });
|
|
421
|
+
if (stopReason !== "tool_use") {
|
|
422
|
+
emit({ type: "turn-end" });
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
const toolCalls = assistantContent.filter((block) => block.type === "tool-call");
|
|
426
|
+
const results = [];
|
|
427
|
+
for (const call of toolCalls) {
|
|
428
|
+
if (signal.aborted)
|
|
429
|
+
break;
|
|
430
|
+
const tool = toolByName.get(call.toolName);
|
|
431
|
+
const result = await runTool(tool, call, ctx);
|
|
432
|
+
results.push(result);
|
|
433
|
+
emit({
|
|
434
|
+
type: "tool-result",
|
|
435
|
+
toolCallId: result.toolCallId,
|
|
436
|
+
toolName: result.toolName,
|
|
437
|
+
output: result.output,
|
|
438
|
+
isError: typeof result.output === "string" ? result.output.startsWith("Error:") : false
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
state.messages.push({ role: "tool", content: results });
|
|
442
|
+
if (signal.aborted)
|
|
443
|
+
break;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
async function runTool(tool, call, ctx) {
|
|
447
|
+
if (!tool) {
|
|
448
|
+
return {
|
|
449
|
+
type: "tool-result",
|
|
450
|
+
toolCallId: call.toolCallId,
|
|
451
|
+
toolName: call.toolName,
|
|
452
|
+
output: `Error: tool "${call.toolName}" not found`
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
try {
|
|
456
|
+
const parsed = tool.parse(call.input);
|
|
457
|
+
const output = await tool.execute(parsed, ctx);
|
|
458
|
+
return {
|
|
459
|
+
type: "tool-result",
|
|
460
|
+
toolCallId: call.toolCallId,
|
|
461
|
+
toolName: call.toolName,
|
|
462
|
+
output
|
|
463
|
+
};
|
|
464
|
+
} catch (error) {
|
|
465
|
+
return {
|
|
466
|
+
type: "tool-result",
|
|
467
|
+
toolCallId: call.toolCallId,
|
|
468
|
+
toolName: call.toolName,
|
|
469
|
+
output: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// src/core/model.ts
|
|
475
|
+
class Model {
|
|
476
|
+
async createMessage(params) {
|
|
477
|
+
const content = [];
|
|
478
|
+
let id = "";
|
|
479
|
+
let stopReason = "end_turn";
|
|
480
|
+
let usage = { inputTokens: 0, outputTokens: 0 };
|
|
481
|
+
for await (const event of this.streamMessage(params)) {
|
|
482
|
+
switch (event.type) {
|
|
483
|
+
case "text-end":
|
|
484
|
+
content.push({ type: "text", text: event.text });
|
|
485
|
+
break;
|
|
486
|
+
case "thinking-end":
|
|
487
|
+
content.push({
|
|
488
|
+
type: "thinking",
|
|
489
|
+
text: event.text,
|
|
490
|
+
...event.signature !== undefined ? { signature: event.signature } : {},
|
|
491
|
+
...event.redactedData !== undefined ? { redactedData: event.redactedData } : {}
|
|
492
|
+
});
|
|
493
|
+
break;
|
|
494
|
+
case "tool-call":
|
|
495
|
+
content.push({
|
|
496
|
+
type: "tool-call",
|
|
497
|
+
toolCallId: event.toolCallId,
|
|
498
|
+
toolName: event.toolName,
|
|
499
|
+
input: event.input
|
|
500
|
+
});
|
|
501
|
+
break;
|
|
502
|
+
case "message-end":
|
|
503
|
+
id = event.id;
|
|
504
|
+
stopReason = event.stopReason;
|
|
505
|
+
usage = event.usage;
|
|
506
|
+
break;
|
|
507
|
+
default:
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return { id, content, stopReason, usage };
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// src/core/skill.ts
|
|
516
|
+
class Skill {
|
|
517
|
+
name;
|
|
518
|
+
description;
|
|
519
|
+
content;
|
|
520
|
+
constructor({
|
|
521
|
+
name,
|
|
522
|
+
description,
|
|
523
|
+
content
|
|
524
|
+
}) {
|
|
525
|
+
this.name = name;
|
|
526
|
+
this.description = description;
|
|
527
|
+
this.content = content;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
export {
|
|
531
|
+
Turn,
|
|
532
|
+
Tool,
|
|
533
|
+
Skill,
|
|
534
|
+
Session,
|
|
535
|
+
Model,
|
|
536
|
+
Agent
|
|
537
|
+
};
|
package/mcp/auth.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type OAuthStorage } from './storage';
|
|
2
|
+
interface AuthProvider {
|
|
3
|
+
getHeader(): Promise<string>;
|
|
4
|
+
onUnauthorized?(): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
declare class BearerAuth implements AuthProvider {
|
|
7
|
+
private token;
|
|
8
|
+
constructor(token: string);
|
|
9
|
+
getHeader(): Promise<string>;
|
|
10
|
+
}
|
|
11
|
+
type OAuthAuthOptions = {
|
|
12
|
+
serverUrl: string;
|
|
13
|
+
storageKey: string;
|
|
14
|
+
storage?: OAuthStorage;
|
|
15
|
+
redirectPort?: number;
|
|
16
|
+
scopes?: string[];
|
|
17
|
+
flowTimeoutMs?: number;
|
|
18
|
+
};
|
|
19
|
+
declare class OAuthAuth implements AuthProvider {
|
|
20
|
+
private serverUrl;
|
|
21
|
+
private storage;
|
|
22
|
+
private storageKey;
|
|
23
|
+
private redirectPort;
|
|
24
|
+
private scopes?;
|
|
25
|
+
private flowTimeoutMs;
|
|
26
|
+
private tokens?;
|
|
27
|
+
private loaded;
|
|
28
|
+
private metadata?;
|
|
29
|
+
private inFlight?;
|
|
30
|
+
constructor(opts: OAuthAuthOptions);
|
|
31
|
+
getHeader(): Promise<string>;
|
|
32
|
+
onUnauthorized(): Promise<void>;
|
|
33
|
+
private ensureTokens;
|
|
34
|
+
private isExpired;
|
|
35
|
+
private getMetadata;
|
|
36
|
+
private authorize;
|
|
37
|
+
private refresh;
|
|
38
|
+
private toTokenSet;
|
|
39
|
+
}
|
|
40
|
+
export { BearerAuth, OAuthAuth, type AuthProvider, type OAuthAuthOptions };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Tool, type McpClient } from '../../core';
|
|
2
|
+
type Options = {
|
|
3
|
+
url: string;
|
|
4
|
+
serviceAccountToken: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
deferred?: boolean;
|
|
7
|
+
};
|
|
8
|
+
declare class Mcp implements McpClient {
|
|
9
|
+
private baseUrl;
|
|
10
|
+
private auth;
|
|
11
|
+
private nameSpace;
|
|
12
|
+
private deferred;
|
|
13
|
+
constructor(opts: Options);
|
|
14
|
+
connect(): Promise<Tool[]>;
|
|
15
|
+
disconnect(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export default Mcp;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Mcp as McpBase } from '../core';
|
|
2
|
+
import type { OAuthStorage } from '../storage';
|
|
3
|
+
type Options = {
|
|
4
|
+
name?: string;
|
|
5
|
+
storage?: OAuthStorage;
|
|
6
|
+
redirectPort?: number;
|
|
7
|
+
};
|
|
8
|
+
declare class Mcp extends McpBase {
|
|
9
|
+
constructor(opts?: Options);
|
|
10
|
+
}
|
|
11
|
+
export default Mcp;
|