@iqai/adk 0.1.20 → 0.1.21

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/dist/index.mjs CHANGED
@@ -1353,7 +1353,7 @@ var BaseLlm = class {
1353
1353
  * @param llmRequest LlmRequest, the request to send to the LLM.
1354
1354
  * @returns BaseLLMConnection, the connection to the LLM.
1355
1355
  */
1356
- connect(llmRequest) {
1356
+ connect(_llmRequest) {
1357
1357
  throw new Error(`Live connection is not supported for ${this.model}.`);
1358
1358
  }
1359
1359
  };
@@ -8088,6 +8088,9 @@ var IdentityLlmRequestProcessor = class extends BaseLlmRequestProcessor {
8088
8088
  };
8089
8089
  var requestProcessor5 = new IdentityLlmRequestProcessor();
8090
8090
 
8091
+ // src/flows/llm-flows/instructions.ts
8092
+ import { zodToJsonSchema as zodToJsonSchema2 } from "zod-to-json-schema";
8093
+
8091
8094
  // src/utils/instructions-utils.ts
8092
8095
  async function injectSessionState(template, readonlyContext) {
8093
8096
  const invocationContext = readonlyContext._invocationContext;
@@ -8202,6 +8205,22 @@ var InstructionsLlmRequestProcessor = class extends BaseLlmRequestProcessor {
8202
8205
  }
8203
8206
  llmRequest.appendInstructions([instruction]);
8204
8207
  }
8208
+ if (agent.outputSchema) {
8209
+ try {
8210
+ const raw = zodToJsonSchema2(agent.outputSchema, {
8211
+ target: "jsonSchema7",
8212
+ $refStrategy: "none"
8213
+ });
8214
+ const { $schema, ...json } = raw || {};
8215
+ llmRequest.appendInstructions([
8216
+ "You must respond with application/json that validates against this JSON Schema:",
8217
+ "```json",
8218
+ JSON.stringify(json, null, 2),
8219
+ "```"
8220
+ ]);
8221
+ } catch {
8222
+ }
8223
+ }
8205
8224
  for await (const _ of []) {
8206
8225
  yield _;
8207
8226
  }
@@ -8493,12 +8512,87 @@ function removeThoughtFromRequest(llmRequest) {
8493
8512
  var requestProcessor7 = new NlPlanningRequestProcessor();
8494
8513
  var responseProcessor2 = new NlPlanningResponseProcessor();
8495
8514
 
8515
+ // src/flows/llm-flows/output-schema.ts
8516
+ init_logger();
8517
+ var OutputSchemaResponseProcessor = class extends BaseLlmResponseProcessor {
8518
+ logger = new Logger({ name: "OutputSchemaResponseProcessor" });
8519
+ async *runAsync(invocationContext, llmResponse) {
8520
+ if (!llmResponse || !llmResponse.content || !llmResponse.content.parts || llmResponse.content.parts.length === 0) {
8521
+ return;
8522
+ }
8523
+ const agent = invocationContext.agent;
8524
+ if (!("outputSchema" in agent) || !agent.outputSchema) {
8525
+ return;
8526
+ }
8527
+ let textContent = llmResponse.content.parts.map((part) => {
8528
+ if (part && typeof part === "object" && "text" in part) {
8529
+ return part.text || "";
8530
+ }
8531
+ return "";
8532
+ }).join("");
8533
+ if (!textContent.trim()) {
8534
+ return;
8535
+ }
8536
+ try {
8537
+ const parsed = JSON.parse(textContent);
8538
+ const validated = agent.outputSchema.parse(parsed);
8539
+ textContent = JSON.stringify(validated, null, 2);
8540
+ llmResponse.content.parts = llmResponse.content.parts.map((part) => {
8541
+ if (part && typeof part === "object" && "text" in part) {
8542
+ return {
8543
+ ...part,
8544
+ text: textContent
8545
+ };
8546
+ }
8547
+ return part;
8548
+ });
8549
+ this.logger.debug("Output schema validation successful", {
8550
+ agent: agent.name,
8551
+ originalLength: textContent.length,
8552
+ validatedKeys: Object.keys(validated)
8553
+ });
8554
+ } catch (error) {
8555
+ const errorMessage = error instanceof Error ? error.message : String(error);
8556
+ const detailedError = `Output schema validation failed for agent '${agent.name}': ${errorMessage}`;
8557
+ this.logger.error(detailedError, {
8558
+ agent: agent.name,
8559
+ responseContent: textContent.substring(0, 200) + (textContent.length > 200 ? "..." : ""),
8560
+ error: errorMessage
8561
+ });
8562
+ llmResponse.errorCode = "OUTPUT_SCHEMA_VALIDATION_FAILED";
8563
+ llmResponse.errorMessage = detailedError;
8564
+ llmResponse.error = new Error(detailedError);
8565
+ const errorEvent = new Event({
8566
+ id: Event.newId(),
8567
+ invocationId: invocationContext.invocationId,
8568
+ author: agent.name,
8569
+ branch: invocationContext.branch,
8570
+ content: {
8571
+ role: "assistant",
8572
+ parts: [
8573
+ {
8574
+ text: `Error: ${detailedError}`
8575
+ }
8576
+ ]
8577
+ }
8578
+ });
8579
+ errorEvent.errorCode = "OUTPUT_SCHEMA_VALIDATION_FAILED";
8580
+ errorEvent.errorMessage = detailedError;
8581
+ errorEvent.error = new Error(detailedError);
8582
+ yield errorEvent;
8583
+ }
8584
+ }
8585
+ };
8586
+ var responseProcessor3 = new OutputSchemaResponseProcessor();
8587
+
8496
8588
  // src/flows/llm-flows/shared-memory.ts
8497
8589
  var SharedMemoryRequestProcessor = class extends BaseLlmRequestProcessor {
8498
8590
  async *runAsync(invocationContext, llmRequest) {
8499
8591
  const memoryService = invocationContext.memoryService;
8500
8592
  if (!memoryService) return;
8501
- const lastUserEvent = invocationContext.session.events.findLast((e) => e.author === "user" && e.content?.parts?.length);
8593
+ const lastUserEvent = invocationContext.session.events.findLast(
8594
+ (e) => e.author === "user" && e.content?.parts?.length
8595
+ );
8502
8596
  if (!lastUserEvent) return;
8503
8597
  const query = (lastUserEvent.content.parts ?? []).map((p) => p.text || "").join(" ");
8504
8598
  const results = await memoryService.searchMemory({
@@ -8557,8 +8651,10 @@ var SingleFlow = class extends BaseLlmFlow {
8557
8651
  this.responseProcessors.push(
8558
8652
  responseProcessor2,
8559
8653
  // Phase 5: NL Planning
8654
+ responseProcessor3,
8655
+ // Phase 6: Output Schema validation and parsing - validates response against agent's output schema
8560
8656
  responseProcessor
8561
- // Phase 5: Code Execution (placeholder)
8657
+ // Phase 7: Code Execution (placeholder)
8562
8658
  );
8563
8659
  this.logger.debug("SingleFlow initialized with processors");
8564
8660
  }
@@ -8731,12 +8827,26 @@ var LlmAgent = class _LlmAgent extends BaseAgent {
8731
8827
  * The input schema when agent is used as a tool
8732
8828
  */
8733
8829
  inputSchema;
8734
- // Schema type - depends on specific implementation
8735
8830
  /**
8736
8831
  * The output schema when agent replies
8737
8832
  */
8738
8833
  outputSchema;
8739
- // Schema type - depends on specific implementation
8834
+ /**
8835
+ * Callback or list of callbacks to be called before calling the LLM
8836
+ */
8837
+ beforeModelCallback;
8838
+ /**
8839
+ * Callback or list of callbacks to be called after calling the LLM
8840
+ */
8841
+ afterModelCallback;
8842
+ /**
8843
+ * Callback or list of callbacks to be called before calling a tool
8844
+ */
8845
+ beforeToolCallback;
8846
+ /**
8847
+ * Callback or list of callbacks to be called after calling a tool
8848
+ */
8849
+ afterToolCallback;
8740
8850
  logger = new Logger({ name: "LlmAgent" });
8741
8851
  /**
8742
8852
  * Constructor for LlmAgent
@@ -8767,6 +8877,11 @@ var LlmAgent = class _LlmAgent extends BaseAgent {
8767
8877
  this.generateContentConfig = config.generateContentConfig;
8768
8878
  this.inputSchema = config.inputSchema;
8769
8879
  this.outputSchema = config.outputSchema;
8880
+ this.beforeModelCallback = config.beforeModelCallback;
8881
+ this.afterModelCallback = config.afterModelCallback;
8882
+ this.beforeToolCallback = config.beforeToolCallback;
8883
+ this.afterToolCallback = config.afterToolCallback;
8884
+ this.validateOutputSchemaConfig();
8770
8885
  }
8771
8886
  /**
8772
8887
  * The resolved model field as BaseLLM
@@ -8783,13 +8898,15 @@ var LlmAgent = class _LlmAgent extends BaseAgent {
8783
8898
  return new AiSdkLlm(this.model);
8784
8899
  }
8785
8900
  let ancestorAgent = this.parentAgent;
8786
- while (ancestorAgent !== null) {
8901
+ while (ancestorAgent !== null && ancestorAgent !== void 0) {
8787
8902
  if (ancestorAgent instanceof _LlmAgent) {
8788
8903
  return ancestorAgent.canonicalModel;
8789
8904
  }
8790
8905
  ancestorAgent = ancestorAgent.parentAgent;
8791
8906
  }
8792
- throw new Error(`No model found for ${this.name}.`);
8907
+ throw new Error(
8908
+ `No model found for agent "${this.name}". Please specify a model directly on this agent using the 'model' property`
8909
+ );
8793
8910
  }
8794
8911
  /**
8795
8912
  * The resolved instruction field to construct instruction for this agent
@@ -8829,6 +8946,80 @@ var LlmAgent = class _LlmAgent extends BaseAgent {
8829
8946
  }
8830
8947
  return resolvedTools;
8831
8948
  }
8949
+ /**
8950
+ * Gets the canonical before model callbacks as an array
8951
+ */
8952
+ get canonicalBeforeModelCallbacks() {
8953
+ if (!this.beforeModelCallback) {
8954
+ return [];
8955
+ }
8956
+ if (Array.isArray(this.beforeModelCallback)) {
8957
+ return this.beforeModelCallback;
8958
+ }
8959
+ return [this.beforeModelCallback];
8960
+ }
8961
+ /**
8962
+ * Gets the canonical after model callbacks as an array
8963
+ */
8964
+ get canonicalAfterModelCallbacks() {
8965
+ if (!this.afterModelCallback) {
8966
+ return [];
8967
+ }
8968
+ if (Array.isArray(this.afterModelCallback)) {
8969
+ return this.afterModelCallback;
8970
+ }
8971
+ return [this.afterModelCallback];
8972
+ }
8973
+ /**
8974
+ * Gets the canonical before tool callbacks as an array
8975
+ */
8976
+ get canonicalBeforeToolCallbacks() {
8977
+ if (!this.beforeToolCallback) {
8978
+ return [];
8979
+ }
8980
+ if (Array.isArray(this.beforeToolCallback)) {
8981
+ return this.beforeToolCallback;
8982
+ }
8983
+ return [this.beforeToolCallback];
8984
+ }
8985
+ /**
8986
+ * Gets the canonical after tool callbacks as an array
8987
+ */
8988
+ get canonicalAfterToolCallbacks() {
8989
+ if (!this.afterToolCallback) {
8990
+ return [];
8991
+ }
8992
+ if (Array.isArray(this.afterToolCallback)) {
8993
+ return this.afterToolCallback;
8994
+ }
8995
+ return [this.afterToolCallback];
8996
+ }
8997
+ /**
8998
+ * Validates output schema configuration
8999
+ * This matches the Python implementation's __check_output_schema
9000
+ */
9001
+ validateOutputSchemaConfig() {
9002
+ if (!this.outputSchema) {
9003
+ return;
9004
+ }
9005
+ if (!this.disallowTransferToParent || !this.disallowTransferToPeers) {
9006
+ this.logger.warn(
9007
+ `Invalid config for agent ${this.name}: output_schema cannot co-exist with agent transfer configurations. Setting disallow_transfer_to_parent=true, disallow_transfer_to_peers=true`
9008
+ );
9009
+ this.disallowTransferToParent = true;
9010
+ this.disallowTransferToPeers = true;
9011
+ }
9012
+ if (this.subAgents && this.subAgents.length > 0) {
9013
+ throw new Error(
9014
+ `Invalid config for agent ${this.name}: if output_schema is set, sub_agents must be empty to disable agent transfer.`
9015
+ );
9016
+ }
9017
+ if (this.tools && this.tools.length > 0) {
9018
+ throw new Error(
9019
+ `Invalid config for agent ${this.name}: if output_schema is set, tools must be empty`
9020
+ );
9021
+ }
9022
+ }
8832
9023
  /**
8833
9024
  * Gets the appropriate LLM flow for this agent
8834
9025
  * This matches the Python implementation's _llm_flow property
@@ -8844,8 +9035,28 @@ var LlmAgent = class _LlmAgent extends BaseAgent {
8844
9035
  * This matches the Python implementation's __maybe_save_output_to_state
8845
9036
  */
8846
9037
  maybeSaveOutputToState(event) {
9038
+ if (event.author !== this.name) {
9039
+ this.logger.debug(
9040
+ `Skipping output save for agent ${this.name}: event authored by ${event.author}`
9041
+ );
9042
+ return;
9043
+ }
8847
9044
  if (this.outputKey && event.isFinalResponse() && event.content?.parts) {
8848
- const result = event.content.parts.map((part) => part.text || "").join("");
9045
+ let result = event.content.parts.map((part) => part.text || "").join("");
9046
+ if (this.outputSchema) {
9047
+ if (!result.trim()) {
9048
+ return;
9049
+ }
9050
+ try {
9051
+ const parsed = JSON.parse(result);
9052
+ result = this.outputSchema.parse(parsed);
9053
+ } catch (error) {
9054
+ this.logger.error("Failed to validate output with schema:", error);
9055
+ throw new Error(
9056
+ `Output validation failed: ${error instanceof Error ? error.message : String(error)}`
9057
+ );
9058
+ }
9059
+ }
8849
9060
  if (result) {
8850
9061
  if (!event.actions.stateDelta) {
8851
9062
  event.actions.stateDelta = {};
@@ -10188,6 +10399,14 @@ var AgentBuilder = class _AgentBuilder {
10188
10399
  this.config.instruction = instruction;
10189
10400
  return this;
10190
10401
  }
10402
+ withInputSchema(schema) {
10403
+ this.config.inputSchema = schema;
10404
+ return this;
10405
+ }
10406
+ withOutputSchema(schema) {
10407
+ this.config.outputSchema = schema;
10408
+ return this;
10409
+ }
10191
10410
  /**
10192
10411
  * Add tools to the agent
10193
10412
  * @param tools Tools to add to the agent
@@ -10394,6 +10613,14 @@ var AgentBuilder = class _AgentBuilder {
10394
10613
  }
10395
10614
  return { agent, runner, session };
10396
10615
  }
10616
+ /**
10617
+ * Type-safe build method for agents with output schemas
10618
+ * Provides better type inference for the ask method return type
10619
+ */
10620
+ async buildWithSchema() {
10621
+ const result = await this.build();
10622
+ return result;
10623
+ }
10397
10624
  /**
10398
10625
  * Quick execution helper - build and run a message
10399
10626
  * @param message Message to send to the agent (string or full message object)
@@ -10428,7 +10655,9 @@ var AgentBuilder = class _AgentBuilder {
10428
10655
  memoryService: this.memoryService,
10429
10656
  artifactService: this.artifactService,
10430
10657
  outputKey: this.config.outputKey,
10431
- sessionService: this.sessionService
10658
+ sessionService: this.sessionService,
10659
+ inputSchema: this.config.inputSchema,
10660
+ outputSchema: this.config.outputSchema
10432
10661
  });
10433
10662
  }
10434
10663
  case "sequential":
@@ -10487,14 +10716,16 @@ var AgentBuilder = class _AgentBuilder {
10487
10716
  return `app-${this.config.name}`;
10488
10717
  }
10489
10718
  /**
10490
- * Create enhanced runner with simplified API
10719
+ * Create enhanced runner with simplified API and proper typing
10491
10720
  * @param baseRunner The base runner instance
10492
10721
  * @param session The session instance
10493
10722
  * @returns Enhanced runner with simplified API
10494
10723
  */
10495
10724
  createEnhancedRunner(baseRunner, session) {
10496
10725
  const sessionOptions = this.sessionOptions;
10726
+ const outputSchema = this.config.outputSchema;
10497
10727
  return {
10728
+ __outputSchema: outputSchema,
10498
10729
  async ask(message) {
10499
10730
  const newMessage = typeof message === "string" ? { parts: [{ text: message }] } : typeof message === "object" && "contents" in message ? { parts: message.contents[message.contents.length - 1].parts } : message;
10500
10731
  let response = "";
@@ -10515,6 +10746,18 @@ var AgentBuilder = class _AgentBuilder {
10515
10746
  }
10516
10747
  }
10517
10748
  }
10749
+ if (outputSchema) {
10750
+ try {
10751
+ const parsed = JSON.parse(response);
10752
+ return outputSchema.parse(parsed);
10753
+ } catch (parseError) {
10754
+ try {
10755
+ return outputSchema.parse(response);
10756
+ } catch (validationError) {
10757
+ return response.trim();
10758
+ }
10759
+ }
10760
+ }
10518
10761
  return response.trim();
10519
10762
  },
10520
10763
  runAsync(params) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iqai/adk",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
4
4
  "description": "Agent Development Kit for TypeScript with multi-provider LLM support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",