bazis 0.98.34 → 0.99.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,11 @@
1
1
  import { inlineGeneratedSchema } from "./Schema.contract";
2
2
  import { describeTool } from "../Tool.contract";
3
- import type { Class, ServiceProvider } from "../../di";
4
- import { getGeneratedOpenApiMetadata, getGeneratedOpenApiSchemaName } from "../../http/OpenApi/generatedOpenApiRegistry";
3
+ import type { ServiceProvider } from "../../di";
4
+ import { getGeneratedOpenApiMetadata } from "../../http/OpenApi/generatedOpenApiRegistry";
5
5
  import { redactSensitive, redactSensitiveText } from "../../../library/redaction";
6
6
  import { AgentRuntimeError } from "../errors";
7
- import { agentModelJson, bindAgentModel } from "./AgentModelBinding";
8
7
  import { validateAgentJsonSchema } from "./AgentJsonSchema";
9
- import type { AgentDefinition, AgentRegistry, AgentTaskDefinition, ToolDefinition } from "../AgentRegistry";
8
+ import type { AgentDefinition, AgentRegistry } from "../AgentRegistry";
10
9
  import {
11
10
  DefaultAgentContextBuilder,
12
11
  mergeAgentContextLimits,
@@ -18,7 +17,6 @@ import {
18
17
  AgentToolExecutor,
19
18
  type AgentToolExecutionOptions,
20
19
  type AgentToolExecutorOptions,
21
- type AgentToolSchemaValidator,
22
20
  } from "../AgentToolExecutor";
23
21
  import type { AgentModelProvider, AgentModelProviderContext } from "../ModelProvider";
24
22
  import {
@@ -29,7 +27,6 @@ import {
29
27
  type AgentExecutionCheckpointV1,
30
28
  } from "./AgentExecutionState";
31
29
  import {
32
- agentClassSchema,
33
30
  agentData,
34
31
  agentJsonSchema,
35
32
  agentMessage,
@@ -78,23 +75,21 @@ export interface AgentRuntimeOptions {
78
75
  readonly maxSteps?: number;
79
76
  readonly maxToolCallsPerStep?: number;
80
77
  readonly modelProfile?: string;
81
- readonly model?: string;
82
78
  /** Provider-call timeout. Defaults to 60 seconds; 0 explicitly disables it. */
83
79
  readonly timeoutMs?: number;
84
80
  readonly contextBuilder?: AgentContextBuilder;
85
81
  readonly contextLimits?: AgentContextLimits;
86
82
  readonly toolExecutorOptions?: AgentToolExecutorOptions;
87
- readonly taskSchemaValidator?: AgentToolSchemaValidator;
88
83
  }
89
84
 
90
85
  export interface AgentRuntimeInvokeOptions {
91
86
  readonly id?: string;
92
87
  readonly input?: unknown;
93
88
  readonly messages?: readonly AgentMessage[];
89
+ /** Structured result: `{ mode: "json", schema }` makes `result.output` the validated value. */
94
90
  readonly output?: AgentOutputContract;
95
91
  readonly metadata?: unknown;
96
92
  readonly modelProfile?: string;
97
- readonly model?: string;
98
93
  readonly maxSteps?: number;
99
94
  readonly maxToolCallsPerStep?: number;
100
95
  readonly maxOutputTokens?: number;
@@ -108,8 +103,6 @@ export interface AgentRuntimeInvokeOptions {
108
103
  readonly onTextDelta?: (event: { readonly step: number; readonly text: string }) => void;
109
104
  }
110
105
 
111
- export interface AgentRuntimeTaskInvokeOptions extends Omit<AgentRuntimeInvokeOptions, "input"> {}
112
-
113
106
  export interface AgentRuntimeResult {
114
107
  readonly invocationId: string;
115
108
  readonly agentName: string;
@@ -119,16 +112,12 @@ export interface AgentRuntimeResult {
119
112
  readonly responses: readonly AgentModelResponse[];
120
113
  readonly toolResults: readonly AgentToolResult[];
121
114
  readonly finalMessage?: AgentMessage;
122
- /** Validated structured value for declared or explicitly requested JSON output. */
115
+ /** Validated structured value when `output` requested JSON. */
123
116
  readonly output?: JsonValue;
124
117
  readonly error?: AgentToolError;
125
118
  readonly metadata: JsonObject;
126
119
  }
127
120
 
128
- type PreparedTaskContract =
129
- | { readonly ok: true; readonly instance: object; readonly value: JsonValue }
130
- | { readonly ok: false; readonly error: AgentToolError };
131
-
132
121
  type PreparedAgentPlan = {
133
122
  readonly agent: AgentDefinition;
134
123
  readonly invocationId: string;
@@ -144,29 +133,12 @@ type PreparedAgentPlan = {
144
133
  readonly executorToolOptions: AgentToolExecutionOptions;
145
134
  readonly sessionToolTimeouts?: ReadonlyMap<string, number>;
146
135
  readonly options: AgentRuntimeInvokeOptions;
147
- readonly taskFinalization?: TaskFinalizationPlan;
148
- };
149
-
150
- type TaskFinalizationPlan = {
151
- readonly task: AgentTaskDefinition;
152
- readonly timeoutMs: number | undefined;
153
- readonly signal: AbortSignal | undefined;
154
136
  };
155
137
 
156
138
  type AgentPreparation =
157
139
  | { readonly ok: true; readonly plan: PreparedAgentPlan }
158
140
  | { readonly ok: false; readonly result: AgentRuntimeResult };
159
141
 
160
- type PreparedTaskPlan = {
161
- readonly task: AgentTaskDefinition;
162
- readonly timeoutMs: number | undefined;
163
- readonly plan: PreparedAgentPlan;
164
- };
165
-
166
- type TaskPreparation =
167
- | { readonly ok: true; readonly prepared: PreparedTaskPlan }
168
- | { readonly ok: false; readonly result: AgentRuntimeResult };
169
-
170
142
  type EngineProgress = Pick<AgentExecutionCheckpointV1, "phase" | "steps" | "messages" | "responses" | "toolResults" | "seenToolCallIds" | "pendingToolBatch" | "terminal">;
171
143
 
172
144
  /** Progress of a run kept only in memory (no checkpoint store). */
@@ -200,7 +172,6 @@ export type AgentExecutionDriveOutcome =
200
172
  export interface AgentSessionPreparationV1 {
201
173
  readonly invocationId: string;
202
174
  readonly agentName: string;
203
- readonly taskName: string | null;
204
175
  readonly input: JsonValue;
205
176
  readonly requested: {
206
177
  readonly maxSteps: number | null;
@@ -380,12 +351,6 @@ function generatedInvocationId(): string {
380
351
  return `inv-${crypto.randomUUID()}`;
381
352
  }
382
353
 
383
- function classDebugName(value: unknown): string {
384
- const name = (value as { readonly name?: unknown }).name;
385
- return typeof name === "string" && name.trim().length > 0 ? name : "<anonymous class>";
386
- }
387
-
388
-
389
354
  function isObjectRecord(value: unknown): value is Record<string, unknown> {
390
355
  return typeof value === "object" && value !== null && !Array.isArray(value);
391
356
  }
@@ -535,11 +500,9 @@ export class AgentExecutionDriver {
535
500
  private readonly defaultMaxSteps: number;
536
501
  private readonly defaultMaxToolCallsPerStep: number;
537
502
  private readonly defaultModelProfile?: string;
538
- private readonly hasConcreteModelOption: boolean;
539
503
  readonly defaultTimeoutMs?: number;
540
504
  private readonly defaultContextLimits?: AgentContextLimits;
541
505
  private readonly contextBuilder: AgentContextBuilder;
542
- private readonly taskSchemaValidator?: AgentToolSchemaValidator;
543
506
 
544
507
  constructor(
545
508
  services: ServiceProvider,
@@ -553,13 +516,11 @@ export class AgentExecutionDriver {
553
516
  this.defaultMaxSteps = options.maxSteps ?? DEFAULT_MAX_STEPS;
554
517
  this.defaultMaxToolCallsPerStep = options.maxToolCallsPerStep ?? DEFAULT_MAX_TOOL_CALLS_PER_STEP;
555
518
  this.defaultModelProfile = optionalText(options.modelProfile, "AgentRuntime.modelProfile");
556
- this.hasConcreteModelOption = options.model !== undefined;
557
519
  this.defaultTimeoutMs = options.timeoutMs === 0
558
520
  ? undefined
559
521
  : options.timeoutMs ?? DEFAULT_MODEL_TIMEOUT_MS;
560
522
  this.defaultContextLimits = normalizeAgentContextLimits(options.contextLimits, "AgentRuntime.contextLimits");
561
523
  this.contextBuilder = options.contextBuilder ?? new DefaultAgentContextBuilder();
562
- this.taskSchemaValidator = options.taskSchemaValidator ?? options.toolExecutorOptions?.schemaValidator;
563
524
  this.toolExecutor = new AgentToolExecutor(services, registry, options.toolExecutorOptions);
564
525
  }
565
526
 
@@ -581,16 +542,13 @@ export class AgentExecutionDriver {
581
542
  contextLimits: undefined,
582
543
  signal: request.signal,
583
544
  };
584
- const prepared = request.taskName === null
585
- ? await this.prepareAgent(request.agentName, options)
586
- : await this.prepareTask(request.agentName, request.taskName, request.input, options);
545
+ const prepared = await this.prepareAgent(request.agentName, options);
587
546
  if (!prepared.ok) return { kind: "rejected", result: prepared.result };
588
- const plan = "plan" in prepared ? prepared.plan : prepared.prepared.plan;
589
- const task = "plan" in prepared ? undefined : prepared.prepared.task;
590
- const maxSteps = request.requested.maxSteps ?? Math.min(task?.metadata.maxSteps ?? plan.agent.metadata.maxSteps ?? request.module.maxSessionSteps, request.module.maxSessionSteps);
547
+ const plan = prepared.plan;
548
+ const maxSteps = request.requested.maxSteps ?? request.module.maxSessionSteps;
591
549
  const maxToolCallsPerStep = request.requested.maxToolCallsPerStep ?? request.module.maxToolCallsPerStep;
592
550
  const runTimeoutMs = request.requested.runTimeoutMs ?? request.module.runTimeoutMs;
593
- const modelProfile = request.requested.modelProfile ?? task?.metadata.modelProfile ?? plan.agent.metadata.modelProfile ?? null;
551
+ const modelProfile = request.requested.modelProfile ?? plan.agent.modelProfile ?? null;
594
552
  if (maxSteps > request.module.maxSessionSteps || maxToolCallsPerStep > request.module.maxToolCallsPerStep || runTimeoutMs > request.module.runTimeoutMs) {
595
553
  throw new AgentRuntimeError("AgentSession requested limits must not exceed module limits.");
596
554
  }
@@ -616,7 +574,6 @@ export class AgentExecutionDriver {
616
574
  [request.module.toolDefaultTimeoutMs, "AgentSession.toolDefaultTimeoutMs"], [request.module.scopeDisposeTimeoutMs, "AgentSession.scopeDisposeTimeoutMs"],
617
575
  ] as const) assertPositiveInteger(value, field);
618
576
  for (const [value, field] of [[request.requested.maxSteps, "AgentSession.maxSteps"], [request.requested.maxToolCallsPerStep, "AgentSession.maxToolCallsPerStep"], [request.requested.runTimeoutMs, "AgentSession.runTimeoutMs"]] as const) assertPositiveInteger(value ?? undefined, field);
619
- if (request.taskName !== null && request.taskName.trim().length === 0) throw new AgentRuntimeError("AgentSession.taskName must be non-empty.");
620
577
  }
621
578
 
622
579
  private initialCheckpoint(plan: PreparedAgentPlan, resolved: {
@@ -624,14 +581,11 @@ export class AgentExecutionDriver {
624
581
  readonly providerTimeoutMs: number; readonly toolDefaultTimeoutMs: number; readonly scopeDisposeTimeoutMs: number;
625
582
  }): AgentExecutionCheckpointV1 {
626
583
  const input = normalizeJsonValue(plan.options.input, "agentSession.input");
627
- const task = plan.taskFinalization?.task.metadata.name;
628
584
  return agentExecutionCheckpointV1({
629
585
  version: "bazis.agent-execution-state/v1",
630
586
  invocation: {
631
- kind: task === undefined ? "agent" : "task",
632
587
  invocationId: plan.invocationId,
633
- agentName: plan.agent.metadata.name,
634
- taskName: task ?? null,
588
+ agentName: plan.agent.name,
635
589
  input,
636
590
  metadata: plan.metadata,
637
591
  options: {
@@ -691,12 +645,6 @@ export class AgentExecutionDriver {
691
645
  const contextLimits = checkpointContextLimits(context);
692
646
  const toolOptions = checkpointToolExecutionOptions(tool, agent, checkpoint.invocation.invocationId);
693
647
  const sessionToolTimeouts = checkpointToolTimeouts(tool);
694
- let taskFinalization: TaskFinalizationPlan | undefined;
695
- if (checkpoint.invocation.kind === "task") {
696
- const task = this.registry.getTask(agent.metadata.name, checkpoint.invocation.taskName!);
697
- if (!task) throw new AgentRuntimeError(`Task "${checkpoint.invocation.taskName}" is not registered on Agent "${agent.metadata.name}".`);
698
- taskFinalization = { task, timeoutMs: providerTimeoutMs, signal: undefined };
699
- }
700
648
  return {
701
649
  agent,
702
650
  invocationId: checkpoint.invocation.invocationId,
@@ -718,9 +666,7 @@ export class AgentExecutionDriver {
718
666
  modelProfile,
719
667
  maxOutputTokens: optionNullablePositiveInteger(output.maxOutputTokens, "checkpoint.options.output.maxOutputTokens"),
720
668
  temperature: optionNullableFiniteNonNegative(output.temperature, "checkpoint.options.output.temperature"),
721
- ...(taskFinalization === undefined ? {} : { output: this.taskOutputContract(taskFinalization.task) }),
722
669
  },
723
- taskFinalization,
724
670
  };
725
671
  }
726
672
 
@@ -737,7 +683,7 @@ export class AgentExecutionDriver {
737
683
  assertPositiveInteger(options.maxSteps, "agentRuntime.maxSteps");
738
684
  assertPositiveInteger(options.maxToolCallsPerStep, "agentRuntime.maxToolCallsPerStep");
739
685
  assertNonNegativeInteger(options.timeoutMs, "agentRuntime.timeoutMs");
740
- maxSteps = options.maxSteps ?? this.registry.getAgent(agentName)?.metadata.maxSteps ?? this.defaultMaxSteps;
686
+ maxSteps = options.maxSteps ?? this.defaultMaxSteps;
741
687
  maxToolCallsPerStep = options.maxToolCallsPerStep ?? this.defaultMaxToolCallsPerStep;
742
688
  timeoutMs = options.timeoutMs === 0 ? undefined : options.timeoutMs ?? this.defaultTimeoutMs;
743
689
  modelProfile = optionalText(options.modelProfile, "agentRuntime.modelProfile");
@@ -745,9 +691,6 @@ export class AgentExecutionDriver {
745
691
  this.defaultContextLimits,
746
692
  normalizeAgentContextLimits(options.contextLimits, "agentRuntime.contextLimits"),
747
693
  );
748
- if (this.hasConcreteModelOption || options.model !== undefined) {
749
- throw new AgentRuntimeError("Concrete model selection is owned by Infra; use modelProfile instead.");
750
- }
751
694
  } catch (error) {
752
695
  return { ok: false, result: runtimeResult({ invocationId, agentName, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: runtimeError("AGENT_RUNTIME_OPTIONS_INVALID", errorMessageOf(error)), metadata: Object.freeze({}) }) };
753
696
  }
@@ -757,22 +700,13 @@ export class AgentExecutionDriver {
757
700
  return { ok: false, result: runtimeResult({ invocationId, agentName, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: runtimeError("AGENT_NOT_REGISTERED", `Agent "${agentName}" is not registered.`), metadata }) };
758
701
  }
759
702
 
760
- let declaredInput: unknown = options.input;
761
- if (agent.metadata.input !== undefined) {
762
- const prepared = await this.prepareTaskContract(agent.metadata.input, options.input, "input", timeoutMs, options.signal, "agent");
763
- if (!prepared.ok) {
764
- return { ok: false, result: runtimeResult({ invocationId, agentName: agent.metadata.name, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: this.agentContractError(prepared.error, "input"), metadata }) };
765
- }
766
- declaredInput = prepared.value;
767
- }
768
-
769
703
  let messages: AgentMessage[];
770
704
  let seenToolCallIds: Set<string>;
771
705
  try {
772
- messages = this.initialMessages({ ...options, input: declaredInput });
706
+ messages = this.initialMessages(options);
773
707
  seenToolCallIds = this.initialToolCallIds(messages);
774
708
  } catch (error) {
775
- return { ok: false, result: runtimeResult({ invocationId, agentName: agent.metadata.name, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: runtimeError("AGENT_INPUT_INVALID", errorMessageOf(error)), metadata }) };
709
+ return { ok: false, result: runtimeResult({ invocationId, agentName: agent.name, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: runtimeError("AGENT_INPUT_INVALID", errorMessageOf(error)), metadata }) };
776
710
  }
777
711
 
778
712
  return {
@@ -790,59 +724,7 @@ export class AgentExecutionDriver {
790
724
  seenToolCallIds,
791
725
  tools: this.toolContracts(agent),
792
726
  executorToolOptions: this.executorToolOptions(options.toolExecution),
793
- options: { ...options, id: invocationId, input: declaredInput },
794
- },
795
- };
796
- }
797
-
798
- private async prepareTask(
799
- agentName: string,
800
- taskName: string,
801
- input: unknown,
802
- options: AgentRuntimeTaskInvokeOptions,
803
- ): Promise<TaskPreparation> {
804
- const invocationId = options.id ?? generatedInvocationId();
805
- const task = this.registry.getTask(agentName, taskName);
806
- if (!task) {
807
- return { ok: false, result: runtimeResult({ invocationId, agentName, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: runtimeError("AGENT_TASK_NOT_REGISTERED", `Task "${taskName}" is not registered on Agent "${agentName}".`), metadata: Object.freeze({ taskName }) }) };
808
- }
809
-
810
- let timeoutMs: number | undefined;
811
- try {
812
- assertNonNegativeInteger(options.timeoutMs, "agentRuntime.timeoutMs");
813
- timeoutMs = options.timeoutMs === 0 ? undefined : options.timeoutMs ?? this.defaultTimeoutMs;
814
- } catch (error) {
815
- return { ok: false, result: runtimeResult({ invocationId, agentName, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: runtimeError("AGENT_RUNTIME_OPTIONS_INVALID", errorMessageOf(error)), metadata: Object.freeze({ taskName }) }) };
816
- }
817
-
818
- let preparedInput: unknown = input;
819
- if (task.metadata.input !== undefined) {
820
- const prepared = await this.prepareTaskContract(task.metadata.input, input, "input", timeoutMs, options.signal, "task");
821
- if (!prepared.ok) {
822
- return { ok: false, result: runtimeResult({ invocationId, agentName: task.agent.metadata.name, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: prepared.error, metadata: Object.freeze({ taskName: task.metadata.name }) }) };
823
- }
824
- preparedInput = prepared.value;
825
- }
826
-
827
- const agent = await this.prepareAgent(task.agent.metadata.name, {
828
- ...options,
829
- id: invocationId,
830
- input: preparedInput,
831
- output: this.taskOutputContract(task) ?? options.output,
832
- modelProfile: options.modelProfile ?? task.metadata.modelProfile,
833
- maxSteps: options.maxSteps ?? task.metadata.maxSteps,
834
- metadata: this.taskInvocationMetadata(options.metadata, task),
835
- });
836
- if (!agent.ok) return agent;
837
- return {
838
- ok: true,
839
- prepared: {
840
- task,
841
- timeoutMs,
842
- plan: {
843
- ...agent.plan,
844
- taskFinalization: { task, timeoutMs, signal: options.signal },
845
- },
727
+ options: { ...options, id: invocationId },
846
728
  },
847
729
  };
848
730
  }
@@ -906,7 +788,7 @@ export class AgentExecutionDriver {
906
788
  let idempotencyKey: string;
907
789
  try {
908
790
  idempotencyKey = !session
909
- ? this.toolIdempotencyKey(plan.options.toolExecution, { invocationId: plan.invocationId, agentName: plan.agent.metadata.name, call })
791
+ ? this.toolIdempotencyKey(plan.options.toolExecution, { invocationId: plan.invocationId, agentName: plan.agent.name, call })
910
792
  : this.sessionIdempotencyKey(plan.invocationId, call.id);
911
793
  } catch (error) {
912
794
  if (session) throw bridge.boundaryError(checkpoint);
@@ -922,7 +804,7 @@ export class AgentExecutionDriver {
922
804
  const result = await this.toolExecutor.execute(call, {
923
805
  ...plan.executorToolOptions,
924
806
  ...(toolTimeoutMs === undefined ? {} : { timeoutMs: toolTimeoutMs }),
925
- agentName: plan.agent.metadata.name,
807
+ agentName: plan.agent.name,
926
808
  invocationId: plan.invocationId,
927
809
  metadata: plan.metadata,
928
810
  signal,
@@ -966,7 +848,7 @@ export class AgentExecutionDriver {
966
848
  const candidate = bridge.evolve(checkpoint, {
967
849
  phase: "terminal", steps: checkpoint.steps, messages: checkpoint.messages, responses: checkpoint.responses,
968
850
  toolResults: checkpoint.toolResults, seenToolCallIds: checkpoint.seenToolCallIds, pendingToolBatch: undefined,
969
- terminal: { status: "failed", error: runtimeError("AGENT_MAX_STEPS_EXCEEDED", `Agent "${plan.agent.metadata.name}" exceeded maxSteps (${plan.maxSteps}).`, { maxSteps: plan.maxSteps }) },
851
+ terminal: { status: "failed", error: runtimeError("AGENT_MAX_STEPS_EXCEEDED", `Agent "${plan.agent.name}" exceeded maxSteps (${plan.maxSteps}).`, { maxSteps: plan.maxSteps }) },
970
852
  });
971
853
  const stopped = await control(candidate);
972
854
  return stopped ?? terminal(candidate, this.resultFromCheckpoint(plan, candidate));
@@ -980,10 +862,10 @@ export class AgentExecutionDriver {
980
862
  const context = this.contextBuilder.build({ invocationId: plan.invocationId, agent: plan.agent, messages: checkpoint.messages, metadata: plan.metadata, limits: plan.contextLimits });
981
863
  modelRequest = agentModelRequest({
982
864
  invocationId: plan.invocationId, messages: context.messages, tools: plan.tools,
983
- output: this.providerOutputContract(plan.agent.metadata.output === undefined ? plan.options.output : this.agentOutputContract(plan.agent)),
865
+ output: this.providerOutputContract(plan.options.output),
984
866
  modelProfile: plan.modelProfile,
985
867
  maxOutputTokens: plan.options.maxOutputTokens, temperature: plan.options.temperature,
986
- metadata: { ...plan.metadata, agentName: plan.agent.metadata.name, step, modelProfile: plan.modelProfile ?? null, agentContext: context.metadata },
868
+ metadata: { ...plan.metadata, agentName: plan.agent.name, step, modelProfile: plan.modelProfile ?? null, agentContext: context.metadata },
987
869
  });
988
870
  } catch (error) {
989
871
  const candidate = bridge.evolve(checkpoint, {
@@ -999,7 +881,7 @@ export class AgentExecutionDriver {
999
881
  } catch {
1000
882
  return suspend("before-model-rejected");
1001
883
  }
1002
- const response = await this.completeModel(modelRequest, plan.agent.metadata.name, plan.modelProfile, plan.metadata, signal, plan.timeoutMs,
884
+ const response = await this.completeModel(modelRequest, plan.agent.name, plan.modelProfile, plan.metadata, signal, plan.timeoutMs,
1003
885
  plan.options.onTextDelta ? text => plan.options.onTextDelta!(Object.freeze({ step, text })) : undefined);
1004
886
  if (!response.ok) {
1005
887
  const candidate = bridge.evolve(checkpoint, {
@@ -1010,7 +892,7 @@ export class AgentExecutionDriver {
1010
892
  const stopped = await committedControl(candidate);
1011
893
  return stopped ?? terminal(candidate, this.resultFromCheckpoint(plan, candidate));
1012
894
  }
1013
- const candidate = await this.modelCandidate(plan, checkpoint, step, response.value, signal, bridge);
895
+ const candidate = await this.modelCandidate(plan, checkpoint, step, response.value, bridge);
1014
896
  try { await boundary.afterModelSettlement(checkpoint, candidate.state, step, { response: response.value }); } catch { throw bridge.boundaryError(checkpoint); }
1015
897
  const stopped = await committedControl(candidate.state);
1016
898
  if (stopped !== undefined) return stopped;
@@ -1025,13 +907,13 @@ export class AgentExecutionDriver {
1025
907
  private resultFromCheckpoint(plan: PreparedAgentPlan, checkpoint: EngineProgress): AgentRuntimeResult {
1026
908
  const terminal = checkpoint.terminal;
1027
909
  if (terminal === undefined) throw new AgentRuntimeError("terminal checkpoint is required.");
1028
- return runtimeResult({ invocationId: plan.invocationId, agentName: plan.agent.metadata.name, status: terminal.status,
910
+ return runtimeResult({ invocationId: plan.invocationId, agentName: plan.agent.name, status: terminal.status,
1029
911
  steps: checkpoint.steps, messages: checkpoint.messages, responses: checkpoint.responses, toolResults: checkpoint.toolResults,
1030
912
  finalMessage: terminal.finalMessage, output: terminal.output, error: terminal.error, metadata: plan.metadata });
1031
913
  }
1032
914
 
1033
915
  private async modelCandidate<TState extends EngineProgress>(
1034
- plan: PreparedAgentPlan, checkpoint: TState, step: number, response: AgentModelResponse, signal: AbortSignal | undefined, bridge: PhaseBridge<TState>,
916
+ plan: PreparedAgentPlan, checkpoint: TState, step: number, response: AgentModelResponse, bridge: PhaseBridge<TState>,
1035
917
  ): Promise<{ readonly state: TState; readonly result?: AgentRuntimeResult }> {
1036
918
  const rejected = (code: string, message: string, retainResponse = true): { readonly state: TState; readonly result: AgentRuntimeResult } => {
1037
919
  const state = bridge.evolve(checkpoint, { phase: "terminal", steps: step, messages: checkpoint.messages,
@@ -1053,25 +935,11 @@ export class AgentExecutionDriver {
1053
935
  const messages = message === undefined ? checkpoint.messages : [...checkpoint.messages, message];
1054
936
  let result: AgentRuntimeResult;
1055
937
  if (response.finishReason !== "stop" || message === undefined) {
1056
- result = runtimeResult({ invocationId: plan.invocationId, agentName: plan.agent.metadata.name, status: "failed", steps: step, messages, responses: [...checkpoint.responses, response], toolResults: checkpoint.toolResults, finalMessage: message, metadata: plan.metadata,
938
+ result = runtimeResult({ invocationId: plan.invocationId, agentName: plan.agent.name, status: "failed", steps: step, messages, responses: [...checkpoint.responses, response], toolResults: checkpoint.toolResults, finalMessage: message, metadata: plan.metadata,
1057
939
  error: runtimeError("AGENT_PROVIDER_STOPPED", `Model provider stopped with finishReason "${response.finishReason}".`) });
1058
940
  } else {
1059
- result = runtimeResult({ invocationId: plan.invocationId, agentName: plan.agent.metadata.name, status: "completed", steps: step, messages, responses: [...checkpoint.responses, response], toolResults: checkpoint.toolResults, finalMessage: message, metadata: plan.metadata });
1060
- if (plan.agent.metadata.output !== undefined) {
1061
- try {
1062
- const output = this.parseTaskOutput(message);
1063
- const prepared = await this.prepareTaskContract(plan.agent.metadata.output, output, "output", plan.timeoutMs, signal, "agent");
1064
- result = prepared.ok
1065
- ? runtimeResult({ ...result, output: prepared.value })
1066
- : this.failedTaskResult(result, this.agentContractError(prepared.error, "output"));
1067
- } catch (error) {
1068
- result = this.failedTaskResult(result, runtimeError("AGENT_OUTPUT_INVALID", errorMessageOf(error)));
1069
- }
1070
- }
1071
- if (plan.agent.metadata.output === undefined && plan.taskFinalization?.task.metadata.output === undefined && plan.options.output?.mode === "json") {
1072
- result = this.validateExplicitOutput(result, plan.options.output);
1073
- }
1074
- if (result.status === "completed") result = await this.finalizeCompleted(plan, result, signal);
941
+ result = runtimeResult({ invocationId: plan.invocationId, agentName: plan.agent.name, status: "completed", steps: step, messages, responses: [...checkpoint.responses, response], toolResults: checkpoint.toolResults, finalMessage: message, metadata: plan.metadata });
942
+ if (plan.options.output?.mode === "json") result = this.validateExplicitOutput(result, plan.options.output);
1075
943
  }
1076
944
  const state = bridge.evolve(checkpoint, { phase: "terminal", steps: step, messages: result.messages, responses: result.responses, toolResults: result.toolResults, seenToolCallIds: checkpoint.seenToolCallIds, pendingToolBatch: undefined,
1077
945
  terminal: result.status === "completed" ? { status: "completed", finalMessage: result.finalMessage, output: result.output } : { status: "failed", finalMessage: result.finalMessage, error: result.error! } });
@@ -1080,20 +948,20 @@ export class AgentExecutionDriver {
1080
948
 
1081
949
  private validateExplicitOutput(result: AgentRuntimeResult, contract: AgentOutputContract): AgentRuntimeResult {
1082
950
  try {
1083
- const output = normalizeJsonValue(this.parseTaskOutput(result.finalMessage), "agent.output");
951
+ const output = normalizeJsonValue(this.parseJsonOutput(result.finalMessage), "agent.output");
1084
952
  const declared = contract.schema;
1085
953
  if (declared !== undefined) {
1086
954
  const generated = declared.kind === "class" ? getGeneratedOpenApiMetadata().schemas[declared.name] : undefined;
1087
955
  if (declared.kind === "class" && generated === undefined) {
1088
- return this.failedTaskResult(result, runtimeError("AGENT_OUTPUT_SCHEMA_UNAVAILABLE", `Output class "${declared.name}" has no generated JSON schema.`));
956
+ return this.failedResult(result, runtimeError("AGENT_OUTPUT_SCHEMA_UNAVAILABLE", `Output class "${declared.name}" has no generated JSON schema.`));
1089
957
  }
1090
958
  const schema = declared.kind === "json-schema" ? declared.schema : inlineGeneratedSchema(generated, getGeneratedOpenApiMetadata().schemas);
1091
959
  const issues = validateAgentJsonSchema(output, schema);
1092
- if (issues.length > 0) return this.failedTaskResult(result, runtimeError("AGENT_OUTPUT_INVALID", "Agent output failed JSON Schema validation.", { schema: declared.name, issues }));
960
+ if (issues.length > 0) return this.failedResult(result, runtimeError("AGENT_OUTPUT_INVALID", "Agent output failed JSON Schema validation.", { schema: declared.name, issues }));
1093
961
  }
1094
962
  return runtimeResult({ ...result, output });
1095
963
  } catch (error) {
1096
- return this.failedTaskResult(result, runtimeError("AGENT_OUTPUT_INVALID", errorMessageOf(error)));
964
+ return this.failedResult(result, runtimeError("AGENT_OUTPUT_INVALID", errorMessageOf(error)));
1097
965
  }
1098
966
  }
1099
967
 
@@ -1108,174 +976,33 @@ export class AgentExecutionDriver {
1108
976
  evolve(previous, progress) { return Object.freeze({ ...previous, ...progress }); },
1109
977
  boundaryError() { return new AgentRuntimeError("in-memory execution boundary rejected a transition."); },
1110
978
  };
1111
- const resolvedPlan = { ...plan, modelProfile: plan.modelProfile ?? plan.agent.metadata.modelProfile ?? this.defaultModelProfile };
979
+ const resolvedPlan = { ...plan, modelProfile: plan.modelProfile ?? plan.agent.modelProfile ?? this.defaultModelProfile };
1112
980
  const outcome = await this.drivePhaseEngine(resolvedPlan, initial, inMemoryBoundary, plan.options.signal, inMemoryBridge, false);
1113
981
  if (outcome.kind === "terminal") return outcome.result;
1114
982
  throw new AgentRuntimeError("in-memory execution cannot suspend.");
1115
983
  }
1116
- async invokeTask(
1117
- agentName: string,
1118
- taskName: string,
1119
- input: unknown,
1120
- options: AgentRuntimeTaskInvokeOptions = {},
1121
- ): Promise<AgentRuntimeResult> {
1122
- const preparation = await this.prepareTask(agentName, taskName, input, options);
1123
- if (!preparation.ok) return preparation.result;
1124
- return this.drive(preparation.prepared.plan);
1125
- }
1126
-
1127
- private async prepareTaskContract(
1128
- contract: Class<object>,
1129
- value: unknown,
1130
- direction: "input" | "output",
1131
- timeoutMs?: number,
1132
- signal?: AbortSignal,
1133
- contractKind: "agent" | "task" = "task",
1134
- ): Promise<PreparedTaskContract> {
1135
- if (signal?.aborted) {
1136
- return { ok: false, error: runtimeError("AGENT_ABORTED", "Agent runtime invocation was aborted.") };
1137
- }
1138
- try {
1139
- value = value instanceof contract
1140
- ? agentModelJson(value, `task.${direction}`)
1141
- : normalizeJsonValue(value, `task.${direction}`);
1142
- } catch (error) {
1143
- return { ok: false, error: runtimeError(direction === "input" ? "AGENT_TASK_INPUT_INVALID" : "AGENT_TASK_OUTPUT_INVALID", errorMessageOf(error)) };
1144
- }
1145
- const name = getGeneratedOpenApiSchemaName(contract) ?? classDebugName(contract);
1146
- if (!isObjectRecord(value)) {
1147
- return {
1148
- ok: false,
1149
- error: runtimeError(
1150
- contractKind === "agent"
1151
- ? direction === "input" ? "AGENT_INPUT_INVALID" : "AGENT_OUTPUT_INVALID"
1152
- : direction === "input" ? "AGENT_TASK_INPUT_INVALID" : "AGENT_TASK_OUTPUT_INVALID",
1153
- `${contractKind === "agent" ? "Agent" : "Task"} ${direction} schema "${name}" expects a JSON object.`,
1154
- ),
1155
- };
1156
- }
1157
-
1158
- const generated = getGeneratedOpenApiMetadata().schemas[name];
1159
- if (generated === undefined && this.taskSchemaValidator === undefined) {
1160
- return {
1161
- ok: false,
1162
- error: runtimeError(
1163
- "AGENT_TASK_SCHEMA_VALIDATOR_MISSING",
1164
- `Task ${direction} schema "${name}" has no generated JSON schema or configured validator.`,
1165
- ),
1166
- };
1167
- }
1168
- if (generated !== undefined) {
1169
- const issues = validateAgentJsonSchema(value, inlineGeneratedSchema(generated, getGeneratedOpenApiMetadata().schemas));
1170
- if (issues.length > 0) {
1171
- return {
1172
- ok: false,
1173
- error: runtimeError(
1174
- direction === "input" ? "AGENT_TASK_INPUT_VALIDATION_FAILED" : "AGENT_TASK_OUTPUT_VALIDATION_FAILED",
1175
- `Task ${direction} failed generated schema validation.`,
1176
- { schema: name, issues },
1177
- ),
1178
- };
1179
- }
1180
- }
1181
-
1182
- let instance: object;
1183
- try {
1184
- instance = bindAgentModel(contract, value);
1185
- } catch (error) {
1186
- return {
1187
- ok: false,
1188
- error: runtimeError(
1189
- direction === "input" ? "AGENT_TASK_INPUT_INVALID" : "AGENT_TASK_OUTPUT_INVALID",
1190
- errorMessageOf(error),
1191
- ),
1192
- };
1193
- }
1194
-
1195
- if (this.taskSchemaValidator !== undefined) {
1196
- try {
1197
- const validation = await timed(
1198
- Promise.resolve(this.taskSchemaValidator.validate(instance)),
1199
- timeoutMs,
1200
- () => undefined,
1201
- signal,
1202
- );
1203
- if (!validation || typeof validation.isValid !== "boolean" || !Array.isArray(validation.errors)) {
1204
- throw new AgentRuntimeError("task schema validator returned an invalid result.");
1205
- }
1206
- if (!validation.isValid) {
1207
- return {
1208
- ok: false,
1209
- error: runtimeError(
1210
- direction === "input" ? "AGENT_TASK_INPUT_VALIDATION_FAILED" : "AGENT_TASK_OUTPUT_VALIDATION_FAILED",
1211
- `Task ${direction} failed model validation.`,
1212
- {
1213
- schema: name,
1214
- issues: validation.errors.map((issue) => ({
1215
- property: String(issue.property),
1216
- message: String(issue.message),
1217
- ...(issue.code !== undefined ? { code: String(issue.code) } : {}),
1218
- })),
1219
- },
1220
- ),
1221
- };
1222
- }
1223
- } catch (error) {
1224
- if (error instanceof AgentRuntimeTimeoutError) {
1225
- return {
1226
- ok: false,
1227
- error: runtimeError("AGENT_TASK_SCHEMA_VALIDATION_TIMEOUT", `Task ${direction} schema validation timed out.`, { schema: name }),
1228
- };
1229
- }
1230
- if (error instanceof AgentRuntimeAbortError) {
1231
- return { ok: false, error: runtimeError("AGENT_ABORTED", "Agent runtime invocation was aborted.") };
1232
- }
1233
- return {
1234
- ok: false,
1235
- error: runtimeError(
1236
- "AGENT_TASK_SCHEMA_VALIDATION_FAILED",
1237
- `Task ${direction} schema validation failed: ${errorMessageOf(error)}`,
1238
- { schema: name },
1239
- ),
1240
- };
1241
- }
1242
- }
1243
-
1244
- try {
1245
- return { ok: true, instance, value: agentModelJson(instance, `task.${direction}`) };
1246
- } catch (error) {
1247
- return {
1248
- ok: false,
1249
- error: runtimeError(
1250
- direction === "input" ? "AGENT_TASK_INPUT_INVALID" : "AGENT_TASK_OUTPUT_INVALID",
1251
- errorMessageOf(error),
1252
- ),
1253
- };
1254
- }
1255
- }
1256
-
1257
- private parseTaskOutput(message: AgentMessage | undefined): unknown {
984
+ private parseJsonOutput(message: AgentMessage | undefined): unknown {
1258
985
  if (message === undefined) {
1259
- throw new AgentRuntimeError("Task provider response does not contain a final message.");
986
+ throw new AgentRuntimeError("Model response does not contain a final message.");
1260
987
  }
1261
988
  if (message.content.length === 1 && message.content[0]?.kind === "data") {
1262
989
  return message.content[0].value;
1263
990
  }
1264
991
  if (!message.content.every((part) => part.kind === "text")) {
1265
- throw new AgentRuntimeError("Task JSON output must contain only text or one data part.");
992
+ throw new AgentRuntimeError("JSON output must contain only text or one data part.");
1266
993
  }
1267
994
  const text = message.content.map((part) => part.kind === "text" ? part.text : "").join("\n").trim();
1268
995
  if (text.length === 0) {
1269
- throw new AgentRuntimeError("Task JSON output is empty.");
996
+ throw new AgentRuntimeError("JSON output is empty.");
1270
997
  }
1271
998
  try {
1272
999
  return JSON.parse(text) as unknown;
1273
1000
  } catch {
1274
- throw new AgentRuntimeError("Task JSON output is malformed.");
1001
+ throw new AgentRuntimeError("JSON output is malformed.");
1275
1002
  }
1276
1003
  }
1277
1004
 
1278
- private failedTaskResult(result: AgentRuntimeResult, error: AgentToolError): AgentRuntimeResult {
1005
+ private failedResult(result: AgentRuntimeResult, error: AgentToolError): AgentRuntimeResult {
1279
1006
  return runtimeResult({
1280
1007
  invocationId: result.invocationId,
1281
1008
  agentName: result.agentName,
@@ -1290,47 +1017,6 @@ export class AgentExecutionDriver {
1290
1017
  });
1291
1018
  }
1292
1019
 
1293
- private async finalizeCompleted(plan: PreparedAgentPlan, result: AgentRuntimeResult, currentSignal?: AbortSignal): Promise<AgentRuntimeResult> {
1294
- const finalization = plan.taskFinalization;
1295
- if (finalization === undefined || finalization.task.metadata.output === undefined) {
1296
- return result;
1297
- }
1298
- let outputValue: unknown;
1299
- try {
1300
- outputValue = this.parseTaskOutput(result.finalMessage);
1301
- } catch (error) {
1302
- return this.failedTaskResult(result, runtimeError("AGENT_TASK_OUTPUT_INVALID", errorMessageOf(error)));
1303
- }
1304
- const preparedOutput = await this.prepareTaskContract(
1305
- finalization.task.metadata.output,
1306
- outputValue,
1307
- "output",
1308
- finalization.timeoutMs,
1309
- currentSignal,
1310
- "task",
1311
- );
1312
- if (!preparedOutput.ok) {
1313
- return this.failedTaskResult(result, preparedOutput.error);
1314
- }
1315
- return runtimeResult({
1316
- invocationId: result.invocationId,
1317
- agentName: result.agentName,
1318
- status: "completed",
1319
- steps: result.steps,
1320
- messages: result.messages,
1321
- responses: result.responses,
1322
- toolResults: result.toolResults,
1323
- finalMessage: result.finalMessage,
1324
- output: preparedOutput.value,
1325
- metadata: result.metadata,
1326
- });
1327
- }
1328
-
1329
- private agentContractError(error: AgentToolError, direction: "input" | "output"): AgentToolError {
1330
- if (error.code === "AGENT_TASK_SCHEMA_VALIDATION_TIMEOUT" || error.code === "AGENT_ABORTED") return error;
1331
- return runtimeError(direction === "input" ? "AGENT_INPUT_INVALID" : "AGENT_OUTPUT_INVALID", error.message, error.details);
1332
- }
1333
-
1334
1020
  private initialMessages(options: AgentRuntimeInvokeOptions): AgentMessage[] {
1335
1021
  const messages: AgentMessage[] = [];
1336
1022
  if (options.messages !== undefined) {
@@ -1398,47 +1084,6 @@ export class AgentExecutionDriver {
1398
1084
  return agentOutputContract({ ...output, schema: agentJsonSchema(output.schema.name, inlineGeneratedSchema(generated, schemas), { strict: output.schema.strict }) });
1399
1085
  }
1400
1086
 
1401
- private taskOutputContract(task: AgentTaskDefinition): AgentOutputContract | undefined {
1402
- if (task.metadata.output === undefined) {
1403
- return undefined;
1404
- }
1405
- return agentOutputContract({
1406
- mode: "json",
1407
- schema: this.schemaContract(task.metadata.output),
1408
- });
1409
- }
1410
-
1411
- private agentOutputContract(agent: AgentDefinition): AgentOutputContract | undefined {
1412
- if (agent.metadata.output === undefined) {
1413
- return undefined;
1414
- }
1415
- return agentOutputContract({ mode: "json", schema: this.schemaContract(agent.metadata.output) });
1416
- }
1417
-
1418
- private schemaContract(model: NonNullable<ToolDefinition["metadata"]["input"]>) {
1419
- const name = getGeneratedOpenApiSchemaName(model) ?? classDebugName(model);
1420
- const schemas = getGeneratedOpenApiMetadata().schemas;
1421
- const generated = schemas[name];
1422
- if (generated === undefined) {
1423
- return agentClassSchema(name);
1424
- }
1425
- return agentJsonSchema(name, inlineGeneratedSchema(generated, schemas) as JsonObject);
1426
- }
1427
-
1428
- private taskInvocationMetadata(metadata: unknown, task: AgentTaskDefinition): unknown {
1429
- const taskMetadata = {
1430
- taskName: task.metadata.name,
1431
- taskMethodName: task.metadata.methodName,
1432
- };
1433
- if (metadata === undefined) {
1434
- return taskMetadata;
1435
- }
1436
- if (metadata !== null && typeof metadata === "object" && !Array.isArray(metadata)) {
1437
- return { ...(metadata as Record<string, unknown>), ...taskMetadata };
1438
- }
1439
- return metadata;
1440
- }
1441
-
1442
1087
  private async completeModel(
1443
1088
  request: AgentModelRequest,
1444
1089
  agentName: string,