@prompty/core 2.0.0-alpha.5 → 2.0.0-alpha.7
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 +724 -299
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +353 -16
- package/dist/index.d.ts +353 -16
- package/dist/index.js +708 -299
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -2220,7 +2220,12 @@ var init_property = __esm({
|
|
|
2220
2220
|
for (const [key, value] of Object.entries(
|
|
2221
2221
|
data
|
|
2222
2222
|
)) {
|
|
2223
|
-
if (
|
|
2223
|
+
if (Array.isArray(value)) {
|
|
2224
|
+
throw new Error(
|
|
2225
|
+
`Invalid 'properties' format: key '${key}' has an array value. 'properties' must be a flat list of objects or a name-keyed dict \u2014 not a nested { ${key}: [...] } structure.`
|
|
2226
|
+
);
|
|
2227
|
+
}
|
|
2228
|
+
if (value && typeof value === "object") {
|
|
2224
2229
|
value["name"] = key;
|
|
2225
2230
|
result.push(Property.load(value, context));
|
|
2226
2231
|
} else {
|
|
@@ -3128,7 +3133,12 @@ var init_tool = __esm({
|
|
|
3128
3133
|
for (const [key, value] of Object.entries(
|
|
3129
3134
|
data
|
|
3130
3135
|
)) {
|
|
3131
|
-
if (
|
|
3136
|
+
if (Array.isArray(value)) {
|
|
3137
|
+
throw new Error(
|
|
3138
|
+
`Invalid 'bindings' format: key '${key}' has an array value. 'bindings' must be a flat list of objects or a name-keyed dict \u2014 not a nested { ${key}: [...] } structure.`
|
|
3139
|
+
);
|
|
3140
|
+
}
|
|
3141
|
+
if (value && typeof value === "object") {
|
|
3132
3142
|
value["name"] = key;
|
|
3133
3143
|
result.push(Binding.load(value, context));
|
|
3134
3144
|
} else {
|
|
@@ -3343,7 +3353,12 @@ var init_tool = __esm({
|
|
|
3343
3353
|
for (const [key, value] of Object.entries(
|
|
3344
3354
|
data
|
|
3345
3355
|
)) {
|
|
3346
|
-
if (
|
|
3356
|
+
if (Array.isArray(value)) {
|
|
3357
|
+
throw new Error(
|
|
3358
|
+
`Invalid 'parameters' format: key '${key}' has an array value. 'parameters' must be a flat list of objects or a name-keyed dict \u2014 not a nested { ${key}: [...] } structure.`
|
|
3359
|
+
);
|
|
3360
|
+
}
|
|
3361
|
+
if (value && typeof value === "object") {
|
|
3347
3362
|
value["name"] = key;
|
|
3348
3363
|
result.push(Property.load(value, context));
|
|
3349
3364
|
} else {
|
|
@@ -4100,7 +4115,12 @@ var init_prompty = __esm({
|
|
|
4100
4115
|
for (const [key, value] of Object.entries(
|
|
4101
4116
|
data
|
|
4102
4117
|
)) {
|
|
4103
|
-
if (
|
|
4118
|
+
if (Array.isArray(value)) {
|
|
4119
|
+
throw new Error(
|
|
4120
|
+
`Invalid 'inputs' format: key '${key}' has an array value. 'inputs' must be a flat list of objects or a name-keyed dict \u2014 not a nested { ${key}: [...] } structure.`
|
|
4121
|
+
);
|
|
4122
|
+
}
|
|
4123
|
+
if (value && typeof value === "object") {
|
|
4104
4124
|
value["name"] = key;
|
|
4105
4125
|
result.push(Property.load(value, context));
|
|
4106
4126
|
} else {
|
|
@@ -4130,7 +4150,12 @@ var init_prompty = __esm({
|
|
|
4130
4150
|
for (const [key, value] of Object.entries(
|
|
4131
4151
|
data
|
|
4132
4152
|
)) {
|
|
4133
|
-
if (
|
|
4153
|
+
if (Array.isArray(value)) {
|
|
4154
|
+
throw new Error(
|
|
4155
|
+
`Invalid 'outputs' format: key '${key}' has an array value. 'outputs' must be a flat list of objects or a name-keyed dict \u2014 not a nested { ${key}: [...] } structure.`
|
|
4156
|
+
);
|
|
4157
|
+
}
|
|
4158
|
+
if (value && typeof value === "object") {
|
|
4134
4159
|
value["name"] = key;
|
|
4135
4160
|
result.push(Property.load(value, context));
|
|
4136
4161
|
} else {
|
|
@@ -4160,7 +4185,12 @@ var init_prompty = __esm({
|
|
|
4160
4185
|
for (const [key, value] of Object.entries(
|
|
4161
4186
|
data
|
|
4162
4187
|
)) {
|
|
4163
|
-
if (
|
|
4188
|
+
if (Array.isArray(value)) {
|
|
4189
|
+
throw new Error(
|
|
4190
|
+
`Invalid 'tools' format: key '${key}' has an array value. 'tools' must be a flat list of objects or a name-keyed dict \u2014 not a nested { ${key}: [...] } structure.`
|
|
4191
|
+
);
|
|
4192
|
+
}
|
|
4193
|
+
if (value && typeof value === "object") {
|
|
4164
4194
|
value["name"] = key;
|
|
4165
4195
|
result.push(Tool.load(value, context));
|
|
4166
4196
|
} else {
|
|
@@ -4499,6 +4529,9 @@ var init_common = __esm({
|
|
|
4499
4529
|
|
|
4500
4530
|
// src/core/tool-dispatch.ts
|
|
4501
4531
|
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
4532
|
+
function registerTool(name, handler) {
|
|
4533
|
+
nameRegistry.set(name, handler);
|
|
4534
|
+
}
|
|
4502
4535
|
function getTool(name) {
|
|
4503
4536
|
return nameRegistry.get(name);
|
|
4504
4537
|
}
|
|
@@ -4522,12 +4555,12 @@ async function dispatchTool(toolName, args, userTools, agent, parentInputs) {
|
|
|
4522
4555
|
const result = await registeredFn(args);
|
|
4523
4556
|
return typeof result === "string" ? result : JSON.stringify(result);
|
|
4524
4557
|
}
|
|
4525
|
-
const
|
|
4526
|
-
if (!
|
|
4558
|
+
const tool2 = agent.tools?.find((t) => t.name === toolName);
|
|
4559
|
+
if (!tool2) {
|
|
4527
4560
|
const available = Object.keys(userTools).sort().join(", ") || "(none)";
|
|
4528
4561
|
return `Error: tool "${toolName}" not found in userTools or agent.tools. Available user tools: ${available}`;
|
|
4529
4562
|
}
|
|
4530
|
-
const kind =
|
|
4563
|
+
const kind = tool2.kind || "*";
|
|
4531
4564
|
let handler;
|
|
4532
4565
|
try {
|
|
4533
4566
|
handler = getToolHandler(kind);
|
|
@@ -4539,7 +4572,7 @@ async function dispatchTool(toolName, args, userTools, agent, parentInputs) {
|
|
|
4539
4572
|
}
|
|
4540
4573
|
}
|
|
4541
4574
|
return await handler.executeTool(
|
|
4542
|
-
|
|
4575
|
+
tool2,
|
|
4543
4576
|
args,
|
|
4544
4577
|
agent,
|
|
4545
4578
|
parentInputs
|
|
@@ -4564,36 +4597,36 @@ var init_tool_dispatch = __esm({
|
|
|
4564
4597
|
nameRegistry = /* @__PURE__ */ new Map();
|
|
4565
4598
|
toolHandlers = /* @__PURE__ */ new Map();
|
|
4566
4599
|
FunctionToolHandler = class {
|
|
4567
|
-
async executeTool(
|
|
4568
|
-
const name =
|
|
4600
|
+
async executeTool(tool2, _args, _agent, _parentInputs) {
|
|
4601
|
+
const name = tool2.name ?? "unknown";
|
|
4569
4602
|
throw new Error(
|
|
4570
|
-
`Function tool '${name}' declared but no callable provided. Pass it via tools: { '${name}': fn } in
|
|
4603
|
+
`Function tool '${name}' declared but no callable provided. Pass it via tools: { '${name}': fn } in turn().`
|
|
4571
4604
|
);
|
|
4572
4605
|
}
|
|
4573
4606
|
};
|
|
4574
4607
|
PromptyToolHandler = class {
|
|
4575
|
-
async executeTool(
|
|
4608
|
+
async executeTool(tool2, args, agent, _parentInputs) {
|
|
4576
4609
|
const { load: load2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
|
|
4577
|
-
const { prepare: prepare2, run: run2,
|
|
4610
|
+
const { prepare: prepare2, run: run2, turn: turn2 } = await Promise.resolve().then(() => (init_pipeline(), pipeline_exports));
|
|
4578
4611
|
const parentPath = (agent.metadata ?? {}).__source_path;
|
|
4579
4612
|
if (!parentPath) {
|
|
4580
|
-
return `Error: cannot resolve PromptyTool '${
|
|
4613
|
+
return `Error: cannot resolve PromptyTool '${tool2.name}': parent has no __source_path`;
|
|
4581
4614
|
}
|
|
4582
|
-
const childPath = resolve2(dirname2(parentPath),
|
|
4615
|
+
const childPath = resolve2(dirname2(parentPath), tool2.path);
|
|
4583
4616
|
const stack = (agent.metadata ?? {}).__prompty_tool_stack ?? [];
|
|
4584
4617
|
const normalizedChild = resolve2(childPath);
|
|
4585
4618
|
const visited = /* @__PURE__ */ new Set([...stack.map((p) => resolve2(p)), resolve2(parentPath)]);
|
|
4586
4619
|
if (visited.has(normalizedChild)) {
|
|
4587
4620
|
const chain = [...stack, parentPath, childPath].join(" \u2192 ");
|
|
4588
|
-
return `Error executing PromptyTool '${
|
|
4621
|
+
return `Error executing PromptyTool '${tool2.name}': circular reference detected: ${chain}`;
|
|
4589
4622
|
}
|
|
4590
4623
|
try {
|
|
4591
4624
|
const child = load2(childPath);
|
|
4592
4625
|
if (!child.metadata) child.metadata = {};
|
|
4593
4626
|
child.metadata.__prompty_tool_stack = [...stack, parentPath];
|
|
4594
|
-
const mode =
|
|
4627
|
+
const mode = tool2.mode ?? "single";
|
|
4595
4628
|
if (mode === "agentic") {
|
|
4596
|
-
const result = await
|
|
4629
|
+
const result = await turn2(child, args);
|
|
4597
4630
|
return typeof result === "string" ? result : JSON.stringify(result);
|
|
4598
4631
|
} else {
|
|
4599
4632
|
const messages = await prepare2(child, args);
|
|
@@ -4601,7 +4634,7 @@ var init_tool_dispatch = __esm({
|
|
|
4601
4634
|
return typeof result === "string" ? result : JSON.stringify(result);
|
|
4602
4635
|
}
|
|
4603
4636
|
} catch (err) {
|
|
4604
|
-
return `Error executing PromptyTool '${
|
|
4637
|
+
return `Error executing PromptyTool '${tool2.name}': ${err instanceof Error ? err.message : String(err)}`;
|
|
4605
4638
|
}
|
|
4606
4639
|
}
|
|
4607
4640
|
};
|
|
@@ -4628,6 +4661,205 @@ var init_tool_dispatch = __esm({
|
|
|
4628
4661
|
}
|
|
4629
4662
|
});
|
|
4630
4663
|
|
|
4664
|
+
// src/core/agent-events.ts
|
|
4665
|
+
function emitEvent(callback, eventType, data) {
|
|
4666
|
+
if (!callback) return;
|
|
4667
|
+
try {
|
|
4668
|
+
callback(eventType, data);
|
|
4669
|
+
} catch (err) {
|
|
4670
|
+
if (typeof globalThis.console?.debug === "function") {
|
|
4671
|
+
globalThis.console.debug(`Event callback error for ${eventType}:`, err);
|
|
4672
|
+
}
|
|
4673
|
+
}
|
|
4674
|
+
}
|
|
4675
|
+
var init_agent_events = __esm({
|
|
4676
|
+
"src/core/agent-events.ts"() {
|
|
4677
|
+
"use strict";
|
|
4678
|
+
}
|
|
4679
|
+
});
|
|
4680
|
+
|
|
4681
|
+
// src/core/cancellation.ts
|
|
4682
|
+
function checkCancellation(signal) {
|
|
4683
|
+
if (signal?.aborted) {
|
|
4684
|
+
throw new CancelledError();
|
|
4685
|
+
}
|
|
4686
|
+
}
|
|
4687
|
+
var CancelledError;
|
|
4688
|
+
var init_cancellation = __esm({
|
|
4689
|
+
"src/core/cancellation.ts"() {
|
|
4690
|
+
"use strict";
|
|
4691
|
+
CancelledError = class extends Error {
|
|
4692
|
+
constructor(message = "Agent loop cancelled") {
|
|
4693
|
+
super(message);
|
|
4694
|
+
this.name = "CancelledError";
|
|
4695
|
+
}
|
|
4696
|
+
};
|
|
4697
|
+
}
|
|
4698
|
+
});
|
|
4699
|
+
|
|
4700
|
+
// src/core/context.ts
|
|
4701
|
+
function estimateChars(messages) {
|
|
4702
|
+
let total = 0;
|
|
4703
|
+
for (const msg of messages) {
|
|
4704
|
+
total += msg.role.length + 4;
|
|
4705
|
+
for (const part of msg.parts) {
|
|
4706
|
+
if (part.kind === "text") {
|
|
4707
|
+
total += part.value.length;
|
|
4708
|
+
} else {
|
|
4709
|
+
total += 200;
|
|
4710
|
+
}
|
|
4711
|
+
}
|
|
4712
|
+
const toolCalls = msg.metadata?.tool_calls;
|
|
4713
|
+
if (toolCalls) {
|
|
4714
|
+
total += JSON.stringify(toolCalls).length;
|
|
4715
|
+
}
|
|
4716
|
+
}
|
|
4717
|
+
return total;
|
|
4718
|
+
}
|
|
4719
|
+
function truncate(text2, maxLen = 200) {
|
|
4720
|
+
return text2.length <= maxLen ? text2 : text2.slice(0, maxLen) + "\u2026";
|
|
4721
|
+
}
|
|
4722
|
+
function summarizeDropped(messages) {
|
|
4723
|
+
const lines = [];
|
|
4724
|
+
for (const msg of messages) {
|
|
4725
|
+
const msgText = msg.text.trim();
|
|
4726
|
+
if (msg.role === "user" && msgText) {
|
|
4727
|
+
lines.push(`User asked: ${truncate(msgText)}`);
|
|
4728
|
+
} else if (msg.role === "assistant") {
|
|
4729
|
+
if (msgText) lines.push(`Assistant: ${truncate(msgText)}`);
|
|
4730
|
+
const toolCalls = msg.metadata?.tool_calls;
|
|
4731
|
+
if (Array.isArray(toolCalls)) {
|
|
4732
|
+
const names = toolCalls.map(
|
|
4733
|
+
(tc) => tc.name ?? (tc.function?.name ?? "?")
|
|
4734
|
+
);
|
|
4735
|
+
lines.push(` Called tools: ${names.join(", ")}`);
|
|
4736
|
+
}
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
4739
|
+
if (lines.length === 0) return "";
|
|
4740
|
+
let result = "[Context summary: ";
|
|
4741
|
+
for (const line of lines) {
|
|
4742
|
+
if (result.length + line.length > 4e3) {
|
|
4743
|
+
result += "\n... (older messages omitted)";
|
|
4744
|
+
break;
|
|
4745
|
+
}
|
|
4746
|
+
result += line + "\n";
|
|
4747
|
+
}
|
|
4748
|
+
return result.trimEnd() + "]";
|
|
4749
|
+
}
|
|
4750
|
+
function trimToContextWindow(messages, budgetChars) {
|
|
4751
|
+
if (estimateChars(messages) <= budgetChars) {
|
|
4752
|
+
return [0, []];
|
|
4753
|
+
}
|
|
4754
|
+
let systemEnd = 0;
|
|
4755
|
+
for (let i = 0; i < messages.length; i++) {
|
|
4756
|
+
if (messages[i].role !== "system") {
|
|
4757
|
+
systemEnd = i;
|
|
4758
|
+
break;
|
|
4759
|
+
}
|
|
4760
|
+
if (i === messages.length - 1) systemEnd = messages.length;
|
|
4761
|
+
}
|
|
4762
|
+
const systemMsgs = messages.slice(0, systemEnd);
|
|
4763
|
+
const rest = messages.slice(systemEnd);
|
|
4764
|
+
const summaryBudget = Math.min(5e3, Math.floor(budgetChars * 0.05));
|
|
4765
|
+
const dropped = [];
|
|
4766
|
+
while (estimateChars([...systemMsgs, ...rest]) > budgetChars - summaryBudget && rest.length > 2) {
|
|
4767
|
+
dropped.push(rest.shift());
|
|
4768
|
+
}
|
|
4769
|
+
const droppedCount = dropped.length;
|
|
4770
|
+
messages.length = 0;
|
|
4771
|
+
messages.push(...systemMsgs);
|
|
4772
|
+
if (droppedCount > 0) {
|
|
4773
|
+
const summaryText = summarizeDropped(dropped);
|
|
4774
|
+
if (summaryText) {
|
|
4775
|
+
messages.push(new Message("user", [{ kind: "text", value: summaryText }]));
|
|
4776
|
+
}
|
|
4777
|
+
}
|
|
4778
|
+
messages.push(...rest);
|
|
4779
|
+
return [droppedCount, dropped];
|
|
4780
|
+
}
|
|
4781
|
+
var init_context2 = __esm({
|
|
4782
|
+
"src/core/context.ts"() {
|
|
4783
|
+
"use strict";
|
|
4784
|
+
init_types();
|
|
4785
|
+
}
|
|
4786
|
+
});
|
|
4787
|
+
|
|
4788
|
+
// src/core/guardrails.ts
|
|
4789
|
+
var GuardrailError, Guardrails;
|
|
4790
|
+
var init_guardrails = __esm({
|
|
4791
|
+
"src/core/guardrails.ts"() {
|
|
4792
|
+
"use strict";
|
|
4793
|
+
GuardrailError = class extends Error {
|
|
4794
|
+
reason;
|
|
4795
|
+
constructor(reason) {
|
|
4796
|
+
super(`Guardrail denied: ${reason}`);
|
|
4797
|
+
this.name = "GuardrailError";
|
|
4798
|
+
this.reason = reason;
|
|
4799
|
+
}
|
|
4800
|
+
};
|
|
4801
|
+
Guardrails = class {
|
|
4802
|
+
inputHook;
|
|
4803
|
+
outputHook;
|
|
4804
|
+
toolHook;
|
|
4805
|
+
constructor(options) {
|
|
4806
|
+
this.inputHook = options?.input;
|
|
4807
|
+
this.outputHook = options?.output;
|
|
4808
|
+
this.toolHook = options?.tool;
|
|
4809
|
+
}
|
|
4810
|
+
checkInput(messages) {
|
|
4811
|
+
if (!this.inputHook) return { allowed: true };
|
|
4812
|
+
return this.inputHook(messages);
|
|
4813
|
+
}
|
|
4814
|
+
checkOutput(message) {
|
|
4815
|
+
if (!this.outputHook) return { allowed: true };
|
|
4816
|
+
return this.outputHook(message);
|
|
4817
|
+
}
|
|
4818
|
+
checkTool(name, args) {
|
|
4819
|
+
if (!this.toolHook) return { allowed: true };
|
|
4820
|
+
return this.toolHook(name, args);
|
|
4821
|
+
}
|
|
4822
|
+
};
|
|
4823
|
+
}
|
|
4824
|
+
});
|
|
4825
|
+
|
|
4826
|
+
// src/core/structured.ts
|
|
4827
|
+
function createStructuredResult(data, rawJson) {
|
|
4828
|
+
const result = { ...data };
|
|
4829
|
+
Object.defineProperty(result, StructuredResultSymbol, {
|
|
4830
|
+
value: rawJson,
|
|
4831
|
+
writable: false,
|
|
4832
|
+
enumerable: false,
|
|
4833
|
+
configurable: false
|
|
4834
|
+
});
|
|
4835
|
+
return result;
|
|
4836
|
+
}
|
|
4837
|
+
function isStructuredResult(value) {
|
|
4838
|
+
return typeof value === "object" && value !== null && StructuredResultSymbol in value;
|
|
4839
|
+
}
|
|
4840
|
+
function cast(result, validator) {
|
|
4841
|
+
let jsonStr;
|
|
4842
|
+
if (isStructuredResult(result)) {
|
|
4843
|
+
jsonStr = result[StructuredResultSymbol];
|
|
4844
|
+
} else if (typeof result === "string") {
|
|
4845
|
+
jsonStr = result;
|
|
4846
|
+
} else {
|
|
4847
|
+
jsonStr = JSON.stringify(result);
|
|
4848
|
+
}
|
|
4849
|
+
const parsed = JSON.parse(jsonStr);
|
|
4850
|
+
if (validator) {
|
|
4851
|
+
return validator(parsed);
|
|
4852
|
+
}
|
|
4853
|
+
return parsed;
|
|
4854
|
+
}
|
|
4855
|
+
var StructuredResultSymbol;
|
|
4856
|
+
var init_structured = __esm({
|
|
4857
|
+
"src/core/structured.ts"() {
|
|
4858
|
+
"use strict";
|
|
4859
|
+
StructuredResultSymbol = /* @__PURE__ */ Symbol("prompty.rawJson");
|
|
4860
|
+
}
|
|
4861
|
+
});
|
|
4862
|
+
|
|
4631
4863
|
// src/core/pipeline.ts
|
|
4632
4864
|
var pipeline_exports = {};
|
|
4633
4865
|
__export(pipeline_exports, {
|
|
@@ -4639,6 +4871,7 @@ __export(pipeline_exports, {
|
|
|
4639
4871
|
render: () => render,
|
|
4640
4872
|
resolveBindings: () => resolveBindings,
|
|
4641
4873
|
run: () => run,
|
|
4874
|
+
turn: () => turn,
|
|
4642
4875
|
validateInputs: () => validateInputs
|
|
4643
4876
|
});
|
|
4644
4877
|
function sanitizeNonces(value) {
|
|
@@ -4829,129 +5062,27 @@ async function invoke(prompt, inputs, options) {
|
|
|
4829
5062
|
emit("description", "Invoke a prompty");
|
|
4830
5063
|
emit("inputs", { prompt: serializeAgent(agent), inputs: inputs ?? {} });
|
|
4831
5064
|
const messages = await prepare(agent, inputs);
|
|
4832
|
-
const
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
const toolDef = agent.tools.find((t) => t.name === toolName);
|
|
4840
|
-
if (!toolDef || !toolDef.bindings || toolDef.bindings.length === 0) return args;
|
|
4841
|
-
const merged = { ...args };
|
|
4842
|
-
for (const binding of toolDef.bindings) {
|
|
4843
|
-
if (binding.input in parentInputs) {
|
|
4844
|
-
merged[binding.name] = parentInputs[binding.input];
|
|
4845
|
-
}
|
|
4846
|
-
}
|
|
4847
|
-
return merged;
|
|
4848
|
-
}
|
|
4849
|
-
function isAsyncIterable(value) {
|
|
4850
|
-
return value != null && typeof value === "object" && Symbol.asyncIterator in value;
|
|
4851
|
-
}
|
|
4852
|
-
function isToolCallLike(item) {
|
|
4853
|
-
return typeof item === "object" && item !== null && "id" in item && "name" in item && "arguments" in item;
|
|
4854
|
-
}
|
|
4855
|
-
async function consumeStream(agent, response) {
|
|
4856
|
-
const processed = await process2(agent, response);
|
|
4857
|
-
const toolCalls = [];
|
|
4858
|
-
const textParts = [];
|
|
4859
|
-
if (isAsyncIterable(processed)) {
|
|
4860
|
-
for await (const item of processed) {
|
|
4861
|
-
if (isToolCallLike(item)) {
|
|
4862
|
-
toolCalls.push(item);
|
|
4863
|
-
} else if (typeof item === "string") {
|
|
4864
|
-
textParts.push(item);
|
|
5065
|
+
const provider = resolveProvider(agent);
|
|
5066
|
+
const executor = getExecutor(provider);
|
|
5067
|
+
const response = await executor.execute(agent, messages);
|
|
5068
|
+
if (options?.raw) {
|
|
5069
|
+
emit("result", response);
|
|
5070
|
+
if (options?.validator) {
|
|
5071
|
+
return cast(response, options.validator);
|
|
4865
5072
|
}
|
|
5073
|
+
return response;
|
|
4866
5074
|
}
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
}
|
|
4872
|
-
async function buildToolMessagesFromCalls(toolCalls, textContent, tools, agent, parentInputs, parentEmit) {
|
|
4873
|
-
const provider = resolveProvider(agent);
|
|
4874
|
-
const apiType = agent.model?.apiType || "chat";
|
|
4875
|
-
const messages = [];
|
|
4876
|
-
const toolInputs = [];
|
|
4877
|
-
if (provider === "anthropic") {
|
|
4878
|
-
const rawContent = [];
|
|
4879
|
-
if (textContent) rawContent.push({ type: "text", text: textContent });
|
|
4880
|
-
for (const tc of toolCalls) {
|
|
4881
|
-
rawContent.push({
|
|
4882
|
-
type: "tool_use",
|
|
4883
|
-
id: tc.id,
|
|
4884
|
-
name: tc.name,
|
|
4885
|
-
input: JSON.parse(tc.arguments)
|
|
4886
|
-
});
|
|
4887
|
-
}
|
|
4888
|
-
messages.push(
|
|
4889
|
-
new Message("assistant", textContent ? [text(textContent)] : [], { content: rawContent })
|
|
4890
|
-
);
|
|
4891
|
-
} else if (apiType === "responses") {
|
|
4892
|
-
for (const tc of toolCalls) {
|
|
4893
|
-
messages.push(
|
|
4894
|
-
new Message("assistant", [], {
|
|
4895
|
-
responses_function_call: {
|
|
4896
|
-
type: "function_call",
|
|
4897
|
-
call_id: tc.id,
|
|
4898
|
-
name: tc.name,
|
|
4899
|
-
arguments: tc.arguments
|
|
4900
|
-
}
|
|
4901
|
-
})
|
|
4902
|
-
);
|
|
4903
|
-
}
|
|
4904
|
-
} else {
|
|
4905
|
-
const rawToolCalls = toolCalls.map((tc) => ({
|
|
4906
|
-
id: tc.id,
|
|
4907
|
-
type: "function",
|
|
4908
|
-
function: { name: tc.name, arguments: tc.arguments }
|
|
4909
|
-
}));
|
|
4910
|
-
messages.push(
|
|
4911
|
-
new Message("assistant", textContent ? [text(textContent)] : [], {
|
|
4912
|
-
tool_calls: rawToolCalls
|
|
4913
|
-
})
|
|
4914
|
-
);
|
|
4915
|
-
}
|
|
4916
|
-
const toolResultBlocks = [];
|
|
4917
|
-
for (const tc of toolCalls) {
|
|
4918
|
-
let result;
|
|
4919
|
-
let parsedArgs;
|
|
4920
|
-
try {
|
|
4921
|
-
parsedArgs = JSON.parse(tc.arguments);
|
|
4922
|
-
if (parentInputs && typeof parsedArgs === "object" && parsedArgs !== null && !Array.isArray(parsedArgs)) {
|
|
4923
|
-
parsedArgs = resolveBindings(agent, tc.name, parsedArgs, parentInputs);
|
|
4924
|
-
}
|
|
4925
|
-
result = await traceSpan(tc.name, async (toolEmit) => {
|
|
4926
|
-
toolEmit("signature", `prompty.tool.${tc.name}`);
|
|
4927
|
-
toolEmit("description", `Execute tool: ${tc.name}`);
|
|
4928
|
-
toolEmit("inputs", { arguments: parsedArgs, id: tc.id });
|
|
4929
|
-
const r = await dispatchTool(tc.name, parsedArgs, tools, agent, parentInputs ?? {});
|
|
4930
|
-
toolEmit("result", r);
|
|
4931
|
-
return r;
|
|
4932
|
-
});
|
|
4933
|
-
} catch (err) {
|
|
4934
|
-
result = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
4935
|
-
}
|
|
4936
|
-
toolInputs.push({ name: tc.name, arguments: parsedArgs, id: tc.id, result });
|
|
4937
|
-
if (provider === "anthropic") {
|
|
4938
|
-
toolResultBlocks.push({ type: "tool_result", tool_use_id: tc.id, content: result });
|
|
4939
|
-
} else {
|
|
4940
|
-
messages.push(
|
|
4941
|
-
new Message("tool", [text(result)], { tool_call_id: tc.id, name: tc.name })
|
|
4942
|
-
);
|
|
5075
|
+
const result = await process2(agent, response);
|
|
5076
|
+
emit("result", result);
|
|
5077
|
+
if (options?.validator) {
|
|
5078
|
+
return cast(result, options.validator);
|
|
4943
5079
|
}
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
messages.push(new Message("user", [], { tool_results: toolResultBlocks }));
|
|
4947
|
-
}
|
|
4948
|
-
if (parentEmit) {
|
|
4949
|
-
parentEmit("inputs", { tool_calls: toolInputs });
|
|
4950
|
-
}
|
|
4951
|
-
return messages;
|
|
5080
|
+
return result;
|
|
5081
|
+
});
|
|
4952
5082
|
}
|
|
4953
|
-
async function
|
|
4954
|
-
|
|
5083
|
+
async function turn(prompt, inputs, options) {
|
|
5084
|
+
const label = options?.turn != null ? `turn ${options.turn}` : "turn";
|
|
5085
|
+
const rawResult = await traceSpan(label, async (emit) => {
|
|
4955
5086
|
const agent = typeof prompt === "string" ? await traceSpan("load", async (loadEmit) => {
|
|
4956
5087
|
loadEmit("signature", "prompty.load");
|
|
4957
5088
|
loadEmit("description", "Load a prompty file.");
|
|
@@ -4960,23 +5091,126 @@ async function invokeAgent(prompt, inputs, options) {
|
|
|
4960
5091
|
loadEmit("result", serializeAgent(loaded));
|
|
4961
5092
|
return loaded;
|
|
4962
5093
|
}) : prompt;
|
|
5094
|
+
emit("signature", "prompty.turn");
|
|
5095
|
+
emit("description", label);
|
|
5096
|
+
emit("inputs", sanitizeValue("inputs", inputs));
|
|
4963
5097
|
const tools = options?.tools ?? {};
|
|
5098
|
+
const hasTools = Object.keys(tools).length > 0;
|
|
5099
|
+
if (!hasTools) {
|
|
5100
|
+
let messages2 = await prepare(agent, inputs);
|
|
5101
|
+
const onEvent2 = options?.onEvent;
|
|
5102
|
+
if (options?.steering) {
|
|
5103
|
+
const pending = options.steering.drain();
|
|
5104
|
+
if (pending.length > 0) {
|
|
5105
|
+
messages2.push(...pending);
|
|
5106
|
+
emitEvent(onEvent2, "messages_updated", { messages: messages2 });
|
|
5107
|
+
}
|
|
5108
|
+
}
|
|
5109
|
+
if (options?.contextBudget !== void 0) {
|
|
5110
|
+
const [droppedCount] = trimToContextWindow(messages2, options.contextBudget);
|
|
5111
|
+
if (droppedCount > 0) {
|
|
5112
|
+
emitEvent(onEvent2, "messages_updated", { messages: messages2 });
|
|
5113
|
+
}
|
|
5114
|
+
}
|
|
5115
|
+
if (options?.guardrails) {
|
|
5116
|
+
const result = options.guardrails.checkInput(messages2);
|
|
5117
|
+
if (!result.allowed) {
|
|
5118
|
+
emitEvent(onEvent2, "error", { message: `Input guardrail denied: ${result.reason}` });
|
|
5119
|
+
throw new GuardrailError(result.reason ?? "Input guardrail denied");
|
|
5120
|
+
}
|
|
5121
|
+
if (result.rewrite) messages2 = result.rewrite;
|
|
5122
|
+
}
|
|
5123
|
+
checkCancellation(options?.signal);
|
|
5124
|
+
const provider2 = resolveProvider(agent);
|
|
5125
|
+
const executor2 = getExecutor(provider2);
|
|
5126
|
+
const response2 = await executor2.execute(agent, messages2);
|
|
5127
|
+
if (options?.raw) {
|
|
5128
|
+
emit("result", response2);
|
|
5129
|
+
return response2;
|
|
5130
|
+
}
|
|
5131
|
+
const processed = await process2(agent, response2);
|
|
5132
|
+
if (options?.guardrails) {
|
|
5133
|
+
const contentStr = typeof processed === "string" ? processed : JSON.stringify(processed);
|
|
5134
|
+
const assistantMsg = new Message("assistant", [text(contentStr)]);
|
|
5135
|
+
const gr = options.guardrails.checkOutput(assistantMsg);
|
|
5136
|
+
if (!gr.allowed) {
|
|
5137
|
+
emitEvent(onEvent2, "error", { message: `Output guardrail denied: ${gr.reason}` });
|
|
5138
|
+
throw new GuardrailError(gr.reason ?? "Output guardrail denied");
|
|
5139
|
+
}
|
|
5140
|
+
if (gr.rewrite !== void 0) {
|
|
5141
|
+
emit("result", gr.rewrite);
|
|
5142
|
+
emitEvent(onEvent2, "done", { response: gr.rewrite, messages: messages2 });
|
|
5143
|
+
return gr.rewrite;
|
|
5144
|
+
}
|
|
5145
|
+
}
|
|
5146
|
+
emit("result", sanitizeValue("result", processed));
|
|
5147
|
+
emitEvent(onEvent2, "done", { response: processed, messages: messages2 });
|
|
5148
|
+
return processed;
|
|
5149
|
+
}
|
|
4964
5150
|
const maxIterations = options?.maxIterations ?? DEFAULT_MAX_ITERATIONS;
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
const
|
|
5151
|
+
const onEvent = options?.onEvent;
|
|
5152
|
+
const signal = options?.signal;
|
|
5153
|
+
const contextBudget = options?.contextBudget;
|
|
5154
|
+
const guardrails = options?.guardrails;
|
|
5155
|
+
const steering = options?.steering;
|
|
5156
|
+
const parallelToolCalls = options?.parallelToolCalls ?? false;
|
|
5157
|
+
let messages = await prepare(agent, inputs);
|
|
4969
5158
|
const parentInputs = inputs ?? {};
|
|
4970
5159
|
const provider = resolveProvider(agent);
|
|
4971
5160
|
const executor = getExecutor(provider);
|
|
4972
|
-
let response =
|
|
5161
|
+
let response = null;
|
|
4973
5162
|
let iteration = 0;
|
|
4974
5163
|
while (true) {
|
|
5164
|
+
try {
|
|
5165
|
+
checkCancellation(signal);
|
|
5166
|
+
} catch (err) {
|
|
5167
|
+
emitEvent(onEvent, "cancelled", {});
|
|
5168
|
+
throw err;
|
|
5169
|
+
}
|
|
5170
|
+
if (steering) {
|
|
5171
|
+
const pending = steering.drain();
|
|
5172
|
+
if (pending.length > 0) {
|
|
5173
|
+
messages.push(...pending);
|
|
5174
|
+
emitEvent(onEvent, "messages_updated", { messages });
|
|
5175
|
+
emitEvent(onEvent, "status", { message: `Injected ${pending.length} steering message(s)` });
|
|
5176
|
+
}
|
|
5177
|
+
}
|
|
5178
|
+
if (contextBudget !== void 0) {
|
|
5179
|
+
const [droppedCount] = trimToContextWindow(messages, contextBudget);
|
|
5180
|
+
if (droppedCount > 0) {
|
|
5181
|
+
emitEvent(onEvent, "messages_updated", { messages });
|
|
5182
|
+
emitEvent(onEvent, "status", { message: `Trimmed ${droppedCount} messages for context budget` });
|
|
5183
|
+
}
|
|
5184
|
+
}
|
|
5185
|
+
if (guardrails) {
|
|
5186
|
+
const result = guardrails.checkInput(messages);
|
|
5187
|
+
if (!result.allowed) {
|
|
5188
|
+
emitEvent(onEvent, "error", { message: `Input guardrail denied: ${result.reason}` });
|
|
5189
|
+
throw new GuardrailError(result.reason ?? "Input guardrail denied");
|
|
5190
|
+
}
|
|
5191
|
+
if (result.rewrite) messages = result.rewrite;
|
|
5192
|
+
}
|
|
5193
|
+
try {
|
|
5194
|
+
checkCancellation(signal);
|
|
5195
|
+
} catch (err) {
|
|
5196
|
+
emitEvent(onEvent, "cancelled", {});
|
|
5197
|
+
throw err;
|
|
5198
|
+
}
|
|
5199
|
+
response = await executor.execute(agent, messages);
|
|
4975
5200
|
if (isAsyncIterable(response)) {
|
|
4976
|
-
const { toolCalls, content } = await consumeStream(agent, response);
|
|
5201
|
+
const { toolCalls, content } = await consumeStream(agent, response, onEvent);
|
|
5202
|
+
if (guardrails && content) {
|
|
5203
|
+
const assistantMsg = new Message("assistant", [text(content)]);
|
|
5204
|
+
const gr = guardrails.checkOutput(assistantMsg);
|
|
5205
|
+
if (!gr.allowed) {
|
|
5206
|
+
emitEvent(onEvent, "error", { message: `Output guardrail denied: ${gr.reason}` });
|
|
5207
|
+
throw new GuardrailError(gr.reason ?? "Output guardrail denied");
|
|
5208
|
+
}
|
|
5209
|
+
}
|
|
4977
5210
|
if (toolCalls.length === 0) {
|
|
4978
5211
|
emit("iterations", iteration);
|
|
4979
5212
|
emit("result", content);
|
|
5213
|
+
emitEvent(onEvent, "done", { response: content, messages });
|
|
4980
5214
|
return content;
|
|
4981
5215
|
}
|
|
4982
5216
|
iteration++;
|
|
@@ -4986,17 +5220,57 @@ async function invokeAgent(prompt, inputs, options) {
|
|
|
4986
5220
|
);
|
|
4987
5221
|
}
|
|
4988
5222
|
const toolMessages2 = await traceSpan("toolCalls", async (toolEmit) => {
|
|
4989
|
-
toolEmit("signature", "prompty.
|
|
5223
|
+
toolEmit("signature", "prompty.turn.toolCalls");
|
|
4990
5224
|
toolEmit("description", `Tool call round ${iteration}`);
|
|
4991
|
-
const
|
|
4992
|
-
|
|
4993
|
-
|
|
5225
|
+
const result = await buildToolMessagesFromCallsWithExtensions(
|
|
5226
|
+
toolCalls,
|
|
5227
|
+
content,
|
|
5228
|
+
tools,
|
|
5229
|
+
agent,
|
|
5230
|
+
parentInputs,
|
|
5231
|
+
toolEmit,
|
|
5232
|
+
{ onEvent, signal, guardrails, parallel: parallelToolCalls }
|
|
5233
|
+
);
|
|
5234
|
+
toolEmit("result", result.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
|
|
5235
|
+
return result;
|
|
4994
5236
|
});
|
|
4995
5237
|
messages.push(...toolMessages2);
|
|
4996
|
-
|
|
5238
|
+
emitEvent(onEvent, "messages_updated", { messages });
|
|
4997
5239
|
continue;
|
|
4998
5240
|
}
|
|
4999
|
-
if (!hasToolCalls(response))
|
|
5241
|
+
if (!hasToolCalls(response)) {
|
|
5242
|
+
const finalResult = options?.raw ? response : await process2(agent, response);
|
|
5243
|
+
if (guardrails) {
|
|
5244
|
+
const contentStr = typeof finalResult === "string" ? finalResult : JSON.stringify(finalResult);
|
|
5245
|
+
const assistantMsg = new Message("assistant", [text(contentStr)]);
|
|
5246
|
+
const gr = guardrails.checkOutput(assistantMsg);
|
|
5247
|
+
if (!gr.allowed) {
|
|
5248
|
+
emitEvent(onEvent, "error", { message: `Output guardrail denied: ${gr.reason}` });
|
|
5249
|
+
throw new GuardrailError(gr.reason ?? "Output guardrail denied");
|
|
5250
|
+
}
|
|
5251
|
+
if (gr.rewrite !== void 0) {
|
|
5252
|
+
emit("iterations", iteration);
|
|
5253
|
+
emit("result", gr.rewrite);
|
|
5254
|
+
emitEvent(onEvent, "done", { response: gr.rewrite, messages });
|
|
5255
|
+
return gr.rewrite;
|
|
5256
|
+
}
|
|
5257
|
+
}
|
|
5258
|
+
emit("iterations", iteration);
|
|
5259
|
+
emit("result", finalResult);
|
|
5260
|
+
emitEvent(onEvent, "done", { response: finalResult, messages });
|
|
5261
|
+
return finalResult;
|
|
5262
|
+
}
|
|
5263
|
+
if (guardrails) {
|
|
5264
|
+
const { textContent } = extractToolInfo(response);
|
|
5265
|
+
if (textContent) {
|
|
5266
|
+
const assistantMsg = new Message("assistant", [text(textContent)]);
|
|
5267
|
+
const gr = guardrails.checkOutput(assistantMsg);
|
|
5268
|
+
if (!gr.allowed) {
|
|
5269
|
+
emitEvent(onEvent, "error", { message: `Output guardrail denied: ${gr.reason}` });
|
|
5270
|
+
throw new GuardrailError(gr.reason ?? "Output guardrail denied");
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5273
|
+
}
|
|
5000
5274
|
iteration++;
|
|
5001
5275
|
if (iteration > maxIterations) {
|
|
5002
5276
|
throw new Error(
|
|
@@ -5004,24 +5278,64 @@ async function invokeAgent(prompt, inputs, options) {
|
|
|
5004
5278
|
);
|
|
5005
5279
|
}
|
|
5006
5280
|
const toolMessages = await traceSpan("toolCalls", async (toolEmit) => {
|
|
5007
|
-
toolEmit("signature", "prompty.
|
|
5281
|
+
toolEmit("signature", "prompty.turn.toolCalls");
|
|
5008
5282
|
toolEmit("description", `Tool call round ${iteration}`);
|
|
5009
|
-
const
|
|
5010
|
-
|
|
5011
|
-
|
|
5283
|
+
const result = await buildToolResultMessagesWithExtensions(
|
|
5284
|
+
response,
|
|
5285
|
+
tools,
|
|
5286
|
+
agent,
|
|
5287
|
+
parentInputs,
|
|
5288
|
+
toolEmit,
|
|
5289
|
+
{ onEvent, signal, guardrails, parallel: parallelToolCalls }
|
|
5290
|
+
);
|
|
5291
|
+
toolEmit("result", result.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
|
|
5292
|
+
return result;
|
|
5012
5293
|
});
|
|
5013
5294
|
messages.push(...toolMessages);
|
|
5014
|
-
|
|
5295
|
+
emitEvent(onEvent, "messages_updated", { messages });
|
|
5015
5296
|
}
|
|
5016
|
-
emit("iterations", iteration);
|
|
5017
|
-
if (options?.raw) {
|
|
5018
|
-
emit("result", response);
|
|
5019
|
-
return response;
|
|
5020
|
-
}
|
|
5021
|
-
const result = await process2(agent, response);
|
|
5022
|
-
emit("result", result);
|
|
5023
|
-
return result;
|
|
5024
5297
|
});
|
|
5298
|
+
if (options?.validator) {
|
|
5299
|
+
return cast(rawResult, options.validator);
|
|
5300
|
+
}
|
|
5301
|
+
return rawResult;
|
|
5302
|
+
}
|
|
5303
|
+
function resolveBindings(agent, toolName, args, parentInputs) {
|
|
5304
|
+
if (!parentInputs || !agent.tools || agent.tools.length === 0) return args;
|
|
5305
|
+
const toolDef = agent.tools.find((t) => t.name === toolName);
|
|
5306
|
+
if (!toolDef || !toolDef.bindings || toolDef.bindings.length === 0) return args;
|
|
5307
|
+
const merged = { ...args };
|
|
5308
|
+
for (const binding of toolDef.bindings) {
|
|
5309
|
+
if (binding.input in parentInputs) {
|
|
5310
|
+
merged[binding.name] = parentInputs[binding.input];
|
|
5311
|
+
}
|
|
5312
|
+
}
|
|
5313
|
+
return merged;
|
|
5314
|
+
}
|
|
5315
|
+
function isAsyncIterable(value) {
|
|
5316
|
+
return value != null && typeof value === "object" && Symbol.asyncIterator in value;
|
|
5317
|
+
}
|
|
5318
|
+
function isToolCallLike(item) {
|
|
5319
|
+
return typeof item === "object" && item !== null && "id" in item && "name" in item && "arguments" in item;
|
|
5320
|
+
}
|
|
5321
|
+
async function consumeStream(agent, response, onEvent) {
|
|
5322
|
+
const processed = await process2(agent, response);
|
|
5323
|
+
const toolCalls = [];
|
|
5324
|
+
const textParts = [];
|
|
5325
|
+
if (isAsyncIterable(processed)) {
|
|
5326
|
+
for await (const item of processed) {
|
|
5327
|
+
if (isToolCallLike(item)) {
|
|
5328
|
+
toolCalls.push(item);
|
|
5329
|
+
} else if (typeof item === "string") {
|
|
5330
|
+
textParts.push(item);
|
|
5331
|
+
emitEvent(onEvent, "token", { token: item });
|
|
5332
|
+
}
|
|
5333
|
+
}
|
|
5334
|
+
} else if (typeof processed === "string") {
|
|
5335
|
+
textParts.push(processed);
|
|
5336
|
+
emitEvent(onEvent, "token", { token: processed });
|
|
5337
|
+
}
|
|
5338
|
+
return { toolCalls, content: textParts.join("") };
|
|
5025
5339
|
}
|
|
5026
5340
|
function expandThreads(messages, nonces, inputs) {
|
|
5027
5341
|
if (nonces.size === 0) return messages;
|
|
@@ -5090,160 +5404,138 @@ function hasToolCalls(response) {
|
|
|
5090
5404
|
}
|
|
5091
5405
|
return false;
|
|
5092
5406
|
}
|
|
5093
|
-
|
|
5407
|
+
function extractToolInfo(response) {
|
|
5408
|
+
if (typeof response !== "object" || response === null) {
|
|
5409
|
+
return { toolCalls: [], textContent: "" };
|
|
5410
|
+
}
|
|
5094
5411
|
const r = response;
|
|
5095
5412
|
if (Array.isArray(r.content) && r.stop_reason === "tool_use") {
|
|
5096
|
-
|
|
5413
|
+
const content = r.content;
|
|
5414
|
+
const toolCalls = content.filter((b) => b.type === "tool_use").map((b) => ({
|
|
5415
|
+
id: b.id,
|
|
5416
|
+
name: b.name,
|
|
5417
|
+
arguments: JSON.stringify(b.input)
|
|
5418
|
+
}));
|
|
5419
|
+
const textContent = content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
5420
|
+
return { toolCalls, textContent };
|
|
5097
5421
|
}
|
|
5098
5422
|
if (r.object === "response" && Array.isArray(r.output)) {
|
|
5099
|
-
|
|
5423
|
+
const funcCalls = r.output.filter(
|
|
5424
|
+
(item) => item.type === "function_call"
|
|
5425
|
+
);
|
|
5426
|
+
const toolCalls = funcCalls.map((fc) => ({
|
|
5427
|
+
id: fc.call_id ?? fc.id ?? "",
|
|
5428
|
+
call_id: fc.call_id ?? fc.id ?? "",
|
|
5429
|
+
name: fc.name,
|
|
5430
|
+
arguments: fc.arguments ?? "{}"
|
|
5431
|
+
}));
|
|
5432
|
+
return { toolCalls, textContent: "" };
|
|
5100
5433
|
}
|
|
5101
|
-
return buildOpenAIToolResultMessages(r, tools, agent, parentInputs, parentEmit);
|
|
5102
|
-
}
|
|
5103
|
-
async function buildOpenAIToolResultMessages(r, tools, agent, parentInputs, parentEmit) {
|
|
5104
5434
|
const choices = r.choices;
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
for (const tc of toolCalls) {
|
|
5117
|
-
const fn = tc.function;
|
|
5118
|
-
const toolName = fn.name;
|
|
5119
|
-
const toolCallId = tc.id;
|
|
5120
|
-
let result;
|
|
5121
|
-
let parsedArgs;
|
|
5122
|
-
try {
|
|
5123
|
-
parsedArgs = JSON.parse(fn.arguments);
|
|
5124
|
-
if (agent && parentInputs && typeof parsedArgs === "object" && parsedArgs !== null && !Array.isArray(parsedArgs)) {
|
|
5125
|
-
parsedArgs = resolveBindings(agent, toolName, parsedArgs, parentInputs);
|
|
5126
|
-
}
|
|
5127
|
-
result = await traceSpan(toolName, async (toolEmit) => {
|
|
5128
|
-
toolEmit("signature", `prompty.tool.${toolName}`);
|
|
5129
|
-
toolEmit("description", `Execute tool: ${toolName}`);
|
|
5130
|
-
toolEmit("inputs", { arguments: parsedArgs, tool_call_id: toolCallId });
|
|
5131
|
-
const r2 = await dispatchTool(toolName, parsedArgs, tools, agent ?? {}, parentInputs ?? {});
|
|
5132
|
-
toolEmit("result", r2);
|
|
5133
|
-
return r2;
|
|
5435
|
+
if (Array.isArray(choices) && choices.length > 0) {
|
|
5436
|
+
const choice = choices[0];
|
|
5437
|
+
const message = choice.message;
|
|
5438
|
+
if (message && Array.isArray(message.tool_calls)) {
|
|
5439
|
+
const toolCalls = message.tool_calls.map((tc) => {
|
|
5440
|
+
const fn = tc.function;
|
|
5441
|
+
return {
|
|
5442
|
+
id: tc.id,
|
|
5443
|
+
name: fn.name,
|
|
5444
|
+
arguments: fn.arguments
|
|
5445
|
+
};
|
|
5134
5446
|
});
|
|
5135
|
-
|
|
5136
|
-
result = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
5447
|
+
return { toolCalls, textContent: message.content ?? "" };
|
|
5137
5448
|
}
|
|
5138
|
-
toolInputs.push({ name: toolName, arguments: parsedArgs, tool_call_id: toolCallId, result });
|
|
5139
|
-
messages.push(
|
|
5140
|
-
new Message("tool", [text(result)], {
|
|
5141
|
-
tool_call_id: toolCallId,
|
|
5142
|
-
name: toolName
|
|
5143
|
-
})
|
|
5144
|
-
);
|
|
5145
|
-
}
|
|
5146
|
-
if (parentEmit) {
|
|
5147
|
-
parentEmit("inputs", { tool_calls: toolInputs });
|
|
5148
5449
|
}
|
|
5149
|
-
return
|
|
5450
|
+
return { toolCalls: [], textContent: "" };
|
|
5150
5451
|
}
|
|
5151
|
-
async function
|
|
5152
|
-
const
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
const toolName = block.name;
|
|
5163
|
-
const toolCallId = block.id;
|
|
5164
|
-
let toolArgs = block.input;
|
|
5165
|
-
if (agent && parentInputs && typeof toolArgs === "object" && toolArgs !== null && !Array.isArray(toolArgs)) {
|
|
5166
|
-
toolArgs = resolveBindings(agent, toolName, toolArgs, parentInputs);
|
|
5167
|
-
}
|
|
5168
|
-
let result;
|
|
5452
|
+
async function dispatchOneToolWithExtensions(tc, tools, agent, parentInputs, ext) {
|
|
5453
|
+
const { onEvent, signal, guardrails } = ext;
|
|
5454
|
+
try {
|
|
5455
|
+
checkCancellation(signal);
|
|
5456
|
+
} catch (err) {
|
|
5457
|
+
emitEvent(onEvent, "cancelled", {});
|
|
5458
|
+
throw err;
|
|
5459
|
+
}
|
|
5460
|
+
emitEvent(onEvent, "tool_call_start", { name: tc.name, arguments: tc.arguments });
|
|
5461
|
+
if (guardrails) {
|
|
5462
|
+
let parsedArgs2 = {};
|
|
5169
5463
|
try {
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5464
|
+
const parsed = JSON.parse(tc.arguments);
|
|
5465
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
5466
|
+
parsedArgs2 = parsed;
|
|
5467
|
+
}
|
|
5468
|
+
} catch {
|
|
5469
|
+
}
|
|
5470
|
+
const gr = guardrails.checkTool(tc.name, parsedArgs2);
|
|
5471
|
+
if (!gr.allowed) {
|
|
5472
|
+
const deniedMsg = `Tool denied by guardrail: ${gr.reason}`;
|
|
5473
|
+
emitEvent(onEvent, "tool_result", { name: tc.name, result: deniedMsg });
|
|
5474
|
+
return deniedMsg;
|
|
5475
|
+
}
|
|
5476
|
+
if (gr.rewrite !== void 0) {
|
|
5477
|
+
tc = { ...tc, arguments: typeof gr.rewrite === "string" ? gr.rewrite : JSON.stringify(gr.rewrite) };
|
|
5180
5478
|
}
|
|
5181
|
-
toolInputs.push({ name: toolName, arguments: toolArgs, tool_use_id: toolCallId, result });
|
|
5182
|
-
toolResultBlocks.push({
|
|
5183
|
-
type: "tool_result",
|
|
5184
|
-
tool_use_id: toolCallId,
|
|
5185
|
-
content: result
|
|
5186
|
-
});
|
|
5187
5479
|
}
|
|
5188
|
-
|
|
5189
|
-
|
|
5480
|
+
let result;
|
|
5481
|
+
let parsedArgs;
|
|
5482
|
+
try {
|
|
5483
|
+
parsedArgs = JSON.parse(tc.arguments);
|
|
5484
|
+
if (agent && parentInputs && typeof parsedArgs === "object" && parsedArgs !== null && !Array.isArray(parsedArgs)) {
|
|
5485
|
+
parsedArgs = resolveBindings(agent, tc.name, parsedArgs, parentInputs);
|
|
5486
|
+
}
|
|
5487
|
+
result = await traceSpan(tc.name, async (toolEmit) => {
|
|
5488
|
+
toolEmit("signature", `prompty.tool.${tc.name}`);
|
|
5489
|
+
toolEmit("description", `Execute tool: ${tc.name}`);
|
|
5490
|
+
toolEmit("inputs", { arguments: parsedArgs, id: tc.id });
|
|
5491
|
+
const r = await dispatchTool(tc.name, parsedArgs, tools, agent, parentInputs);
|
|
5492
|
+
toolEmit("result", r);
|
|
5493
|
+
return r;
|
|
5494
|
+
});
|
|
5495
|
+
} catch (err) {
|
|
5496
|
+
if (err instanceof CancelledError) throw err;
|
|
5497
|
+
result = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
5190
5498
|
}
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
);
|
|
5194
|
-
return messages;
|
|
5499
|
+
emitEvent(onEvent, "tool_result", { name: tc.name, result });
|
|
5500
|
+
return result;
|
|
5195
5501
|
}
|
|
5196
|
-
async function
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
const toolInputs = [];
|
|
5201
|
-
for (const fc of funcCalls) {
|
|
5202
|
-
const toolName = fc.name;
|
|
5203
|
-
const callId = fc.call_id ?? fc.id ?? "";
|
|
5204
|
-
const argsStr = fc.arguments ?? "{}";
|
|
5205
|
-
messages.push(
|
|
5206
|
-
new Message("assistant", [], {
|
|
5207
|
-
responses_function_call: {
|
|
5208
|
-
type: "function_call",
|
|
5209
|
-
call_id: callId,
|
|
5210
|
-
name: toolName,
|
|
5211
|
-
arguments: argsStr
|
|
5212
|
-
}
|
|
5213
|
-
})
|
|
5214
|
-
);
|
|
5215
|
-
let result;
|
|
5216
|
-
let parsedArgs;
|
|
5217
|
-
try {
|
|
5218
|
-
parsedArgs = JSON.parse(argsStr);
|
|
5219
|
-
if (agent && parentInputs && typeof parsedArgs === "object" && parsedArgs !== null && !Array.isArray(parsedArgs)) {
|
|
5220
|
-
parsedArgs = resolveBindings(agent, toolName, parsedArgs, parentInputs);
|
|
5221
|
-
}
|
|
5222
|
-
result = await traceSpan(toolName, async (toolEmit) => {
|
|
5223
|
-
toolEmit("signature", `prompty.tool.${toolName}`);
|
|
5224
|
-
toolEmit("description", `Execute tool: ${toolName}`);
|
|
5225
|
-
toolEmit("inputs", { arguments: parsedArgs, call_id: callId });
|
|
5226
|
-
const r2 = await dispatchTool(toolName, parsedArgs, tools, agent ?? {}, parentInputs ?? {});
|
|
5227
|
-
toolEmit("result", r2);
|
|
5228
|
-
return r2;
|
|
5229
|
-
});
|
|
5230
|
-
} catch (err) {
|
|
5231
|
-
result = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
5232
|
-
}
|
|
5233
|
-
toolInputs.push({ name: toolName, arguments: parsedArgs, call_id: callId, result });
|
|
5234
|
-
messages.push(
|
|
5235
|
-
new Message("tool", [text(result)], {
|
|
5236
|
-
tool_call_id: callId,
|
|
5237
|
-
name: toolName
|
|
5238
|
-
})
|
|
5502
|
+
async function dispatchToolsWithExtensions(toolCalls, tools, agent, parentInputs, ext) {
|
|
5503
|
+
if (ext.parallel && toolCalls.length > 1) {
|
|
5504
|
+
return Promise.all(
|
|
5505
|
+
toolCalls.map((tc) => dispatchOneToolWithExtensions(tc, tools, agent, parentInputs, ext))
|
|
5239
5506
|
);
|
|
5240
5507
|
}
|
|
5508
|
+
const results = [];
|
|
5509
|
+
for (const tc of toolCalls) {
|
|
5510
|
+
results.push(await dispatchOneToolWithExtensions(tc, tools, agent, parentInputs, ext));
|
|
5511
|
+
}
|
|
5512
|
+
return results;
|
|
5513
|
+
}
|
|
5514
|
+
async function buildToolResultMessagesWithExtensions(response, tools, agent, parentInputs, parentEmit, ext) {
|
|
5515
|
+
const { toolCalls, textContent } = extractToolInfo(response);
|
|
5516
|
+
const toolResults = await dispatchToolsWithExtensions(toolCalls, tools, agent, parentInputs, ext);
|
|
5241
5517
|
if (parentEmit) {
|
|
5242
|
-
parentEmit("inputs", {
|
|
5518
|
+
parentEmit("inputs", {
|
|
5519
|
+
tool_calls: toolCalls.map((tc, i) => ({ name: tc.name, arguments: tc.arguments, id: tc.id, result: toolResults[i] }))
|
|
5520
|
+
});
|
|
5521
|
+
}
|
|
5522
|
+
const provider = resolveProvider(agent);
|
|
5523
|
+
const executor = getExecutor(provider);
|
|
5524
|
+
return executor.formatToolMessages(response, toolCalls, toolResults, textContent);
|
|
5525
|
+
}
|
|
5526
|
+
async function buildToolMessagesFromCallsWithExtensions(toolCalls, textContent, tools, agent, parentInputs, parentEmit, ext) {
|
|
5527
|
+
const normalizedCalls = toolCalls.map((tc) => ({ id: tc.id, name: tc.name, arguments: tc.arguments }));
|
|
5528
|
+
const toolResults = await dispatchToolsWithExtensions(normalizedCalls, tools, agent, parentInputs, ext);
|
|
5529
|
+
if (parentEmit) {
|
|
5530
|
+
parentEmit("inputs", {
|
|
5531
|
+
tool_calls: normalizedCalls.map((tc, i) => ({ name: tc.name, arguments: tc.arguments, id: tc.id, result: toolResults[i] }))
|
|
5532
|
+
});
|
|
5243
5533
|
}
|
|
5244
|
-
|
|
5534
|
+
const provider = resolveProvider(agent);
|
|
5535
|
+
const executor = getExecutor(provider);
|
|
5536
|
+
return executor.formatToolMessages(null, normalizedCalls, toolResults, textContent);
|
|
5245
5537
|
}
|
|
5246
|
-
var DEFAULT_FORMAT, DEFAULT_PARSER, DEFAULT_PROVIDER, DEFAULT_MAX_ITERATIONS;
|
|
5538
|
+
var DEFAULT_FORMAT, DEFAULT_PARSER, DEFAULT_PROVIDER, DEFAULT_MAX_ITERATIONS, invokeAgent;
|
|
5247
5539
|
var init_pipeline = __esm({
|
|
5248
5540
|
"src/core/pipeline.ts"() {
|
|
5249
5541
|
"use strict";
|
|
@@ -5253,10 +5545,16 @@ var init_pipeline = __esm({
|
|
|
5253
5545
|
init_tracer();
|
|
5254
5546
|
init_loader();
|
|
5255
5547
|
init_tool_dispatch();
|
|
5548
|
+
init_agent_events();
|
|
5549
|
+
init_cancellation();
|
|
5550
|
+
init_context2();
|
|
5551
|
+
init_guardrails();
|
|
5552
|
+
init_structured();
|
|
5256
5553
|
DEFAULT_FORMAT = "nunjucks";
|
|
5257
5554
|
DEFAULT_PARSER = "prompty";
|
|
5258
5555
|
DEFAULT_PROVIDER = "openai";
|
|
5259
5556
|
DEFAULT_MAX_ITERATIONS = 10;
|
|
5557
|
+
invokeAgent = turn;
|
|
5260
5558
|
}
|
|
5261
5559
|
});
|
|
5262
5560
|
|
|
@@ -5286,6 +5584,101 @@ function clearConnections() {
|
|
|
5286
5584
|
init_loader();
|
|
5287
5585
|
init_pipeline();
|
|
5288
5586
|
init_tool_dispatch();
|
|
5587
|
+
init_agent_events();
|
|
5588
|
+
init_cancellation();
|
|
5589
|
+
init_context2();
|
|
5590
|
+
init_guardrails();
|
|
5591
|
+
|
|
5592
|
+
// src/core/steering.ts
|
|
5593
|
+
init_types();
|
|
5594
|
+
var Steering = class {
|
|
5595
|
+
queue = [];
|
|
5596
|
+
/** Enqueue a message to be injected at the next iteration. */
|
|
5597
|
+
send(message) {
|
|
5598
|
+
this.queue.push(message);
|
|
5599
|
+
}
|
|
5600
|
+
/** Remove and return all queued messages as Message objects. */
|
|
5601
|
+
drain() {
|
|
5602
|
+
const items = this.queue.splice(0);
|
|
5603
|
+
return items.map((text2) => new Message("user", [{ kind: "text", value: text2 }]));
|
|
5604
|
+
}
|
|
5605
|
+
/** Whether there are pending messages without consuming them. */
|
|
5606
|
+
get hasPending() {
|
|
5607
|
+
return this.queue.length > 0;
|
|
5608
|
+
}
|
|
5609
|
+
};
|
|
5610
|
+
|
|
5611
|
+
// src/core/tool-decorator.ts
|
|
5612
|
+
init_tool();
|
|
5613
|
+
init_property();
|
|
5614
|
+
init_tool_dispatch();
|
|
5615
|
+
function tool(fn, options) {
|
|
5616
|
+
const toolName = options?.name ?? fn.name;
|
|
5617
|
+
const toolDesc = options?.description ?? "";
|
|
5618
|
+
const shouldRegister = options?.register !== false;
|
|
5619
|
+
const properties = (options?.parameters ?? []).map(
|
|
5620
|
+
(p) => new Property({
|
|
5621
|
+
name: p.name,
|
|
5622
|
+
kind: p.kind ?? "string",
|
|
5623
|
+
required: p.required ?? p.default === void 0,
|
|
5624
|
+
description: p.description,
|
|
5625
|
+
default: p.default
|
|
5626
|
+
})
|
|
5627
|
+
);
|
|
5628
|
+
const toolDef = new FunctionTool({
|
|
5629
|
+
name: toolName,
|
|
5630
|
+
kind: "function",
|
|
5631
|
+
description: toolDesc,
|
|
5632
|
+
parameters: properties
|
|
5633
|
+
});
|
|
5634
|
+
const wrapped = fn;
|
|
5635
|
+
wrapped.__tool__ = toolDef;
|
|
5636
|
+
if (shouldRegister) {
|
|
5637
|
+
registerTool(toolName, fn);
|
|
5638
|
+
}
|
|
5639
|
+
return wrapped;
|
|
5640
|
+
}
|
|
5641
|
+
function bindTools(agent, tools) {
|
|
5642
|
+
const handlers = {};
|
|
5643
|
+
for (const fn of tools) {
|
|
5644
|
+
const toolDef = fn.__tool__;
|
|
5645
|
+
if (!toolDef) {
|
|
5646
|
+
throw new Error(
|
|
5647
|
+
`Function '${fn.name || "(anonymous)"}' is not a tool()-wrapped function (missing __tool__ property)`
|
|
5648
|
+
);
|
|
5649
|
+
}
|
|
5650
|
+
const name = toolDef.name;
|
|
5651
|
+
if (name in handlers) {
|
|
5652
|
+
throw new Error(`Duplicate tool handler: '${name}'`);
|
|
5653
|
+
}
|
|
5654
|
+
handlers[name] = fn;
|
|
5655
|
+
}
|
|
5656
|
+
const declaredFunctionTools = /* @__PURE__ */ new Set();
|
|
5657
|
+
for (const toolDef of agent.tools ?? []) {
|
|
5658
|
+
if (toolDef.kind === "function") {
|
|
5659
|
+
declaredFunctionTools.add(toolDef.name);
|
|
5660
|
+
}
|
|
5661
|
+
}
|
|
5662
|
+
for (const name of Object.keys(handlers)) {
|
|
5663
|
+
if (!declaredFunctionTools.has(name)) {
|
|
5664
|
+
const declared = [...declaredFunctionTools].sort().join(", ") || "(none)";
|
|
5665
|
+
throw new Error(
|
|
5666
|
+
`Tool handler '${name}' has no matching 'kind: function' declaration in agent.tools. Declared function tools: ${declared}`
|
|
5667
|
+
);
|
|
5668
|
+
}
|
|
5669
|
+
}
|
|
5670
|
+
for (const name of declaredFunctionTools) {
|
|
5671
|
+
if (!(name in handlers)) {
|
|
5672
|
+
console.warn(
|
|
5673
|
+
`Tool '${name}' is declared in agent.tools but no handler was provided to bindTools()`
|
|
5674
|
+
);
|
|
5675
|
+
}
|
|
5676
|
+
}
|
|
5677
|
+
return handlers;
|
|
5678
|
+
}
|
|
5679
|
+
|
|
5680
|
+
// src/core/index.ts
|
|
5681
|
+
init_structured();
|
|
5289
5682
|
|
|
5290
5683
|
// src/renderers/nunjucks.ts
|
|
5291
5684
|
init_common();
|
|
@@ -5678,11 +6071,14 @@ export {
|
|
|
5678
6071
|
ApiKeyConnection,
|
|
5679
6072
|
ArrayProperty,
|
|
5680
6073
|
Binding,
|
|
6074
|
+
CancelledError,
|
|
5681
6075
|
Connection,
|
|
5682
6076
|
CustomTool,
|
|
5683
6077
|
FormatConfig,
|
|
5684
6078
|
FoundryConnection,
|
|
5685
6079
|
FunctionTool,
|
|
6080
|
+
GuardrailError,
|
|
6081
|
+
Guardrails,
|
|
5686
6082
|
InvokerError,
|
|
5687
6083
|
LoadContext,
|
|
5688
6084
|
McpApprovalMode,
|
|
@@ -5708,15 +6104,23 @@ export {
|
|
|
5708
6104
|
ReferenceConnection,
|
|
5709
6105
|
RemoteConnection,
|
|
5710
6106
|
SaveContext,
|
|
6107
|
+
Steering,
|
|
6108
|
+
StructuredResultSymbol,
|
|
5711
6109
|
Template,
|
|
5712
6110
|
ThreadMarker,
|
|
5713
6111
|
Tool,
|
|
5714
6112
|
Tracer,
|
|
6113
|
+
bindTools,
|
|
6114
|
+
cast,
|
|
6115
|
+
checkCancellation,
|
|
5715
6116
|
clearCache,
|
|
5716
6117
|
clearConnections,
|
|
5717
6118
|
consoleTracer,
|
|
6119
|
+
createStructuredResult,
|
|
5718
6120
|
dictContentToPart,
|
|
5719
6121
|
dictToMessage,
|
|
6122
|
+
emitEvent,
|
|
6123
|
+
estimateChars,
|
|
5720
6124
|
getConnection,
|
|
5721
6125
|
getExecutor,
|
|
5722
6126
|
getParser,
|
|
@@ -5724,6 +6128,7 @@ export {
|
|
|
5724
6128
|
getRenderer,
|
|
5725
6129
|
invoke,
|
|
5726
6130
|
invokeAgent,
|
|
6131
|
+
isStructuredResult,
|
|
5727
6132
|
load,
|
|
5728
6133
|
otelTracer,
|
|
5729
6134
|
parse,
|
|
@@ -5738,12 +6143,16 @@ export {
|
|
|
5738
6143
|
resolveBindings,
|
|
5739
6144
|
run,
|
|
5740
6145
|
sanitizeValue,
|
|
6146
|
+
summarizeDropped,
|
|
5741
6147
|
text,
|
|
5742
6148
|
textMessage,
|
|
5743
6149
|
toSerializable,
|
|
6150
|
+
tool,
|
|
5744
6151
|
trace,
|
|
5745
6152
|
traceMethod,
|
|
5746
6153
|
traceSpan,
|
|
6154
|
+
trimToContextWindow,
|
|
6155
|
+
turn,
|
|
5747
6156
|
validateInputs
|
|
5748
6157
|
};
|
|
5749
6158
|
//# sourceMappingURL=index.js.map
|