@theokit/agents 0.3.0 → 0.5.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/dist/bridge.d.ts +124 -14
- package/dist/bridge.js +17 -4
- package/dist/{chunk-SWPOX3LR.js → chunk-2MI27XCA.js} +423 -312
- package/dist/chunk-2MI27XCA.js.map +1 -0
- package/dist/chunk-7QVYU63E.js +7 -0
- package/dist/chunk-7QVYU63E.js.map +1 -0
- package/dist/{chunk-3LCIXX3T.js → chunk-MVEY7HEY.js} +76 -7
- package/dist/chunk-MVEY7HEY.js.map +1 -0
- package/dist/{chunk-QNPXMBSH.js → chunk-XWVZS2PQ.js} +23 -64
- package/dist/chunk-XWVZS2PQ.js.map +1 -0
- package/dist/decorators.d.ts +4 -39
- package/dist/decorators.js +7 -6
- package/dist/index.d.ts +5 -4
- package/dist/index.js +22 -9
- package/dist/{mcp-DmtwLSF-.d.ts → skills-DnfvEUSg.d.ts} +52 -17
- package/dist/testing.d.ts +47 -0
- package/dist/testing.js +73 -0
- package/dist/testing.js.map +1 -0
- package/package.json +25 -8
- package/dist/chunk-3LCIXX3T.js.map +0 -1
- package/dist/chunk-QNPXMBSH.js.map +0 -1
- package/dist/chunk-SWPOX3LR.js.map +0 -1
|
@@ -2,21 +2,26 @@ import {
|
|
|
2
2
|
AGENT_CONFIG,
|
|
3
3
|
AGENT_MAIN_LOOP,
|
|
4
4
|
Audit,
|
|
5
|
+
Budget,
|
|
5
6
|
RequiresApproval,
|
|
6
7
|
TOOLBOX_CONFIG,
|
|
7
8
|
TOOL_CONFIG,
|
|
8
9
|
TOOL_METHODS,
|
|
9
10
|
Trace,
|
|
10
|
-
__name,
|
|
11
11
|
getAgentConfig,
|
|
12
|
+
getContextWindowConfig,
|
|
12
13
|
getGatewayConfig,
|
|
13
14
|
getMcpConfig,
|
|
14
15
|
getMemoryConfig,
|
|
15
16
|
getMeta,
|
|
16
17
|
getMixins,
|
|
18
|
+
getProjectContextConfig,
|
|
17
19
|
getSkillsConfig,
|
|
18
20
|
getSubAgents
|
|
19
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-MVEY7HEY.js";
|
|
22
|
+
import {
|
|
23
|
+
__name
|
|
24
|
+
} from "./chunk-7QVYU63E.js";
|
|
20
25
|
|
|
21
26
|
// src/bridge/agent-execution-context.ts
|
|
22
27
|
function createAgentExecutionContext(base, agent, run, toolCall) {
|
|
@@ -37,13 +42,82 @@ function isAgentContext(ctx) {
|
|
|
37
42
|
}
|
|
38
43
|
__name(isAgentContext, "isAgentContext");
|
|
39
44
|
|
|
45
|
+
// src/bridge/compile-context-window.ts
|
|
46
|
+
var STRATEGY_KNOBS = [
|
|
47
|
+
"compactionStrategy",
|
|
48
|
+
"preserveLastN",
|
|
49
|
+
"preserveToolResults",
|
|
50
|
+
"preserveSystemPrompt"
|
|
51
|
+
];
|
|
52
|
+
function compileContextWindow(options) {
|
|
53
|
+
const context = {};
|
|
54
|
+
if (typeof options.maxTokens === "number") {
|
|
55
|
+
context.maxTokens = options.maxTokens;
|
|
56
|
+
}
|
|
57
|
+
const opts = options;
|
|
58
|
+
const metadataOnlyKnobs = STRATEGY_KNOBS.filter((knob) => opts[knob] !== void 0);
|
|
59
|
+
return {
|
|
60
|
+
context,
|
|
61
|
+
metadataOnlyKnobs
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
__name(compileContextWindow, "compileContextWindow");
|
|
65
|
+
|
|
66
|
+
// src/bridge/compile-project-context.ts
|
|
67
|
+
var UNMAPPED_KNOBS = [
|
|
68
|
+
"indexStrategy",
|
|
69
|
+
"relevanceStrategy",
|
|
70
|
+
"maxFilesInContext",
|
|
71
|
+
"includeExtensions",
|
|
72
|
+
"rootMarkers"
|
|
73
|
+
];
|
|
74
|
+
function projectContextMetadataOnlyKnobs(options) {
|
|
75
|
+
const opts = options;
|
|
76
|
+
return UNMAPPED_KNOBS.filter((knob) => opts[knob] !== void 0);
|
|
77
|
+
}
|
|
78
|
+
__name(projectContextMetadataOnlyKnobs, "projectContextMetadataOnlyKnobs");
|
|
79
|
+
function compileProjectContext(options, base) {
|
|
80
|
+
return async (promptCtx) => {
|
|
81
|
+
const cwd = promptCtx.cwd;
|
|
82
|
+
if (!cwd) {
|
|
83
|
+
return base ?? "";
|
|
84
|
+
}
|
|
85
|
+
const { buildEnvContext, buildRepoMap } = await import("@theokit/sdk-tools");
|
|
86
|
+
const { readProjectInstructions } = await import("@theokit/sdk/project");
|
|
87
|
+
const env = buildEnvContext(cwd);
|
|
88
|
+
const repoMap = buildRepoMap(cwd, {
|
|
89
|
+
ignore: options.ignorePatterns
|
|
90
|
+
});
|
|
91
|
+
let instructions = "";
|
|
92
|
+
try {
|
|
93
|
+
instructions = (await readProjectInstructions(cwd)).content ?? "";
|
|
94
|
+
} catch {
|
|
95
|
+
instructions = "";
|
|
96
|
+
}
|
|
97
|
+
return [
|
|
98
|
+
env,
|
|
99
|
+
repoMap,
|
|
100
|
+
instructions,
|
|
101
|
+
base
|
|
102
|
+
].filter(Boolean).join("\n\n");
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
__name(compileProjectContext, "compileProjectContext");
|
|
106
|
+
|
|
40
107
|
// src/bridge/walk-agent-metadata.ts
|
|
41
108
|
import "reflect-metadata";
|
|
42
|
-
import { Reflector } from "@theokit/http
|
|
43
|
-
var reflectorInstance = new Reflector();
|
|
109
|
+
import { Reflector } from "@theokit/http";
|
|
44
110
|
var USE_GUARDS = /* @__PURE__ */ Symbol.for("theokit:http-decorators:use-guards");
|
|
45
111
|
var USE_INTERCEPTORS = /* @__PURE__ */ Symbol.for("theokit:http-decorators:use-interceptors");
|
|
46
112
|
var USE_FILTERS = /* @__PURE__ */ Symbol.for("theokit:http-decorators:use-filters");
|
|
113
|
+
var AgentWarningCode = {
|
|
114
|
+
INTERCEPTOR_METADATA_ONLY: "THEO_AGENT_INTERCEPTOR_METADATA_ONLY",
|
|
115
|
+
FILTER_METADATA_ONLY: "THEO_AGENT_FILTER_METADATA_ONLY",
|
|
116
|
+
BUDGET_TOP_LEVEL_METADATA_ONLY: "THEO_AGENT_BUDGET_TOP_LEVEL_METADATA_ONLY",
|
|
117
|
+
CONTEXT_STRATEGY_METADATA_ONLY: "THEO_AGENT_CONTEXT_STRATEGY_METADATA_ONLY",
|
|
118
|
+
PROJECT_CONTEXT_KNOB_METADATA_ONLY: "THEO_AGENT_PROJECT_CONTEXT_KNOB_METADATA_ONLY"
|
|
119
|
+
};
|
|
120
|
+
var reflectorInstance = new Reflector();
|
|
47
121
|
function walkToolbox(ToolboxClass) {
|
|
48
122
|
const config = getMeta(TOOLBOX_CONFIG, ToolboxClass) ?? {};
|
|
49
123
|
const methods = getMeta(TOOL_METHODS, ToolboxClass) ?? [];
|
|
@@ -80,6 +154,21 @@ function walkToolbox(ToolboxClass) {
|
|
|
80
154
|
};
|
|
81
155
|
}
|
|
82
156
|
__name(walkToolbox, "walkToolbox");
|
|
157
|
+
function warnUnmappedDecoratorKnobs(agentName, contextWindow, projectContext) {
|
|
158
|
+
if (contextWindow) {
|
|
159
|
+
const { metadataOnlyKnobs } = compileContextWindow(contextWindow);
|
|
160
|
+
if (metadataOnlyKnobs.length > 0) {
|
|
161
|
+
console.warn(`[${AgentWarningCode.CONTEXT_STRATEGY_METADATA_ONLY}] Agent ${agentName}: @ContextWindow knob(s) ${metadataOnlyKnobs.join(", ")} are metadata-only \u2014 the SDK manages transcript compaction internally. Only maxTokens is forwarded to Agent.create({ context }).`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (projectContext) {
|
|
165
|
+
const unmapped = projectContextMetadataOnlyKnobs(projectContext);
|
|
166
|
+
if (unmapped.length > 0) {
|
|
167
|
+
console.warn(`[${AgentWarningCode.PROJECT_CONTEXT_KNOB_METADATA_ONLY}] Agent ${agentName}: @ProjectContext knob(s) ${unmapped.join(", ")} are metadata-only \u2014 the repo map is composed via buildRepoMap/buildEnvContext/readProjectInstructions; only ignorePatterns is forwarded.`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
__name(warnUnmappedDecoratorKnobs, "warnUnmappedDecoratorKnobs");
|
|
83
172
|
var agentWalkCache = /* @__PURE__ */ new WeakMap();
|
|
84
173
|
function walkAgentMetadata(AgentClass, toolboxClasses = []) {
|
|
85
174
|
if (toolboxClasses.length === 0) {
|
|
@@ -96,13 +185,26 @@ function walkAgentMetadata(AgentClass, toolboxClasses = []) {
|
|
|
96
185
|
}
|
|
97
186
|
const guards = getMeta(USE_GUARDS, AgentClass) ?? [];
|
|
98
187
|
const interceptors = getMeta(USE_INTERCEPTORS, AgentClass) ?? [];
|
|
188
|
+
if (interceptors.length > 0) {
|
|
189
|
+
console.warn(`[${AgentWarningCode.INTERCEPTOR_METADATA_ONLY}] Agent ${AgentClass.name}: @UseInterceptors is metadata-only on agents and will not execute. Agent pipeline shares guards with HTTP but uses a distinct execution model. Interceptors are reserved for future agent-specific lifecycle hooks.`);
|
|
190
|
+
}
|
|
99
191
|
const filters = getMeta(USE_FILTERS, AgentClass) ?? [];
|
|
192
|
+
if (filters.length > 0) {
|
|
193
|
+
console.warn(`[${AgentWarningCode.FILTER_METADATA_ONLY}] Agent ${AgentClass.name}: @UseFilters is metadata-only on agents and will not catch agent runtime errors. Agent errors flow through SSE error events, not HTTP exception filters. Filters are reserved for future agent-specific error handling.`);
|
|
194
|
+
}
|
|
195
|
+
const agentBudget = reflectorInstance.get(Budget, AgentClass);
|
|
196
|
+
if (agentBudget) {
|
|
197
|
+
console.warn(`[${AgentWarningCode.BUDGET_TOP_LEVEL_METADATA_ONLY}] Agent ${AgentClass.name}: @Budget on top-level agents is metadata-only in this version. Budget enforcement currently applies to delegate() calls only. Top-level run enforcement will be wired through SDK cost tracking in a future release.`);
|
|
198
|
+
}
|
|
100
199
|
const toolboxes = toolboxClasses.map(walkToolbox);
|
|
101
200
|
const gateway = getGatewayConfig(AgentClass);
|
|
102
201
|
const subAgentClasses = getSubAgents(AgentClass);
|
|
103
202
|
const memory = getMemoryConfig(AgentClass);
|
|
104
203
|
const skills = getSkillsConfig(AgentClass);
|
|
105
204
|
const mcpServers = getMcpConfig(AgentClass);
|
|
205
|
+
const contextWindow = getContextWindowConfig(AgentClass);
|
|
206
|
+
const projectContext = getProjectContextConfig(AgentClass);
|
|
207
|
+
warnUnmappedDecoratorKnobs(AgentClass.name, contextWindow, projectContext);
|
|
106
208
|
const result = {
|
|
107
209
|
agentConfig,
|
|
108
210
|
mainLoop,
|
|
@@ -115,6 +217,8 @@ function walkAgentMetadata(AgentClass, toolboxClasses = []) {
|
|
|
115
217
|
subAgentClasses,
|
|
116
218
|
memory,
|
|
117
219
|
skills,
|
|
220
|
+
contextWindow,
|
|
221
|
+
projectContext,
|
|
118
222
|
mcpServers
|
|
119
223
|
};
|
|
120
224
|
if (toolboxClasses.length === 0) {
|
|
@@ -135,6 +239,20 @@ function validateUniqueRoutes(results) {
|
|
|
135
239
|
}
|
|
136
240
|
__name(validateUniqueRoutes, "validateUniqueRoutes");
|
|
137
241
|
|
|
242
|
+
// src/bridge/compile-skills.ts
|
|
243
|
+
function compileSkills(options) {
|
|
244
|
+
if (options.autoDiscover) {
|
|
245
|
+
return {
|
|
246
|
+
autoInject: true
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
enabled: options.include,
|
|
251
|
+
autoInject: true
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
__name(compileSkills, "compileSkills");
|
|
255
|
+
|
|
138
256
|
// src/bridge/agent-compiler.ts
|
|
139
257
|
function compileTools(toolboxes, toolboxInstances) {
|
|
140
258
|
const tools = [];
|
|
@@ -182,7 +300,9 @@ function compileAgent(walkResult, toolboxInstances = /* @__PURE__ */ new Map())
|
|
|
182
300
|
tools,
|
|
183
301
|
agents,
|
|
184
302
|
memory: walkResult.memory,
|
|
185
|
-
skills: walkResult.skills,
|
|
303
|
+
skills: walkResult.skills ? compileSkills(walkResult.skills) : void 0,
|
|
304
|
+
context: walkResult.contextWindow ? compileContextWindow(walkResult.contextWindow).context : void 0,
|
|
305
|
+
projectContext: walkResult.projectContext,
|
|
186
306
|
mcpServers: walkResult.mcpServers,
|
|
187
307
|
maxIterations: walkResult.mainLoop.maxIterations ?? walkResult.agentConfig.maxIterations,
|
|
188
308
|
timeoutMs: walkResult.mainLoop.timeoutMs ?? walkResult.agentConfig.timeoutMs,
|
|
@@ -299,7 +419,8 @@ function generateAgentRoutes(ctx) {
|
|
|
299
419
|
}
|
|
300
420
|
});
|
|
301
421
|
}
|
|
302
|
-
const
|
|
422
|
+
const rawSessionId = body?.sessionId;
|
|
423
|
+
const sessionId = typeof rawSessionId === "string" ? rawSessionId : `session-${Date.now()}`;
|
|
303
424
|
return streamAgentResponse(createRun(message, sessionId));
|
|
304
425
|
}, "handler")
|
|
305
426
|
});
|
|
@@ -337,281 +458,234 @@ function generateAgentRoutes(ctx) {
|
|
|
337
458
|
}
|
|
338
459
|
__name(generateAgentRoutes, "generateAgentRoutes");
|
|
339
460
|
|
|
340
|
-
// src/bridge/
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
function
|
|
358
|
-
const
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
const
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
461
|
+
// src/bridge/event-translator.ts
|
|
462
|
+
function asString(value, fallback) {
|
|
463
|
+
if (typeof value === "string") return value;
|
|
464
|
+
return fallback;
|
|
465
|
+
}
|
|
466
|
+
__name(asString, "asString");
|
|
467
|
+
function translateSystemEvent(msg, runId) {
|
|
468
|
+
return [
|
|
469
|
+
{
|
|
470
|
+
type: "run_started",
|
|
471
|
+
runId,
|
|
472
|
+
agentName: asString(msg.agent_id, "agent"),
|
|
473
|
+
model: asString(msg.model, "unknown")
|
|
474
|
+
}
|
|
475
|
+
];
|
|
476
|
+
}
|
|
477
|
+
__name(translateSystemEvent, "translateSystemEvent");
|
|
478
|
+
function translateAssistantEvent(msg) {
|
|
479
|
+
const events = [];
|
|
480
|
+
const content = msg.content;
|
|
481
|
+
if (!Array.isArray(content)) return events;
|
|
482
|
+
for (const block of content) {
|
|
483
|
+
const b = block;
|
|
484
|
+
if (b.type === "text" && b.text) {
|
|
485
|
+
events.push({
|
|
486
|
+
type: "text_delta",
|
|
487
|
+
content: b.text
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
if (b.type === "tool_use") {
|
|
491
|
+
events.push({
|
|
492
|
+
type: "tool_call",
|
|
493
|
+
callId: b.id ?? `tc-${Date.now()}`,
|
|
494
|
+
toolName: b.name ?? "unknown",
|
|
495
|
+
input: b.input ?? {}
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return events;
|
|
500
|
+
}
|
|
501
|
+
__name(translateAssistantEvent, "translateAssistantEvent");
|
|
502
|
+
function translateToolCallEvent(msg) {
|
|
503
|
+
const status = msg.status;
|
|
504
|
+
if (status === "completed") {
|
|
505
|
+
return [
|
|
506
|
+
{
|
|
507
|
+
type: "tool_result",
|
|
508
|
+
callId: asString(msg.id, `tc-${Date.now()}`),
|
|
509
|
+
toolName: asString(msg.name, "unknown"),
|
|
510
|
+
output: asString(msg.result, ""),
|
|
511
|
+
durationMs: 0,
|
|
512
|
+
isError: false
|
|
513
|
+
}
|
|
514
|
+
];
|
|
515
|
+
}
|
|
516
|
+
if (status === "error") {
|
|
517
|
+
return [
|
|
518
|
+
{
|
|
519
|
+
type: "tool_result",
|
|
520
|
+
callId: asString(msg.id, `tc-${Date.now()}`),
|
|
521
|
+
toolName: asString(msg.name, "unknown"),
|
|
522
|
+
output: asString(msg.error, "Tool failed"),
|
|
523
|
+
durationMs: 0,
|
|
524
|
+
isError: true
|
|
525
|
+
}
|
|
526
|
+
];
|
|
527
|
+
}
|
|
528
|
+
return [];
|
|
529
|
+
}
|
|
530
|
+
__name(translateToolCallEvent, "translateToolCallEvent");
|
|
531
|
+
function translateStatusEvent(msg) {
|
|
532
|
+
const s = msg.status;
|
|
533
|
+
if (s === "done" || s === "completed") {
|
|
534
|
+
return [
|
|
535
|
+
{
|
|
536
|
+
type: "done",
|
|
537
|
+
result: "",
|
|
538
|
+
usage: {
|
|
539
|
+
inputTokens: 0,
|
|
540
|
+
outputTokens: 0,
|
|
541
|
+
totalTokens: 0
|
|
542
|
+
},
|
|
543
|
+
durationMs: 0,
|
|
544
|
+
cost: 0
|
|
371
545
|
}
|
|
546
|
+
];
|
|
547
|
+
}
|
|
548
|
+
if (s === "error") {
|
|
549
|
+
return [
|
|
550
|
+
{
|
|
551
|
+
type: "error",
|
|
552
|
+
code: "AGENT_ERROR",
|
|
553
|
+
message: asString(msg.error, "Agent error"),
|
|
554
|
+
retryable: false
|
|
555
|
+
}
|
|
556
|
+
];
|
|
557
|
+
}
|
|
558
|
+
return [];
|
|
559
|
+
}
|
|
560
|
+
__name(translateStatusEvent, "translateStatusEvent");
|
|
561
|
+
function translateSdkEvent(msg, runId) {
|
|
562
|
+
switch (msg.type) {
|
|
563
|
+
case "system":
|
|
564
|
+
return translateSystemEvent(msg, runId);
|
|
565
|
+
case "assistant":
|
|
566
|
+
return translateAssistantEvent(msg);
|
|
567
|
+
case "tool_call":
|
|
568
|
+
return translateToolCallEvent(msg);
|
|
569
|
+
case "thinking":
|
|
570
|
+
return [
|
|
571
|
+
{
|
|
572
|
+
type: "thinking",
|
|
573
|
+
content: asString(msg.content, "")
|
|
574
|
+
}
|
|
575
|
+
];
|
|
576
|
+
case "status":
|
|
577
|
+
return translateStatusEvent(msg);
|
|
578
|
+
default:
|
|
579
|
+
return [];
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
__name(translateSdkEvent, "translateSdkEvent");
|
|
583
|
+
|
|
584
|
+
// src/bridge/sdk-adapter.ts
|
|
585
|
+
function assembleM8CreateOptions(compiled) {
|
|
586
|
+
const options = {};
|
|
587
|
+
const applied = [];
|
|
588
|
+
const base = compiled.systemPrompt;
|
|
589
|
+
if (compiled.skills) {
|
|
590
|
+
options.skills = compiled.skills;
|
|
591
|
+
options.local = {
|
|
592
|
+
settingSources: [
|
|
593
|
+
"project"
|
|
594
|
+
]
|
|
372
595
|
};
|
|
373
|
-
|
|
374
|
-
|
|
596
|
+
applied.push("skills");
|
|
597
|
+
}
|
|
598
|
+
if (compiled.context) {
|
|
599
|
+
options.context = compiled.context;
|
|
600
|
+
applied.push("context");
|
|
601
|
+
}
|
|
602
|
+
if (compiled.projectContext) {
|
|
603
|
+
options.systemPrompt = compileProjectContext(compiled.projectContext, base);
|
|
604
|
+
applied.push("projectContext");
|
|
605
|
+
} else if (base !== void 0) {
|
|
606
|
+
options.systemPrompt = base;
|
|
607
|
+
}
|
|
608
|
+
return {
|
|
609
|
+
options,
|
|
610
|
+
applied
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
__name(assembleM8CreateOptions, "assembleM8CreateOptions");
|
|
614
|
+
function createSdkAgentStream(compiled, compiledTools, apiKey, envModel) {
|
|
615
|
+
const model = envModel ?? compiled.model ?? "openai/gpt-4o-mini";
|
|
616
|
+
return (message, _sessionId) => ({
|
|
375
617
|
async *[Symbol.asyncIterator]() {
|
|
376
618
|
const runId = `run-${Date.now()}`;
|
|
377
619
|
const t0 = Date.now();
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
{
|
|
386
|
-
role: "system",
|
|
387
|
-
content: agentWalk.agentConfig.systemPrompt ?? "You are a helpful assistant."
|
|
388
|
-
}
|
|
389
|
-
],
|
|
390
|
-
createdAt: Date.now(),
|
|
391
|
-
totalCostUsd: 0
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
const session = sessions.get(sessionId);
|
|
395
|
-
session.messages.push({
|
|
396
|
-
role: "user",
|
|
397
|
-
content: message
|
|
398
|
-
});
|
|
399
|
-
yield {
|
|
400
|
-
type: "run_started",
|
|
401
|
-
runId,
|
|
402
|
-
agentName: agentWalk.agentConfig.name,
|
|
403
|
-
model
|
|
404
|
-
};
|
|
405
|
-
const maxIter = agentWalk.mainLoop.maxIterations ?? 5;
|
|
406
|
-
let inTok = 0, outTok = 0;
|
|
407
|
-
for (let iter = 1; iter <= maxIter; iter++) {
|
|
620
|
+
let Agent;
|
|
621
|
+
let defineTool;
|
|
622
|
+
try {
|
|
623
|
+
const sdk = await import("@theokit/sdk");
|
|
624
|
+
Agent = sdk.Agent;
|
|
625
|
+
defineTool = sdk.defineTool;
|
|
626
|
+
} catch {
|
|
408
627
|
yield {
|
|
409
|
-
type: "
|
|
410
|
-
|
|
411
|
-
|
|
628
|
+
type: "error",
|
|
629
|
+
code: "SDK_NOT_INSTALLED",
|
|
630
|
+
message: "Install @theokit/sdk: pnpm add @theokit/sdk",
|
|
631
|
+
retryable: false
|
|
412
632
|
};
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const errorBody = await res.text();
|
|
429
|
-
console.error(`[theokit:agents] OpenRouter ${res.status}:`, errorBody);
|
|
430
|
-
yield {
|
|
431
|
-
type: "error",
|
|
432
|
-
code: "LLM_ERROR",
|
|
433
|
-
message: `LLM request failed (${res.status})`,
|
|
434
|
-
retryable: res.status === 429
|
|
435
|
-
};
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
|
-
const reader = res.body.getReader();
|
|
439
|
-
const dec = new TextDecoder();
|
|
440
|
-
let buf = "";
|
|
441
|
-
let content = "";
|
|
442
|
-
let tcs = [];
|
|
443
|
-
let finish = "";
|
|
444
|
-
while (true) {
|
|
445
|
-
const { done, value } = await reader.read();
|
|
446
|
-
if (done) break;
|
|
447
|
-
buf += dec.decode(value, {
|
|
448
|
-
stream: true
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
const sdkTools = compiledTools.map((t) => defineTool({
|
|
636
|
+
name: t.name,
|
|
637
|
+
description: t.description,
|
|
638
|
+
inputSchema: t.inputSchema,
|
|
639
|
+
handler: t.handler
|
|
640
|
+
}));
|
|
641
|
+
try {
|
|
642
|
+
const { options: m8, applied } = assembleM8CreateOptions(compiled);
|
|
643
|
+
if (applied.length > 0) {
|
|
644
|
+
console.debug("[THEO_AGENT_M8_RUNTIME_APPLIED]", {
|
|
645
|
+
skills: applied.includes("skills"),
|
|
646
|
+
context: applied.includes("context"),
|
|
647
|
+
projectContext: applied.includes("projectContext")
|
|
449
648
|
});
|
|
450
|
-
const lines = buf.split("\n");
|
|
451
|
-
buf = lines.pop() ?? "";
|
|
452
|
-
for (const line of lines) {
|
|
453
|
-
if (!line.startsWith("data: ")) continue;
|
|
454
|
-
const d = line.slice(6).trim();
|
|
455
|
-
if (d === "[DONE]") continue;
|
|
456
|
-
try {
|
|
457
|
-
const c = JSON.parse(d);
|
|
458
|
-
const delta = c.choices?.[0]?.delta;
|
|
459
|
-
if (delta?.content) {
|
|
460
|
-
content += delta.content;
|
|
461
|
-
yield {
|
|
462
|
-
type: "text_delta",
|
|
463
|
-
content: delta.content
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
if (delta?.tool_calls) {
|
|
467
|
-
for (const tc of delta.tool_calls) {
|
|
468
|
-
if (tc.id) tcs[tc.index] = {
|
|
469
|
-
id: tc.id,
|
|
470
|
-
type: "function",
|
|
471
|
-
function: {
|
|
472
|
-
name: tc.function?.name ?? "",
|
|
473
|
-
arguments: ""
|
|
474
|
-
}
|
|
475
|
-
};
|
|
476
|
-
if (tc.function?.arguments && tcs[tc.index]) tcs[tc.index].function.arguments += tc.function.arguments;
|
|
477
|
-
if (tc.function?.name && tcs[tc.index]) tcs[tc.index].function.name = tc.function.name;
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
if (c.choices[0]?.finish_reason) finish = c.choices[0].finish_reason;
|
|
481
|
-
if (c.usage) {
|
|
482
|
-
inTok += c.usage.prompt_tokens;
|
|
483
|
-
outTok += c.usage.completion_tokens;
|
|
484
|
-
if (c.usage.cost) session.totalCostUsd += c.usage.cost;
|
|
485
|
-
}
|
|
486
|
-
} catch (parseErr) {
|
|
487
|
-
console.warn("[theokit:agents] Malformed SSE chunk skipped:", parseErr instanceof Error ? parseErr.message : "unknown");
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
649
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
input: JSON.parse(tc.function.arguments || "{}")
|
|
505
|
-
};
|
|
506
|
-
if (!tool) {
|
|
507
|
-
session.messages.push({
|
|
508
|
-
role: "tool",
|
|
509
|
-
content: "Tool not found",
|
|
510
|
-
tool_call_id: tc.id
|
|
511
|
-
});
|
|
512
|
-
yield {
|
|
513
|
-
type: "tool_result",
|
|
514
|
-
callId: tc.id,
|
|
515
|
-
toolName: orig,
|
|
516
|
-
output: "Not found",
|
|
517
|
-
durationMs: 0,
|
|
518
|
-
isError: true
|
|
519
|
-
};
|
|
520
|
-
continue;
|
|
521
|
-
}
|
|
522
|
-
const s = Date.now();
|
|
523
|
-
try {
|
|
524
|
-
const rawArgs = JSON.parse(tc.function.arguments || "{}");
|
|
525
|
-
if (tool.inputSchema && typeof tool.inputSchema === "object" && "safeParse" in tool.inputSchema) {
|
|
526
|
-
const validated = tool.inputSchema.safeParse(rawArgs);
|
|
527
|
-
if (!validated.success) {
|
|
528
|
-
session.messages.push({
|
|
529
|
-
role: "tool",
|
|
530
|
-
content: "Invalid tool arguments",
|
|
531
|
-
tool_call_id: tc.id
|
|
532
|
-
});
|
|
533
|
-
yield {
|
|
534
|
-
type: "tool_result",
|
|
535
|
-
callId: tc.id,
|
|
536
|
-
toolName: orig,
|
|
537
|
-
output: "Invalid tool arguments",
|
|
538
|
-
durationMs: Date.now() - s,
|
|
539
|
-
isError: true
|
|
540
|
-
};
|
|
541
|
-
continue;
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
const r = await tool.handler(rawArgs);
|
|
545
|
-
session.messages.push({
|
|
546
|
-
role: "tool",
|
|
547
|
-
content: r,
|
|
548
|
-
tool_call_id: tc.id
|
|
549
|
-
});
|
|
550
|
-
yield {
|
|
551
|
-
type: "tool_result",
|
|
552
|
-
callId: tc.id,
|
|
553
|
-
toolName: orig,
|
|
554
|
-
output: r.substring(0, 200),
|
|
555
|
-
durationMs: Date.now() - s,
|
|
556
|
-
isError: false
|
|
557
|
-
};
|
|
558
|
-
} catch (e) {
|
|
559
|
-
const m = e instanceof Error ? e.message : "Tool execution failed";
|
|
560
|
-
session.messages.push({
|
|
561
|
-
role: "tool",
|
|
562
|
-
content: `Error: ${m}`,
|
|
563
|
-
tool_call_id: tc.id
|
|
564
|
-
});
|
|
565
|
-
yield {
|
|
566
|
-
type: "tool_result",
|
|
567
|
-
callId: tc.id,
|
|
568
|
-
toolName: orig,
|
|
569
|
-
output: "Tool execution failed",
|
|
570
|
-
durationMs: Date.now() - s,
|
|
571
|
-
isError: true
|
|
572
|
-
};
|
|
573
|
-
}
|
|
650
|
+
const agent = await Agent.create({
|
|
651
|
+
apiKey,
|
|
652
|
+
model: {
|
|
653
|
+
id: model
|
|
654
|
+
},
|
|
655
|
+
tools: sdkTools,
|
|
656
|
+
...m8
|
|
657
|
+
});
|
|
658
|
+
const run = await agent.send(message);
|
|
659
|
+
for await (const sdkEvent of run.stream()) {
|
|
660
|
+
const translated = translateSdkEvent(sdkEvent, runId);
|
|
661
|
+
for (const event of translated) {
|
|
662
|
+
yield event;
|
|
574
663
|
}
|
|
575
|
-
tcs = [];
|
|
576
|
-
content = "";
|
|
577
|
-
continue;
|
|
578
664
|
}
|
|
579
|
-
if (content) session.messages.push({
|
|
580
|
-
role: "assistant",
|
|
581
|
-
content
|
|
582
|
-
});
|
|
583
665
|
yield {
|
|
584
666
|
type: "done",
|
|
585
|
-
result:
|
|
667
|
+
result: "",
|
|
586
668
|
usage: {
|
|
587
|
-
inputTokens:
|
|
588
|
-
outputTokens:
|
|
589
|
-
totalTokens:
|
|
669
|
+
inputTokens: 0,
|
|
670
|
+
outputTokens: 0,
|
|
671
|
+
totalTokens: 0
|
|
590
672
|
},
|
|
591
673
|
durationMs: Date.now() - t0,
|
|
592
|
-
cost:
|
|
674
|
+
cost: 0
|
|
675
|
+
};
|
|
676
|
+
await agent.dispose();
|
|
677
|
+
} catch (err) {
|
|
678
|
+
yield {
|
|
679
|
+
type: "error",
|
|
680
|
+
code: "SDK_ERROR",
|
|
681
|
+
message: err instanceof Error ? err.message : "SDK agent error",
|
|
682
|
+
retryable: false
|
|
593
683
|
};
|
|
594
|
-
return;
|
|
595
684
|
}
|
|
596
|
-
yield {
|
|
597
|
-
type: "error",
|
|
598
|
-
code: "MAX_ITERATIONS",
|
|
599
|
-
message: `Max iterations (${maxIter})`,
|
|
600
|
-
retryable: false
|
|
601
|
-
};
|
|
602
685
|
}
|
|
603
686
|
});
|
|
604
687
|
}
|
|
605
|
-
__name(
|
|
606
|
-
function convertZodToJsonSchema(schema) {
|
|
607
|
-
if (!schema || typeof schema !== "object") return {
|
|
608
|
-
type: "object",
|
|
609
|
-
properties: {}
|
|
610
|
-
};
|
|
611
|
-
const { $schema: _, ...rest } = z.toJSONSchema(schema);
|
|
612
|
-
return rest;
|
|
613
|
-
}
|
|
614
|
-
__name(convertZodToJsonSchema, "convertZodToJsonSchema");
|
|
688
|
+
__name(createSdkAgentStream, "createSdkAgentStream");
|
|
615
689
|
|
|
616
690
|
// src/bridge/agent-orchestrator.ts
|
|
617
691
|
var BudgetExceededError = class extends Error {
|
|
@@ -637,68 +711,90 @@ var DelegationError = class extends Error {
|
|
|
637
711
|
this.name = "DelegationError";
|
|
638
712
|
}
|
|
639
713
|
};
|
|
640
|
-
|
|
714
|
+
function asString2(value, fallback) {
|
|
715
|
+
if (typeof value === "string") return value;
|
|
716
|
+
return fallback;
|
|
717
|
+
}
|
|
718
|
+
__name(asString2, "asString");
|
|
719
|
+
function asNumber(value, fallback) {
|
|
720
|
+
if (typeof value === "number") return value;
|
|
721
|
+
return fallback;
|
|
722
|
+
}
|
|
723
|
+
__name(asNumber, "asNumber");
|
|
724
|
+
function requireApiKey(opts, agentName) {
|
|
641
725
|
const apiKey = opts.apiKey ?? "";
|
|
642
726
|
if (!apiKey) {
|
|
643
|
-
throw new DelegationError(
|
|
727
|
+
throw new DelegationError(agentName, "No API key provided. Pass apiKey in DelegateOptions.");
|
|
644
728
|
}
|
|
729
|
+
return apiKey;
|
|
730
|
+
}
|
|
731
|
+
__name(requireApiKey, "requireApiKey");
|
|
732
|
+
function mergeTools(parentTools, subTools) {
|
|
733
|
+
const subToolNames = new Set(subTools.map((t) => t.name));
|
|
734
|
+
const inherited = parentTools.filter((t) => !subToolNames.has(t.name));
|
|
735
|
+
return [
|
|
736
|
+
...inherited,
|
|
737
|
+
...subTools
|
|
738
|
+
];
|
|
739
|
+
}
|
|
740
|
+
__name(mergeTools, "mergeTools");
|
|
741
|
+
function processStreamEvent(event, acc, budget, agentName) {
|
|
742
|
+
if (event.type === "text_delta" && typeof event.content === "string") {
|
|
743
|
+
acc.response += event.content;
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
if (event.type === "tool_result") {
|
|
747
|
+
acc.toolCalls.push({
|
|
748
|
+
name: asString2(event.toolName, "unknown"),
|
|
749
|
+
input: event.input ?? {},
|
|
750
|
+
output: asString2(event.output, "")
|
|
751
|
+
});
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
if (event.type === "done") {
|
|
755
|
+
acc.cost = asNumber(event.cost, 0);
|
|
756
|
+
const usage = event.usage;
|
|
757
|
+
acc.tokens = usage?.totalTokens ?? 0;
|
|
758
|
+
if (Number.isFinite(budget) && acc.cost > budget) {
|
|
759
|
+
throw new BudgetExceededError(agentName, acc.cost, budget);
|
|
760
|
+
}
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
if (event.type === "error") {
|
|
764
|
+
throw new DelegationError(agentName, asString2(event.message, "Unknown agent error"));
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
__name(processStreamEvent, "processStreamEvent");
|
|
768
|
+
async function delegate(SubAgentClass, message, opts = {}) {
|
|
769
|
+
const apiKey = requireApiKey(opts, SubAgentClass.name);
|
|
645
770
|
const walk = walkAgentMetadata(SubAgentClass, []);
|
|
646
771
|
const toolboxInstances = new Map(walk.toolboxes.map((tb) => [
|
|
647
772
|
tb.class,
|
|
648
773
|
new tb.class()
|
|
649
774
|
]));
|
|
650
775
|
const compiled = compileAgent(walk, toolboxInstances);
|
|
651
|
-
const
|
|
652
|
-
const subToolNames = new Set(compiled.tools.map((t) => t.name));
|
|
653
|
-
const inherited = parentTools.filter((t) => !subToolNames.has(t.name));
|
|
654
|
-
const allTools = [
|
|
655
|
-
...inherited,
|
|
656
|
-
...compiled.tools
|
|
657
|
-
];
|
|
776
|
+
const allTools = mergeTools(opts.parentTools ?? [], compiled.tools);
|
|
658
777
|
const budget = Math.min(opts.budget ?? Infinity, opts.parentBudgetRemaining ?? Infinity);
|
|
659
|
-
const streamFactory =
|
|
778
|
+
const streamFactory = createSdkAgentStream(compiled, allTools, apiKey, walk.agentConfig.model);
|
|
660
779
|
const sessionId = opts.sessionId ?? `sub-${crypto.randomUUID()}`;
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
780
|
+
const acc = {
|
|
781
|
+
response: "",
|
|
782
|
+
toolCalls: [],
|
|
783
|
+
cost: 0,
|
|
784
|
+
tokens: 0
|
|
785
|
+
};
|
|
665
786
|
try {
|
|
666
|
-
const
|
|
667
|
-
|
|
668
|
-
if (event.type === "text_delta" && event.content) {
|
|
669
|
-
response += event.content;
|
|
670
|
-
}
|
|
671
|
-
if (event.type === "tool_result") {
|
|
672
|
-
toolCalls.push({
|
|
673
|
-
name: event.toolName ?? "unknown",
|
|
674
|
-
input: event.input ?? {},
|
|
675
|
-
output: event.output ?? ""
|
|
676
|
-
});
|
|
677
|
-
}
|
|
678
|
-
if (event.type === "done") {
|
|
679
|
-
cost = event.cost ?? 0;
|
|
680
|
-
tokens = event.usage?.totalTokens ?? 0;
|
|
681
|
-
if (Number.isFinite(budget) && cost > budget) {
|
|
682
|
-
throw new BudgetExceededError(SubAgentClass.name, cost, budget);
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
if (event.type === "error") {
|
|
686
|
-
throw new DelegationError(SubAgentClass.name, event.message ?? "Unknown agent error");
|
|
687
|
-
}
|
|
787
|
+
for await (const event of streamFactory(message, sessionId)) {
|
|
788
|
+
processStreamEvent(event, acc, budget, SubAgentClass.name);
|
|
688
789
|
}
|
|
689
790
|
} catch (err) {
|
|
690
791
|
if (err instanceof BudgetExceededError || err instanceof DelegationError) throw err;
|
|
691
792
|
throw new DelegationError(SubAgentClass.name, err);
|
|
692
793
|
}
|
|
693
|
-
if (Number.isFinite(budget) && cost > budget) {
|
|
694
|
-
throw new BudgetExceededError(SubAgentClass.name, cost, budget);
|
|
794
|
+
if (Number.isFinite(budget) && acc.cost > budget) {
|
|
795
|
+
throw new BudgetExceededError(SubAgentClass.name, acc.cost, budget);
|
|
695
796
|
}
|
|
696
|
-
return
|
|
697
|
-
response,
|
|
698
|
-
toolCalls,
|
|
699
|
-
cost,
|
|
700
|
-
tokens
|
|
701
|
-
};
|
|
797
|
+
return acc;
|
|
702
798
|
}
|
|
703
799
|
__name(delegate, "delegate");
|
|
704
800
|
|
|
@@ -753,7 +849,7 @@ function agentsPlugin(opts) {
|
|
|
753
849
|
name: "@theokit/agents",
|
|
754
850
|
register(app) {
|
|
755
851
|
app.addHook("onRequest", async (pluginCtx) => {
|
|
756
|
-
|
|
852
|
+
routes ??= initRoutes(opts);
|
|
757
853
|
const request = pluginCtx.request;
|
|
758
854
|
const url = new URL(request.url);
|
|
759
855
|
const method = request.method.toUpperCase();
|
|
@@ -786,11 +882,12 @@ function initRoutes(opts) {
|
|
|
786
882
|
allRoutes.push(...agentRoutes);
|
|
787
883
|
}
|
|
788
884
|
validateUniqueRoutes(walkResults);
|
|
789
|
-
return allRoutes;
|
|
885
|
+
return compileRoutePatterns(allRoutes);
|
|
790
886
|
}
|
|
791
887
|
__name(initRoutes, "initRoutes");
|
|
792
888
|
function defaultCreateRun(compiled) {
|
|
793
889
|
return async function* (_message, _sessionId) {
|
|
890
|
+
await Promise.resolve();
|
|
794
891
|
yield {
|
|
795
892
|
type: "run_started",
|
|
796
893
|
runId: `run-${Date.now()}`,
|
|
@@ -805,13 +902,21 @@ function defaultCreateRun(compiled) {
|
|
|
805
902
|
};
|
|
806
903
|
}
|
|
807
904
|
__name(defaultCreateRun, "defaultCreateRun");
|
|
905
|
+
function compileRoutePatterns(routes) {
|
|
906
|
+
return routes.map((r) => {
|
|
907
|
+
if (!r.path.includes(":")) return r;
|
|
908
|
+
const regexSource = r.path.replace(/:[^/]+/g, "[^/]+");
|
|
909
|
+
return {
|
|
910
|
+
...r,
|
|
911
|
+
regex: RegExp(`^${regexSource}$`)
|
|
912
|
+
};
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
__name(compileRoutePatterns, "compileRoutePatterns");
|
|
808
916
|
function matchRoute(routes, method, pathname) {
|
|
809
917
|
return routes.find((r) => {
|
|
810
918
|
if (r.method !== method) return false;
|
|
811
|
-
if (r.
|
|
812
|
-
const pattern = r.path.replace(/:[^/]+/g, "[^/]+");
|
|
813
|
-
return new RegExp(`^${pattern}$`).test(pathname);
|
|
814
|
-
}
|
|
919
|
+
if (r.regex) return r.regex.test(pathname);
|
|
815
920
|
return r.path === pathname;
|
|
816
921
|
});
|
|
817
922
|
}
|
|
@@ -820,8 +925,13 @@ __name(matchRoute, "matchRoute");
|
|
|
820
925
|
export {
|
|
821
926
|
createAgentExecutionContext,
|
|
822
927
|
isAgentContext,
|
|
928
|
+
compileContextWindow,
|
|
929
|
+
projectContextMetadataOnlyKnobs,
|
|
930
|
+
compileProjectContext,
|
|
931
|
+
AgentWarningCode,
|
|
823
932
|
walkAgentMetadata,
|
|
824
933
|
validateUniqueRoutes,
|
|
934
|
+
compileSkills,
|
|
825
935
|
compileTools,
|
|
826
936
|
compileAgent,
|
|
827
937
|
streamAgentResponse,
|
|
@@ -832,11 +942,12 @@ export {
|
|
|
832
942
|
isError,
|
|
833
943
|
isApprovalRequired,
|
|
834
944
|
generateAgentRoutes,
|
|
835
|
-
|
|
945
|
+
translateSdkEvent,
|
|
946
|
+
createSdkAgentStream,
|
|
836
947
|
BudgetExceededError,
|
|
837
948
|
DelegationError,
|
|
838
949
|
delegate,
|
|
839
950
|
generateAgentManifest,
|
|
840
951
|
agentsPlugin
|
|
841
952
|
};
|
|
842
|
-
//# sourceMappingURL=chunk-
|
|
953
|
+
//# sourceMappingURL=chunk-2MI27XCA.js.map
|