@nestjs-adk/core 0.0.3 → 1.0.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/README.md +40 -1
- package/dist/index.cjs +176 -23
- package/dist/index.d.ts +2 -1
- package/dist/index.mjs +173 -24
- package/dist/lib/errors/index.d.ts +1 -1
- package/dist/lib/errors/runtime.errors.d.ts +25 -0
- package/dist/lib/module/adk-options.d.ts +4 -0
- package/dist/lib/runner/agent-runner.d.ts +4 -0
- package/dist/lib/runner/run-logger.d.ts +3 -1
- package/dist/lib/runner/state-bag.d.ts +9 -1
- package/dist/lib/types/events.d.ts +2 -0
- package/dist/lib/types/options.d.ts +3 -0
- package/dist/lib/types/tool-context.d.ts +7 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -183,6 +183,45 @@ Pass a `sessionId` to `ask()` and the conversation becomes persistent. The agent
|
|
|
183
183
|
|
|
184
184
|
Storage goes through the `SessionStore` contract. The default implementation keeps everything in memory, which is perfect for development. For production you implement the contract with your own database and pass the class to `forRoot({ session })`. The store is the single source of truth: engines read from it and write to it, and never keep a private copy of the history.
|
|
185
185
|
|
|
186
|
+
## Validating the session state
|
|
187
|
+
|
|
188
|
+
The session state is a shared bag. Your code writes to it, tools write to it, and it can arrive from outside through a stored session. By default nothing checks those values, so a malformed value can travel all the way into your database layer. If you want a guarantee, declare a schema on the agent:
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
const reportState = z.object({ tenantId: z.string().min(1), count: z.number() });
|
|
192
|
+
|
|
193
|
+
@Agent({ name: "reporter", description: "Builds reports.", state: reportState, ... })
|
|
194
|
+
class ReporterAgent extends AdkAgent {}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
From that moment the framework validates the declared keys at every border. When a run starts, the state coming from `ask()` and from the stored session is checked before any call to the model, so an invalid value fails fast with an `AgentStateInvalidError` and costs zero tokens. When a tool writes with `ctx.state.set`, the write is checked at that moment. Keys that the schema does not declare keep flowing freely, which matters for pipelines where one agent writes its output for the next one.
|
|
198
|
+
|
|
199
|
+
Inside a tool you can also demand a value instead of hoping it is there:
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
execute(input, ctx: ToolContext<z.infer<typeof reportState>>) {
|
|
203
|
+
const tenantId = ctx.state.require("tenantId"); // typed as string, throws AgentStateMissingError if absent
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The generic on `ToolContext` is an annotation you choose, because the same tool can serve many agents. Typing it gives you autocomplete and typed reads. If a tool serves two agents, annotate it with the union of the two state types and TypeScript will only let you touch the keys both agents share.
|
|
208
|
+
|
|
209
|
+
One note about errors: `AgentStateInvalidError` exposes the raw Zod issues in `error.issues`. Decide what your application logs, because in Zod v4 the issues can include the rejected value.
|
|
210
|
+
|
|
211
|
+
## Capping the loop
|
|
212
|
+
|
|
213
|
+
A lost model can call tools forever, and a broken tool can fail forever while the model retries. Both burn tokens. The framework ships two optional caps:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
@Agent({ name: "reporter", maxIterations: 16, maxConsecutiveToolFailures: 2, ... })
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`maxIterations` limits the model and tool round trips in a single run. Passing the cap aborts the run with an `AgentMaxIterationsError` that carries the aggregated token usage and the last requested tool, so you know what the loop cost before it died. `maxConsecutiveToolFailures` is a circuit breaker per tool: when the same tool fails that many times in a row the run aborts with a `ToolRepeatedFailureError`, without waiting for the bigger cap. A success resets the count.
|
|
220
|
+
|
|
221
|
+
Both are off unless you set them. You can define module wide defaults with `forRoot({ defaults: { maxIterations: 16 } })`, override them per agent in the decorator, and override both per call in `ask()`. The call wins over the agent, and the agent wins over the module. Because the per call override wins, build your `RunInput` in your own code and never from a raw external payload.
|
|
222
|
+
|
|
223
|
+
These caps protect runs that go through `ask()`, `stream()` and the runner. The `adk web` playground resolves agents through a different path and does not count iterations, which is fine because it is a development tool.
|
|
224
|
+
|
|
186
225
|
## Keeping the context small
|
|
187
226
|
|
|
188
227
|
Long conversations and big tool results eat your context window. The framework handles both cases for you.
|
|
@@ -247,7 +286,7 @@ Modes are `sequential`, `parallel` and `loop`. A workflow is also an agent: you
|
|
|
247
286
|
|
|
248
287
|
`stream()` yields a normalized event loop: `run_start`, `tool_call`, `tool_result`, `llm_response`, `model_rerouted`, `approval_required` and `final`. Every event carries a `raw` field with the original payload from the provider, so no information is lost. `ask()` consumes the same loop and aggregates it into a `RunResult` with `text`, `usage`, `events`, `status` and, when declared, `output`.
|
|
249
288
|
|
|
250
|
-
Errors are not events. They throw as typed classes that extend `AdkError` and carry a `code`. Configuration problems throw at startup and point at the class that caused them. Runtime problems throw classes like `AiEmptyResponseError`, `OutputValidationError`, `ToolExecutionError` and `
|
|
289
|
+
Errors are not events. They throw as typed classes that extend `AdkError` and carry a `code`. Configuration problems throw at startup and point at the class that caused them. Runtime problems throw classes like `AiEmptyResponseError`, `OutputValidationError`, `ToolExecutionError`, `ModelsExhaustedError`, `AgentStateInvalidError` and `AgentMaxIterationsError`, so you can catch exactly what you care about.
|
|
251
290
|
|
|
252
291
|
## Logs
|
|
253
292
|
|
package/dist/index.cjs
CHANGED
|
@@ -159,6 +159,42 @@ class OutputValidationError extends AdkError {
|
|
|
159
159
|
this.code = "OUTPUT_VALIDATION_FAILED";
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
|
+
class AgentStateInvalidError extends AdkError {
|
|
163
|
+
constructor(agent, issues, key) {
|
|
164
|
+
super(key
|
|
165
|
+
? `Agent "${agent}" received a value for state key "${key}" that does not match its declared state schema.`
|
|
166
|
+
: `Agent "${agent}" received state that does not match its declared state schema.`);
|
|
167
|
+
this.issues = issues;
|
|
168
|
+
this.key = key;
|
|
169
|
+
this.code = "AGENT_STATE_INVALID";
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
class AgentStateMissingError extends AdkError {
|
|
173
|
+
constructor(agent, key) {
|
|
174
|
+
super(`Agent "${agent}" requires state key "${key}" but it is absent.`);
|
|
175
|
+
this.key = key;
|
|
176
|
+
this.code = "AGENT_STATE_MISSING";
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
class AgentMaxIterationsError extends AdkError {
|
|
180
|
+
constructor(agent, limit, usage, lastTool) {
|
|
181
|
+
super(`Agent "${agent}" exceeded maxIterations (${limit}) — the run was aborted.${lastTool ? ` Last requested tool: "${lastTool}".` : ""}`);
|
|
182
|
+
this.limit = limit;
|
|
183
|
+
this.usage = usage;
|
|
184
|
+
this.lastTool = lastTool;
|
|
185
|
+
this.code = "AGENT_MAX_ITERATIONS";
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
class ToolRepeatedFailureError extends AdkError {
|
|
189
|
+
constructor(agent, tool, failures, cause) {
|
|
190
|
+
super(`Tool "${tool}" failed ${failures} consecutive times on agent "${agent}" — the run was aborted.`, {
|
|
191
|
+
cause,
|
|
192
|
+
});
|
|
193
|
+
this.tool = tool;
|
|
194
|
+
this.failures = failures;
|
|
195
|
+
this.code = "TOOL_REPEATED_FAILURE";
|
|
196
|
+
}
|
|
197
|
+
}
|
|
162
198
|
class McpConnectionError extends AdkError {
|
|
163
199
|
constructor(server, cause) {
|
|
164
200
|
super(`MCP server "${server}" connection failed.`, { cause });
|
|
@@ -827,6 +863,13 @@ class RunLogger {
|
|
|
827
863
|
this.logger.verbose(json(event));
|
|
828
864
|
}
|
|
829
865
|
}
|
|
866
|
+
abort(error, usage) {
|
|
867
|
+
this.logger.warn(`run aborted after ${Date.now() - this.startedAt}ms: ${error.message}${usageSuffix(usage)}`);
|
|
868
|
+
}
|
|
869
|
+
toolFailure(tool, count, limit) {
|
|
870
|
+
if (this.enabled("debug"))
|
|
871
|
+
this.logger.debug(`tool "${tool}" failed (${count}/${limit ?? "∞"} consecutive)`);
|
|
872
|
+
}
|
|
830
873
|
enabled(level) {
|
|
831
874
|
return LEVEL_WEIGHT[level] <= LEVEL_WEIGHT[this.level];
|
|
832
875
|
}
|
|
@@ -852,9 +895,17 @@ function json(value) {
|
|
|
852
895
|
}
|
|
853
896
|
|
|
854
897
|
class DeltaStateBag {
|
|
855
|
-
constructor(initial) {
|
|
898
|
+
constructor(initial, guard = {}) {
|
|
856
899
|
this.initial = initial;
|
|
900
|
+
this.guard = guard;
|
|
857
901
|
this.changes = new Map();
|
|
902
|
+
const schema = guard.schema;
|
|
903
|
+
if (!schema)
|
|
904
|
+
return;
|
|
905
|
+
for (const key of Object.keys(schema.shape)) {
|
|
906
|
+
if (initial[key] !== undefined)
|
|
907
|
+
this.validate(key, initial[key]);
|
|
908
|
+
}
|
|
858
909
|
}
|
|
859
910
|
get(key) {
|
|
860
911
|
if (this.changes.has(key))
|
|
@@ -862,11 +913,28 @@ class DeltaStateBag {
|
|
|
862
913
|
return this.initial[key];
|
|
863
914
|
}
|
|
864
915
|
set(key, value) {
|
|
916
|
+
this.validate(key, value);
|
|
865
917
|
this.changes.set(key, value);
|
|
866
918
|
}
|
|
919
|
+
require(key) {
|
|
920
|
+
const value = this.get(key);
|
|
921
|
+
if (value === undefined)
|
|
922
|
+
throw new AgentStateMissingError(this.guard.agent ?? "unknown", key);
|
|
923
|
+
return value;
|
|
924
|
+
}
|
|
867
925
|
delta() {
|
|
868
926
|
return Object.fromEntries(this.changes);
|
|
869
927
|
}
|
|
928
|
+
validate(key, value) {
|
|
929
|
+
const shape = this.guard.schema?.shape;
|
|
930
|
+
if (!shape || !Object.hasOwn(shape, key))
|
|
931
|
+
return;
|
|
932
|
+
const field = shape[key];
|
|
933
|
+
const result = field.safeParse(value);
|
|
934
|
+
if (!result.success) {
|
|
935
|
+
throw new AgentStateInvalidError(this.guard.agent ?? "unknown", result.error?.issues, key);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
870
938
|
}
|
|
871
939
|
|
|
872
940
|
const EMPTY_USAGE = { promptTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
@@ -885,23 +953,54 @@ exports.AgentRunner = class AgentRunner {
|
|
|
885
953
|
const log = RunLogger.create(this.options.logging, definition.name);
|
|
886
954
|
log?.start(input);
|
|
887
955
|
const session = await this.openSession(input);
|
|
888
|
-
const state =
|
|
889
|
-
const
|
|
890
|
-
const
|
|
956
|
+
const state = this.stateBagFor(definition, { ...(session?.state ?? {}), ...(input.state ?? {}) });
|
|
957
|
+
const controller = new AbortController();
|
|
958
|
+
const signal = input.signal ? AbortSignal.any([input.signal, controller.signal]) : controller.signal;
|
|
959
|
+
const runtime = this.createRuntime(definition, input, controller, log);
|
|
960
|
+
const ctx = this.createToolContext(definition, input, state, signal);
|
|
891
961
|
const resolved = await this.resolveAgent(definition, ctx, runtime);
|
|
892
|
-
const engineInput = { ...input, history: session?.events };
|
|
962
|
+
const engineInput = { ...input, signal, history: session?.events };
|
|
893
963
|
if (session)
|
|
894
964
|
await this.persist(session.id, "user", "message", { text: input.message });
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
965
|
+
let iterations = 0;
|
|
966
|
+
let usage = EMPTY_USAGE;
|
|
967
|
+
let lastEventType;
|
|
968
|
+
try {
|
|
969
|
+
for await (const event of this.engine.run(resolved, engineInput)) {
|
|
970
|
+
if (runtime.fatal)
|
|
971
|
+
break;
|
|
972
|
+
if (event.type === "llm_response" && event.usage)
|
|
973
|
+
usage = addUsage(usage, event.usage);
|
|
974
|
+
if (event.type === "tool_call" && lastEventType !== "tool_call") {
|
|
975
|
+
iterations += 1;
|
|
976
|
+
const limit = runtime.limits.maxIterations;
|
|
977
|
+
if (limit !== undefined && iterations > limit) {
|
|
978
|
+
runtime.abort(new AgentMaxIterationsError(definition.name, limit, usage, event.tool));
|
|
979
|
+
break;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
lastEventType = event.type;
|
|
983
|
+
log?.event(event);
|
|
984
|
+
if (session)
|
|
985
|
+
await this.persistAgentEvent(session.id, event);
|
|
986
|
+
if (event.type === "final" && definition.output && definition.outputKey) {
|
|
987
|
+
const parsed = definition.output.safeParse(tryParseJson(event.text));
|
|
988
|
+
if (parsed.success)
|
|
989
|
+
state.set(definition.outputKey, parsed.data);
|
|
990
|
+
}
|
|
991
|
+
yield event;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
catch (error) {
|
|
995
|
+
if (runtime.fatal) {
|
|
996
|
+
log?.abort(runtime.fatal, usage);
|
|
997
|
+
throw runtime.fatal;
|
|
903
998
|
}
|
|
904
|
-
|
|
999
|
+
throw error;
|
|
1000
|
+
}
|
|
1001
|
+
if (runtime.fatal) {
|
|
1002
|
+
log?.abort(runtime.fatal, usage);
|
|
1003
|
+
throw runtime.fatal;
|
|
905
1004
|
}
|
|
906
1005
|
for (const pending of runtime.pendings) {
|
|
907
1006
|
const approval = {
|
|
@@ -960,7 +1059,7 @@ exports.AgentRunner = class AgentRunner {
|
|
|
960
1059
|
const binding = definition.tools.find((candidate) => candidate.options.name === entry.tool);
|
|
961
1060
|
if (!binding)
|
|
962
1061
|
throw new ApprovalNotFoundError(params.callId, params.sessionId);
|
|
963
|
-
const state =
|
|
1062
|
+
const state = this.stateBagFor(definition, session.state);
|
|
964
1063
|
const ctx = this.createToolContext(definition, { message: "", sessionId: session.id, userId: session.userId }, state);
|
|
965
1064
|
const result = await this.executeBinding(definition, binding, entry.args, ctx);
|
|
966
1065
|
await this.persist(session.id, "tool", "tool_result", { callId: entry.callId, tool: entry.tool, result });
|
|
@@ -978,11 +1077,9 @@ exports.AgentRunner = class AgentRunner {
|
|
|
978
1077
|
}
|
|
979
1078
|
resolve(agentType, input = { message: "" }) {
|
|
980
1079
|
const definition = this.definitionOf(agentType);
|
|
981
|
-
const state =
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
pendings: [],
|
|
985
|
-
});
|
|
1080
|
+
const state = this.stateBagFor(definition, { ...(input.state ?? {}) });
|
|
1081
|
+
const runtime = this.createRuntime(definition, input);
|
|
1082
|
+
return this.resolveAgent(definition, this.createToolContext(definition, input, state), runtime);
|
|
986
1083
|
}
|
|
987
1084
|
definitionOf(agentType) {
|
|
988
1085
|
return typeof agentType === "string" ? this.registry.get(agentType) : this.registry.getByType(agentType);
|
|
@@ -1005,17 +1102,42 @@ exports.AgentRunner = class AgentRunner {
|
|
|
1005
1102
|
throw new ApprovalNotFoundError(callId, sessionId);
|
|
1006
1103
|
return { session, entry, rest: pendings.filter((candidate) => candidate.callId !== callId) };
|
|
1007
1104
|
}
|
|
1008
|
-
createToolContext(definition, input, state) {
|
|
1105
|
+
createToolContext(definition, input, state, signal) {
|
|
1009
1106
|
return {
|
|
1010
1107
|
agentName: definition.name,
|
|
1011
1108
|
sessionId: input.sessionId,
|
|
1012
1109
|
userId: input.userId,
|
|
1013
1110
|
state,
|
|
1014
1111
|
attributes: input.attributes ?? {},
|
|
1015
|
-
signal: input.signal ?? new AbortController().signal,
|
|
1112
|
+
signal: signal ?? input.signal ?? new AbortController().signal,
|
|
1016
1113
|
actions: { endRun: () => undefined },
|
|
1017
1114
|
};
|
|
1018
1115
|
}
|
|
1116
|
+
stateBagFor(definition, initial) {
|
|
1117
|
+
return new DeltaStateBag(initial, { schema: definition.options?.state, agent: definition.name });
|
|
1118
|
+
}
|
|
1119
|
+
createRuntime(definition, input, controller, log) {
|
|
1120
|
+
const runtime = {
|
|
1121
|
+
scope: input.sessionId ?? node_crypto.randomUUID(),
|
|
1122
|
+
pendings: [],
|
|
1123
|
+
failures: new Map(),
|
|
1124
|
+
limits: this.limitsFor(definition, input),
|
|
1125
|
+
log,
|
|
1126
|
+
abort: (error) => {
|
|
1127
|
+
runtime.fatal ??= error;
|
|
1128
|
+
controller?.abort();
|
|
1129
|
+
},
|
|
1130
|
+
};
|
|
1131
|
+
return runtime;
|
|
1132
|
+
}
|
|
1133
|
+
limitsFor(definition, input) {
|
|
1134
|
+
return {
|
|
1135
|
+
maxIterations: input.maxIterations ?? definition.options?.maxIterations ?? this.options.defaults?.maxIterations,
|
|
1136
|
+
maxConsecutiveToolFailures: input.maxConsecutiveToolFailures ??
|
|
1137
|
+
definition.options?.maxConsecutiveToolFailures ??
|
|
1138
|
+
this.options.defaults?.maxConsecutiveToolFailures,
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1019
1141
|
policyOf(definition) {
|
|
1020
1142
|
return definition.options?.context ?? this.options.context;
|
|
1021
1143
|
}
|
|
@@ -1044,7 +1166,7 @@ exports.AgentRunner = class AgentRunner {
|
|
|
1044
1166
|
note: `Action "${pending.tool}" requires user approval and was NOT executed. Let the user know it is awaiting approval.`,
|
|
1045
1167
|
};
|
|
1046
1168
|
}
|
|
1047
|
-
const raw = await this.
|
|
1169
|
+
const raw = await this.executeGuarded(definition, binding, input, ctx, runtime);
|
|
1048
1170
|
if (!offloadEnabled || binding.options.offload === false)
|
|
1049
1171
|
return raw;
|
|
1050
1172
|
return this.maybeOffload(raw, binding.options.name ?? "", threshold, runtime.scope);
|
|
@@ -1102,6 +1224,26 @@ exports.AgentRunner = class AgentRunner {
|
|
|
1102
1224
|
const self = binding.kind === "class" ? binding.instance : definition.instance;
|
|
1103
1225
|
return requirement.call(self, input, ctx);
|
|
1104
1226
|
}
|
|
1227
|
+
async executeGuarded(definition, binding, input, ctx, runtime) {
|
|
1228
|
+
const tool = binding.options.name ?? "";
|
|
1229
|
+
try {
|
|
1230
|
+
const raw = await this.executeBinding(definition, binding, input, ctx);
|
|
1231
|
+
runtime.failures.delete(tool);
|
|
1232
|
+
return raw;
|
|
1233
|
+
}
|
|
1234
|
+
catch (error) {
|
|
1235
|
+
const count = (runtime.failures.get(tool) ?? 0) + 1;
|
|
1236
|
+
runtime.failures.set(tool, count);
|
|
1237
|
+
const limit = runtime.limits.maxConsecutiveToolFailures;
|
|
1238
|
+
runtime.log?.toolFailure(tool, count, limit);
|
|
1239
|
+
if (limit !== undefined && count >= limit) {
|
|
1240
|
+
const fatal = new ToolRepeatedFailureError(definition.name, tool, count, error);
|
|
1241
|
+
runtime.abort(fatal);
|
|
1242
|
+
throw fatal;
|
|
1243
|
+
}
|
|
1244
|
+
throw error;
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1105
1247
|
async executeBinding(definition, binding, input, ctx) {
|
|
1106
1248
|
try {
|
|
1107
1249
|
if (binding.kind === "class")
|
|
@@ -1197,6 +1339,13 @@ exports.AgentRunner = __decorate([
|
|
|
1197
1339
|
SessionStore,
|
|
1198
1340
|
ArtifactStore, Object, ToolsetResolver])
|
|
1199
1341
|
], exports.AgentRunner);
|
|
1342
|
+
function addUsage(total, delta) {
|
|
1343
|
+
return {
|
|
1344
|
+
promptTokens: total.promptTokens + delta.promptTokens,
|
|
1345
|
+
outputTokens: total.outputTokens + delta.outputTokens,
|
|
1346
|
+
totalTokens: total.totalTokens + delta.totalTokens,
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1200
1349
|
function tryParseJson(text) {
|
|
1201
1350
|
try {
|
|
1202
1351
|
return JSON.parse(text);
|
|
@@ -1404,8 +1553,11 @@ exports.AdkTool = AdkTool;
|
|
|
1404
1553
|
exports.AdkWorkflow = AdkWorkflow;
|
|
1405
1554
|
exports.Agent = Agent;
|
|
1406
1555
|
exports.AgentDefinition = AgentDefinition;
|
|
1556
|
+
exports.AgentMaxIterationsError = AgentMaxIterationsError;
|
|
1407
1557
|
exports.AgentNotFoundError = AgentNotFoundError;
|
|
1408
1558
|
exports.AgentRef = AgentRef;
|
|
1559
|
+
exports.AgentStateInvalidError = AgentStateInvalidError;
|
|
1560
|
+
exports.AgentStateMissingError = AgentStateMissingError;
|
|
1409
1561
|
exports.AiEmptyResponseError = AiEmptyResponseError;
|
|
1410
1562
|
exports.ApprovalNotFoundError = ApprovalNotFoundError;
|
|
1411
1563
|
exports.ArtifactStore = ArtifactStore;
|
|
@@ -1433,6 +1585,7 @@ exports.Skill = Skill;
|
|
|
1433
1585
|
exports.SkillNotFoundError = SkillNotFoundError;
|
|
1434
1586
|
exports.Tool = Tool;
|
|
1435
1587
|
exports.ToolExecutionError = ToolExecutionError;
|
|
1588
|
+
exports.ToolRepeatedFailureError = ToolRepeatedFailureError;
|
|
1436
1589
|
exports.ToolsetResolver = ToolsetResolver;
|
|
1437
1590
|
exports.UnregisteredPromptError = UnregisteredPromptError;
|
|
1438
1591
|
exports.UnregisteredSkillError = UnregisteredSkillError;
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export { AgentRunner } from "./lib/runner/agent-runner";
|
|
|
27
27
|
export { RunLogger } from "./lib/runner/run-logger";
|
|
28
28
|
export type { LoggingOption } from "./lib/runner/run-logger";
|
|
29
29
|
export { DeltaStateBag } from "./lib/runner/state-bag";
|
|
30
|
+
export type { StateGuard } from "./lib/runner/state-bag";
|
|
30
31
|
export { buildInstruction, skillContent } from "./lib/runner/instruction-builder";
|
|
31
32
|
export { Gemini, ModelRouter, OpenAiLike, isModelSpec } from "./lib/models/model-specs";
|
|
32
33
|
export { DEFAULT_OFFLOAD_THRESHOLD, contextPolicy } from "./lib/models/context-policy";
|
|
@@ -40,7 +41,7 @@ export type { SkillBinding, ToolBinding } from "./lib/registry/agent-definition"
|
|
|
40
41
|
export { AgentRef } from "./lib/registry/agent-ref";
|
|
41
42
|
export { AgentRegistry } from "./lib/registry/agent-registry";
|
|
42
43
|
export { AdkBootError, AdkError, DuplicateAgentNameError, ConflictingPromptError, InvalidWorkflowError, MissingModelError, ReservedMethodError, UnregisteredPromptError, UnregisteredSkillError, UnregisteredSubAgentError, UnregisteredToolError, UnresolvedToolsetError, } from "./lib/errors";
|
|
43
|
-
export { AgentNotFoundError, AiEmptyResponseError, ApprovalNotFoundError, EmbedderNotConfiguredError, McpConnectionError, ModelsExhaustedError, OutputValidationError, SessionNotFoundError, SkillNotFoundError, ToolExecutionError, } from "./lib/errors/runtime.errors";
|
|
44
|
+
export { AgentMaxIterationsError, AgentNotFoundError, AgentStateInvalidError, AgentStateMissingError, AiEmptyResponseError, ApprovalNotFoundError, EmbedderNotConfiguredError, McpConnectionError, ModelsExhaustedError, OutputValidationError, SessionNotFoundError, SkillNotFoundError, ToolExecutionError, ToolRepeatedFailureError, } from "./lib/errors/runtime.errors";
|
|
44
45
|
export type { AgentEvent, ArtifactPart, ArtifactRef, PendingApproval, RawRef, RunInput, RunResult, Session, SessionEvent, SessionInit, TokenUsage, } from "./lib/types/events";
|
|
45
46
|
export type { AgentOptions, AnyZodObject, ModelInput, SkillMode, SkillOptions, ToolOptions, WorkflowMode, WorkflowOptions, } from "./lib/types/options";
|
|
46
47
|
export type { StateBag, ToolContext } from "./lib/types/tool-context";
|
package/dist/index.mjs
CHANGED
|
@@ -157,6 +157,42 @@ class OutputValidationError extends AdkError {
|
|
|
157
157
|
this.code = "OUTPUT_VALIDATION_FAILED";
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
|
+
class AgentStateInvalidError extends AdkError {
|
|
161
|
+
constructor(agent, issues, key) {
|
|
162
|
+
super(key
|
|
163
|
+
? `Agent "${agent}" received a value for state key "${key}" that does not match its declared state schema.`
|
|
164
|
+
: `Agent "${agent}" received state that does not match its declared state schema.`);
|
|
165
|
+
this.issues = issues;
|
|
166
|
+
this.key = key;
|
|
167
|
+
this.code = "AGENT_STATE_INVALID";
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
class AgentStateMissingError extends AdkError {
|
|
171
|
+
constructor(agent, key) {
|
|
172
|
+
super(`Agent "${agent}" requires state key "${key}" but it is absent.`);
|
|
173
|
+
this.key = key;
|
|
174
|
+
this.code = "AGENT_STATE_MISSING";
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
class AgentMaxIterationsError extends AdkError {
|
|
178
|
+
constructor(agent, limit, usage, lastTool) {
|
|
179
|
+
super(`Agent "${agent}" exceeded maxIterations (${limit}) — the run was aborted.${lastTool ? ` Last requested tool: "${lastTool}".` : ""}`);
|
|
180
|
+
this.limit = limit;
|
|
181
|
+
this.usage = usage;
|
|
182
|
+
this.lastTool = lastTool;
|
|
183
|
+
this.code = "AGENT_MAX_ITERATIONS";
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
class ToolRepeatedFailureError extends AdkError {
|
|
187
|
+
constructor(agent, tool, failures, cause) {
|
|
188
|
+
super(`Tool "${tool}" failed ${failures} consecutive times on agent "${agent}" — the run was aborted.`, {
|
|
189
|
+
cause,
|
|
190
|
+
});
|
|
191
|
+
this.tool = tool;
|
|
192
|
+
this.failures = failures;
|
|
193
|
+
this.code = "TOOL_REPEATED_FAILURE";
|
|
194
|
+
}
|
|
195
|
+
}
|
|
160
196
|
class McpConnectionError extends AdkError {
|
|
161
197
|
constructor(server, cause) {
|
|
162
198
|
super(`MCP server "${server}" connection failed.`, { cause });
|
|
@@ -825,6 +861,13 @@ class RunLogger {
|
|
|
825
861
|
this.logger.verbose(json(event));
|
|
826
862
|
}
|
|
827
863
|
}
|
|
864
|
+
abort(error, usage) {
|
|
865
|
+
this.logger.warn(`run aborted after ${Date.now() - this.startedAt}ms: ${error.message}${usageSuffix(usage)}`);
|
|
866
|
+
}
|
|
867
|
+
toolFailure(tool, count, limit) {
|
|
868
|
+
if (this.enabled("debug"))
|
|
869
|
+
this.logger.debug(`tool "${tool}" failed (${count}/${limit ?? "∞"} consecutive)`);
|
|
870
|
+
}
|
|
828
871
|
enabled(level) {
|
|
829
872
|
return LEVEL_WEIGHT[level] <= LEVEL_WEIGHT[this.level];
|
|
830
873
|
}
|
|
@@ -850,9 +893,17 @@ function json(value) {
|
|
|
850
893
|
}
|
|
851
894
|
|
|
852
895
|
class DeltaStateBag {
|
|
853
|
-
constructor(initial) {
|
|
896
|
+
constructor(initial, guard = {}) {
|
|
854
897
|
this.initial = initial;
|
|
898
|
+
this.guard = guard;
|
|
855
899
|
this.changes = new Map();
|
|
900
|
+
const schema = guard.schema;
|
|
901
|
+
if (!schema)
|
|
902
|
+
return;
|
|
903
|
+
for (const key of Object.keys(schema.shape)) {
|
|
904
|
+
if (initial[key] !== undefined)
|
|
905
|
+
this.validate(key, initial[key]);
|
|
906
|
+
}
|
|
856
907
|
}
|
|
857
908
|
get(key) {
|
|
858
909
|
if (this.changes.has(key))
|
|
@@ -860,11 +911,28 @@ class DeltaStateBag {
|
|
|
860
911
|
return this.initial[key];
|
|
861
912
|
}
|
|
862
913
|
set(key, value) {
|
|
914
|
+
this.validate(key, value);
|
|
863
915
|
this.changes.set(key, value);
|
|
864
916
|
}
|
|
917
|
+
require(key) {
|
|
918
|
+
const value = this.get(key);
|
|
919
|
+
if (value === undefined)
|
|
920
|
+
throw new AgentStateMissingError(this.guard.agent ?? "unknown", key);
|
|
921
|
+
return value;
|
|
922
|
+
}
|
|
865
923
|
delta() {
|
|
866
924
|
return Object.fromEntries(this.changes);
|
|
867
925
|
}
|
|
926
|
+
validate(key, value) {
|
|
927
|
+
const shape = this.guard.schema?.shape;
|
|
928
|
+
if (!shape || !Object.hasOwn(shape, key))
|
|
929
|
+
return;
|
|
930
|
+
const field = shape[key];
|
|
931
|
+
const result = field.safeParse(value);
|
|
932
|
+
if (!result.success) {
|
|
933
|
+
throw new AgentStateInvalidError(this.guard.agent ?? "unknown", result.error?.issues, key);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
868
936
|
}
|
|
869
937
|
|
|
870
938
|
const EMPTY_USAGE = { promptTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
@@ -883,23 +951,54 @@ let AgentRunner = class AgentRunner {
|
|
|
883
951
|
const log = RunLogger.create(this.options.logging, definition.name);
|
|
884
952
|
log?.start(input);
|
|
885
953
|
const session = await this.openSession(input);
|
|
886
|
-
const state =
|
|
887
|
-
const
|
|
888
|
-
const
|
|
954
|
+
const state = this.stateBagFor(definition, { ...(session?.state ?? {}), ...(input.state ?? {}) });
|
|
955
|
+
const controller = new AbortController();
|
|
956
|
+
const signal = input.signal ? AbortSignal.any([input.signal, controller.signal]) : controller.signal;
|
|
957
|
+
const runtime = this.createRuntime(definition, input, controller, log);
|
|
958
|
+
const ctx = this.createToolContext(definition, input, state, signal);
|
|
889
959
|
const resolved = await this.resolveAgent(definition, ctx, runtime);
|
|
890
|
-
const engineInput = { ...input, history: session?.events };
|
|
960
|
+
const engineInput = { ...input, signal, history: session?.events };
|
|
891
961
|
if (session)
|
|
892
962
|
await this.persist(session.id, "user", "message", { text: input.message });
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
963
|
+
let iterations = 0;
|
|
964
|
+
let usage = EMPTY_USAGE;
|
|
965
|
+
let lastEventType;
|
|
966
|
+
try {
|
|
967
|
+
for await (const event of this.engine.run(resolved, engineInput)) {
|
|
968
|
+
if (runtime.fatal)
|
|
969
|
+
break;
|
|
970
|
+
if (event.type === "llm_response" && event.usage)
|
|
971
|
+
usage = addUsage(usage, event.usage);
|
|
972
|
+
if (event.type === "tool_call" && lastEventType !== "tool_call") {
|
|
973
|
+
iterations += 1;
|
|
974
|
+
const limit = runtime.limits.maxIterations;
|
|
975
|
+
if (limit !== undefined && iterations > limit) {
|
|
976
|
+
runtime.abort(new AgentMaxIterationsError(definition.name, limit, usage, event.tool));
|
|
977
|
+
break;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
lastEventType = event.type;
|
|
981
|
+
log?.event(event);
|
|
982
|
+
if (session)
|
|
983
|
+
await this.persistAgentEvent(session.id, event);
|
|
984
|
+
if (event.type === "final" && definition.output && definition.outputKey) {
|
|
985
|
+
const parsed = definition.output.safeParse(tryParseJson(event.text));
|
|
986
|
+
if (parsed.success)
|
|
987
|
+
state.set(definition.outputKey, parsed.data);
|
|
988
|
+
}
|
|
989
|
+
yield event;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
catch (error) {
|
|
993
|
+
if (runtime.fatal) {
|
|
994
|
+
log?.abort(runtime.fatal, usage);
|
|
995
|
+
throw runtime.fatal;
|
|
901
996
|
}
|
|
902
|
-
|
|
997
|
+
throw error;
|
|
998
|
+
}
|
|
999
|
+
if (runtime.fatal) {
|
|
1000
|
+
log?.abort(runtime.fatal, usage);
|
|
1001
|
+
throw runtime.fatal;
|
|
903
1002
|
}
|
|
904
1003
|
for (const pending of runtime.pendings) {
|
|
905
1004
|
const approval = {
|
|
@@ -958,7 +1057,7 @@ let AgentRunner = class AgentRunner {
|
|
|
958
1057
|
const binding = definition.tools.find((candidate) => candidate.options.name === entry.tool);
|
|
959
1058
|
if (!binding)
|
|
960
1059
|
throw new ApprovalNotFoundError(params.callId, params.sessionId);
|
|
961
|
-
const state =
|
|
1060
|
+
const state = this.stateBagFor(definition, session.state);
|
|
962
1061
|
const ctx = this.createToolContext(definition, { message: "", sessionId: session.id, userId: session.userId }, state);
|
|
963
1062
|
const result = await this.executeBinding(definition, binding, entry.args, ctx);
|
|
964
1063
|
await this.persist(session.id, "tool", "tool_result", { callId: entry.callId, tool: entry.tool, result });
|
|
@@ -976,11 +1075,9 @@ let AgentRunner = class AgentRunner {
|
|
|
976
1075
|
}
|
|
977
1076
|
resolve(agentType, input = { message: "" }) {
|
|
978
1077
|
const definition = this.definitionOf(agentType);
|
|
979
|
-
const state =
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
pendings: [],
|
|
983
|
-
});
|
|
1078
|
+
const state = this.stateBagFor(definition, { ...(input.state ?? {}) });
|
|
1079
|
+
const runtime = this.createRuntime(definition, input);
|
|
1080
|
+
return this.resolveAgent(definition, this.createToolContext(definition, input, state), runtime);
|
|
984
1081
|
}
|
|
985
1082
|
definitionOf(agentType) {
|
|
986
1083
|
return typeof agentType === "string" ? this.registry.get(agentType) : this.registry.getByType(agentType);
|
|
@@ -1003,17 +1100,42 @@ let AgentRunner = class AgentRunner {
|
|
|
1003
1100
|
throw new ApprovalNotFoundError(callId, sessionId);
|
|
1004
1101
|
return { session, entry, rest: pendings.filter((candidate) => candidate.callId !== callId) };
|
|
1005
1102
|
}
|
|
1006
|
-
createToolContext(definition, input, state) {
|
|
1103
|
+
createToolContext(definition, input, state, signal) {
|
|
1007
1104
|
return {
|
|
1008
1105
|
agentName: definition.name,
|
|
1009
1106
|
sessionId: input.sessionId,
|
|
1010
1107
|
userId: input.userId,
|
|
1011
1108
|
state,
|
|
1012
1109
|
attributes: input.attributes ?? {},
|
|
1013
|
-
signal: input.signal ?? new AbortController().signal,
|
|
1110
|
+
signal: signal ?? input.signal ?? new AbortController().signal,
|
|
1014
1111
|
actions: { endRun: () => undefined },
|
|
1015
1112
|
};
|
|
1016
1113
|
}
|
|
1114
|
+
stateBagFor(definition, initial) {
|
|
1115
|
+
return new DeltaStateBag(initial, { schema: definition.options?.state, agent: definition.name });
|
|
1116
|
+
}
|
|
1117
|
+
createRuntime(definition, input, controller, log) {
|
|
1118
|
+
const runtime = {
|
|
1119
|
+
scope: input.sessionId ?? randomUUID(),
|
|
1120
|
+
pendings: [],
|
|
1121
|
+
failures: new Map(),
|
|
1122
|
+
limits: this.limitsFor(definition, input),
|
|
1123
|
+
log,
|
|
1124
|
+
abort: (error) => {
|
|
1125
|
+
runtime.fatal ??= error;
|
|
1126
|
+
controller?.abort();
|
|
1127
|
+
},
|
|
1128
|
+
};
|
|
1129
|
+
return runtime;
|
|
1130
|
+
}
|
|
1131
|
+
limitsFor(definition, input) {
|
|
1132
|
+
return {
|
|
1133
|
+
maxIterations: input.maxIterations ?? definition.options?.maxIterations ?? this.options.defaults?.maxIterations,
|
|
1134
|
+
maxConsecutiveToolFailures: input.maxConsecutiveToolFailures ??
|
|
1135
|
+
definition.options?.maxConsecutiveToolFailures ??
|
|
1136
|
+
this.options.defaults?.maxConsecutiveToolFailures,
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1017
1139
|
policyOf(definition) {
|
|
1018
1140
|
return definition.options?.context ?? this.options.context;
|
|
1019
1141
|
}
|
|
@@ -1042,7 +1164,7 @@ let AgentRunner = class AgentRunner {
|
|
|
1042
1164
|
note: `Action "${pending.tool}" requires user approval and was NOT executed. Let the user know it is awaiting approval.`,
|
|
1043
1165
|
};
|
|
1044
1166
|
}
|
|
1045
|
-
const raw = await this.
|
|
1167
|
+
const raw = await this.executeGuarded(definition, binding, input, ctx, runtime);
|
|
1046
1168
|
if (!offloadEnabled || binding.options.offload === false)
|
|
1047
1169
|
return raw;
|
|
1048
1170
|
return this.maybeOffload(raw, binding.options.name ?? "", threshold, runtime.scope);
|
|
@@ -1100,6 +1222,26 @@ let AgentRunner = class AgentRunner {
|
|
|
1100
1222
|
const self = binding.kind === "class" ? binding.instance : definition.instance;
|
|
1101
1223
|
return requirement.call(self, input, ctx);
|
|
1102
1224
|
}
|
|
1225
|
+
async executeGuarded(definition, binding, input, ctx, runtime) {
|
|
1226
|
+
const tool = binding.options.name ?? "";
|
|
1227
|
+
try {
|
|
1228
|
+
const raw = await this.executeBinding(definition, binding, input, ctx);
|
|
1229
|
+
runtime.failures.delete(tool);
|
|
1230
|
+
return raw;
|
|
1231
|
+
}
|
|
1232
|
+
catch (error) {
|
|
1233
|
+
const count = (runtime.failures.get(tool) ?? 0) + 1;
|
|
1234
|
+
runtime.failures.set(tool, count);
|
|
1235
|
+
const limit = runtime.limits.maxConsecutiveToolFailures;
|
|
1236
|
+
runtime.log?.toolFailure(tool, count, limit);
|
|
1237
|
+
if (limit !== undefined && count >= limit) {
|
|
1238
|
+
const fatal = new ToolRepeatedFailureError(definition.name, tool, count, error);
|
|
1239
|
+
runtime.abort(fatal);
|
|
1240
|
+
throw fatal;
|
|
1241
|
+
}
|
|
1242
|
+
throw error;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1103
1245
|
async executeBinding(definition, binding, input, ctx) {
|
|
1104
1246
|
try {
|
|
1105
1247
|
if (binding.kind === "class")
|
|
@@ -1195,6 +1337,13 @@ AgentRunner = __decorate([
|
|
|
1195
1337
|
SessionStore,
|
|
1196
1338
|
ArtifactStore, Object, ToolsetResolver])
|
|
1197
1339
|
], AgentRunner);
|
|
1340
|
+
function addUsage(total, delta) {
|
|
1341
|
+
return {
|
|
1342
|
+
promptTokens: total.promptTokens + delta.promptTokens,
|
|
1343
|
+
outputTokens: total.outputTokens + delta.outputTokens,
|
|
1344
|
+
totalTokens: total.totalTokens + delta.totalTokens,
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1198
1347
|
function tryParseJson(text) {
|
|
1199
1348
|
try {
|
|
1200
1349
|
return JSON.parse(text);
|
|
@@ -1391,4 +1540,4 @@ function isScriptedModel(model) {
|
|
|
1391
1540
|
return typeof model === "object" && model !== null && "__adkScriptedModel" in model;
|
|
1392
1541
|
}
|
|
1393
1542
|
|
|
1394
|
-
export { ADK_OPTIONS, AdkAgent, AdkBootError, AdkEngine, AdkError, AdkModule, AdkPrompt, AdkSkill, AdkTool, AdkWorkflow, Agent, AgentDefinition, AgentNotFoundError, AgentRef, AgentRegistry, AgentRunner, AgentSessions, AiEmptyResponseError, ApprovalNotFoundError, ArtifactStore, ConflictingPromptError, DEFAULT_OFFLOAD_THRESHOLD, DeltaStateBag, DuplicateAgentNameError, Embedder, EmbedderNotConfiguredError, Gemini, InMemoryArtifactStore, InMemorySessionStore, InvalidWorkflowError, McpConnectionError, MemoryStore, MissingModelError, ModelRouter, ModelsExhaustedError, OpenAiLike, OutputValidationError, PromptFiles, ReservedMethodError, RunLogger, ScriptedEngine, ScriptedModel, SessionNotFoundError, SessionStore, Similarity, Skill, SkillNotFoundError, Tool, ToolExecutionError, ToolsetResolver, UnregisteredPromptError, UnregisteredSkillError, UnregisteredSubAgentError, UnregisteredToolError, UnresolvedToolsetError, WorkflowAgent, buildInstruction, callTool, contextPolicy, fail, isModelSpec, isScriptedModel, isToolsetRef, skillContent, text, toolset };
|
|
1543
|
+
export { ADK_OPTIONS, AdkAgent, AdkBootError, AdkEngine, AdkError, AdkModule, AdkPrompt, AdkSkill, AdkTool, AdkWorkflow, Agent, AgentDefinition, AgentMaxIterationsError, AgentNotFoundError, AgentRef, AgentRegistry, AgentRunner, AgentSessions, AgentStateInvalidError, AgentStateMissingError, AiEmptyResponseError, ApprovalNotFoundError, ArtifactStore, ConflictingPromptError, DEFAULT_OFFLOAD_THRESHOLD, DeltaStateBag, DuplicateAgentNameError, Embedder, EmbedderNotConfiguredError, Gemini, InMemoryArtifactStore, InMemorySessionStore, InvalidWorkflowError, McpConnectionError, MemoryStore, MissingModelError, ModelRouter, ModelsExhaustedError, OpenAiLike, OutputValidationError, PromptFiles, ReservedMethodError, RunLogger, ScriptedEngine, ScriptedModel, SessionNotFoundError, SessionStore, Similarity, Skill, SkillNotFoundError, Tool, ToolExecutionError, ToolRepeatedFailureError, ToolsetResolver, UnregisteredPromptError, UnregisteredSkillError, UnregisteredSubAgentError, UnregisteredToolError, UnresolvedToolsetError, WorkflowAgent, buildInstruction, callTool, contextPolicy, fail, isModelSpec, isScriptedModel, isToolsetRef, skillContent, text, toolset };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { AdkError } from "./adk.error";
|
|
2
2
|
export { AdkBootError, DuplicateAgentNameError, ConflictingPromptError, InvalidWorkflowError, MissingModelError, ReservedMethodError, UnregisteredPromptError, UnregisteredSkillError, UnregisteredSubAgentError, UnregisteredToolError, UnresolvedToolsetError, } from "./boot.errors";
|
|
3
|
-
export { AgentNotFoundError, ApprovalNotFoundError, EmbedderNotConfiguredError, AiEmptyResponseError, McpConnectionError, ModelsExhaustedError, OutputValidationError, SessionNotFoundError, SkillNotFoundError, ToolExecutionError, } from "./runtime.errors";
|
|
3
|
+
export { AgentMaxIterationsError, AgentNotFoundError, AgentStateInvalidError, AgentStateMissingError, ApprovalNotFoundError, EmbedderNotConfiguredError, AiEmptyResponseError, McpConnectionError, ModelsExhaustedError, OutputValidationError, SessionNotFoundError, SkillNotFoundError, ToolExecutionError, ToolRepeatedFailureError, } from "./runtime.errors";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TokenUsage } from "../types/events";
|
|
1
2
|
import { AdkError } from "./adk.error";
|
|
2
3
|
export declare class AiEmptyResponseError extends AdkError {
|
|
3
4
|
readonly code = "AI_EMPTY_RESPONSE";
|
|
@@ -41,6 +42,30 @@ export declare class OutputValidationError extends AdkError {
|
|
|
41
42
|
readonly code = "OUTPUT_VALIDATION_FAILED";
|
|
42
43
|
constructor(agent: string, rawOutput: unknown, issues: unknown);
|
|
43
44
|
}
|
|
45
|
+
export declare class AgentStateInvalidError extends AdkError {
|
|
46
|
+
readonly issues: unknown;
|
|
47
|
+
readonly key?: string | undefined;
|
|
48
|
+
readonly code = "AGENT_STATE_INVALID";
|
|
49
|
+
constructor(agent: string, issues: unknown, key?: string | undefined);
|
|
50
|
+
}
|
|
51
|
+
export declare class AgentStateMissingError extends AdkError {
|
|
52
|
+
readonly key: string;
|
|
53
|
+
readonly code = "AGENT_STATE_MISSING";
|
|
54
|
+
constructor(agent: string, key: string);
|
|
55
|
+
}
|
|
56
|
+
export declare class AgentMaxIterationsError extends AdkError {
|
|
57
|
+
readonly limit: number;
|
|
58
|
+
readonly usage: TokenUsage;
|
|
59
|
+
readonly lastTool?: string | undefined;
|
|
60
|
+
readonly code = "AGENT_MAX_ITERATIONS";
|
|
61
|
+
constructor(agent: string, limit: number, usage: TokenUsage, lastTool?: string | undefined);
|
|
62
|
+
}
|
|
63
|
+
export declare class ToolRepeatedFailureError extends AdkError {
|
|
64
|
+
readonly tool: string;
|
|
65
|
+
readonly failures: number;
|
|
66
|
+
readonly code = "TOOL_REPEATED_FAILURE";
|
|
67
|
+
constructor(agent: string, tool: string, failures: number, cause: unknown);
|
|
68
|
+
}
|
|
44
69
|
export declare class McpConnectionError extends AdkError {
|
|
45
70
|
readonly code = "MCP_CONNECTION_FAILED";
|
|
46
71
|
constructor(server: string, cause: unknown);
|
|
@@ -16,6 +16,10 @@ export interface AdkModuleOptions {
|
|
|
16
16
|
};
|
|
17
17
|
logging?: import("../runner/run-logger").LoggingOption;
|
|
18
18
|
context?: import("../models/context-policy").ContextPolicy;
|
|
19
|
+
defaults?: {
|
|
20
|
+
maxIterations?: number;
|
|
21
|
+
maxConsecutiveToolFailures?: number;
|
|
22
|
+
};
|
|
19
23
|
}
|
|
20
24
|
export interface AdkModuleAsyncOptions extends Pick<ModuleMetadata, "imports"> {
|
|
21
25
|
engine: Type<AdkEngine>;
|
|
@@ -32,9 +32,13 @@ export declare class AgentRunner {
|
|
|
32
32
|
private openSession;
|
|
33
33
|
private takePending;
|
|
34
34
|
private createToolContext;
|
|
35
|
+
private stateBagFor;
|
|
36
|
+
private createRuntime;
|
|
37
|
+
private limitsFor;
|
|
35
38
|
private policyOf;
|
|
36
39
|
private resolveAgent;
|
|
37
40
|
private needsApproval;
|
|
41
|
+
private executeGuarded;
|
|
38
42
|
private executeBinding;
|
|
39
43
|
private maybeOffload;
|
|
40
44
|
private createReadArtifactTool;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentEvent, RunInput } from "../types/events";
|
|
1
|
+
import type { AgentEvent, RunInput, TokenUsage } from "../types/events";
|
|
2
2
|
export type LoggingOption = boolean | "info" | "debug" | "verbose" | undefined;
|
|
3
3
|
export declare class RunLogger {
|
|
4
4
|
private readonly level;
|
|
@@ -8,6 +8,8 @@ export declare class RunLogger {
|
|
|
8
8
|
private constructor();
|
|
9
9
|
start(input: RunInput): void;
|
|
10
10
|
event(event: AgentEvent): void;
|
|
11
|
+
abort(error: Error, usage: TokenUsage): void;
|
|
12
|
+
toolFailure(tool: string, count: number, limit: number | undefined): void;
|
|
11
13
|
private enabled;
|
|
12
14
|
private preview;
|
|
13
15
|
}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
import type { AnyZodObject } from "../types/options";
|
|
1
2
|
import type { StateBag } from "../types/tool-context";
|
|
3
|
+
export interface StateGuard {
|
|
4
|
+
schema?: AnyZodObject;
|
|
5
|
+
agent?: string;
|
|
6
|
+
}
|
|
2
7
|
export declare class DeltaStateBag implements StateBag {
|
|
3
8
|
private readonly initial;
|
|
9
|
+
private readonly guard;
|
|
4
10
|
private readonly changes;
|
|
5
|
-
constructor(initial: Record<string, unknown
|
|
11
|
+
constructor(initial: Record<string, unknown>, guard?: StateGuard);
|
|
6
12
|
get<T = unknown>(key: string): T | undefined;
|
|
7
13
|
set(key: string, value: unknown): void;
|
|
14
|
+
require<T = unknown>(key: string): T;
|
|
8
15
|
delta(): Record<string, unknown>;
|
|
16
|
+
private validate;
|
|
9
17
|
}
|
|
@@ -66,6 +66,8 @@ export interface RunInput {
|
|
|
66
66
|
attributes?: Record<string, unknown>;
|
|
67
67
|
labels?: Record<string, string>;
|
|
68
68
|
signal?: AbortSignal;
|
|
69
|
+
maxIterations?: number;
|
|
70
|
+
maxConsecutiveToolFailures?: number;
|
|
69
71
|
history?: SessionEvent[];
|
|
70
72
|
}
|
|
71
73
|
export interface PendingApproval {
|
|
@@ -20,6 +20,9 @@ export interface AgentOptions {
|
|
|
20
20
|
output?: ZodObject<ZodRawShape>;
|
|
21
21
|
outputKey?: string;
|
|
22
22
|
context?: import("../models/context-policy").ContextPolicy;
|
|
23
|
+
state?: AnyZodObject;
|
|
24
|
+
maxIterations?: number;
|
|
25
|
+
maxConsecutiveToolFailures?: number;
|
|
23
26
|
}
|
|
24
27
|
export interface ToolOptions<S extends AnyZodObject = AnyZodObject> {
|
|
25
28
|
name?: string;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
export interface ToolContext {
|
|
1
|
+
export interface ToolContext<TState extends Record<string, unknown> = Record<string, unknown>> {
|
|
2
2
|
agentName: string;
|
|
3
3
|
sessionId?: string;
|
|
4
4
|
userId?: string;
|
|
5
|
-
state: StateBag
|
|
5
|
+
state: StateBag<TState>;
|
|
6
6
|
attributes: Record<string, unknown>;
|
|
7
7
|
signal: AbortSignal;
|
|
8
8
|
actions: {
|
|
9
9
|
endRun(): void;
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
|
-
export interface StateBag {
|
|
12
|
+
export interface StateBag<TState extends Record<string, unknown> = Record<string, unknown>> {
|
|
13
|
+
get<K extends keyof TState & string, V extends TState[K]>(key: K): V | undefined;
|
|
13
14
|
get<T = unknown>(key: string): T | undefined;
|
|
14
|
-
set(key:
|
|
15
|
+
set<K extends keyof TState & string>(key: K, value: TState[K]): void;
|
|
16
|
+
require<K extends keyof TState & string, V extends TState[K]>(key: K): V;
|
|
17
|
+
require<T = unknown>(key: string): T;
|
|
15
18
|
}
|
package/package.json
CHANGED