@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.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 (value && typeof value === "object" && !Array.isArray(value)) {
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 (value && typeof value === "object" && !Array.isArray(value)) {
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 (value && typeof value === "object" && !Array.isArray(value)) {
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 (value && typeof value === "object" && !Array.isArray(value)) {
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 (value && typeof value === "object" && !Array.isArray(value)) {
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 (value && typeof value === "object" && !Array.isArray(value)) {
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 {
@@ -4570,14 +4600,14 @@ var init_tool_dispatch = __esm({
4570
4600
  async executeTool(tool2, _args, _agent, _parentInputs) {
4571
4601
  const name = tool2.name ?? "unknown";
4572
4602
  throw new Error(
4573
- `Function tool '${name}' declared but no callable provided. Pass it via tools: { '${name}': fn } in invokeAgent().`
4603
+ `Function tool '${name}' declared but no callable provided. Pass it via tools: { '${name}': fn } in turn().`
4574
4604
  );
4575
4605
  }
4576
4606
  };
4577
4607
  PromptyToolHandler = class {
4578
4608
  async executeTool(tool2, args, agent, _parentInputs) {
4579
4609
  const { load: load2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
4580
- const { prepare: prepare2, run: run2, invokeAgent: invokeAgent2 } = await Promise.resolve().then(() => (init_pipeline(), pipeline_exports));
4610
+ const { prepare: prepare2, run: run2, turn: turn2 } = await Promise.resolve().then(() => (init_pipeline(), pipeline_exports));
4581
4611
  const parentPath = (agent.metadata ?? {}).__source_path;
4582
4612
  if (!parentPath) {
4583
4613
  return `Error: cannot resolve PromptyTool '${tool2.name}': parent has no __source_path`;
@@ -4596,7 +4626,7 @@ var init_tool_dispatch = __esm({
4596
4626
  child.metadata.__prompty_tool_stack = [...stack, parentPath];
4597
4627
  const mode = tool2.mode ?? "single";
4598
4628
  if (mode === "agentic") {
4599
- const result = await invokeAgent2(child, args);
4629
+ const result = await turn2(child, args);
4600
4630
  return typeof result === "string" ? result : JSON.stringify(result);
4601
4631
  } else {
4602
4632
  const messages = await prepare2(child, args);
@@ -4841,6 +4871,7 @@ __export(pipeline_exports, {
4841
4871
  render: () => render,
4842
4872
  resolveBindings: () => resolveBindings,
4843
4873
  run: () => run,
4874
+ turn: () => turn,
4844
4875
  validateInputs: () => validateInputs
4845
4876
  });
4846
4877
  function sanitizeNonces(value) {
@@ -5031,7 +5062,17 @@ async function invoke(prompt, inputs, options) {
5031
5062
  emit("description", "Invoke a prompty");
5032
5063
  emit("inputs", { prompt: serializeAgent(agent), inputs: inputs ?? {} });
5033
5064
  const messages = await prepare(agent, inputs);
5034
- const result = await run(agent, messages, options);
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);
5072
+ }
5073
+ return response;
5074
+ }
5075
+ const result = await process2(agent, response);
5035
5076
  emit("result", result);
5036
5077
  if (options?.validator) {
5037
5078
  return cast(result, options.validator);
@@ -5039,45 +5080,9 @@ async function invoke(prompt, inputs, options) {
5039
5080
  return result;
5040
5081
  });
5041
5082
  }
5042
- function resolveBindings(agent, toolName, args, parentInputs) {
5043
- if (!parentInputs || !agent.tools || agent.tools.length === 0) return args;
5044
- const toolDef = agent.tools.find((t) => t.name === toolName);
5045
- if (!toolDef || !toolDef.bindings || toolDef.bindings.length === 0) return args;
5046
- const merged = { ...args };
5047
- for (const binding of toolDef.bindings) {
5048
- if (binding.input in parentInputs) {
5049
- merged[binding.name] = parentInputs[binding.input];
5050
- }
5051
- }
5052
- return merged;
5053
- }
5054
- function isAsyncIterable(value) {
5055
- return value != null && typeof value === "object" && Symbol.asyncIterator in value;
5056
- }
5057
- function isToolCallLike(item) {
5058
- return typeof item === "object" && item !== null && "id" in item && "name" in item && "arguments" in item;
5059
- }
5060
- async function consumeStream(agent, response, onEvent) {
5061
- const processed = await process2(agent, response);
5062
- const toolCalls = [];
5063
- const textParts = [];
5064
- if (isAsyncIterable(processed)) {
5065
- for await (const item of processed) {
5066
- if (isToolCallLike(item)) {
5067
- toolCalls.push(item);
5068
- } else if (typeof item === "string") {
5069
- textParts.push(item);
5070
- emitEvent(onEvent, "token", { token: item });
5071
- }
5072
- }
5073
- } else if (typeof processed === "string") {
5074
- textParts.push(processed);
5075
- emitEvent(onEvent, "token", { token: processed });
5076
- }
5077
- return { toolCalls, content: textParts.join("") };
5078
- }
5079
- async function invokeAgent(prompt, inputs, options) {
5080
- const rawResult = await traceSpan("invokeAgent", async (emit) => {
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) => {
5081
5086
  const agent = typeof prompt === "string" ? await traceSpan("load", async (loadEmit) => {
5082
5087
  loadEmit("signature", "prompty.load");
5083
5088
  loadEmit("description", "Load a prompty file.");
@@ -5086,7 +5091,62 @@ async function invokeAgent(prompt, inputs, options) {
5086
5091
  loadEmit("result", serializeAgent(loaded));
5087
5092
  return loaded;
5088
5093
  }) : prompt;
5094
+ emit("signature", "prompty.turn");
5095
+ emit("description", label);
5096
+ emit("inputs", sanitizeValue("inputs", inputs));
5089
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
+ }
5090
5150
  const maxIterations = options?.maxIterations ?? DEFAULT_MAX_ITERATIONS;
5091
5151
  const onEvent = options?.onEvent;
5092
5152
  const signal = options?.signal;
@@ -5094,9 +5154,6 @@ async function invokeAgent(prompt, inputs, options) {
5094
5154
  const guardrails = options?.guardrails;
5095
5155
  const steering = options?.steering;
5096
5156
  const parallelToolCalls = options?.parallelToolCalls ?? false;
5097
- emit("signature", "prompty.invokeAgent");
5098
- emit("description", "Invoke a prompty with tool calling");
5099
- emit("inputs", { prompt: serializeAgent(agent), tools: Object.keys(tools), inputs: inputs ?? {} });
5100
5157
  let messages = await prepare(agent, inputs);
5101
5158
  const parentInputs = inputs ?? {};
5102
5159
  const provider = resolveProvider(agent);
@@ -5126,12 +5183,12 @@ async function invokeAgent(prompt, inputs, options) {
5126
5183
  }
5127
5184
  }
5128
5185
  if (guardrails) {
5129
- const result2 = guardrails.checkInput(messages);
5130
- if (!result2.allowed) {
5131
- emitEvent(onEvent, "error", { message: `Input guardrail denied: ${result2.reason}` });
5132
- throw new GuardrailError(result2.reason ?? "Input guardrail denied");
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");
5133
5190
  }
5134
- if (result2.rewrite) messages = result2.rewrite;
5191
+ if (result.rewrite) messages = result.rewrite;
5135
5192
  }
5136
5193
  try {
5137
5194
  checkCancellation(signal);
@@ -5163,9 +5220,9 @@ async function invokeAgent(prompt, inputs, options) {
5163
5220
  );
5164
5221
  }
5165
5222
  const toolMessages2 = await traceSpan("toolCalls", async (toolEmit) => {
5166
- toolEmit("signature", "prompty.invokeAgent.toolCalls");
5223
+ toolEmit("signature", "prompty.turn.toolCalls");
5167
5224
  toolEmit("description", `Tool call round ${iteration}`);
5168
- const result2 = await buildToolMessagesFromCallsWithExtensions(
5225
+ const result = await buildToolMessagesFromCallsWithExtensions(
5169
5226
  toolCalls,
5170
5227
  content,
5171
5228
  tools,
@@ -5174,8 +5231,8 @@ async function invokeAgent(prompt, inputs, options) {
5174
5231
  toolEmit,
5175
5232
  { onEvent, signal, guardrails, parallel: parallelToolCalls }
5176
5233
  );
5177
- toolEmit("result", result2.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
5178
- return result2;
5234
+ toolEmit("result", result.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
5235
+ return result;
5179
5236
  });
5180
5237
  messages.push(...toolMessages2);
5181
5238
  emitEvent(onEvent, "messages_updated", { messages });
@@ -5221,9 +5278,9 @@ async function invokeAgent(prompt, inputs, options) {
5221
5278
  );
5222
5279
  }
5223
5280
  const toolMessages = await traceSpan("toolCalls", async (toolEmit) => {
5224
- toolEmit("signature", "prompty.invokeAgent.toolCalls");
5281
+ toolEmit("signature", "prompty.turn.toolCalls");
5225
5282
  toolEmit("description", `Tool call round ${iteration}`);
5226
- const result2 = await buildToolResultMessagesWithExtensions(
5283
+ const result = await buildToolResultMessagesWithExtensions(
5227
5284
  response,
5228
5285
  tools,
5229
5286
  agent,
@@ -5231,28 +5288,55 @@ async function invokeAgent(prompt, inputs, options) {
5231
5288
  toolEmit,
5232
5289
  { onEvent, signal, guardrails, parallel: parallelToolCalls }
5233
5290
  );
5234
- toolEmit("result", result2.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
5235
- return result2;
5291
+ toolEmit("result", result.map((m) => ({ role: m.role, content: m.parts.map((p) => p.value ?? "").join(""), metadata: m.metadata })));
5292
+ return result;
5236
5293
  });
5237
5294
  messages.push(...toolMessages);
5238
5295
  emitEvent(onEvent, "messages_updated", { messages });
5239
5296
  }
5240
- emit("iterations", iteration);
5241
- if (options?.raw) {
5242
- emit("result", response);
5243
- emitEvent(onEvent, "done", { response, messages });
5244
- return response;
5245
- }
5246
- const result = await process2(agent, response);
5247
- emit("result", result);
5248
- emitEvent(onEvent, "done", { response: result, messages });
5249
- return result;
5250
5297
  });
5251
5298
  if (options?.validator) {
5252
5299
  return cast(rawResult, options.validator);
5253
5300
  }
5254
5301
  return rawResult;
5255
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("") };
5339
+ }
5256
5340
  function expandThreads(messages, nonces, inputs) {
5257
5341
  if (nonces.size === 0) return messages;
5258
5342
  const nonceToName = /* @__PURE__ */ new Map();
@@ -5451,7 +5535,7 @@ async function buildToolMessagesFromCallsWithExtensions(toolCalls, textContent,
5451
5535
  const executor = getExecutor(provider);
5452
5536
  return executor.formatToolMessages(null, normalizedCalls, toolResults, textContent);
5453
5537
  }
5454
- var DEFAULT_FORMAT, DEFAULT_PARSER, DEFAULT_PROVIDER, DEFAULT_MAX_ITERATIONS;
5538
+ var DEFAULT_FORMAT, DEFAULT_PARSER, DEFAULT_PROVIDER, DEFAULT_MAX_ITERATIONS, invokeAgent;
5455
5539
  var init_pipeline = __esm({
5456
5540
  "src/core/pipeline.ts"() {
5457
5541
  "use strict";
@@ -5470,6 +5554,7 @@ var init_pipeline = __esm({
5470
5554
  DEFAULT_PARSER = "prompty";
5471
5555
  DEFAULT_PROVIDER = "openai";
5472
5556
  DEFAULT_MAX_ITERATIONS = 10;
5557
+ invokeAgent = turn;
5473
5558
  }
5474
5559
  });
5475
5560
 
@@ -6067,6 +6152,7 @@ export {
6067
6152
  traceMethod,
6068
6153
  traceSpan,
6069
6154
  trimToContextWindow,
6155
+ turn,
6070
6156
  validateInputs
6071
6157
  };
6072
6158
  //# sourceMappingURL=index.js.map