bazis 0.98.34 → 0.99.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/cli/templates/module.ts +2 -60
- package/cli/templates/passport.ts +13 -17
- package/core/agent/AgentContextBuilder.ts +4 -98
- package/core/agent/AgentRegistry.ts +79 -473
- package/core/agent/AgentRuntime.ts +47 -19
- package/core/agent/AgentToolExecutor.ts +3 -3
- package/core/agent/README.md +89 -181
- package/core/agent/index.ts +3 -31
- package/core/agent/internal/AgentExecutionDriver.ts +37 -392
- package/core/agent/internal/AgentExecutionState.ts +1 -9
- package/core/agent/metadata.ts +8 -303
- package/core/agent/semantic.ts +0 -4
- package/core/agent/session/contracts.ts +5 -7
- package/core/agent/session/entities.ts +0 -1
- package/core/generatedRuntime.ts +0 -31
- package/core/infra/connectors/codex/CodexAppServerClient.ts +1 -1
- package/core/infra/connectors/llm.ts +15 -1
- package/core/infra/connectors/llmRouter.ts +4 -0
- package/core/scripts/di-generate.ts +28 -42
- package/core/scripts/tool-codegen.ts +122 -0
- package/index.ts +3 -22
- package/package.json +1 -1
- package/core/agent/decorators/Agent.ts +0 -11
- package/core/agent/decorators/Prompt.ts +0 -11
- package/core/agent/decorators/Task.ts +0 -29
- package/core/agent/generated/catalog.ts +0 -26
- package/core/scripts/agent-codegen.ts +0 -1166
|
@@ -1,539 +1,145 @@
|
|
|
1
|
-
import { DiContainer,
|
|
2
|
-
import { loadBazisGeneratedAgentMetadata } from "../generatedRuntime";
|
|
1
|
+
import { DiContainer, type Class, type ServiceProvider } from "../di";
|
|
3
2
|
import { AgentSetupError } from "./errors";
|
|
4
3
|
import type { AgentDataDefinition } from "./AgentDataDefinition";
|
|
5
4
|
import { getAgentModuleContributionsV1 } from "./moduleContributions-v1";
|
|
6
|
-
import {
|
|
7
|
-
agentMetadataOf,
|
|
8
|
-
promptMetadataOf,
|
|
9
|
-
toolMetadataOf,
|
|
10
|
-
type AgentMetadata,
|
|
11
|
-
type AgentTaskMetadata,
|
|
12
|
-
type PromptMetadata,
|
|
13
|
-
type ToolMetadata,
|
|
14
|
-
} from "./metadata";
|
|
15
|
-
|
|
16
|
-
export interface AgentDefinition {
|
|
17
|
-
readonly target: Class<object>;
|
|
18
|
-
readonly metadata: AgentMetadata;
|
|
19
|
-
readonly prompt?: PromptDefinition;
|
|
20
|
-
readonly tools: readonly ToolDefinition[];
|
|
21
|
-
readonly tasks: readonly AgentTaskDefinition[];
|
|
22
|
-
}
|
|
5
|
+
import { toolMetadataOf, type ToolMetadata } from "./metadata";
|
|
23
6
|
|
|
7
|
+
/** A Tool of the application: the class registered in `@Module.tools` and its `@Tool` metadata. */
|
|
24
8
|
export interface ToolDefinition {
|
|
25
9
|
readonly target: Class<object>;
|
|
26
10
|
readonly metadata: ToolMetadata;
|
|
27
11
|
}
|
|
28
12
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
readonly
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
readonly agent: AgentDefinition;
|
|
36
|
-
readonly metadata: AgentTaskMetadata;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface AgentCatalog {
|
|
40
|
-
readonly agents: readonly AgentDefinition[];
|
|
13
|
+
/** A meta-agent prepared for one run: its data and the Tools it may call. */
|
|
14
|
+
export interface AgentDefinition {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly description?: string;
|
|
17
|
+
readonly instructions: string;
|
|
18
|
+
readonly modelProfile?: string;
|
|
41
19
|
readonly tools: readonly ToolDefinition[];
|
|
42
|
-
readonly prompts: readonly PromptDefinition[];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface AgentCatalogExtras {
|
|
46
|
-
readonly agents?: readonly Class<object>[];
|
|
47
|
-
readonly tools?: readonly Class<object>[];
|
|
48
|
-
readonly prompts?: readonly Class<object>[];
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface AgentMetadataIndex {
|
|
52
|
-
readonly agents: ReadonlyMap<Class<object>, AgentMetadata>;
|
|
53
|
-
readonly tools: ReadonlyMap<Class<object>, ToolMetadata>;
|
|
54
|
-
readonly prompts: ReadonlyMap<Class<object>, PromptMetadata>;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
interface AgentModuleFields {
|
|
58
|
-
readonly agents?: readonly Class<object>[];
|
|
59
|
-
readonly tools?: readonly Class<object>[];
|
|
60
|
-
readonly prompts?: readonly Class<object>[];
|
|
61
20
|
}
|
|
62
21
|
|
|
63
|
-
|
|
64
|
-
// data agents have no decorated tasks or module registrations.
|
|
65
|
-
class DataAgentTarget {}
|
|
66
|
-
|
|
22
|
+
const IDENTIFIER = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/;
|
|
67
23
|
const containerCatalogs = new WeakMap<DiContainer, AgentRegistry>();
|
|
68
24
|
|
|
69
|
-
function
|
|
70
|
-
return target.name || "<anonymous class>";
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function appendClass(target: Class<object>, out: Class<object>[], seen: Set<Class<object>>): void {
|
|
74
|
-
if (!seen.has(target)) {
|
|
75
|
-
seen.add(target);
|
|
76
|
-
out.push(target);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function appendClasses(
|
|
81
|
-
values: readonly Class<object>[] | undefined,
|
|
82
|
-
out: Class<object>[],
|
|
83
|
-
seen: Set<Class<object>>,
|
|
84
|
-
): void {
|
|
85
|
-
if (values === undefined) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
for (let index = 0; index < values.length; index += 1) {
|
|
89
|
-
appendClass(values[index] as Class<object>, out, seen);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function assertUniqueName(
|
|
94
|
-
kind: "agent" | "tool" | "prompt",
|
|
95
|
-
name: string,
|
|
96
|
-
target: Class<object>,
|
|
97
|
-
names: Map<string, Class<object>>,
|
|
98
|
-
): void {
|
|
99
|
-
const existing = names.get(name);
|
|
100
|
-
if (existing && existing !== target) {
|
|
101
|
-
throw new AgentSetupError(
|
|
102
|
-
`Duplicate ${kind} name "${name}" on ${debugNameOf(existing)} and ${debugNameOf(target)}.`,
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
names.set(name, target);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function assertUniqueTaskName(agentName: string, task: AgentTaskMetadata, names: Map<string, AgentTaskMetadata>): void {
|
|
109
|
-
const existing = names.get(task.name);
|
|
110
|
-
if (existing && existing.methodName !== task.methodName) {
|
|
111
|
-
throw new AgentSetupError(
|
|
112
|
-
`Duplicate task name "${task.name}" on Agent "${agentName}" methods ` +
|
|
113
|
-
`"${existing.methodName}" and "${task.methodName}".`,
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
names.set(task.name, task);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function registerDefinition<TDefinition extends { readonly target: Class<object>; readonly metadata: { readonly name: string } }>(
|
|
120
|
-
kind: "agent" | "tool" | "prompt",
|
|
121
|
-
definition: TDefinition,
|
|
122
|
-
byName: Map<string, TDefinition>,
|
|
123
|
-
names: Map<string, Class<object>>,
|
|
124
|
-
): void {
|
|
125
|
-
assertUniqueName(kind, definition.metadata.name, definition.target, names);
|
|
126
|
-
byName.set(definition.metadata.name, definition);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function readAgentMetadata(target: Class<object>, metadataIndex?: AgentMetadataIndex): AgentMetadata | undefined {
|
|
130
|
-
return metadataIndex?.agents.get(target) ?? agentMetadataOf(target);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function readToolMetadata(target: Class<object>, metadataIndex?: AgentMetadataIndex): ToolMetadata | undefined {
|
|
134
|
-
return metadataIndex?.tools.get(target) ?? toolMetadataOf(target);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function readPromptMetadata(target: Class<object>, metadataIndex?: AgentMetadataIndex): PromptMetadata | undefined {
|
|
138
|
-
return metadataIndex?.prompts.get(target) ?? promptMetadataOf(target);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function requireAgentMetadata(target: Class<object>, metadataIndex?: AgentMetadataIndex): AgentMetadata {
|
|
142
|
-
const metadata = readAgentMetadata(target, metadataIndex);
|
|
143
|
-
if (!metadata) {
|
|
144
|
-
throw new AgentSetupError(`${debugNameOf(target)} is listed as an agent but is not decorated with @Agent(...).`);
|
|
145
|
-
}
|
|
146
|
-
return metadata;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function requireToolMetadata(target: Class<object>, owner?: string, metadataIndex?: AgentMetadataIndex): ToolMetadata {
|
|
150
|
-
const metadata = readToolMetadata(target, metadataIndex);
|
|
151
|
-
if (!metadata) {
|
|
152
|
-
const prefix = owner ? `${owner} references ` : "";
|
|
153
|
-
throw new AgentSetupError(`${prefix}${debugNameOf(target)} as a tool, but it is not decorated with @Tool(...).`);
|
|
154
|
-
}
|
|
155
|
-
return metadata;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function requirePromptMetadata(target: Class<object>, owner?: string, metadataIndex?: AgentMetadataIndex): PromptMetadata {
|
|
159
|
-
const metadata = readPromptMetadata(target, metadataIndex);
|
|
160
|
-
if (!metadata) {
|
|
161
|
-
const prefix = owner ? `${owner} references ` : "";
|
|
162
|
-
throw new AgentSetupError(`${prefix}${debugNameOf(target)} as a prompt, but it is not decorated with @Prompt(...).`);
|
|
163
|
-
}
|
|
164
|
-
return metadata;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function emptyCatalog(): AgentCatalog {
|
|
25
|
+
function snapshotTool(definition: ToolDefinition): ToolDefinition {
|
|
168
26
|
return Object.freeze({
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
prompts: Object.freeze([]),
|
|
27
|
+
target: definition.target,
|
|
28
|
+
metadata: Object.freeze({ ...definition.metadata, tags: Object.freeze([...definition.metadata.tags]) }),
|
|
172
29
|
});
|
|
173
30
|
}
|
|
174
31
|
|
|
175
32
|
/**
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
33
|
+
* The Tools of an application (`fromContainer`) and, for one run, the
|
|
34
|
+
* meta-agent allowed to call some of them (`fromDefinition`). An immutable
|
|
35
|
+
* snapshot: a later change of the definition affects the next run only.
|
|
179
36
|
*/
|
|
180
|
-
export
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const seenTools = new Set<Class<object>>();
|
|
192
|
-
const seenPrompts = new Set<Class<object>>();
|
|
193
|
-
const agentClasses: Class<object>[] = [];
|
|
194
|
-
const toolClasses: Class<object>[] = [];
|
|
195
|
-
const promptClasses: Class<object>[] = [];
|
|
196
|
-
|
|
197
|
-
const visit = (moduleRef: BazisModuleRef): void => {
|
|
198
|
-
if (loaded.has(moduleRef)) {
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
loaded.add(moduleRef);
|
|
202
|
-
|
|
203
|
-
const agentFields = moduleRef as AgentModuleFields;
|
|
204
|
-
appendClasses(agentFields.agents, agentClasses, seenAgents);
|
|
205
|
-
appendClasses(agentFields.tools, toolClasses, seenTools);
|
|
206
|
-
appendClasses(agentFields.prompts, promptClasses, seenPrompts);
|
|
207
|
-
|
|
208
|
-
const imports = moduleRef.imports;
|
|
209
|
-
if (imports) {
|
|
210
|
-
for (let index = 0; index < imports.length; index += 1) {
|
|
211
|
-
visit(imports[index] as BazisModuleRef);
|
|
37
|
+
export class AgentRegistry {
|
|
38
|
+
private readonly toolsByName = new Map<string, ToolDefinition>();
|
|
39
|
+
private readonly tools: readonly ToolDefinition[];
|
|
40
|
+
private readonly agent?: AgentDefinition;
|
|
41
|
+
|
|
42
|
+
private constructor(tools: readonly ToolDefinition[], agent?: AgentDefinition) {
|
|
43
|
+
this.tools = Object.freeze(tools.map(snapshotTool));
|
|
44
|
+
for (const tool of this.tools) {
|
|
45
|
+
const existing = this.toolsByName.get(tool.metadata.name);
|
|
46
|
+
if (existing !== undefined && existing.target !== tool.target) {
|
|
47
|
+
throw new AgentSetupError(`Duplicate tool name "${tool.metadata.name}" on ${existing.target.name || "<anonymous class>"} and ${tool.target.name || "<anonymous class>"}.`);
|
|
212
48
|
}
|
|
49
|
+
this.toolsByName.set(tool.metadata.name, tool);
|
|
213
50
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
for (let index = 0; index < expanded.length; index += 1) {
|
|
217
|
-
visit(expanded[index] as BazisModuleRef);
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
for (let index = 0; index < roots.length; index += 1) {
|
|
222
|
-
visit(roots[index] as BazisModuleRef);
|
|
223
|
-
}
|
|
224
|
-
appendClasses(extras.agents, agentClasses, seenAgents);
|
|
225
|
-
appendClasses(extras.tools, toolClasses, seenTools);
|
|
226
|
-
appendClasses(extras.prompts, promptClasses, seenPrompts);
|
|
227
|
-
|
|
228
|
-
const agentNames = new Map<string, Class<object>>();
|
|
229
|
-
const agentsMeta = new Map<Class<object>, AgentMetadata>();
|
|
230
|
-
for (let index = 0; index < agentClasses.length; index += 1) {
|
|
231
|
-
const target = agentClasses[index] as Class<object>;
|
|
232
|
-
const metadata = requireAgentMetadata(target, metadataIndex);
|
|
233
|
-
assertUniqueName("agent", metadata.name, target, agentNames);
|
|
234
|
-
const taskNames = new Map<string, AgentTaskMetadata>();
|
|
235
|
-
for (let taskIndex = 0; taskIndex < metadata.tasks.length; taskIndex += 1) {
|
|
236
|
-
assertUniqueTaskName(metadata.name, metadata.tasks[taskIndex] as AgentTaskMetadata, taskNames);
|
|
237
|
-
}
|
|
238
|
-
agentsMeta.set(target, metadata);
|
|
239
|
-
const agentName = `Agent "${metadata.name}"`;
|
|
240
|
-
if (metadata.prompt) {
|
|
241
|
-
requirePromptMetadata(metadata.prompt, agentName, metadataIndex);
|
|
242
|
-
appendClass(metadata.prompt, promptClasses, seenPrompts);
|
|
243
|
-
}
|
|
244
|
-
for (let toolIndex = 0; toolIndex < metadata.tools.length; toolIndex += 1) {
|
|
245
|
-
requireToolMetadata(metadata.tools[toolIndex] as Class<object>, agentName, metadataIndex);
|
|
51
|
+
if (agent !== undefined) {
|
|
52
|
+
this.agent = Object.freeze({ ...agent, tools: Object.freeze(agent.tools.map((tool) => this.toolsByName.get(tool.metadata.name) as ToolDefinition)) });
|
|
246
53
|
}
|
|
247
|
-
appendClasses(metadata.tools, toolClasses, seenTools);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const toolNames = new Map<string, Class<object>>();
|
|
251
|
-
const toolsByClass = new Map<Class<object>, ToolDefinition>();
|
|
252
|
-
const tools: ToolDefinition[] = [];
|
|
253
|
-
for (let index = 0; index < toolClasses.length; index += 1) {
|
|
254
|
-
const target = toolClasses[index] as Class<object>;
|
|
255
|
-
const metadata = requireToolMetadata(target, undefined, metadataIndex);
|
|
256
|
-
assertUniqueName("tool", metadata.name, target, toolNames);
|
|
257
|
-
const definition: ToolDefinition = Object.freeze({ target, metadata });
|
|
258
|
-
toolsByClass.set(target, definition);
|
|
259
|
-
tools.push(definition);
|
|
260
54
|
}
|
|
261
55
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
prompts.push(definition);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const agents: AgentDefinition[] = [];
|
|
275
|
-
for (let index = 0; index < agentClasses.length; index += 1) {
|
|
276
|
-
const target = agentClasses[index] as Class<object>;
|
|
277
|
-
const metadata = agentsMeta.get(target) as AgentMetadata;
|
|
278
|
-
const agentName = `Agent "${metadata.name}"`;
|
|
279
|
-
const resolvedTools: ToolDefinition[] = [];
|
|
280
|
-
for (let toolIndex = 0; toolIndex < metadata.tools.length; toolIndex += 1) {
|
|
281
|
-
const toolTarget = metadata.tools[toolIndex] as Class<object>;
|
|
282
|
-
requireToolMetadata(toolTarget, agentName, metadataIndex);
|
|
283
|
-
resolvedTools.push(toolsByClass.get(toolTarget) as ToolDefinition);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
let prompt: PromptDefinition | undefined;
|
|
287
|
-
if (metadata.prompt) {
|
|
288
|
-
requirePromptMetadata(metadata.prompt, agentName, metadataIndex);
|
|
289
|
-
prompt = promptsByClass.get(metadata.prompt);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const agentDefinition = {
|
|
293
|
-
target,
|
|
294
|
-
metadata,
|
|
295
|
-
prompt,
|
|
296
|
-
tools: Object.freeze(resolvedTools),
|
|
297
|
-
tasks: [] as AgentTaskDefinition[],
|
|
298
|
-
} as AgentDefinition & { tasks: AgentTaskDefinition[] };
|
|
299
|
-
for (let taskIndex = 0; taskIndex < metadata.tasks.length; taskIndex += 1) {
|
|
300
|
-
agentDefinition.tasks.push(Object.freeze({
|
|
301
|
-
agent: agentDefinition,
|
|
302
|
-
metadata: metadata.tasks[taskIndex] as AgentTaskMetadata,
|
|
303
|
-
}));
|
|
56
|
+
/**
|
|
57
|
+
* One meta-agent with the Tools it names, taken only from `allowedTools`
|
|
58
|
+
* (the application's catalog). An unknown or repeated tool name is an
|
|
59
|
+
* AgentSetupError before the model is called.
|
|
60
|
+
*/
|
|
61
|
+
static fromDefinition(input: AgentDataDefinition, allowedTools: readonly ToolDefinition[] = []): AgentRegistry {
|
|
62
|
+
if (!input || typeof input !== "object") throw new AgentSetupError("An agent definition must be an object.");
|
|
63
|
+
if (typeof input.name !== "string" || !IDENTIFIER.test(input.name)) {
|
|
64
|
+
throw new AgentSetupError("Agent name must be 1-128 latin letters, digits, dots, hyphens or underscores, starting with a letter or digit.");
|
|
304
65
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
return Object.freeze({
|
|
310
|
-
agents: Object.freeze(agents),
|
|
311
|
-
tools: Object.freeze(tools),
|
|
312
|
-
prompts: Object.freeze(prompts),
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
export class AgentRegistry {
|
|
317
|
-
private readonly catalog: AgentCatalog;
|
|
318
|
-
private readonly agentsByName = new Map<string, AgentDefinition>();
|
|
319
|
-
private readonly toolsByName = new Map<string, ToolDefinition>();
|
|
320
|
-
private readonly promptsByName = new Map<string, PromptDefinition>();
|
|
321
|
-
private readonly tasksByAgentAndName = new Map<string, AgentTaskDefinition>();
|
|
322
|
-
|
|
323
|
-
constructor(catalog: AgentCatalog = emptyCatalog()) {
|
|
324
|
-
// The registry is a snapshot: callers must not be able to mutate its list
|
|
325
|
-
// view after indexes and task backlinks have been constructed.
|
|
326
|
-
// Definitions can be present only on an Agent. Memoization is intentionally
|
|
327
|
-
// by source object, not class: two source definitions for one class may
|
|
328
|
-
// carry different valid metadata, while a shared definition needs one
|
|
329
|
-
// shared immutable snapshot wherever it is referenced.
|
|
330
|
-
const toolSnapshots = new WeakMap<ToolDefinition, ToolDefinition>();
|
|
331
|
-
const promptSnapshots = new WeakMap<PromptDefinition, PromptDefinition>();
|
|
332
|
-
const taskMetadataSnapshots = new WeakMap<AgentTaskMetadata, AgentTaskMetadata>();
|
|
333
|
-
const snapshotTool = (definition: ToolDefinition): ToolDefinition => {
|
|
334
|
-
const existing = toolSnapshots.get(definition);
|
|
335
|
-
if (existing) return existing;
|
|
336
|
-
const snapshot = Object.freeze({
|
|
337
|
-
target: definition.target,
|
|
338
|
-
metadata: Object.freeze({ ...definition.metadata, tags: Object.freeze([...definition.metadata.tags]) }),
|
|
339
|
-
});
|
|
340
|
-
toolSnapshots.set(definition, snapshot);
|
|
341
|
-
return snapshot;
|
|
342
|
-
};
|
|
343
|
-
const snapshotPrompt = (definition: PromptDefinition): PromptDefinition => {
|
|
344
|
-
const existing = promptSnapshots.get(definition);
|
|
345
|
-
if (existing) return existing;
|
|
346
|
-
const snapshot = Object.freeze({
|
|
347
|
-
target: definition.target,
|
|
348
|
-
metadata: Object.freeze({
|
|
349
|
-
...definition.metadata,
|
|
350
|
-
instructions: Object.freeze([...definition.metadata.instructions]),
|
|
351
|
-
constraints: Object.freeze([...definition.metadata.constraints]),
|
|
352
|
-
sections: Object.freeze(definition.metadata.sections.map((section) => Object.freeze({ ...section, content: Object.freeze([...section.content]) }))),
|
|
353
|
-
}),
|
|
354
|
-
});
|
|
355
|
-
promptSnapshots.set(definition, snapshot);
|
|
356
|
-
return snapshot;
|
|
357
|
-
};
|
|
358
|
-
const snapshotTaskMetadata = (metadata: AgentTaskMetadata): AgentTaskMetadata => {
|
|
359
|
-
const existing = taskMetadataSnapshots.get(metadata);
|
|
360
|
-
if (existing) return existing;
|
|
361
|
-
const snapshot = Object.freeze({ ...metadata });
|
|
362
|
-
taskMetadataSnapshots.set(metadata, snapshot);
|
|
363
|
-
return snapshot;
|
|
364
|
-
};
|
|
365
|
-
const tools = Object.freeze(catalog.tools.map(snapshotTool));
|
|
366
|
-
const prompts = Object.freeze(catalog.prompts.map(snapshotPrompt));
|
|
367
|
-
const agents = Object.freeze(catalog.agents.map((definition) => {
|
|
368
|
-
const metadata = Object.freeze({
|
|
369
|
-
...definition.metadata,
|
|
370
|
-
instructions: Object.freeze([...definition.metadata.instructions]), constraints: Object.freeze([...definition.metadata.constraints]),
|
|
371
|
-
sections: Object.freeze(definition.metadata.sections.map((section) => Object.freeze({ ...section, content: Object.freeze([...section.content]) }))),
|
|
372
|
-
tools: Object.freeze([...definition.metadata.tools]),
|
|
373
|
-
tasks: Object.freeze(definition.metadata.tasks.map(snapshotTaskMetadata)),
|
|
374
|
-
});
|
|
375
|
-
const agent = { target: definition.target, metadata, prompt: definition.prompt === undefined ? undefined : snapshotPrompt(definition.prompt), tools: Object.freeze(definition.tools.map(snapshotTool)), tasks: [] as AgentTaskDefinition[] } as AgentDefinition & { tasks: AgentTaskDefinition[] };
|
|
376
|
-
agent.tasks.push(...definition.tasks.map((task) => Object.freeze({ agent, metadata: snapshotTaskMetadata(task.metadata) })));
|
|
377
|
-
Object.freeze(agent.tasks);
|
|
378
|
-
return Object.freeze(agent);
|
|
379
|
-
}));
|
|
380
|
-
this.catalog = Object.freeze({ agents, tools, prompts });
|
|
381
|
-
|
|
382
|
-
const agentNames = new Map<string, Class<object>>();
|
|
383
|
-
const toolNames = new Map<string, Class<object>>();
|
|
384
|
-
const promptNames = new Map<string, Class<object>>();
|
|
385
|
-
|
|
386
|
-
for (let index = 0; index < agents.length; index += 1) {
|
|
387
|
-
const definition = agents[index] as AgentDefinition;
|
|
388
|
-
registerDefinition("agent", definition, this.agentsByName, agentNames);
|
|
389
|
-
for (let taskIndex = 0; taskIndex < definition.tasks.length; taskIndex += 1) {
|
|
390
|
-
const task = definition.tasks[taskIndex] as AgentTaskDefinition;
|
|
391
|
-
this.tasksByAgentAndName.set(taskKey(definition.metadata.name, task.metadata.name), task);
|
|
392
|
-
}
|
|
66
|
+
if (typeof input.instructions !== "string" || input.instructions.length > 100_000) {
|
|
67
|
+
throw new AgentSetupError(`Agent "${input.name}": instructions must be a string of at most 100000 characters.`);
|
|
393
68
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
registerDefinition("tool", definition, this.toolsByName, toolNames);
|
|
69
|
+
if (input.description !== undefined && (typeof input.description !== "string" || input.description.length > 4000)) {
|
|
70
|
+
throw new AgentSetupError(`Agent "${input.name}": description must be a string of at most 4000 characters.`);
|
|
397
71
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
registerDefinition("prompt", definition, this.promptsByName, promptNames);
|
|
72
|
+
if (input.modelProfile !== undefined && (typeof input.modelProfile !== "string" || !IDENTIFIER.test(input.modelProfile))) {
|
|
73
|
+
throw new AgentSetupError(`Agent "${input.name}": modelProfile must be an identifier of 1-128 characters.`);
|
|
401
74
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
/** Each invocation gets an immutable data snapshot and only host-approved tools. */
|
|
405
|
-
static fromDefinition(input: AgentDataDefinition, allowedTools: readonly ToolDefinition[] = []): AgentRegistry {
|
|
406
|
-
if (!input || typeof input.name !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(input.name)
|
|
407
|
-
|| typeof input.instructions !== "string" || input.instructions.length > 100_000
|
|
408
|
-
|| (input.description !== undefined && (typeof input.description !== "string" || input.description.length > 4000))
|
|
409
|
-
|| (input.modelProfile !== undefined && (typeof input.modelProfile !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(input.modelProfile)))
|
|
410
|
-
|| (input.toolNames !== undefined && (!Array.isArray(input.toolNames) || input.toolNames.length > 128))) {
|
|
411
|
-
throw new AgentSetupError("Invalid data agent definition.");
|
|
75
|
+
if (input.toolNames !== undefined && (!Array.isArray(input.toolNames) || input.toolNames.length > 128)) {
|
|
76
|
+
throw new AgentSetupError(`Agent "${input.name}": toolNames must be an array of at most 128 names.`);
|
|
412
77
|
}
|
|
413
78
|
const available = new Map<string, ToolDefinition>();
|
|
414
79
|
for (const tool of allowedTools) {
|
|
415
|
-
if (available.has(tool.metadata.name)) throw new AgentSetupError(
|
|
80
|
+
if (available.has(tool.metadata.name)) throw new AgentSetupError(`Duplicate tool name "${tool.metadata.name}" in the application catalog.`);
|
|
416
81
|
available.set(tool.metadata.name, tool);
|
|
417
82
|
}
|
|
418
83
|
const seen = new Set<string>();
|
|
419
|
-
const tools = (input.toolNames ?? []).map(name => {
|
|
84
|
+
const tools = (input.toolNames ?? []).map((name) => {
|
|
85
|
+
if (typeof name !== "string") throw new AgentSetupError(`Agent "${input.name}": tool names must be strings.`);
|
|
86
|
+
if (seen.has(name)) throw new AgentSetupError(`Agent "${input.name}": tool "${name}" is listed twice.`);
|
|
420
87
|
const tool = available.get(name);
|
|
421
|
-
if (
|
|
88
|
+
if (tool === undefined) {
|
|
89
|
+
const names = [...available.keys()].sort();
|
|
90
|
+
throw new AgentSetupError(`Agent "${input.name}": tool "${name}" is not registered in the application${names.length ? ` (registered: ${names.join(", ")})` : " (no tools are registered in @Module.tools)"}.`);
|
|
91
|
+
}
|
|
422
92
|
seen.add(name);
|
|
423
93
|
return tool;
|
|
424
94
|
});
|
|
425
|
-
const
|
|
426
|
-
name: input.name,
|
|
427
|
-
instructions: input.instructions
|
|
428
|
-
|
|
95
|
+
const agent: AgentDefinition = {
|
|
96
|
+
name: input.name,
|
|
97
|
+
instructions: input.instructions,
|
|
98
|
+
tools,
|
|
99
|
+
...(input.description === undefined ? {} : { description: input.description }),
|
|
100
|
+
...(input.modelProfile === undefined ? {} : { modelProfile: input.modelProfile }),
|
|
429
101
|
};
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
static fromModules(roots: readonly BazisModuleRef[], extras?: AgentCatalogExtras): AgentRegistry {
|
|
434
|
-
return new AgentRegistry(collectAgentCatalog(roots, extras));
|
|
102
|
+
// The whole catalog stays known so that a call of an unnamed tool is denied as
|
|
103
|
+
// not visible to this agent; the model is offered only `agent.tools`.
|
|
104
|
+
return new AgentRegistry(allowedTools, agent);
|
|
435
105
|
}
|
|
436
106
|
|
|
437
|
-
/**
|
|
107
|
+
/** The application's Tools from the `@Module.tools` registrations, without constructing them. */
|
|
438
108
|
static fromContainer(services: ServiceProvider): AgentRegistry {
|
|
439
|
-
if (!(services instanceof DiContainer)) throw new AgentSetupError("
|
|
109
|
+
if (!(services instanceof DiContainer)) throw new AgentSetupError("The Tool catalog requires the framework DiContainer.");
|
|
440
110
|
const existing = containerCatalogs.get(services);
|
|
441
111
|
if (existing) return existing;
|
|
442
|
-
const tools = getAgentModuleContributionsV1(services).tools.map(({ payload }) =>
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
112
|
+
const tools = getAgentModuleContributionsV1(services).tools.map(({ payload }) => {
|
|
113
|
+
const metadata = toolMetadataOf(payload.target);
|
|
114
|
+
if (metadata === undefined) throw new AgentSetupError(`${payload.target.name || "<anonymous class>"} is listed in @Module.tools but is not decorated with @Tool(...).`);
|
|
115
|
+
return { target: payload.target, metadata };
|
|
116
|
+
});
|
|
117
|
+
const registry = new AgentRegistry(tools);
|
|
446
118
|
containerCatalogs.set(services, registry);
|
|
447
119
|
return registry;
|
|
448
120
|
}
|
|
449
121
|
|
|
450
|
-
static async fromGeneratedModules(roots: readonly BazisModuleRef[], extras?: AgentCatalogExtras): Promise<AgentRegistry> {
|
|
451
|
-
const generated = await loadBazisGeneratedAgentMetadata(collectAgentMetadataTargets(roots, extras));
|
|
452
|
-
return new AgentRegistry(collectAgentCatalog(roots, extras, generated));
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
listAgents(): readonly AgentDefinition[] {
|
|
456
|
-
return this.catalog.agents;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
122
|
listTools(): readonly ToolDefinition[] {
|
|
460
|
-
return this.
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
listPrompts(): readonly PromptDefinition[] {
|
|
464
|
-
return this.catalog.prompts;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
getAgent(name: string): AgentDefinition | undefined {
|
|
468
|
-
return this.agentsByName.get(name);
|
|
123
|
+
return this.tools;
|
|
469
124
|
}
|
|
470
125
|
|
|
471
126
|
getTool(name: string): ToolDefinition | undefined {
|
|
472
127
|
return this.toolsByName.get(name);
|
|
473
128
|
}
|
|
474
129
|
|
|
475
|
-
getPrompt(name: string): PromptDefinition | undefined {
|
|
476
|
-
return this.promptsByName.get(name);
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
getTask(agentName: string, taskName: string): AgentTaskDefinition | undefined {
|
|
480
|
-
return this.tasksByAgentAndName.get(taskKey(agentName, taskName));
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
requireAgent(name: string): AgentDefinition {
|
|
484
|
-
const definition = this.getAgent(name);
|
|
485
|
-
if (!definition) {
|
|
486
|
-
throw new AgentSetupError(`Agent "${name}" is not registered.`);
|
|
487
|
-
}
|
|
488
|
-
return definition;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
130
|
requireTool(name: string): ToolDefinition {
|
|
492
131
|
const definition = this.getTool(name);
|
|
493
|
-
if (!definition) {
|
|
494
|
-
throw new AgentSetupError(`Tool "${name}" is not registered.`);
|
|
495
|
-
}
|
|
132
|
+
if (!definition) throw new AgentSetupError(`Tool "${name}" is not registered.`);
|
|
496
133
|
return definition;
|
|
497
134
|
}
|
|
498
135
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
if (!definition) {
|
|
502
|
-
throw new AgentSetupError(`Prompt "${name}" is not registered.`);
|
|
503
|
-
}
|
|
504
|
-
return definition;
|
|
136
|
+
getAgent(name: string): AgentDefinition | undefined {
|
|
137
|
+
return this.agent?.name === name ? this.agent : undefined;
|
|
505
138
|
}
|
|
506
139
|
|
|
507
|
-
|
|
508
|
-
const definition = this.
|
|
509
|
-
if (!definition) {
|
|
510
|
-
throw new AgentSetupError(`Task "${taskName}" is not registered on Agent "${agentName}".`);
|
|
511
|
-
}
|
|
140
|
+
requireAgent(name: string): AgentDefinition {
|
|
141
|
+
const definition = this.getAgent(name);
|
|
142
|
+
if (!definition) throw new AgentSetupError(`Agent "${name}" is not part of this run.`);
|
|
512
143
|
return definition;
|
|
513
144
|
}
|
|
514
145
|
}
|
|
515
|
-
|
|
516
|
-
function collectAgentMetadataTargets(roots: readonly BazisModuleRef[], extras: AgentCatalogExtras = {}): readonly Class<object>[] {
|
|
517
|
-
const loaded = new Set<BazisModuleRef>();
|
|
518
|
-
const targets: Class<object>[] = [];
|
|
519
|
-
const seen = new Set<Class<object>>();
|
|
520
|
-
const visit = (moduleRef: BazisModuleRef): void => {
|
|
521
|
-
if (loaded.has(moduleRef)) return;
|
|
522
|
-
loaded.add(moduleRef);
|
|
523
|
-
const fields = moduleRef as AgentModuleFields;
|
|
524
|
-
appendClasses(fields.agents, targets, seen);
|
|
525
|
-
appendClasses(fields.tools, targets, seen);
|
|
526
|
-
appendClasses(fields.prompts, targets, seen);
|
|
527
|
-
for (const imported of moduleRef.imports ?? []) visit(imported as BazisModuleRef);
|
|
528
|
-
for (const expanded of expandModuleMetadata(moduleRef)) visit(expanded as BazisModuleRef);
|
|
529
|
-
};
|
|
530
|
-
for (const root of roots) visit(root);
|
|
531
|
-
appendClasses(extras.agents, targets, seen);
|
|
532
|
-
appendClasses(extras.tools, targets, seen);
|
|
533
|
-
appendClasses(extras.prompts, targets, seen);
|
|
534
|
-
return targets;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
function taskKey(agentName: string, taskName: string): string {
|
|
538
|
-
return `${agentName}\u0000${taskName}`;
|
|
539
|
-
}
|