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.
- package/cli/templates/module.ts +4 -64
- package/cli/templates/passport.ts +14 -18
- 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/cache/COMPATIBILITY.md +4 -4
- package/core/cache/README.md +2 -2
- package/core/cache/SPEC.md +30 -48
- package/core/cache/decorators/Cacheable.ts +4 -3
- package/core/cache/decorators/CacheableRedis.ts +3 -4
- package/core/cache/di/classProviderHook.ts +31 -0
- package/core/cache/distributed/DistributedCache.ts +96 -25
- package/core/cache/distributed/IDistributedCache.ts +9 -0
- package/core/cache/distributed/codecs.ts +49 -2
- package/core/cache/distributed/index.ts +1 -1
- package/core/cache/errors/CacheError.ts +17 -2
- package/core/cache/http/outputRedisCacheMiddleware.ts +11 -2
- package/core/cache/index.ts +2 -6
- package/core/cache/services/cacheProxy.ts +6 -2
- package/core/generatedRuntime.ts +0 -31
- package/core/infra/cache/RedisDistributedCacheBackend.ts +3 -0
- 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/infra/connectors/redis.ts +9 -1
- package/core/scripts/di-generate.ts +28 -42
- package/core/scripts/tool-codegen.ts +122 -0
- package/index.ts +3 -24
- 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,12 +1,11 @@
|
|
|
1
1
|
import { inlineGeneratedSchema } from "./Schema.contract";
|
|
2
2
|
import { describeTool } from "../Tool.contract";
|
|
3
|
-
import type {
|
|
4
|
-
import { getGeneratedOpenApiMetadata
|
|
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
|
|
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
|
|
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.
|
|
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 =
|
|
589
|
-
const
|
|
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 ??
|
|
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.
|
|
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.
|
|
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(
|
|
706
|
+
messages = this.initialMessages(options);
|
|
773
707
|
seenToolCallIds = this.initialToolCallIds(messages);
|
|
774
708
|
} catch (error) {
|
|
775
|
-
return { ok: false, result: runtimeResult({ invocationId, agentName: agent.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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,
|
|
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.
|
|
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,
|
|
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.
|
|
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.
|
|
1060
|
-
if (plan.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
1001
|
+
throw new AgentRuntimeError("JSON output is malformed.");
|
|
1275
1002
|
}
|
|
1276
1003
|
}
|
|
1277
1004
|
|
|
1278
|
-
private
|
|
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,
|