@prompty/core 2.0.0-alpha.6 → 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 CHANGED
@@ -2236,7 +2236,12 @@ var init_property = __esm({
2236
2236
  for (const [key, value] of Object.entries(
2237
2237
  data
2238
2238
  )) {
2239
- if (value && typeof value === "object" && !Array.isArray(value)) {
2239
+ if (Array.isArray(value)) {
2240
+ throw new Error(
2241
+ `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.`
2242
+ );
2243
+ }
2244
+ if (value && typeof value === "object") {
2240
2245
  value["name"] = key;
2241
2246
  result.push(Property.load(value, context));
2242
2247
  } else {
@@ -3144,7 +3149,12 @@ var init_tool = __esm({
3144
3149
  for (const [key, value] of Object.entries(
3145
3150
  data
3146
3151
  )) {
3147
- if (value && typeof value === "object" && !Array.isArray(value)) {
3152
+ if (Array.isArray(value)) {
3153
+ throw new Error(
3154
+ `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.`
3155
+ );
3156
+ }
3157
+ if (value && typeof value === "object") {
3148
3158
  value["name"] = key;
3149
3159
  result.push(Binding.load(value, context));
3150
3160
  } else {
@@ -3359,7 +3369,12 @@ var init_tool = __esm({
3359
3369
  for (const [key, value] of Object.entries(
3360
3370
  data
3361
3371
  )) {
3362
- if (value && typeof value === "object" && !Array.isArray(value)) {
3372
+ if (Array.isArray(value)) {
3373
+ throw new Error(
3374
+ `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.`
3375
+ );
3376
+ }
3377
+ if (value && typeof value === "object") {
3363
3378
  value["name"] = key;
3364
3379
  result.push(Property.load(value, context));
3365
3380
  } else {
@@ -4116,7 +4131,12 @@ var init_prompty = __esm({
4116
4131
  for (const [key, value] of Object.entries(
4117
4132
  data
4118
4133
  )) {
4119
- if (value && typeof value === "object" && !Array.isArray(value)) {
4134
+ if (Array.isArray(value)) {
4135
+ throw new Error(
4136
+ `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.`
4137
+ );
4138
+ }
4139
+ if (value && typeof value === "object") {
4120
4140
  value["name"] = key;
4121
4141
  result.push(Property.load(value, context));
4122
4142
  } else {
@@ -4146,7 +4166,12 @@ var init_prompty = __esm({
4146
4166
  for (const [key, value] of Object.entries(
4147
4167
  data
4148
4168
  )) {
4149
- if (value && typeof value === "object" && !Array.isArray(value)) {
4169
+ if (Array.isArray(value)) {
4170
+ throw new Error(
4171
+ `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.`
4172
+ );
4173
+ }
4174
+ if (value && typeof value === "object") {
4150
4175
  value["name"] = key;
4151
4176
  result.push(Property.load(value, context));
4152
4177
  } else {
@@ -4176,7 +4201,12 @@ var init_prompty = __esm({
4176
4201
  for (const [key, value] of Object.entries(
4177
4202
  data
4178
4203
  )) {
4179
- if (value && typeof value === "object" && !Array.isArray(value)) {
4204
+ if (Array.isArray(value)) {
4205
+ throw new Error(
4206
+ `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.`
4207
+ );
4208
+ }
4209
+ if (value && typeof value === "object") {
4180
4210
  value["name"] = key;
4181
4211
  result.push(Tool.load(value, context));
4182
4212
  } else {
@@ -4587,14 +4617,14 @@ var init_tool_dispatch = __esm({
4587
4617
  async executeTool(tool2, _args, _agent, _parentInputs) {
4588
4618
  const name = tool2.name ?? "unknown";
4589
4619
  throw new Error(
4590
- `Function tool '${name}' declared but no callable provided. Pass it via tools: { '${name}': fn } in invokeAgent().`
4620
+ `Function tool '${name}' declared but no callable provided. Pass it via tools: { '${name}': fn } in turn().`
4591
4621
  );
4592
4622
  }
4593
4623
  };
4594
4624
  PromptyToolHandler = class {
4595
4625
  async executeTool(tool2, args, agent, _parentInputs) {
4596
4626
  const { load: load2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
4597
- const { prepare: prepare2, run: run2, invokeAgent: invokeAgent2 } = await Promise.resolve().then(() => (init_pipeline(), pipeline_exports));
4627
+ const { prepare: prepare2, run: run2, turn: turn2 } = await Promise.resolve().then(() => (init_pipeline(), pipeline_exports));
4598
4628
  const parentPath = (agent.metadata ?? {}).__source_path;
4599
4629
  if (!parentPath) {
4600
4630
  return `Error: cannot resolve PromptyTool '${tool2.name}': parent has no __source_path`;
@@ -4613,7 +4643,7 @@ var init_tool_dispatch = __esm({
4613
4643
  child.metadata.__prompty_tool_stack = [...stack, parentPath];
4614
4644
  const mode = tool2.mode ?? "single";
4615
4645
  if (mode === "agentic") {
4616
- const result = await invokeAgent2(child, args);
4646
+ const result = await turn2(child, args);
4617
4647
  return typeof result === "string" ? result : JSON.stringify(result);
4618
4648
  } else {
4619
4649
  const messages = await prepare2(child, args);
@@ -4858,6 +4888,7 @@ __export(pipeline_exports, {
4858
4888
  render: () => render,
4859
4889
  resolveBindings: () => resolveBindings,
4860
4890
  run: () => run,
4891
+ turn: () => turn,
4861
4892
  validateInputs: () => validateInputs
4862
4893
  });
4863
4894
  function sanitizeNonces(value) {
@@ -5048,7 +5079,17 @@ async function invoke(prompt, inputs, options) {
5048
5079
  emit("description", "Invoke a prompty");
5049
5080
  emit("inputs", { prompt: serializeAgent(agent), inputs: inputs ?? {} });
5050
5081
  const messages = await prepare(agent, inputs);
5051
- const result = await run(agent, messages, options);
5082
+ const provider = resolveProvider(agent);
5083
+ const executor = getExecutor(provider);
5084
+ const response = await executor.execute(agent, messages);
5085
+ if (options?.raw) {
5086
+ emit("result", response);
5087
+ if (options?.validator) {
5088
+ return cast(response, options.validator);
5089
+ }
5090
+ return response;
5091
+ }
5092
+ const result = await process2(agent, response);
5052
5093
  emit("result", result);
5053
5094
  if (options?.validator) {
5054
5095
  return cast(result, options.validator);
@@ -5056,45 +5097,9 @@ async function invoke(prompt, inputs, options) {
5056
5097
  return result;
5057
5098
  });
5058
5099
  }
5059
- function resolveBindings(agent, toolName, args, parentInputs) {
5060
- if (!parentInputs || !agent.tools || agent.tools.length === 0) return args;
5061
- const toolDef = agent.tools.find((t) => t.name === toolName);
5062
- if (!toolDef || !toolDef.bindings || toolDef.bindings.length === 0) return args;
5063
- const merged = { ...args };
5064
- for (const binding of toolDef.bindings) {
5065
- if (binding.input in parentInputs) {
5066
- merged[binding.name] = parentInputs[binding.input];
5067
- }
5068
- }
5069
- return merged;
5070
- }
5071
- function isAsyncIterable(value) {
5072
- return value != null && typeof value === "object" && Symbol.asyncIterator in value;
5073
- }
5074
- function isToolCallLike(item) {
5075
- return typeof item === "object" && item !== null && "id" in item && "name" in item && "arguments" in item;
5076
- }
5077
- async function consumeStream(agent, response, onEvent) {
5078
- const processed = await process2(agent, response);
5079
- const toolCalls = [];
5080
- const textParts = [];
5081
- if (isAsyncIterable(processed)) {
5082
- for await (const item of processed) {
5083
- if (isToolCallLike(item)) {
5084
- toolCalls.push(item);
5085
- } else if (typeof item === "string") {
5086
- textParts.push(item);
5087
- emitEvent(onEvent, "token", { token: item });
5088
- }
5089
- }
5090
- } else if (typeof processed === "string") {
5091
- textParts.push(processed);
5092
- emitEvent(onEvent, "token", { token: processed });
5093
- }
5094
- return { toolCalls, content: textParts.join("") };
5095
- }
5096
- async function invokeAgent(prompt, inputs, options) {
5097
- const rawResult = await traceSpan("invokeAgent", async (emit) => {
5100
+ async function turn(prompt, inputs, options) {
5101
+ const label = options?.turn != null ? `turn ${options.turn}` : "turn";
5102
+ const rawResult = await traceSpan(label, async (emit) => {
5098
5103
  const agent = typeof prompt === "string" ? await traceSpan("load", async (loadEmit) => {
5099
5104
  loadEmit("signature", "prompty.load");
5100
5105
  loadEmit("description", "Load a prompty file.");
@@ -5103,7 +5108,62 @@ async function invokeAgent(prompt, inputs, options) {
5103
5108
  loadEmit("result", serializeAgent(loaded));
5104
5109
  return loaded;
5105
5110
  }) : prompt;
5111
+ emit("signature", "prompty.turn");
5112
+ emit("description", label);
5113
+ emit("inputs", sanitizeValue("inputs", inputs));
5106
5114
  const tools = options?.tools ?? {};
5115
+ const hasTools = Object.keys(tools).length > 0;
5116
+ if (!hasTools) {
5117
+ let messages2 = await prepare(agent, inputs);
5118
+ const onEvent2 = options?.onEvent;
5119
+ if (options?.steering) {
5120
+ const pending = options.steering.drain();
5121
+ if (pending.length > 0) {
5122
+ messages2.push(...pending);
5123
+ emitEvent(onEvent2, "messages_updated", { messages: messages2 });
5124
+ }
5125
+ }
5126
+ if (options?.contextBudget !== void 0) {
5127
+ const [droppedCount] = trimToContextWindow(messages2, options.contextBudget);
5128
+ if (droppedCount > 0) {
5129
+ emitEvent(onEvent2, "messages_updated", { messages: messages2 });
5130
+ }
5131
+ }
5132
+ if (options?.guardrails) {
5133
+ const result = options.guardrails.checkInput(messages2);
5134
+ if (!result.allowed) {
5135
+ emitEvent(onEvent2, "error", { message: `Input guardrail denied: ${result.reason}` });
5136
+ throw new GuardrailError(result.reason ?? "Input guardrail denied");
5137
+ }
5138
+ if (result.rewrite) messages2 = result.rewrite;
5139
+ }
5140
+ checkCancellation(options?.signal);
5141
+ const provider2 = resolveProvider(agent);
5142
+ const executor2 = getExecutor(provider2);
5143
+ const response2 = await executor2.execute(agent, messages2);
5144
+ if (options?.raw) {
5145
+ emit("result", response2);
5146
+ return response2;
5147
+ }
5148
+ const processed = await process2(agent, response2);
5149
+ if (options?.guardrails) {
5150
+ const contentStr = typeof processed === "string" ? processed : JSON.stringify(processed);
5151
+ const assistantMsg = new Message("assistant", [text(contentStr)]);
5152
+ const gr = options.guardrails.checkOutput(assistantMsg);
5153
+ if (!gr.allowed) {
5154
+ emitEvent(onEvent2, "error", { message: `Output guardrail denied: ${gr.reason}` });
5155
+ throw new GuardrailError(gr.reason ?? "Output guardrail denied");
5156
+ }
5157
+ if (gr.rewrite !== void 0) {
5158
+ emit("result", gr.rewrite);
5159
+ emitEvent(onEvent2, "done", { response: gr.rewrite, messages: messages2 });
5160
+ return gr.rewrite;
5161
+ }
5162
+ }
5163
+ emit("result", sanitizeValue("result", processed));
5164
+ emitEvent(onEvent2, "done", { response: processed, messages: messages2 });
5165
+ return processed;
5166
+ }
5107
5167
  const maxIterations = options?.maxIterations ?? DEFAULT_MAX_ITERATIONS;
5108
5168
  const onEvent = options?.onEvent;
5109
5169
  const signal = options?.signal;
@@ -5111,9 +5171,6 @@ async function invokeAgent(prompt, inputs, options) {
5111
5171
  const guardrails = options?.guardrails;
5112
5172
  const steering = options?.steering;
5113
5173
  const parallelToolCalls = options?.parallelToolCalls ?? false;
5114
- emit("signature", "prompty.invokeAgent");
5115
- emit("description", "Invoke a prompty with tool calling");
5116
- emit("inputs", { prompt: serializeAgent(agent), tools: Object.keys(tools), inputs: inputs ?? {} });
5117
5174
  let messages = await prepare(agent, inputs);
5118
5175
  const parentInputs = inputs ?? {};
5119
5176
  const provider = resolveProvider(agent);
@@ -5143,12 +5200,12 @@ async function invokeAgent(prompt, inputs, options) {
5143
5200
  }
5144
5201
  }
5145
5202
  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");
5203
+ const result = guardrails.checkInput(messages);
5204
+ if (!result.allowed) {
5205
+ emitEvent(onEvent, "error", { message: `Input guardrail denied: ${result.reason}` });
5206
+ throw new GuardrailError(result.reason ?? "Input guardrail denied");
5150
5207
  }
5151
- if (result2.rewrite) messages = result2.rewrite;
5208
+ if (result.rewrite) messages = result.rewrite;
5152
5209
  }
5153
5210
  try {
5154
5211
  checkCancellation(signal);
@@ -5180,9 +5237,9 @@ async function invokeAgent(prompt, inputs, options) {
5180
5237
  );
5181
5238
  }
5182
5239
  const toolMessages2 = await traceSpan("toolCalls", async (toolEmit) => {
5183
- toolEmit("signature", "prompty.invokeAgent.toolCalls");
5240
+ toolEmit("signature", "prompty.turn.toolCalls");
5184
5241
  toolEmit("description", `Tool call round ${iteration}`);
5185
- const result2 = await buildToolMessagesFromCallsWithExtensions(
5242
+ const result = await buildToolMessagesFromCallsWithExtensions(
5186
5243
  toolCalls,
5187
5244
  content,
5188
5245
  tools,
@@ -5191,8 +5248,8 @@ async function invokeAgent(prompt, inputs, options) {
5191
5248
  toolEmit,
5192
5249
  { onEvent, signal, guardrails, parallel: parallelToolCalls }
5193
5250
  );
5194
- toolEmit("result", result2.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
5195
- return result2;
5251
+ toolEmit("result", result.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
5252
+ return result;
5196
5253
  });
5197
5254
  messages.push(...toolMessages2);
5198
5255
  emitEvent(onEvent, "messages_updated", { messages });
@@ -5238,9 +5295,9 @@ async function invokeAgent(prompt, inputs, options) {
5238
5295
  );
5239
5296
  }
5240
5297
  const toolMessages = await traceSpan("toolCalls", async (toolEmit) => {
5241
- toolEmit("signature", "prompty.invokeAgent.toolCalls");
5298
+ toolEmit("signature", "prompty.turn.toolCalls");
5242
5299
  toolEmit("description", `Tool call round ${iteration}`);
5243
- const result2 = await buildToolResultMessagesWithExtensions(
5300
+ const result = await buildToolResultMessagesWithExtensions(
5244
5301
  response,
5245
5302
  tools,
5246
5303
  agent,
@@ -5248,28 +5305,55 @@ async function invokeAgent(prompt, inputs, options) {
5248
5305
  toolEmit,
5249
5306
  { onEvent, signal, guardrails, parallel: parallelToolCalls }
5250
5307
  );
5251
- toolEmit("result", result2.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
5252
- return result2;
5308
+ toolEmit("result", result.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
5309
+ return result;
5253
5310
  });
5254
5311
  messages.push(...toolMessages);
5255
5312
  emitEvent(onEvent, "messages_updated", { messages });
5256
5313
  }
5257
- emit("iterations", iteration);
5258
- if (options?.raw) {
5259
- emit("result", response);
5260
- emitEvent(onEvent, "done", { response, messages });
5261
- return response;
5262
- }
5263
- const result = await process2(agent, response);
5264
- emit("result", result);
5265
- emitEvent(onEvent, "done", { response: result, messages });
5266
- return result;
5267
5314
  });
5268
5315
  if (options?.validator) {
5269
5316
  return cast(rawResult, options.validator);
5270
5317
  }
5271
5318
  return rawResult;
5272
5319
  }
5320
+ function resolveBindings(agent, toolName, args, parentInputs) {
5321
+ if (!parentInputs || !agent.tools || agent.tools.length === 0) return args;
5322
+ const toolDef = agent.tools.find((t) => t.name === toolName);
5323
+ if (!toolDef || !toolDef.bindings || toolDef.bindings.length === 0) return args;
5324
+ const merged = { ...args };
5325
+ for (const binding of toolDef.bindings) {
5326
+ if (binding.input in parentInputs) {
5327
+ merged[binding.name] = parentInputs[binding.input];
5328
+ }
5329
+ }
5330
+ return merged;
5331
+ }
5332
+ function isAsyncIterable(value) {
5333
+ return value != null && typeof value === "object" && Symbol.asyncIterator in value;
5334
+ }
5335
+ function isToolCallLike(item) {
5336
+ return typeof item === "object" && item !== null && "id" in item && "name" in item && "arguments" in item;
5337
+ }
5338
+ async function consumeStream(agent, response, onEvent) {
5339
+ const processed = await process2(agent, response);
5340
+ const toolCalls = [];
5341
+ const textParts = [];
5342
+ if (isAsyncIterable(processed)) {
5343
+ for await (const item of processed) {
5344
+ if (isToolCallLike(item)) {
5345
+ toolCalls.push(item);
5346
+ } else if (typeof item === "string") {
5347
+ textParts.push(item);
5348
+ emitEvent(onEvent, "token", { token: item });
5349
+ }
5350
+ }
5351
+ } else if (typeof processed === "string") {
5352
+ textParts.push(processed);
5353
+ emitEvent(onEvent, "token", { token: processed });
5354
+ }
5355
+ return { toolCalls, content: textParts.join("") };
5356
+ }
5273
5357
  function expandThreads(messages, nonces, inputs) {
5274
5358
  if (nonces.size === 0) return messages;
5275
5359
  const nonceToName = /* @__PURE__ */ new Map();
@@ -5468,7 +5552,7 @@ async function buildToolMessagesFromCallsWithExtensions(toolCalls, textContent,
5468
5552
  const executor = getExecutor(provider);
5469
5553
  return executor.formatToolMessages(null, normalizedCalls, toolResults, textContent);
5470
5554
  }
5471
- var DEFAULT_FORMAT, DEFAULT_PARSER, DEFAULT_PROVIDER, DEFAULT_MAX_ITERATIONS;
5555
+ var DEFAULT_FORMAT, DEFAULT_PARSER, DEFAULT_PROVIDER, DEFAULT_MAX_ITERATIONS, invokeAgent;
5472
5556
  var init_pipeline = __esm({
5473
5557
  "src/core/pipeline.ts"() {
5474
5558
  "use strict";
@@ -5487,6 +5571,7 @@ var init_pipeline = __esm({
5487
5571
  DEFAULT_PARSER = "prompty";
5488
5572
  DEFAULT_PROVIDER = "openai";
5489
5573
  DEFAULT_MAX_ITERATIONS = 10;
5574
+ invokeAgent = turn;
5490
5575
  }
5491
5576
  });
5492
5577
 
@@ -5579,6 +5664,7 @@ __export(index_exports, {
5579
5664
  traceMethod: () => traceMethod,
5580
5665
  traceSpan: () => traceSpan,
5581
5666
  trimToContextWindow: () => trimToContextWindow,
5667
+ turn: () => turn,
5582
5668
  validateInputs: () => validateInputs
5583
5669
  });
5584
5670
  module.exports = __toCommonJS(index_exports);
@@ -6178,6 +6264,7 @@ registerParser("prompty", new PromptyChatParser());
6178
6264
  traceMethod,
6179
6265
  traceSpan,
6180
6266
  trimToContextWindow,
6267
+ turn,
6181
6268
  validateInputs
6182
6269
  });
6183
6270
  //# sourceMappingURL=index.cjs.map