bazis 0.98.33 → 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.
Files changed (43) hide show
  1. package/cli/templates/module.ts +4 -64
  2. package/cli/templates/passport.ts +14 -18
  3. package/core/agent/AgentContextBuilder.ts +4 -98
  4. package/core/agent/AgentRegistry.ts +79 -473
  5. package/core/agent/AgentRuntime.ts +47 -19
  6. package/core/agent/AgentToolExecutor.ts +3 -3
  7. package/core/agent/README.md +89 -181
  8. package/core/agent/index.ts +3 -31
  9. package/core/agent/internal/AgentExecutionDriver.ts +37 -392
  10. package/core/agent/internal/AgentExecutionState.ts +1 -9
  11. package/core/agent/metadata.ts +8 -303
  12. package/core/agent/semantic.ts +0 -4
  13. package/core/agent/session/contracts.ts +5 -7
  14. package/core/agent/session/entities.ts +0 -1
  15. package/core/cache/COMPATIBILITY.md +4 -4
  16. package/core/cache/README.md +2 -2
  17. package/core/cache/SPEC.md +30 -48
  18. package/core/cache/decorators/Cacheable.ts +4 -3
  19. package/core/cache/decorators/CacheableRedis.ts +3 -4
  20. package/core/cache/di/classProviderHook.ts +31 -0
  21. package/core/cache/distributed/DistributedCache.ts +96 -25
  22. package/core/cache/distributed/IDistributedCache.ts +9 -0
  23. package/core/cache/distributed/codecs.ts +49 -2
  24. package/core/cache/distributed/index.ts +1 -1
  25. package/core/cache/errors/CacheError.ts +17 -2
  26. package/core/cache/http/outputRedisCacheMiddleware.ts +11 -2
  27. package/core/cache/index.ts +2 -6
  28. package/core/cache/services/cacheProxy.ts +6 -2
  29. package/core/generatedRuntime.ts +0 -31
  30. package/core/infra/cache/RedisDistributedCacheBackend.ts +3 -0
  31. package/core/infra/connectors/codex/CodexAppServerClient.ts +1 -1
  32. package/core/infra/connectors/llm.ts +15 -1
  33. package/core/infra/connectors/llmRouter.ts +4 -0
  34. package/core/infra/connectors/redis.ts +9 -1
  35. package/core/scripts/di-generate.ts +28 -42
  36. package/core/scripts/tool-codegen.ts +122 -0
  37. package/index.ts +3 -24
  38. package/package.json +1 -1
  39. package/core/agent/decorators/Agent.ts +0 -11
  40. package/core/agent/decorators/Prompt.ts +0 -11
  41. package/core/agent/decorators/Task.ts +0 -29
  42. package/core/agent/generated/catalog.ts +0 -26
  43. package/core/scripts/agent-codegen.ts +0 -1166
@@ -1,539 +1,145 @@
1
- import { DiContainer, expandModuleMetadata, type Class, type BazisModuleRef, type ServiceProvider } from "../di";
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
- export interface PromptDefinition {
30
- readonly target: Class<object>;
31
- readonly metadata: PromptMetadata;
32
- }
33
-
34
- export interface AgentTaskDefinition {
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
- // Compatibility identity for the class-based catalog contract. Never instantiated;
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 debugNameOf(target: Class<object>): string {
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
- agents: Object.freeze([]),
170
- tools: Object.freeze([]),
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
- * Collects agent declarations from a module tree. The collector follows
177
- * `imports` and registered module metadata expanders, just like DI/container
178
- * discovery, but it keeps the AI layer outside the DI foundation.
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 function collectAgentCatalog(
181
- roots: readonly BazisModuleRef[],
182
- extras: AgentCatalogExtras = {},
183
- metadataIndex?: AgentMetadataIndex,
184
- ): AgentCatalog {
185
- if (roots.length === 0 && !extras.agents?.length && !extras.tools?.length && !extras.prompts?.length) {
186
- return emptyCatalog();
187
- }
188
-
189
- const loaded = new Set<BazisModuleRef>();
190
- const seenAgents = new Set<Class<object>>();
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
- const expanded = expandModuleMetadata(moduleRef);
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
- const promptNames = new Map<string, Class<object>>();
263
- const promptsByClass = new Map<Class<object>, PromptDefinition>();
264
- const prompts: PromptDefinition[] = [];
265
- for (let index = 0; index < promptClasses.length; index += 1) {
266
- const target = promptClasses[index] as Class<object>;
267
- const metadata = requirePromptMetadata(target, undefined, metadataIndex);
268
- assertUniqueName("prompt", metadata.name, target, promptNames);
269
- const definition: PromptDefinition = Object.freeze({ target, metadata });
270
- promptsByClass.set(target, definition);
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
- Object.freeze(agentDefinition.tasks);
306
- agents.push(Object.freeze(agentDefinition));
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
- for (let index = 0; index < tools.length; index += 1) {
395
- const definition = tools[index] as ToolDefinition;
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
- for (let index = 0; index < prompts.length; index += 1) {
399
- const definition = prompts[index] as PromptDefinition;
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("Duplicate host tool name.");
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 (typeof name !== "string" || !tool || seen.has(name)) throw new AgentSetupError("Agent tool is unavailable or duplicated.");
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 metadata: AgentMetadata = {
426
- name: input.name, description: input.description, modelProfile: input.modelProfile,
427
- instructions: input.instructions.trim() ? [input.instructions] : [],
428
- constraints: [], sections: [], tasks: [], tools: tools.map(tool => tool.target),
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
- return new AgentRegistry({ agents: [{ target: DataAgentTarget, metadata, tools, tasks: [] }], tools, prompts: [] });
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
- /** Host Tool catalog from actual owner-bound registrations, without constructing Tools or importing the app root. */
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("A host Tool catalog requires a framework DiContainer.");
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
- target: payload.target, metadata: requireToolMetadata(payload.target),
444
- }));
445
- const registry = new AgentRegistry({ agents: [], prompts: [], tools });
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.catalog.tools;
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
- requirePrompt(name: string): PromptDefinition {
500
- const definition = this.getPrompt(name);
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
- requireTask(agentName: string, taskName: string): AgentTaskDefinition {
508
- const definition = this.getTask(agentName, taskName);
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
- }