@prompty/core 2.0.0-alpha.1 → 2.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -105
- package/dist/index.cjs +265 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +265 -7
- package/dist/index.js.map +1 -1
- package/package.json +61 -61
package/dist/index.js
CHANGED
|
@@ -4445,6 +4445,114 @@ async function execute(prompt, inputs, options) {
|
|
|
4445
4445
|
return result;
|
|
4446
4446
|
});
|
|
4447
4447
|
}
|
|
4448
|
+
function isAsyncIterable(value) {
|
|
4449
|
+
return value != null && typeof value === "object" && Symbol.asyncIterator in value;
|
|
4450
|
+
}
|
|
4451
|
+
function isToolCallLike(item) {
|
|
4452
|
+
return typeof item === "object" && item !== null && "id" in item && "name" in item && "arguments" in item;
|
|
4453
|
+
}
|
|
4454
|
+
async function consumeStream(agent, response) {
|
|
4455
|
+
const processed = await process2(agent, response);
|
|
4456
|
+
const toolCalls = [];
|
|
4457
|
+
const textParts = [];
|
|
4458
|
+
if (isAsyncIterable(processed)) {
|
|
4459
|
+
for await (const item of processed) {
|
|
4460
|
+
if (isToolCallLike(item)) {
|
|
4461
|
+
toolCalls.push(item);
|
|
4462
|
+
} else if (typeof item === "string") {
|
|
4463
|
+
textParts.push(item);
|
|
4464
|
+
}
|
|
4465
|
+
}
|
|
4466
|
+
} else if (typeof processed === "string") {
|
|
4467
|
+
textParts.push(processed);
|
|
4468
|
+
}
|
|
4469
|
+
return { toolCalls, content: textParts.join("") };
|
|
4470
|
+
}
|
|
4471
|
+
async function buildToolMessagesFromCalls(toolCalls, textContent, tools, agent, parentEmit) {
|
|
4472
|
+
const provider = resolveProvider(agent);
|
|
4473
|
+
const apiType = agent.model?.apiType || "chat";
|
|
4474
|
+
const messages = [];
|
|
4475
|
+
const toolInputs = [];
|
|
4476
|
+
if (provider === "anthropic") {
|
|
4477
|
+
const rawContent = [];
|
|
4478
|
+
if (textContent) rawContent.push({ type: "text", text: textContent });
|
|
4479
|
+
for (const tc of toolCalls) {
|
|
4480
|
+
rawContent.push({
|
|
4481
|
+
type: "tool_use",
|
|
4482
|
+
id: tc.id,
|
|
4483
|
+
name: tc.name,
|
|
4484
|
+
input: JSON.parse(tc.arguments)
|
|
4485
|
+
});
|
|
4486
|
+
}
|
|
4487
|
+
messages.push(
|
|
4488
|
+
new Message("assistant", textContent ? [text(textContent)] : [], { content: rawContent })
|
|
4489
|
+
);
|
|
4490
|
+
} else if (apiType === "responses") {
|
|
4491
|
+
for (const tc of toolCalls) {
|
|
4492
|
+
messages.push(
|
|
4493
|
+
new Message("assistant", [], {
|
|
4494
|
+
responses_function_call: {
|
|
4495
|
+
type: "function_call",
|
|
4496
|
+
call_id: tc.id,
|
|
4497
|
+
name: tc.name,
|
|
4498
|
+
arguments: tc.arguments
|
|
4499
|
+
}
|
|
4500
|
+
})
|
|
4501
|
+
);
|
|
4502
|
+
}
|
|
4503
|
+
} else {
|
|
4504
|
+
const rawToolCalls = toolCalls.map((tc) => ({
|
|
4505
|
+
id: tc.id,
|
|
4506
|
+
type: "function",
|
|
4507
|
+
function: { name: tc.name, arguments: tc.arguments }
|
|
4508
|
+
}));
|
|
4509
|
+
messages.push(
|
|
4510
|
+
new Message("assistant", textContent ? [text(textContent)] : [], {
|
|
4511
|
+
tool_calls: rawToolCalls
|
|
4512
|
+
})
|
|
4513
|
+
);
|
|
4514
|
+
}
|
|
4515
|
+
const toolResultBlocks = [];
|
|
4516
|
+
for (const tc of toolCalls) {
|
|
4517
|
+
let result;
|
|
4518
|
+
let parsedArgs;
|
|
4519
|
+
try {
|
|
4520
|
+
parsedArgs = JSON.parse(tc.arguments);
|
|
4521
|
+
const toolFn = tools[tc.name];
|
|
4522
|
+
if (!toolFn) {
|
|
4523
|
+
result = `Error: tool "${tc.name}" not found`;
|
|
4524
|
+
} else {
|
|
4525
|
+
const toolResult = await traceSpan(tc.name, async (toolEmit) => {
|
|
4526
|
+
toolEmit("signature", `prompty.tool.${tc.name}`);
|
|
4527
|
+
toolEmit("description", `Execute tool: ${tc.name}`);
|
|
4528
|
+
toolEmit("inputs", { arguments: parsedArgs, id: tc.id });
|
|
4529
|
+
const r = await toolFn(...Array.isArray(parsedArgs) ? parsedArgs : [parsedArgs]);
|
|
4530
|
+
const str = typeof r === "string" ? r : JSON.stringify(r);
|
|
4531
|
+
toolEmit("result", str);
|
|
4532
|
+
return str;
|
|
4533
|
+
});
|
|
4534
|
+
result = toolResult;
|
|
4535
|
+
}
|
|
4536
|
+
} catch (err) {
|
|
4537
|
+
result = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
4538
|
+
}
|
|
4539
|
+
toolInputs.push({ name: tc.name, arguments: parsedArgs, id: tc.id, result });
|
|
4540
|
+
if (provider === "anthropic") {
|
|
4541
|
+
toolResultBlocks.push({ type: "tool_result", tool_use_id: tc.id, content: result });
|
|
4542
|
+
} else {
|
|
4543
|
+
messages.push(
|
|
4544
|
+
new Message("tool", [text(result)], { tool_call_id: tc.id, name: tc.name })
|
|
4545
|
+
);
|
|
4546
|
+
}
|
|
4547
|
+
}
|
|
4548
|
+
if (provider === "anthropic" && toolResultBlocks.length > 0) {
|
|
4549
|
+
messages.push(new Message("user", [], { tool_results: toolResultBlocks }));
|
|
4550
|
+
}
|
|
4551
|
+
if (parentEmit) {
|
|
4552
|
+
parentEmit("inputs", { tool_calls: toolInputs });
|
|
4553
|
+
}
|
|
4554
|
+
return messages;
|
|
4555
|
+
}
|
|
4448
4556
|
async function executeAgent(prompt, inputs, options) {
|
|
4449
4557
|
return traceSpan("executeAgent", async (emit) => {
|
|
4450
4558
|
const agent = typeof prompt === "string" ? await traceSpan("load", async (loadEmit) => {
|
|
@@ -4465,7 +4573,32 @@ async function executeAgent(prompt, inputs, options) {
|
|
|
4465
4573
|
const executor = getExecutor(provider);
|
|
4466
4574
|
let response = await executor.execute(agent, messages);
|
|
4467
4575
|
let iteration = 0;
|
|
4468
|
-
while (
|
|
4576
|
+
while (true) {
|
|
4577
|
+
if (isAsyncIterable(response)) {
|
|
4578
|
+
const { toolCalls, content } = await consumeStream(agent, response);
|
|
4579
|
+
if (toolCalls.length === 0) {
|
|
4580
|
+
emit("iterations", iteration);
|
|
4581
|
+
emit("result", content);
|
|
4582
|
+
return content;
|
|
4583
|
+
}
|
|
4584
|
+
iteration++;
|
|
4585
|
+
if (iteration > maxIterations) {
|
|
4586
|
+
throw new Error(
|
|
4587
|
+
`Agent loop exceeded maxIterations (${maxIterations}). The model kept requesting tool calls. Increase maxIterations or check your tools.`
|
|
4588
|
+
);
|
|
4589
|
+
}
|
|
4590
|
+
const toolMessages2 = await traceSpan("toolCalls", async (toolEmit) => {
|
|
4591
|
+
toolEmit("signature", "prompty.executeAgent.toolCalls");
|
|
4592
|
+
toolEmit("description", `Tool call round ${iteration}`);
|
|
4593
|
+
const result2 = await buildToolMessagesFromCalls(toolCalls, content, tools, agent, toolEmit);
|
|
4594
|
+
toolEmit("result", result2.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
|
|
4595
|
+
return result2;
|
|
4596
|
+
});
|
|
4597
|
+
messages.push(...toolMessages2);
|
|
4598
|
+
response = await executor.execute(agent, messages);
|
|
4599
|
+
continue;
|
|
4600
|
+
}
|
|
4601
|
+
if (!hasToolCalls(response)) break;
|
|
4469
4602
|
iteration++;
|
|
4470
4603
|
if (iteration > maxIterations) {
|
|
4471
4604
|
throw new Error(
|
|
@@ -4539,15 +4672,37 @@ function hasToolCalls(response) {
|
|
|
4539
4672
|
if (typeof response !== "object" || response === null) return false;
|
|
4540
4673
|
const r = response;
|
|
4541
4674
|
const choices = r.choices;
|
|
4542
|
-
if (
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4675
|
+
if (Array.isArray(choices) && choices.length > 0) {
|
|
4676
|
+
const choice = choices[0];
|
|
4677
|
+
const message = choice.message;
|
|
4678
|
+
if (message) {
|
|
4679
|
+
const toolCalls = message.tool_calls;
|
|
4680
|
+
if (Array.isArray(toolCalls) && toolCalls.length > 0) return true;
|
|
4681
|
+
}
|
|
4682
|
+
}
|
|
4683
|
+
if (r.stop_reason === "tool_use" && Array.isArray(r.content)) {
|
|
4684
|
+
return r.content.some(
|
|
4685
|
+
(block) => block.type === "tool_use"
|
|
4686
|
+
);
|
|
4687
|
+
}
|
|
4688
|
+
if (r.object === "response" && Array.isArray(r.output)) {
|
|
4689
|
+
return r.output.some(
|
|
4690
|
+
(item) => item.type === "function_call"
|
|
4691
|
+
);
|
|
4692
|
+
}
|
|
4693
|
+
return false;
|
|
4548
4694
|
}
|
|
4549
4695
|
async function buildToolResultMessages(response, tools, parentEmit) {
|
|
4550
4696
|
const r = response;
|
|
4697
|
+
if (Array.isArray(r.content) && r.stop_reason === "tool_use") {
|
|
4698
|
+
return buildAnthropicToolResultMessages(r, tools, parentEmit);
|
|
4699
|
+
}
|
|
4700
|
+
if (r.object === "response" && Array.isArray(r.output)) {
|
|
4701
|
+
return buildResponsesToolResultMessages(r, tools, parentEmit);
|
|
4702
|
+
}
|
|
4703
|
+
return buildOpenAIToolResultMessages(r, tools, parentEmit);
|
|
4704
|
+
}
|
|
4705
|
+
async function buildOpenAIToolResultMessages(r, tools, parentEmit) {
|
|
4551
4706
|
const choices = r.choices;
|
|
4552
4707
|
const choice = choices[0];
|
|
4553
4708
|
const message = choice.message;
|
|
@@ -4599,6 +4754,109 @@ async function buildToolResultMessages(response, tools, parentEmit) {
|
|
|
4599
4754
|
}
|
|
4600
4755
|
return messages;
|
|
4601
4756
|
}
|
|
4757
|
+
async function buildAnthropicToolResultMessages(r, tools, parentEmit) {
|
|
4758
|
+
const content = r.content;
|
|
4759
|
+
const toolUseBlocks = content.filter((block) => block.type === "tool_use");
|
|
4760
|
+
const messages = [];
|
|
4761
|
+
const textParts = content.filter((block) => block.type === "text").map((block) => text(block.text));
|
|
4762
|
+
messages.push(
|
|
4763
|
+
new Message("assistant", textParts, { content })
|
|
4764
|
+
);
|
|
4765
|
+
const toolInputs = [];
|
|
4766
|
+
const toolResultBlocks = [];
|
|
4767
|
+
for (const block of toolUseBlocks) {
|
|
4768
|
+
const toolName = block.name;
|
|
4769
|
+
const toolCallId = block.id;
|
|
4770
|
+
const toolArgs = block.input;
|
|
4771
|
+
let result;
|
|
4772
|
+
try {
|
|
4773
|
+
const toolFn = tools[toolName];
|
|
4774
|
+
if (!toolFn) {
|
|
4775
|
+
result = `Error: tool "${toolName}" not found`;
|
|
4776
|
+
} else {
|
|
4777
|
+
const toolResult = await traceSpan(toolName, async (toolEmit) => {
|
|
4778
|
+
toolEmit("signature", `prompty.tool.${toolName}`);
|
|
4779
|
+
toolEmit("description", `Execute tool: ${toolName}`);
|
|
4780
|
+
toolEmit("inputs", { arguments: toolArgs, tool_use_id: toolCallId });
|
|
4781
|
+
const r2 = await toolFn(...Array.isArray(toolArgs) ? toolArgs : [toolArgs]);
|
|
4782
|
+
const str = typeof r2 === "string" ? r2 : JSON.stringify(r2);
|
|
4783
|
+
toolEmit("result", str);
|
|
4784
|
+
return str;
|
|
4785
|
+
});
|
|
4786
|
+
result = toolResult;
|
|
4787
|
+
}
|
|
4788
|
+
} catch (err) {
|
|
4789
|
+
result = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
4790
|
+
}
|
|
4791
|
+
toolInputs.push({ name: toolName, arguments: toolArgs, tool_use_id: toolCallId, result });
|
|
4792
|
+
toolResultBlocks.push({
|
|
4793
|
+
type: "tool_result",
|
|
4794
|
+
tool_use_id: toolCallId,
|
|
4795
|
+
content: result
|
|
4796
|
+
});
|
|
4797
|
+
}
|
|
4798
|
+
if (parentEmit) {
|
|
4799
|
+
parentEmit("inputs", { tool_calls: toolInputs });
|
|
4800
|
+
}
|
|
4801
|
+
messages.push(
|
|
4802
|
+
new Message("user", [], { tool_results: toolResultBlocks })
|
|
4803
|
+
);
|
|
4804
|
+
return messages;
|
|
4805
|
+
}
|
|
4806
|
+
async function buildResponsesToolResultMessages(r, tools, parentEmit) {
|
|
4807
|
+
const output = r.output;
|
|
4808
|
+
const funcCalls = output.filter((item) => item.type === "function_call");
|
|
4809
|
+
const messages = [];
|
|
4810
|
+
const toolInputs = [];
|
|
4811
|
+
for (const fc of funcCalls) {
|
|
4812
|
+
const toolName = fc.name;
|
|
4813
|
+
const callId = fc.call_id ?? fc.id ?? "";
|
|
4814
|
+
const argsStr = fc.arguments ?? "{}";
|
|
4815
|
+
messages.push(
|
|
4816
|
+
new Message("assistant", [], {
|
|
4817
|
+
responses_function_call: {
|
|
4818
|
+
type: "function_call",
|
|
4819
|
+
call_id: callId,
|
|
4820
|
+
name: toolName,
|
|
4821
|
+
arguments: argsStr
|
|
4822
|
+
}
|
|
4823
|
+
})
|
|
4824
|
+
);
|
|
4825
|
+
let result;
|
|
4826
|
+
let parsedArgs;
|
|
4827
|
+
try {
|
|
4828
|
+
parsedArgs = JSON.parse(argsStr);
|
|
4829
|
+
const toolFn = tools[toolName];
|
|
4830
|
+
if (!toolFn) {
|
|
4831
|
+
result = `Error: tool "${toolName}" not found`;
|
|
4832
|
+
} else {
|
|
4833
|
+
const toolResult = await traceSpan(toolName, async (toolEmit) => {
|
|
4834
|
+
toolEmit("signature", `prompty.tool.${toolName}`);
|
|
4835
|
+
toolEmit("description", `Execute tool: ${toolName}`);
|
|
4836
|
+
toolEmit("inputs", { arguments: parsedArgs, call_id: callId });
|
|
4837
|
+
const r2 = await toolFn(...Array.isArray(parsedArgs) ? parsedArgs : [parsedArgs]);
|
|
4838
|
+
const str = typeof r2 === "string" ? r2 : JSON.stringify(r2);
|
|
4839
|
+
toolEmit("result", str);
|
|
4840
|
+
return str;
|
|
4841
|
+
});
|
|
4842
|
+
result = toolResult;
|
|
4843
|
+
}
|
|
4844
|
+
} catch (err) {
|
|
4845
|
+
result = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
4846
|
+
}
|
|
4847
|
+
toolInputs.push({ name: toolName, arguments: parsedArgs, call_id: callId, result });
|
|
4848
|
+
messages.push(
|
|
4849
|
+
new Message("tool", [text(result)], {
|
|
4850
|
+
tool_call_id: callId,
|
|
4851
|
+
name: toolName
|
|
4852
|
+
})
|
|
4853
|
+
);
|
|
4854
|
+
}
|
|
4855
|
+
if (parentEmit) {
|
|
4856
|
+
parentEmit("inputs", { tool_calls: toolInputs });
|
|
4857
|
+
}
|
|
4858
|
+
return messages;
|
|
4859
|
+
}
|
|
4602
4860
|
var runAgent = executeAgent;
|
|
4603
4861
|
|
|
4604
4862
|
// src/renderers/nunjucks.ts
|