@prompty/core 2.0.0-alpha.4 → 2.0.0-alpha.6

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.cjs CHANGED
@@ -4515,6 +4515,9 @@ var init_common = __esm({
4515
4515
  });
4516
4516
 
4517
4517
  // src/core/tool-dispatch.ts
4518
+ function registerTool(name, handler) {
4519
+ nameRegistry.set(name, handler);
4520
+ }
4518
4521
  function getTool(name) {
4519
4522
  return nameRegistry.get(name);
4520
4523
  }
@@ -4538,12 +4541,12 @@ async function dispatchTool(toolName, args, userTools, agent, parentInputs) {
4538
4541
  const result = await registeredFn(args);
4539
4542
  return typeof result === "string" ? result : JSON.stringify(result);
4540
4543
  }
4541
- const tool = agent.tools?.find((t) => t.name === toolName);
4542
- if (!tool) {
4544
+ const tool2 = agent.tools?.find((t) => t.name === toolName);
4545
+ if (!tool2) {
4543
4546
  const available = Object.keys(userTools).sort().join(", ") || "(none)";
4544
4547
  return `Error: tool "${toolName}" not found in userTools or agent.tools. Available user tools: ${available}`;
4545
4548
  }
4546
- const kind = tool.kind || "*";
4549
+ const kind = tool2.kind || "*";
4547
4550
  let handler;
4548
4551
  try {
4549
4552
  handler = getToolHandler(kind);
@@ -4555,7 +4558,7 @@ async function dispatchTool(toolName, args, userTools, agent, parentInputs) {
4555
4558
  }
4556
4559
  }
4557
4560
  return await handler.executeTool(
4558
- tool,
4561
+ tool2,
4559
4562
  args,
4560
4563
  agent,
4561
4564
  parentInputs
@@ -4581,36 +4584,36 @@ var init_tool_dispatch = __esm({
4581
4584
  nameRegistry = /* @__PURE__ */ new Map();
4582
4585
  toolHandlers = /* @__PURE__ */ new Map();
4583
4586
  FunctionToolHandler = class {
4584
- async executeTool(tool, _args, _agent, _parentInputs) {
4585
- const name = tool.name ?? "unknown";
4587
+ async executeTool(tool2, _args, _agent, _parentInputs) {
4588
+ const name = tool2.name ?? "unknown";
4586
4589
  throw new Error(
4587
- `Function tool '${name}' declared but no callable provided. Pass it via tools: { '${name}': fn } in executeAgent().`
4590
+ `Function tool '${name}' declared but no callable provided. Pass it via tools: { '${name}': fn } in invokeAgent().`
4588
4591
  );
4589
4592
  }
4590
4593
  };
4591
4594
  PromptyToolHandler = class {
4592
- async executeTool(tool, args, agent, _parentInputs) {
4595
+ async executeTool(tool2, args, agent, _parentInputs) {
4593
4596
  const { load: load2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
4594
- const { prepare: prepare2, run: run2, executeAgent: executeAgent2 } = await Promise.resolve().then(() => (init_pipeline(), pipeline_exports));
4597
+ const { prepare: prepare2, run: run2, invokeAgent: invokeAgent2 } = await Promise.resolve().then(() => (init_pipeline(), pipeline_exports));
4595
4598
  const parentPath = (agent.metadata ?? {}).__source_path;
4596
4599
  if (!parentPath) {
4597
- return `Error: cannot resolve PromptyTool '${tool.name}': parent has no __source_path`;
4600
+ return `Error: cannot resolve PromptyTool '${tool2.name}': parent has no __source_path`;
4598
4601
  }
4599
- const childPath = (0, import_node_path2.resolve)((0, import_node_path2.dirname)(parentPath), tool.path);
4602
+ const childPath = (0, import_node_path2.resolve)((0, import_node_path2.dirname)(parentPath), tool2.path);
4600
4603
  const stack = (agent.metadata ?? {}).__prompty_tool_stack ?? [];
4601
4604
  const normalizedChild = (0, import_node_path2.resolve)(childPath);
4602
4605
  const visited = /* @__PURE__ */ new Set([...stack.map((p) => (0, import_node_path2.resolve)(p)), (0, import_node_path2.resolve)(parentPath)]);
4603
4606
  if (visited.has(normalizedChild)) {
4604
4607
  const chain = [...stack, parentPath, childPath].join(" \u2192 ");
4605
- return `Error executing PromptyTool '${tool.name}': circular reference detected: ${chain}`;
4608
+ return `Error executing PromptyTool '${tool2.name}': circular reference detected: ${chain}`;
4606
4609
  }
4607
4610
  try {
4608
4611
  const child = load2(childPath);
4609
4612
  if (!child.metadata) child.metadata = {};
4610
4613
  child.metadata.__prompty_tool_stack = [...stack, parentPath];
4611
- const mode = tool.mode ?? "single";
4614
+ const mode = tool2.mode ?? "single";
4612
4615
  if (mode === "agentic") {
4613
- const result = await executeAgent2(child, args);
4616
+ const result = await invokeAgent2(child, args);
4614
4617
  return typeof result === "string" ? result : JSON.stringify(result);
4615
4618
  } else {
4616
4619
  const messages = await prepare2(child, args);
@@ -4618,7 +4621,7 @@ var init_tool_dispatch = __esm({
4618
4621
  return typeof result === "string" ? result : JSON.stringify(result);
4619
4622
  }
4620
4623
  } catch (err) {
4621
- return `Error executing PromptyTool '${tool.name}': ${err instanceof Error ? err.message : String(err)}`;
4624
+ return `Error executing PromptyTool '${tool2.name}': ${err instanceof Error ? err.message : String(err)}`;
4622
4625
  }
4623
4626
  }
4624
4627
  };
@@ -4645,18 +4648,216 @@ var init_tool_dispatch = __esm({
4645
4648
  }
4646
4649
  });
4647
4650
 
4651
+ // src/core/agent-events.ts
4652
+ function emitEvent(callback, eventType, data) {
4653
+ if (!callback) return;
4654
+ try {
4655
+ callback(eventType, data);
4656
+ } catch (err) {
4657
+ if (typeof globalThis.console?.debug === "function") {
4658
+ globalThis.console.debug(`Event callback error for ${eventType}:`, err);
4659
+ }
4660
+ }
4661
+ }
4662
+ var init_agent_events = __esm({
4663
+ "src/core/agent-events.ts"() {
4664
+ "use strict";
4665
+ }
4666
+ });
4667
+
4668
+ // src/core/cancellation.ts
4669
+ function checkCancellation(signal) {
4670
+ if (signal?.aborted) {
4671
+ throw new CancelledError();
4672
+ }
4673
+ }
4674
+ var CancelledError;
4675
+ var init_cancellation = __esm({
4676
+ "src/core/cancellation.ts"() {
4677
+ "use strict";
4678
+ CancelledError = class extends Error {
4679
+ constructor(message = "Agent loop cancelled") {
4680
+ super(message);
4681
+ this.name = "CancelledError";
4682
+ }
4683
+ };
4684
+ }
4685
+ });
4686
+
4687
+ // src/core/context.ts
4688
+ function estimateChars(messages) {
4689
+ let total = 0;
4690
+ for (const msg of messages) {
4691
+ total += msg.role.length + 4;
4692
+ for (const part of msg.parts) {
4693
+ if (part.kind === "text") {
4694
+ total += part.value.length;
4695
+ } else {
4696
+ total += 200;
4697
+ }
4698
+ }
4699
+ const toolCalls = msg.metadata?.tool_calls;
4700
+ if (toolCalls) {
4701
+ total += JSON.stringify(toolCalls).length;
4702
+ }
4703
+ }
4704
+ return total;
4705
+ }
4706
+ function truncate(text2, maxLen = 200) {
4707
+ return text2.length <= maxLen ? text2 : text2.slice(0, maxLen) + "\u2026";
4708
+ }
4709
+ function summarizeDropped(messages) {
4710
+ const lines = [];
4711
+ for (const msg of messages) {
4712
+ const msgText = msg.text.trim();
4713
+ if (msg.role === "user" && msgText) {
4714
+ lines.push(`User asked: ${truncate(msgText)}`);
4715
+ } else if (msg.role === "assistant") {
4716
+ if (msgText) lines.push(`Assistant: ${truncate(msgText)}`);
4717
+ const toolCalls = msg.metadata?.tool_calls;
4718
+ if (Array.isArray(toolCalls)) {
4719
+ const names = toolCalls.map(
4720
+ (tc) => tc.name ?? (tc.function?.name ?? "?")
4721
+ );
4722
+ lines.push(` Called tools: ${names.join(", ")}`);
4723
+ }
4724
+ }
4725
+ }
4726
+ if (lines.length === 0) return "";
4727
+ let result = "[Context summary: ";
4728
+ for (const line of lines) {
4729
+ if (result.length + line.length > 4e3) {
4730
+ result += "\n... (older messages omitted)";
4731
+ break;
4732
+ }
4733
+ result += line + "\n";
4734
+ }
4735
+ return result.trimEnd() + "]";
4736
+ }
4737
+ function trimToContextWindow(messages, budgetChars) {
4738
+ if (estimateChars(messages) <= budgetChars) {
4739
+ return [0, []];
4740
+ }
4741
+ let systemEnd = 0;
4742
+ for (let i = 0; i < messages.length; i++) {
4743
+ if (messages[i].role !== "system") {
4744
+ systemEnd = i;
4745
+ break;
4746
+ }
4747
+ if (i === messages.length - 1) systemEnd = messages.length;
4748
+ }
4749
+ const systemMsgs = messages.slice(0, systemEnd);
4750
+ const rest = messages.slice(systemEnd);
4751
+ const summaryBudget = Math.min(5e3, Math.floor(budgetChars * 0.05));
4752
+ const dropped = [];
4753
+ while (estimateChars([...systemMsgs, ...rest]) > budgetChars - summaryBudget && rest.length > 2) {
4754
+ dropped.push(rest.shift());
4755
+ }
4756
+ const droppedCount = dropped.length;
4757
+ messages.length = 0;
4758
+ messages.push(...systemMsgs);
4759
+ if (droppedCount > 0) {
4760
+ const summaryText = summarizeDropped(dropped);
4761
+ if (summaryText) {
4762
+ messages.push(new Message("user", [{ kind: "text", value: summaryText }]));
4763
+ }
4764
+ }
4765
+ messages.push(...rest);
4766
+ return [droppedCount, dropped];
4767
+ }
4768
+ var init_context2 = __esm({
4769
+ "src/core/context.ts"() {
4770
+ "use strict";
4771
+ init_types();
4772
+ }
4773
+ });
4774
+
4775
+ // src/core/guardrails.ts
4776
+ var GuardrailError, Guardrails;
4777
+ var init_guardrails = __esm({
4778
+ "src/core/guardrails.ts"() {
4779
+ "use strict";
4780
+ GuardrailError = class extends Error {
4781
+ reason;
4782
+ constructor(reason) {
4783
+ super(`Guardrail denied: ${reason}`);
4784
+ this.name = "GuardrailError";
4785
+ this.reason = reason;
4786
+ }
4787
+ };
4788
+ Guardrails = class {
4789
+ inputHook;
4790
+ outputHook;
4791
+ toolHook;
4792
+ constructor(options) {
4793
+ this.inputHook = options?.input;
4794
+ this.outputHook = options?.output;
4795
+ this.toolHook = options?.tool;
4796
+ }
4797
+ checkInput(messages) {
4798
+ if (!this.inputHook) return { allowed: true };
4799
+ return this.inputHook(messages);
4800
+ }
4801
+ checkOutput(message) {
4802
+ if (!this.outputHook) return { allowed: true };
4803
+ return this.outputHook(message);
4804
+ }
4805
+ checkTool(name, args) {
4806
+ if (!this.toolHook) return { allowed: true };
4807
+ return this.toolHook(name, args);
4808
+ }
4809
+ };
4810
+ }
4811
+ });
4812
+
4813
+ // src/core/structured.ts
4814
+ function createStructuredResult(data, rawJson) {
4815
+ const result = { ...data };
4816
+ Object.defineProperty(result, StructuredResultSymbol, {
4817
+ value: rawJson,
4818
+ writable: false,
4819
+ enumerable: false,
4820
+ configurable: false
4821
+ });
4822
+ return result;
4823
+ }
4824
+ function isStructuredResult(value) {
4825
+ return typeof value === "object" && value !== null && StructuredResultSymbol in value;
4826
+ }
4827
+ function cast(result, validator) {
4828
+ let jsonStr;
4829
+ if (isStructuredResult(result)) {
4830
+ jsonStr = result[StructuredResultSymbol];
4831
+ } else if (typeof result === "string") {
4832
+ jsonStr = result;
4833
+ } else {
4834
+ jsonStr = JSON.stringify(result);
4835
+ }
4836
+ const parsed = JSON.parse(jsonStr);
4837
+ if (validator) {
4838
+ return validator(parsed);
4839
+ }
4840
+ return parsed;
4841
+ }
4842
+ var StructuredResultSymbol;
4843
+ var init_structured = __esm({
4844
+ "src/core/structured.ts"() {
4845
+ "use strict";
4846
+ StructuredResultSymbol = /* @__PURE__ */ Symbol("prompty.rawJson");
4847
+ }
4848
+ });
4849
+
4648
4850
  // src/core/pipeline.ts
4649
4851
  var pipeline_exports = {};
4650
4852
  __export(pipeline_exports, {
4651
- execute: () => execute,
4652
- executeAgent: () => executeAgent,
4853
+ invoke: () => invoke,
4854
+ invokeAgent: () => invokeAgent,
4653
4855
  parse: () => parse,
4654
4856
  prepare: () => prepare,
4655
4857
  process: () => process2,
4656
4858
  render: () => render,
4657
4859
  resolveBindings: () => resolveBindings,
4658
4860
  run: () => run,
4659
- runAgent: () => runAgent,
4660
4861
  validateInputs: () => validateInputs
4661
4862
  });
4662
4863
  function sanitizeNonces(value) {
@@ -4833,8 +5034,8 @@ async function run(agent, messages, options) {
4833
5034
  return result;
4834
5035
  });
4835
5036
  }
4836
- async function execute(prompt, inputs, options) {
4837
- return traceSpan("execute", async (emit) => {
5037
+ async function invoke(prompt, inputs, options) {
5038
+ return traceSpan("invoke", async (emit) => {
4838
5039
  const agent = typeof prompt === "string" ? await traceSpan("load", async (loadEmit) => {
4839
5040
  loadEmit("signature", "prompty.load");
4840
5041
  loadEmit("description", "Load a prompty file.");
@@ -4843,12 +5044,15 @@ async function execute(prompt, inputs, options) {
4843
5044
  loadEmit("result", serializeAgent(loaded));
4844
5045
  return loaded;
4845
5046
  }) : prompt;
4846
- emit("signature", "prompty.execute");
4847
- emit("description", "Execute a prompty");
5047
+ emit("signature", "prompty.invoke");
5048
+ emit("description", "Invoke a prompty");
4848
5049
  emit("inputs", { prompt: serializeAgent(agent), inputs: inputs ?? {} });
4849
5050
  const messages = await prepare(agent, inputs);
4850
5051
  const result = await run(agent, messages, options);
4851
5052
  emit("result", result);
5053
+ if (options?.validator) {
5054
+ return cast(result, options.validator);
5055
+ }
4852
5056
  return result;
4853
5057
  });
4854
5058
  }
@@ -4870,7 +5074,7 @@ function isAsyncIterable(value) {
4870
5074
  function isToolCallLike(item) {
4871
5075
  return typeof item === "object" && item !== null && "id" in item && "name" in item && "arguments" in item;
4872
5076
  }
4873
- async function consumeStream(agent, response) {
5077
+ async function consumeStream(agent, response, onEvent) {
4874
5078
  const processed = await process2(agent, response);
4875
5079
  const toolCalls = [];
4876
5080
  const textParts = [];
@@ -4880,96 +5084,17 @@ async function consumeStream(agent, response) {
4880
5084
  toolCalls.push(item);
4881
5085
  } else if (typeof item === "string") {
4882
5086
  textParts.push(item);
5087
+ emitEvent(onEvent, "token", { token: item });
4883
5088
  }
4884
5089
  }
4885
5090
  } else if (typeof processed === "string") {
4886
5091
  textParts.push(processed);
5092
+ emitEvent(onEvent, "token", { token: processed });
4887
5093
  }
4888
5094
  return { toolCalls, content: textParts.join("") };
4889
5095
  }
4890
- async function buildToolMessagesFromCalls(toolCalls, textContent, tools, agent, parentInputs, parentEmit) {
4891
- const provider = resolveProvider(agent);
4892
- const apiType = agent.model?.apiType || "chat";
4893
- const messages = [];
4894
- const toolInputs = [];
4895
- if (provider === "anthropic") {
4896
- const rawContent = [];
4897
- if (textContent) rawContent.push({ type: "text", text: textContent });
4898
- for (const tc of toolCalls) {
4899
- rawContent.push({
4900
- type: "tool_use",
4901
- id: tc.id,
4902
- name: tc.name,
4903
- input: JSON.parse(tc.arguments)
4904
- });
4905
- }
4906
- messages.push(
4907
- new Message("assistant", textContent ? [text(textContent)] : [], { content: rawContent })
4908
- );
4909
- } else if (apiType === "responses") {
4910
- for (const tc of toolCalls) {
4911
- messages.push(
4912
- new Message("assistant", [], {
4913
- responses_function_call: {
4914
- type: "function_call",
4915
- call_id: tc.id,
4916
- name: tc.name,
4917
- arguments: tc.arguments
4918
- }
4919
- })
4920
- );
4921
- }
4922
- } else {
4923
- const rawToolCalls = toolCalls.map((tc) => ({
4924
- id: tc.id,
4925
- type: "function",
4926
- function: { name: tc.name, arguments: tc.arguments }
4927
- }));
4928
- messages.push(
4929
- new Message("assistant", textContent ? [text(textContent)] : [], {
4930
- tool_calls: rawToolCalls
4931
- })
4932
- );
4933
- }
4934
- const toolResultBlocks = [];
4935
- for (const tc of toolCalls) {
4936
- let result;
4937
- let parsedArgs;
4938
- try {
4939
- parsedArgs = JSON.parse(tc.arguments);
4940
- if (parentInputs && typeof parsedArgs === "object" && parsedArgs !== null && !Array.isArray(parsedArgs)) {
4941
- parsedArgs = resolveBindings(agent, tc.name, parsedArgs, parentInputs);
4942
- }
4943
- result = await traceSpan(tc.name, async (toolEmit) => {
4944
- toolEmit("signature", `prompty.tool.${tc.name}`);
4945
- toolEmit("description", `Execute tool: ${tc.name}`);
4946
- toolEmit("inputs", { arguments: parsedArgs, id: tc.id });
4947
- const r = await dispatchTool(tc.name, parsedArgs, tools, agent, parentInputs ?? {});
4948
- toolEmit("result", r);
4949
- return r;
4950
- });
4951
- } catch (err) {
4952
- result = `Error: ${err instanceof Error ? err.message : String(err)}`;
4953
- }
4954
- toolInputs.push({ name: tc.name, arguments: parsedArgs, id: tc.id, result });
4955
- if (provider === "anthropic") {
4956
- toolResultBlocks.push({ type: "tool_result", tool_use_id: tc.id, content: result });
4957
- } else {
4958
- messages.push(
4959
- new Message("tool", [text(result)], { tool_call_id: tc.id, name: tc.name })
4960
- );
4961
- }
4962
- }
4963
- if (provider === "anthropic" && toolResultBlocks.length > 0) {
4964
- messages.push(new Message("user", [], { tool_results: toolResultBlocks }));
4965
- }
4966
- if (parentEmit) {
4967
- parentEmit("inputs", { tool_calls: toolInputs });
4968
- }
4969
- return messages;
4970
- }
4971
- async function executeAgent(prompt, inputs, options) {
4972
- return traceSpan("executeAgent", async (emit) => {
5096
+ async function invokeAgent(prompt, inputs, options) {
5097
+ const rawResult = await traceSpan("invokeAgent", async (emit) => {
4973
5098
  const agent = typeof prompt === "string" ? await traceSpan("load", async (loadEmit) => {
4974
5099
  loadEmit("signature", "prompty.load");
4975
5100
  loadEmit("description", "Load a prompty file.");
@@ -4980,21 +5105,72 @@ async function executeAgent(prompt, inputs, options) {
4980
5105
  }) : prompt;
4981
5106
  const tools = options?.tools ?? {};
4982
5107
  const maxIterations = options?.maxIterations ?? DEFAULT_MAX_ITERATIONS;
4983
- emit("signature", "prompty.executeAgent");
4984
- emit("description", "Execute a prompty with tool calling");
5108
+ const onEvent = options?.onEvent;
5109
+ const signal = options?.signal;
5110
+ const contextBudget = options?.contextBudget;
5111
+ const guardrails = options?.guardrails;
5112
+ const steering = options?.steering;
5113
+ const parallelToolCalls = options?.parallelToolCalls ?? false;
5114
+ emit("signature", "prompty.invokeAgent");
5115
+ emit("description", "Invoke a prompty with tool calling");
4985
5116
  emit("inputs", { prompt: serializeAgent(agent), tools: Object.keys(tools), inputs: inputs ?? {} });
4986
- const messages = await prepare(agent, inputs);
5117
+ let messages = await prepare(agent, inputs);
4987
5118
  const parentInputs = inputs ?? {};
4988
5119
  const provider = resolveProvider(agent);
4989
5120
  const executor = getExecutor(provider);
4990
- let response = await executor.execute(agent, messages);
5121
+ let response = null;
4991
5122
  let iteration = 0;
4992
5123
  while (true) {
5124
+ try {
5125
+ checkCancellation(signal);
5126
+ } catch (err) {
5127
+ emitEvent(onEvent, "cancelled", {});
5128
+ throw err;
5129
+ }
5130
+ if (steering) {
5131
+ const pending = steering.drain();
5132
+ if (pending.length > 0) {
5133
+ messages.push(...pending);
5134
+ emitEvent(onEvent, "messages_updated", { messages });
5135
+ emitEvent(onEvent, "status", { message: `Injected ${pending.length} steering message(s)` });
5136
+ }
5137
+ }
5138
+ if (contextBudget !== void 0) {
5139
+ const [droppedCount] = trimToContextWindow(messages, contextBudget);
5140
+ if (droppedCount > 0) {
5141
+ emitEvent(onEvent, "messages_updated", { messages });
5142
+ emitEvent(onEvent, "status", { message: `Trimmed ${droppedCount} messages for context budget` });
5143
+ }
5144
+ }
5145
+ if (guardrails) {
5146
+ const result2 = guardrails.checkInput(messages);
5147
+ if (!result2.allowed) {
5148
+ emitEvent(onEvent, "error", { message: `Input guardrail denied: ${result2.reason}` });
5149
+ throw new GuardrailError(result2.reason ?? "Input guardrail denied");
5150
+ }
5151
+ if (result2.rewrite) messages = result2.rewrite;
5152
+ }
5153
+ try {
5154
+ checkCancellation(signal);
5155
+ } catch (err) {
5156
+ emitEvent(onEvent, "cancelled", {});
5157
+ throw err;
5158
+ }
5159
+ response = await executor.execute(agent, messages);
4993
5160
  if (isAsyncIterable(response)) {
4994
- const { toolCalls, content } = await consumeStream(agent, response);
5161
+ const { toolCalls, content } = await consumeStream(agent, response, onEvent);
5162
+ if (guardrails && content) {
5163
+ const assistantMsg = new Message("assistant", [text(content)]);
5164
+ const gr = guardrails.checkOutput(assistantMsg);
5165
+ if (!gr.allowed) {
5166
+ emitEvent(onEvent, "error", { message: `Output guardrail denied: ${gr.reason}` });
5167
+ throw new GuardrailError(gr.reason ?? "Output guardrail denied");
5168
+ }
5169
+ }
4995
5170
  if (toolCalls.length === 0) {
4996
5171
  emit("iterations", iteration);
4997
5172
  emit("result", content);
5173
+ emitEvent(onEvent, "done", { response: content, messages });
4998
5174
  return content;
4999
5175
  }
5000
5176
  iteration++;
@@ -5004,17 +5180,57 @@ async function executeAgent(prompt, inputs, options) {
5004
5180
  );
5005
5181
  }
5006
5182
  const toolMessages2 = await traceSpan("toolCalls", async (toolEmit) => {
5007
- toolEmit("signature", "prompty.executeAgent.toolCalls");
5183
+ toolEmit("signature", "prompty.invokeAgent.toolCalls");
5008
5184
  toolEmit("description", `Tool call round ${iteration}`);
5009
- const result2 = await buildToolMessagesFromCalls(toolCalls, content, tools, agent, parentInputs, toolEmit);
5185
+ const result2 = await buildToolMessagesFromCallsWithExtensions(
5186
+ toolCalls,
5187
+ content,
5188
+ tools,
5189
+ agent,
5190
+ parentInputs,
5191
+ toolEmit,
5192
+ { onEvent, signal, guardrails, parallel: parallelToolCalls }
5193
+ );
5010
5194
  toolEmit("result", result2.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
5011
5195
  return result2;
5012
5196
  });
5013
5197
  messages.push(...toolMessages2);
5014
- response = await executor.execute(agent, messages);
5198
+ emitEvent(onEvent, "messages_updated", { messages });
5015
5199
  continue;
5016
5200
  }
5017
- if (!hasToolCalls(response)) break;
5201
+ if (!hasToolCalls(response)) {
5202
+ const finalResult = options?.raw ? response : await process2(agent, response);
5203
+ if (guardrails) {
5204
+ const contentStr = typeof finalResult === "string" ? finalResult : JSON.stringify(finalResult);
5205
+ const assistantMsg = new Message("assistant", [text(contentStr)]);
5206
+ const gr = guardrails.checkOutput(assistantMsg);
5207
+ if (!gr.allowed) {
5208
+ emitEvent(onEvent, "error", { message: `Output guardrail denied: ${gr.reason}` });
5209
+ throw new GuardrailError(gr.reason ?? "Output guardrail denied");
5210
+ }
5211
+ if (gr.rewrite !== void 0) {
5212
+ emit("iterations", iteration);
5213
+ emit("result", gr.rewrite);
5214
+ emitEvent(onEvent, "done", { response: gr.rewrite, messages });
5215
+ return gr.rewrite;
5216
+ }
5217
+ }
5218
+ emit("iterations", iteration);
5219
+ emit("result", finalResult);
5220
+ emitEvent(onEvent, "done", { response: finalResult, messages });
5221
+ return finalResult;
5222
+ }
5223
+ if (guardrails) {
5224
+ const { textContent } = extractToolInfo(response);
5225
+ if (textContent) {
5226
+ const assistantMsg = new Message("assistant", [text(textContent)]);
5227
+ const gr = guardrails.checkOutput(assistantMsg);
5228
+ if (!gr.allowed) {
5229
+ emitEvent(onEvent, "error", { message: `Output guardrail denied: ${gr.reason}` });
5230
+ throw new GuardrailError(gr.reason ?? "Output guardrail denied");
5231
+ }
5232
+ }
5233
+ }
5018
5234
  iteration++;
5019
5235
  if (iteration > maxIterations) {
5020
5236
  throw new Error(
@@ -5022,24 +5238,37 @@ async function executeAgent(prompt, inputs, options) {
5022
5238
  );
5023
5239
  }
5024
5240
  const toolMessages = await traceSpan("toolCalls", async (toolEmit) => {
5025
- toolEmit("signature", "prompty.executeAgent.toolCalls");
5241
+ toolEmit("signature", "prompty.invokeAgent.toolCalls");
5026
5242
  toolEmit("description", `Tool call round ${iteration}`);
5027
- const result2 = await buildToolResultMessages(response, tools, agent, parentInputs, toolEmit);
5243
+ const result2 = await buildToolResultMessagesWithExtensions(
5244
+ response,
5245
+ tools,
5246
+ agent,
5247
+ parentInputs,
5248
+ toolEmit,
5249
+ { onEvent, signal, guardrails, parallel: parallelToolCalls }
5250
+ );
5028
5251
  toolEmit("result", result2.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
5029
5252
  return result2;
5030
5253
  });
5031
5254
  messages.push(...toolMessages);
5032
- response = await executor.execute(agent, messages);
5255
+ emitEvent(onEvent, "messages_updated", { messages });
5033
5256
  }
5034
5257
  emit("iterations", iteration);
5035
5258
  if (options?.raw) {
5036
5259
  emit("result", response);
5260
+ emitEvent(onEvent, "done", { response, messages });
5037
5261
  return response;
5038
5262
  }
5039
5263
  const result = await process2(agent, response);
5040
5264
  emit("result", result);
5265
+ emitEvent(onEvent, "done", { response: result, messages });
5041
5266
  return result;
5042
5267
  });
5268
+ if (options?.validator) {
5269
+ return cast(rawResult, options.validator);
5270
+ }
5271
+ return rawResult;
5043
5272
  }
5044
5273
  function expandThreads(messages, nonces, inputs) {
5045
5274
  if (nonces.size === 0) return messages;
@@ -5108,160 +5337,138 @@ function hasToolCalls(response) {
5108
5337
  }
5109
5338
  return false;
5110
5339
  }
5111
- async function buildToolResultMessages(response, tools, agent, parentInputs, parentEmit) {
5340
+ function extractToolInfo(response) {
5341
+ if (typeof response !== "object" || response === null) {
5342
+ return { toolCalls: [], textContent: "" };
5343
+ }
5112
5344
  const r = response;
5113
5345
  if (Array.isArray(r.content) && r.stop_reason === "tool_use") {
5114
- return buildAnthropicToolResultMessages(r, tools, agent, parentInputs, parentEmit);
5346
+ const content = r.content;
5347
+ const toolCalls = content.filter((b) => b.type === "tool_use").map((b) => ({
5348
+ id: b.id,
5349
+ name: b.name,
5350
+ arguments: JSON.stringify(b.input)
5351
+ }));
5352
+ const textContent = content.filter((b) => b.type === "text").map((b) => b.text).join("");
5353
+ return { toolCalls, textContent };
5115
5354
  }
5116
5355
  if (r.object === "response" && Array.isArray(r.output)) {
5117
- return buildResponsesToolResultMessages(r, tools, agent, parentInputs, parentEmit);
5356
+ const funcCalls = r.output.filter(
5357
+ (item) => item.type === "function_call"
5358
+ );
5359
+ const toolCalls = funcCalls.map((fc) => ({
5360
+ id: fc.call_id ?? fc.id ?? "",
5361
+ call_id: fc.call_id ?? fc.id ?? "",
5362
+ name: fc.name,
5363
+ arguments: fc.arguments ?? "{}"
5364
+ }));
5365
+ return { toolCalls, textContent: "" };
5118
5366
  }
5119
- return buildOpenAIToolResultMessages(r, tools, agent, parentInputs, parentEmit);
5120
- }
5121
- async function buildOpenAIToolResultMessages(r, tools, agent, parentInputs, parentEmit) {
5122
5367
  const choices = r.choices;
5123
- const choice = choices[0];
5124
- const message = choice.message;
5125
- const toolCalls = message.tool_calls;
5126
- const messages = [];
5127
- const assistantContent = message.content ?? "";
5128
- messages.push(
5129
- new Message("assistant", assistantContent ? [text(assistantContent)] : [], {
5130
- tool_calls: toolCalls
5131
- })
5132
- );
5133
- const toolInputs = [];
5134
- for (const tc of toolCalls) {
5135
- const fn = tc.function;
5136
- const toolName = fn.name;
5137
- const toolCallId = tc.id;
5138
- let result;
5139
- let parsedArgs;
5140
- try {
5141
- parsedArgs = JSON.parse(fn.arguments);
5142
- if (agent && parentInputs && typeof parsedArgs === "object" && parsedArgs !== null && !Array.isArray(parsedArgs)) {
5143
- parsedArgs = resolveBindings(agent, toolName, parsedArgs, parentInputs);
5144
- }
5145
- result = await traceSpan(toolName, async (toolEmit) => {
5146
- toolEmit("signature", `prompty.tool.${toolName}`);
5147
- toolEmit("description", `Execute tool: ${toolName}`);
5148
- toolEmit("inputs", { arguments: parsedArgs, tool_call_id: toolCallId });
5149
- const r2 = await dispatchTool(toolName, parsedArgs, tools, agent ?? {}, parentInputs ?? {});
5150
- toolEmit("result", r2);
5151
- return r2;
5368
+ if (Array.isArray(choices) && choices.length > 0) {
5369
+ const choice = choices[0];
5370
+ const message = choice.message;
5371
+ if (message && Array.isArray(message.tool_calls)) {
5372
+ const toolCalls = message.tool_calls.map((tc) => {
5373
+ const fn = tc.function;
5374
+ return {
5375
+ id: tc.id,
5376
+ name: fn.name,
5377
+ arguments: fn.arguments
5378
+ };
5152
5379
  });
5153
- } catch (err) {
5154
- result = `Error: ${err instanceof Error ? err.message : String(err)}`;
5380
+ return { toolCalls, textContent: message.content ?? "" };
5155
5381
  }
5156
- toolInputs.push({ name: toolName, arguments: parsedArgs, tool_call_id: toolCallId, result });
5157
- messages.push(
5158
- new Message("tool", [text(result)], {
5159
- tool_call_id: toolCallId,
5160
- name: toolName
5161
- })
5162
- );
5163
- }
5164
- if (parentEmit) {
5165
- parentEmit("inputs", { tool_calls: toolInputs });
5166
5382
  }
5167
- return messages;
5383
+ return { toolCalls: [], textContent: "" };
5168
5384
  }
5169
- async function buildAnthropicToolResultMessages(r, tools, agent, parentInputs, parentEmit) {
5170
- const content = r.content;
5171
- const toolUseBlocks = content.filter((block) => block.type === "tool_use");
5172
- const messages = [];
5173
- const textParts = content.filter((block) => block.type === "text").map((block) => text(block.text));
5174
- messages.push(
5175
- new Message("assistant", textParts, { content })
5176
- );
5177
- const toolInputs = [];
5178
- const toolResultBlocks = [];
5179
- for (const block of toolUseBlocks) {
5180
- const toolName = block.name;
5181
- const toolCallId = block.id;
5182
- let toolArgs = block.input;
5183
- if (agent && parentInputs && typeof toolArgs === "object" && toolArgs !== null && !Array.isArray(toolArgs)) {
5184
- toolArgs = resolveBindings(agent, toolName, toolArgs, parentInputs);
5185
- }
5186
- let result;
5385
+ async function dispatchOneToolWithExtensions(tc, tools, agent, parentInputs, ext) {
5386
+ const { onEvent, signal, guardrails } = ext;
5387
+ try {
5388
+ checkCancellation(signal);
5389
+ } catch (err) {
5390
+ emitEvent(onEvent, "cancelled", {});
5391
+ throw err;
5392
+ }
5393
+ emitEvent(onEvent, "tool_call_start", { name: tc.name, arguments: tc.arguments });
5394
+ if (guardrails) {
5395
+ let parsedArgs2 = {};
5187
5396
  try {
5188
- result = await traceSpan(toolName, async (toolEmit) => {
5189
- toolEmit("signature", `prompty.tool.${toolName}`);
5190
- toolEmit("description", `Execute tool: ${toolName}`);
5191
- toolEmit("inputs", { arguments: toolArgs, tool_use_id: toolCallId });
5192
- const r2 = await dispatchTool(toolName, toolArgs, tools, agent ?? {}, parentInputs ?? {});
5193
- toolEmit("result", r2);
5194
- return r2;
5195
- });
5196
- } catch (err) {
5197
- result = `Error: ${err instanceof Error ? err.message : String(err)}`;
5397
+ const parsed = JSON.parse(tc.arguments);
5398
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
5399
+ parsedArgs2 = parsed;
5400
+ }
5401
+ } catch {
5402
+ }
5403
+ const gr = guardrails.checkTool(tc.name, parsedArgs2);
5404
+ if (!gr.allowed) {
5405
+ const deniedMsg = `Tool denied by guardrail: ${gr.reason}`;
5406
+ emitEvent(onEvent, "tool_result", { name: tc.name, result: deniedMsg });
5407
+ return deniedMsg;
5408
+ }
5409
+ if (gr.rewrite !== void 0) {
5410
+ tc = { ...tc, arguments: typeof gr.rewrite === "string" ? gr.rewrite : JSON.stringify(gr.rewrite) };
5198
5411
  }
5199
- toolInputs.push({ name: toolName, arguments: toolArgs, tool_use_id: toolCallId, result });
5200
- toolResultBlocks.push({
5201
- type: "tool_result",
5202
- tool_use_id: toolCallId,
5203
- content: result
5204
- });
5205
5412
  }
5206
- if (parentEmit) {
5207
- parentEmit("inputs", { tool_calls: toolInputs });
5413
+ let result;
5414
+ let parsedArgs;
5415
+ try {
5416
+ parsedArgs = JSON.parse(tc.arguments);
5417
+ if (agent && parentInputs && typeof parsedArgs === "object" && parsedArgs !== null && !Array.isArray(parsedArgs)) {
5418
+ parsedArgs = resolveBindings(agent, tc.name, parsedArgs, parentInputs);
5419
+ }
5420
+ result = await traceSpan(tc.name, async (toolEmit) => {
5421
+ toolEmit("signature", `prompty.tool.${tc.name}`);
5422
+ toolEmit("description", `Execute tool: ${tc.name}`);
5423
+ toolEmit("inputs", { arguments: parsedArgs, id: tc.id });
5424
+ const r = await dispatchTool(tc.name, parsedArgs, tools, agent, parentInputs);
5425
+ toolEmit("result", r);
5426
+ return r;
5427
+ });
5428
+ } catch (err) {
5429
+ if (err instanceof CancelledError) throw err;
5430
+ result = `Error: ${err instanceof Error ? err.message : String(err)}`;
5208
5431
  }
5209
- messages.push(
5210
- new Message("user", [], { tool_results: toolResultBlocks })
5211
- );
5212
- return messages;
5432
+ emitEvent(onEvent, "tool_result", { name: tc.name, result });
5433
+ return result;
5213
5434
  }
5214
- async function buildResponsesToolResultMessages(r, tools, agent, parentInputs, parentEmit) {
5215
- const output = r.output;
5216
- const funcCalls = output.filter((item) => item.type === "function_call");
5217
- const messages = [];
5218
- const toolInputs = [];
5219
- for (const fc of funcCalls) {
5220
- const toolName = fc.name;
5221
- const callId = fc.call_id ?? fc.id ?? "";
5222
- const argsStr = fc.arguments ?? "{}";
5223
- messages.push(
5224
- new Message("assistant", [], {
5225
- responses_function_call: {
5226
- type: "function_call",
5227
- call_id: callId,
5228
- name: toolName,
5229
- arguments: argsStr
5230
- }
5231
- })
5232
- );
5233
- let result;
5234
- let parsedArgs;
5235
- try {
5236
- parsedArgs = JSON.parse(argsStr);
5237
- if (agent && parentInputs && typeof parsedArgs === "object" && parsedArgs !== null && !Array.isArray(parsedArgs)) {
5238
- parsedArgs = resolveBindings(agent, toolName, parsedArgs, parentInputs);
5239
- }
5240
- result = await traceSpan(toolName, async (toolEmit) => {
5241
- toolEmit("signature", `prompty.tool.${toolName}`);
5242
- toolEmit("description", `Execute tool: ${toolName}`);
5243
- toolEmit("inputs", { arguments: parsedArgs, call_id: callId });
5244
- const r2 = await dispatchTool(toolName, parsedArgs, tools, agent ?? {}, parentInputs ?? {});
5245
- toolEmit("result", r2);
5246
- return r2;
5247
- });
5248
- } catch (err) {
5249
- result = `Error: ${err instanceof Error ? err.message : String(err)}`;
5250
- }
5251
- toolInputs.push({ name: toolName, arguments: parsedArgs, call_id: callId, result });
5252
- messages.push(
5253
- new Message("tool", [text(result)], {
5254
- tool_call_id: callId,
5255
- name: toolName
5256
- })
5435
+ async function dispatchToolsWithExtensions(toolCalls, tools, agent, parentInputs, ext) {
5436
+ if (ext.parallel && toolCalls.length > 1) {
5437
+ return Promise.all(
5438
+ toolCalls.map((tc) => dispatchOneToolWithExtensions(tc, tools, agent, parentInputs, ext))
5257
5439
  );
5258
5440
  }
5441
+ const results = [];
5442
+ for (const tc of toolCalls) {
5443
+ results.push(await dispatchOneToolWithExtensions(tc, tools, agent, parentInputs, ext));
5444
+ }
5445
+ return results;
5446
+ }
5447
+ async function buildToolResultMessagesWithExtensions(response, tools, agent, parentInputs, parentEmit, ext) {
5448
+ const { toolCalls, textContent } = extractToolInfo(response);
5449
+ const toolResults = await dispatchToolsWithExtensions(toolCalls, tools, agent, parentInputs, ext);
5450
+ if (parentEmit) {
5451
+ parentEmit("inputs", {
5452
+ tool_calls: toolCalls.map((tc, i) => ({ name: tc.name, arguments: tc.arguments, id: tc.id, result: toolResults[i] }))
5453
+ });
5454
+ }
5455
+ const provider = resolveProvider(agent);
5456
+ const executor = getExecutor(provider);
5457
+ return executor.formatToolMessages(response, toolCalls, toolResults, textContent);
5458
+ }
5459
+ async function buildToolMessagesFromCallsWithExtensions(toolCalls, textContent, tools, agent, parentInputs, parentEmit, ext) {
5460
+ const normalizedCalls = toolCalls.map((tc) => ({ id: tc.id, name: tc.name, arguments: tc.arguments }));
5461
+ const toolResults = await dispatchToolsWithExtensions(normalizedCalls, tools, agent, parentInputs, ext);
5259
5462
  if (parentEmit) {
5260
- parentEmit("inputs", { tool_calls: toolInputs });
5463
+ parentEmit("inputs", {
5464
+ tool_calls: normalizedCalls.map((tc, i) => ({ name: tc.name, arguments: tc.arguments, id: tc.id, result: toolResults[i] }))
5465
+ });
5261
5466
  }
5262
- return messages;
5467
+ const provider = resolveProvider(agent);
5468
+ const executor = getExecutor(provider);
5469
+ return executor.formatToolMessages(null, normalizedCalls, toolResults, textContent);
5263
5470
  }
5264
- var DEFAULT_FORMAT, DEFAULT_PARSER, DEFAULT_PROVIDER, DEFAULT_MAX_ITERATIONS, runAgent;
5471
+ var DEFAULT_FORMAT, DEFAULT_PARSER, DEFAULT_PROVIDER, DEFAULT_MAX_ITERATIONS;
5265
5472
  var init_pipeline = __esm({
5266
5473
  "src/core/pipeline.ts"() {
5267
5474
  "use strict";
@@ -5271,11 +5478,15 @@ var init_pipeline = __esm({
5271
5478
  init_tracer();
5272
5479
  init_loader();
5273
5480
  init_tool_dispatch();
5481
+ init_agent_events();
5482
+ init_cancellation();
5483
+ init_context2();
5484
+ init_guardrails();
5485
+ init_structured();
5274
5486
  DEFAULT_FORMAT = "nunjucks";
5275
5487
  DEFAULT_PARSER = "prompty";
5276
5488
  DEFAULT_PROVIDER = "openai";
5277
5489
  DEFAULT_MAX_ITERATIONS = 10;
5278
- runAgent = executeAgent;
5279
5490
  }
5280
5491
  });
5281
5492
 
@@ -5287,11 +5498,14 @@ __export(index_exports, {
5287
5498
  ApiKeyConnection: () => ApiKeyConnection,
5288
5499
  ArrayProperty: () => ArrayProperty,
5289
5500
  Binding: () => Binding,
5501
+ CancelledError: () => CancelledError,
5290
5502
  Connection: () => Connection,
5291
5503
  CustomTool: () => CustomTool,
5292
5504
  FormatConfig: () => FormatConfig,
5293
5505
  FoundryConnection: () => FoundryConnection,
5294
5506
  FunctionTool: () => FunctionTool,
5507
+ GuardrailError: () => GuardrailError,
5508
+ Guardrails: () => Guardrails,
5295
5509
  InvokerError: () => InvokerError,
5296
5510
  LoadContext: () => LoadContext,
5297
5511
  McpApprovalMode: () => McpApprovalMode,
@@ -5317,22 +5531,31 @@ __export(index_exports, {
5317
5531
  ReferenceConnection: () => ReferenceConnection,
5318
5532
  RemoteConnection: () => RemoteConnection,
5319
5533
  SaveContext: () => SaveContext,
5534
+ Steering: () => Steering,
5535
+ StructuredResultSymbol: () => StructuredResultSymbol,
5320
5536
  Template: () => Template,
5321
5537
  ThreadMarker: () => ThreadMarker,
5322
5538
  Tool: () => Tool,
5323
5539
  Tracer: () => Tracer,
5540
+ bindTools: () => bindTools,
5541
+ cast: () => cast,
5542
+ checkCancellation: () => checkCancellation,
5324
5543
  clearCache: () => clearCache,
5325
5544
  clearConnections: () => clearConnections,
5326
5545
  consoleTracer: () => consoleTracer,
5546
+ createStructuredResult: () => createStructuredResult,
5327
5547
  dictContentToPart: () => dictContentToPart,
5328
5548
  dictToMessage: () => dictToMessage,
5329
- execute: () => execute,
5330
- executeAgent: () => executeAgent,
5549
+ emitEvent: () => emitEvent,
5550
+ estimateChars: () => estimateChars,
5331
5551
  getConnection: () => getConnection,
5332
5552
  getExecutor: () => getExecutor,
5333
5553
  getParser: () => getParser,
5334
5554
  getProcessor: () => getProcessor,
5335
5555
  getRenderer: () => getRenderer,
5556
+ invoke: () => invoke,
5557
+ invokeAgent: () => invokeAgent,
5558
+ isStructuredResult: () => isStructuredResult,
5336
5559
  load: () => load,
5337
5560
  otelTracer: () => otelTracer,
5338
5561
  parse: () => parse,
@@ -5346,14 +5569,16 @@ __export(index_exports, {
5346
5569
  render: () => render,
5347
5570
  resolveBindings: () => resolveBindings,
5348
5571
  run: () => run,
5349
- runAgent: () => runAgent,
5350
5572
  sanitizeValue: () => sanitizeValue,
5573
+ summarizeDropped: () => summarizeDropped,
5351
5574
  text: () => text,
5352
5575
  textMessage: () => textMessage,
5353
5576
  toSerializable: () => toSerializable,
5577
+ tool: () => tool,
5354
5578
  trace: () => trace,
5355
5579
  traceMethod: () => traceMethod,
5356
5580
  traceSpan: () => traceSpan,
5581
+ trimToContextWindow: () => trimToContextWindow,
5357
5582
  validateInputs: () => validateInputs
5358
5583
  });
5359
5584
  module.exports = __toCommonJS(index_exports);
@@ -5384,6 +5609,101 @@ function clearConnections() {
5384
5609
  init_loader();
5385
5610
  init_pipeline();
5386
5611
  init_tool_dispatch();
5612
+ init_agent_events();
5613
+ init_cancellation();
5614
+ init_context2();
5615
+ init_guardrails();
5616
+
5617
+ // src/core/steering.ts
5618
+ init_types();
5619
+ var Steering = class {
5620
+ queue = [];
5621
+ /** Enqueue a message to be injected at the next iteration. */
5622
+ send(message) {
5623
+ this.queue.push(message);
5624
+ }
5625
+ /** Remove and return all queued messages as Message objects. */
5626
+ drain() {
5627
+ const items = this.queue.splice(0);
5628
+ return items.map((text2) => new Message("user", [{ kind: "text", value: text2 }]));
5629
+ }
5630
+ /** Whether there are pending messages without consuming them. */
5631
+ get hasPending() {
5632
+ return this.queue.length > 0;
5633
+ }
5634
+ };
5635
+
5636
+ // src/core/tool-decorator.ts
5637
+ init_tool();
5638
+ init_property();
5639
+ init_tool_dispatch();
5640
+ function tool(fn, options) {
5641
+ const toolName = options?.name ?? fn.name;
5642
+ const toolDesc = options?.description ?? "";
5643
+ const shouldRegister = options?.register !== false;
5644
+ const properties = (options?.parameters ?? []).map(
5645
+ (p) => new Property({
5646
+ name: p.name,
5647
+ kind: p.kind ?? "string",
5648
+ required: p.required ?? p.default === void 0,
5649
+ description: p.description,
5650
+ default: p.default
5651
+ })
5652
+ );
5653
+ const toolDef = new FunctionTool({
5654
+ name: toolName,
5655
+ kind: "function",
5656
+ description: toolDesc,
5657
+ parameters: properties
5658
+ });
5659
+ const wrapped = fn;
5660
+ wrapped.__tool__ = toolDef;
5661
+ if (shouldRegister) {
5662
+ registerTool(toolName, fn);
5663
+ }
5664
+ return wrapped;
5665
+ }
5666
+ function bindTools(agent, tools) {
5667
+ const handlers = {};
5668
+ for (const fn of tools) {
5669
+ const toolDef = fn.__tool__;
5670
+ if (!toolDef) {
5671
+ throw new Error(
5672
+ `Function '${fn.name || "(anonymous)"}' is not a tool()-wrapped function (missing __tool__ property)`
5673
+ );
5674
+ }
5675
+ const name = toolDef.name;
5676
+ if (name in handlers) {
5677
+ throw new Error(`Duplicate tool handler: '${name}'`);
5678
+ }
5679
+ handlers[name] = fn;
5680
+ }
5681
+ const declaredFunctionTools = /* @__PURE__ */ new Set();
5682
+ for (const toolDef of agent.tools ?? []) {
5683
+ if (toolDef.kind === "function") {
5684
+ declaredFunctionTools.add(toolDef.name);
5685
+ }
5686
+ }
5687
+ for (const name of Object.keys(handlers)) {
5688
+ if (!declaredFunctionTools.has(name)) {
5689
+ const declared = [...declaredFunctionTools].sort().join(", ") || "(none)";
5690
+ throw new Error(
5691
+ `Tool handler '${name}' has no matching 'kind: function' declaration in agent.tools. Declared function tools: ${declared}`
5692
+ );
5693
+ }
5694
+ }
5695
+ for (const name of declaredFunctionTools) {
5696
+ if (!(name in handlers)) {
5697
+ console.warn(
5698
+ `Tool '${name}' is declared in agent.tools but no handler was provided to bindTools()`
5699
+ );
5700
+ }
5701
+ }
5702
+ return handlers;
5703
+ }
5704
+
5705
+ // src/core/index.ts
5706
+ init_structured();
5387
5707
 
5388
5708
  // src/renderers/nunjucks.ts
5389
5709
  var import_nunjucks = __toESM(require("nunjucks"), 1);
@@ -5777,11 +6097,14 @@ registerParser("prompty", new PromptyChatParser());
5777
6097
  ApiKeyConnection,
5778
6098
  ArrayProperty,
5779
6099
  Binding,
6100
+ CancelledError,
5780
6101
  Connection,
5781
6102
  CustomTool,
5782
6103
  FormatConfig,
5783
6104
  FoundryConnection,
5784
6105
  FunctionTool,
6106
+ GuardrailError,
6107
+ Guardrails,
5785
6108
  InvokerError,
5786
6109
  LoadContext,
5787
6110
  McpApprovalMode,
@@ -5807,22 +6130,31 @@ registerParser("prompty", new PromptyChatParser());
5807
6130
  ReferenceConnection,
5808
6131
  RemoteConnection,
5809
6132
  SaveContext,
6133
+ Steering,
6134
+ StructuredResultSymbol,
5810
6135
  Template,
5811
6136
  ThreadMarker,
5812
6137
  Tool,
5813
6138
  Tracer,
6139
+ bindTools,
6140
+ cast,
6141
+ checkCancellation,
5814
6142
  clearCache,
5815
6143
  clearConnections,
5816
6144
  consoleTracer,
6145
+ createStructuredResult,
5817
6146
  dictContentToPart,
5818
6147
  dictToMessage,
5819
- execute,
5820
- executeAgent,
6148
+ emitEvent,
6149
+ estimateChars,
5821
6150
  getConnection,
5822
6151
  getExecutor,
5823
6152
  getParser,
5824
6153
  getProcessor,
5825
6154
  getRenderer,
6155
+ invoke,
6156
+ invokeAgent,
6157
+ isStructuredResult,
5826
6158
  load,
5827
6159
  otelTracer,
5828
6160
  parse,
@@ -5836,14 +6168,16 @@ registerParser("prompty", new PromptyChatParser());
5836
6168
  render,
5837
6169
  resolveBindings,
5838
6170
  run,
5839
- runAgent,
5840
6171
  sanitizeValue,
6172
+ summarizeDropped,
5841
6173
  text,
5842
6174
  textMessage,
5843
6175
  toSerializable,
6176
+ tool,
5844
6177
  trace,
5845
6178
  traceMethod,
5846
6179
  traceSpan,
6180
+ trimToContextWindow,
5847
6181
  validateInputs
5848
6182
  });
5849
6183
  //# sourceMappingURL=index.cjs.map