extrait 0.3.1 → 0.5.1

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
@@ -697,45 +697,38 @@ function unwrap(schema) {
697
697
  let optional = false;
698
698
  let nullable = false;
699
699
  while (true) {
700
- const typeName = current?._def?.typeName;
700
+ const typeName = current?._def?.type;
701
701
  if (!typeName) {
702
702
  break;
703
703
  }
704
- if (typeName === "ZodOptional") {
704
+ if (typeName === "optional") {
705
705
  optional = true;
706
706
  current = current._def?.innerType ?? current;
707
707
  continue;
708
708
  }
709
- if (typeName === "ZodDefault") {
709
+ if (typeName === "default") {
710
710
  optional = true;
711
711
  current = current._def?.innerType ?? current;
712
712
  continue;
713
713
  }
714
- if (typeName === "ZodNullable") {
714
+ if (typeName === "nullable") {
715
715
  nullable = true;
716
716
  current = current._def?.innerType ?? current;
717
717
  continue;
718
718
  }
719
- if (typeName === "ZodEffects") {
720
- current = current._def?.schema ?? current;
721
- continue;
722
- }
723
- if (typeName === "ZodBranded") {
724
- current = current._def?.type ?? current;
725
- continue;
726
- }
727
- if (typeName === "ZodCatch") {
728
- current = current._def?.innerType ?? current;
719
+ if (typeName === "pipe") {
720
+ const outType = current._def?.out?._def?.type;
721
+ if (outType === "transform") {
722
+ current = current._def?.in ?? current;
723
+ } else {
724
+ current = current._def?.out ?? current;
725
+ }
729
726
  continue;
730
727
  }
731
- if (typeName === "ZodReadonly") {
728
+ if (typeName === "catch" || typeName === "readonly") {
732
729
  current = current._def?.innerType ?? current;
733
730
  continue;
734
731
  }
735
- if (typeName === "ZodPipeline") {
736
- current = current._def?.out ?? current;
737
- continue;
738
- }
739
732
  break;
740
733
  }
741
734
  return {
@@ -749,81 +742,74 @@ function formatCore(schema, depth, seen) {
749
742
  return "unknown";
750
743
  }
751
744
  seen.add(schema);
752
- const typeName = schema?._def?.typeName;
745
+ const typeName = schema?._def?.type;
753
746
  switch (typeName) {
754
- case "ZodString":
747
+ case "string":
755
748
  return "string";
756
- case "ZodNumber":
749
+ case "number":
757
750
  return isIntegerNumber(schema) ? "int" : "number";
758
- case "ZodBoolean":
751
+ case "boolean":
759
752
  return "boolean";
760
- case "ZodBigInt":
753
+ case "bigint":
761
754
  return "bigint";
762
- case "ZodDate":
755
+ case "date":
763
756
  return "Date";
764
- case "ZodUndefined":
757
+ case "undefined":
765
758
  return "undefined";
766
- case "ZodNull":
759
+ case "null":
767
760
  return "null";
768
- case "ZodAny":
761
+ case "any":
769
762
  return "any";
770
- case "ZodUnknown":
763
+ case "unknown":
771
764
  return "unknown";
772
- case "ZodNever":
765
+ case "never":
773
766
  return "never";
774
- case "ZodVoid":
767
+ case "void":
775
768
  return "void";
776
- case "ZodLiteral": {
777
- const value = schema._def?.value;
769
+ case "literal": {
770
+ const value = schema._def?.values?.[0];
778
771
  return JSON.stringify(value);
779
772
  }
780
- case "ZodEnum": {
781
- const values = schema._def?.values ?? [];
782
- return values.map((value) => JSON.stringify(value)).join(" | ") || "string";
783
- }
784
- case "ZodNativeEnum": {
785
- const values = Object.values(schema._def?.values ?? {});
786
- const unique = [...new Set(values.filter((value) => typeof value !== "string" || Number.isNaN(Number(value))))];
787
- return unique.map((value) => JSON.stringify(value)).join(" | ") || "string";
773
+ case "enum": {
774
+ const entries = schema._def?.entries;
775
+ const values = Object.values(entries ?? {});
776
+ const unique = [...new Set(values.filter((v) => typeof v !== "string" || Number.isNaN(Number(v))))];
777
+ return unique.map((v) => JSON.stringify(v)).join(" | ") || "string";
788
778
  }
789
- case "ZodArray": {
790
- const inner = formatType(schema._def?.type ?? schema, depth, seen);
779
+ case "array": {
780
+ const inner = formatType(schema._def?.element ?? schema, depth, seen);
791
781
  return requiresParentheses(inner) ? `(${inner})[]` : `${inner}[]`;
792
782
  }
793
- case "ZodTuple": {
783
+ case "tuple": {
794
784
  const items = (schema._def?.items ?? []).map((item) => formatType(item, depth, seen));
795
785
  return `[${items.join(", ")}]`;
796
786
  }
797
- case "ZodUnion": {
787
+ case "union": {
798
788
  const options = (schema._def?.options ?? []).map((option) => formatType(option, depth, seen));
799
789
  return options.join(" | ") || "unknown";
800
790
  }
801
- case "ZodDiscriminatedUnion": {
802
- const options = Array.from((schema._def?.options ?? new Map).values()).map((option) => formatType(option, depth, seen));
803
- return options.join(" | ") || "unknown";
804
- }
805
- case "ZodIntersection": {
791
+ case "intersection": {
806
792
  const left = formatType(schema._def?.left ?? schema, depth, seen);
807
793
  const right = formatType(schema._def?.right ?? schema, depth, seen);
808
794
  return `${left} & ${right}`;
809
795
  }
810
- case "ZodRecord": {
796
+ case "record": {
811
797
  const keyType = formatType(schema._def?.keyType ?? schema, depth, seen);
812
798
  const valueType = formatType(schema._def?.valueType ?? schema, depth, seen);
813
799
  return `Record<${keyType}, ${valueType}>`;
814
800
  }
815
- case "ZodMap": {
801
+ case "map": {
816
802
  const keyType = formatType(schema._def?.keyType ?? schema, depth, seen);
817
803
  const valueType = formatType(schema._def?.valueType ?? schema, depth, seen);
818
804
  return `Map<${keyType}, ${valueType}>`;
819
805
  }
820
- case "ZodSet": {
806
+ case "set": {
821
807
  const valueType = formatType(schema._def?.valueType ?? schema, depth, seen);
822
808
  return `Set<${valueType}>`;
823
809
  }
824
- case "ZodObject":
810
+ case "object":
825
811
  return formatObject(schema, depth, seen);
826
- case "ZodLazy":
812
+ case "lazy":
827
813
  return "unknown";
828
814
  default:
829
815
  return "unknown";
@@ -859,40 +845,28 @@ function requiresParentheses(typeText) {
859
845
  }
860
846
  function isIntegerNumber(schema) {
861
847
  const checks = schema._def?.checks ?? [];
862
- return checks.some((check) => check.kind === "int");
848
+ return checks.some((check) => check.isInt === true);
863
849
  }
864
850
  function readSchemaDescription(schema) {
865
851
  let current = schema;
866
- while (current?._def?.typeName) {
867
- const direct = current._def.description;
868
- if (typeof direct === "string" && direct.trim().length > 0) {
869
- return sanitizeDescription(direct);
852
+ while (current?._def?.type) {
853
+ const desc = current.description;
854
+ if (typeof desc === "string" && desc.trim().length > 0) {
855
+ return sanitizeDescription(desc);
870
856
  }
871
- const fallback = current.description;
872
- if (typeof fallback === "string" && fallback.trim().length > 0) {
873
- return sanitizeDescription(fallback);
874
- }
875
- const typeName = current._def.typeName;
876
- if (typeName === "ZodOptional" || typeName === "ZodDefault" || typeName === "ZodNullable") {
857
+ const typeName = current._def.type;
858
+ if (typeName === "optional" || typeName === "default" || typeName === "nullable") {
877
859
  current = current._def.innerType ?? current;
878
860
  continue;
879
861
  }
880
- if (typeName === "ZodEffects") {
881
- current = current._def.schema ?? current;
882
- continue;
883
- }
884
- if (typeName === "ZodBranded") {
885
- current = current._def.type ?? current;
862
+ if (typeName === "pipe") {
863
+ current = current._def.in ?? current;
886
864
  continue;
887
865
  }
888
- if (typeName === "ZodCatch" || typeName === "ZodReadonly") {
866
+ if (typeName === "catch" || typeName === "readonly") {
889
867
  current = current._def.innerType ?? current;
890
868
  continue;
891
869
  }
892
- if (typeName === "ZodPipeline") {
893
- current = current._def.out ?? current;
894
- continue;
895
- }
896
870
  break;
897
871
  }
898
872
  return;
@@ -1245,7 +1219,12 @@ async function executeMCPToolCalls(calls, toolset, context) {
1245
1219
  out.push({ call: metadata2, execution });
1246
1220
  continue;
1247
1221
  }
1248
- const args = isRecord(parsedArguments) ? parsedArguments : {};
1222
+ const rawArgs = isRecord(parsedArguments) ? parsedArguments : {};
1223
+ const args = context.request.transformToolArguments ? await context.request.transformToolArguments(rawArgs, {
1224
+ name: toolName,
1225
+ remoteName: tool.remoteName,
1226
+ clientId: tool.clientId
1227
+ }) : rawArgs;
1249
1228
  const metadata = {
1250
1229
  id: callId,
1251
1230
  type: call.type ?? "function",
@@ -1564,7 +1543,8 @@ function createOpenAICompatibleAdapter(options) {
1564
1543
  temperature: request.temperature,
1565
1544
  max_tokens: request.maxTokens,
1566
1545
  stream: true
1567
- }))
1546
+ })),
1547
+ signal: request.signal
1568
1548
  });
1569
1549
  if (!response.ok) {
1570
1550
  const message = await response.text();
@@ -1635,7 +1615,8 @@ async function completeWithChatCompletionsPassThrough(options, fetcher, path, re
1635
1615
  temperature: request.temperature,
1636
1616
  max_tokens: request.maxTokens,
1637
1617
  stream: false
1638
- }))
1618
+ })),
1619
+ signal: request.signal
1639
1620
  });
1640
1621
  if (!response.ok) {
1641
1622
  const message = await response.text();
@@ -1679,7 +1660,8 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
1679
1660
  tools: transportTools,
1680
1661
  tool_choice: request.toolChoice,
1681
1662
  parallel_tool_calls: request.parallelToolCalls
1682
- }))
1663
+ })),
1664
+ signal: request.signal
1683
1665
  });
1684
1666
  if (!response.ok) {
1685
1667
  const message = await response.text();
@@ -1744,7 +1726,8 @@ async function completeWithResponsesAPIPassThrough(options, fetcher, path, reque
1744
1726
  previous_response_id: pickString(body?.previous_response_id),
1745
1727
  temperature: request.temperature,
1746
1728
  max_output_tokens: request.maxTokens
1747
- }))
1729
+ })),
1730
+ signal: request.signal
1748
1731
  });
1749
1732
  if (!response.ok) {
1750
1733
  const message = await response.text();
@@ -1786,7 +1769,8 @@ async function completeWithResponsesAPIWithMCP(options, fetcher, path, request)
1786
1769
  tools: transportTools,
1787
1770
  tool_choice: request.toolChoice,
1788
1771
  parallel_tool_calls: request.parallelToolCalls
1789
- }))
1772
+ })),
1773
+ signal: request.signal
1790
1774
  });
1791
1775
  if (!response.ok) {
1792
1776
  const message = await response.text();
@@ -1862,7 +1846,8 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1862
1846
  tool_choice: request.toolChoice,
1863
1847
  parallel_tool_calls: request.parallelToolCalls,
1864
1848
  stream: true
1865
- }))
1849
+ })),
1850
+ signal: request.signal
1866
1851
  });
1867
1852
  if (!response.ok) {
1868
1853
  const message = await response.text();
@@ -1964,7 +1949,8 @@ async function streamWithResponsesAPIPassThrough(options, fetcher, path, request
1964
1949
  temperature: request.temperature,
1965
1950
  max_output_tokens: request.maxTokens,
1966
1951
  stream: true
1967
- }))
1952
+ })),
1953
+ signal: request.signal
1968
1954
  });
1969
1955
  if (!response.ok) {
1970
1956
  const message = await response.text();
@@ -2046,7 +2032,8 @@ async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, ca
2046
2032
  tool_choice: request.toolChoice,
2047
2033
  parallel_tool_calls: request.parallelToolCalls,
2048
2034
  stream: true
2049
- }))
2035
+ })),
2036
+ signal: request.signal
2050
2037
  });
2051
2038
  if (!response.ok) {
2052
2039
  const message = await response.text();
@@ -2164,6 +2151,12 @@ function buildHeaders(options) {
2164
2151
  };
2165
2152
  }
2166
2153
  function buildMessages(request) {
2154
+ if (Array.isArray(request.messages) && request.messages.length > 0) {
2155
+ return request.messages.map((message) => toOpenAIMessage(message));
2156
+ }
2157
+ if (typeof request.prompt !== "string" || request.prompt.trim().length === 0) {
2158
+ throw new Error("LLMRequest must include a prompt or messages.");
2159
+ }
2167
2160
  const messages = [];
2168
2161
  if (request.systemPrompt) {
2169
2162
  messages.push({ role: "system", content: request.systemPrompt });
@@ -2175,18 +2168,16 @@ function buildResponsesInput(request) {
2175
2168
  if (isRecord2(request.body) && "input" in request.body) {
2176
2169
  return request.body.input;
2177
2170
  }
2178
- const input = [];
2179
- if (request.systemPrompt) {
2180
- input.push({
2181
- role: "system",
2182
- content: request.systemPrompt
2183
- });
2171
+ if (Array.isArray(request.messages) && request.messages.length > 0) {
2172
+ return request.messages.map((message) => toOpenAIMessage(message));
2184
2173
  }
2185
- input.push({
2186
- role: "user",
2187
- content: request.prompt
2188
- });
2189
- return input;
2174
+ return buildMessages(request);
2175
+ }
2176
+ function toOpenAIMessage(message) {
2177
+ return {
2178
+ role: message.role,
2179
+ content: message.content
2180
+ };
2190
2181
  }
2191
2182
  function toResponsesTools(tools) {
2192
2183
  if (!Array.isArray(tools) || tools.length === 0) {
@@ -2598,6 +2589,7 @@ function createAnthropicCompatibleAdapter(options) {
2598
2589
  if (hasMCPClients(request.mcpClients)) {
2599
2590
  return streamWithMCPToolLoop(options, fetcher, path, request, callbacks);
2600
2591
  }
2592
+ const input = resolveAnthropicInput(request);
2601
2593
  const response = await fetcher(buildURL(options.baseURL, path), {
2602
2594
  method: "POST",
2603
2595
  headers: buildHeaders2(options),
@@ -2605,12 +2597,13 @@ function createAnthropicCompatibleAdapter(options) {
2605
2597
  ...options.defaultBody,
2606
2598
  ...request.body,
2607
2599
  model: options.model,
2608
- system: request.systemPrompt,
2609
- messages: [{ role: "user", content: request.prompt }],
2600
+ system: input.systemPrompt,
2601
+ messages: input.messages,
2610
2602
  temperature: request.temperature,
2611
2603
  max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2612
2604
  stream: true
2613
- }))
2605
+ })),
2606
+ signal: request.signal
2614
2607
  });
2615
2608
  if (!response.ok) {
2616
2609
  const message = await response.text();
@@ -2656,6 +2649,7 @@ function createAnthropicCompatibleAdapter(options) {
2656
2649
  };
2657
2650
  }
2658
2651
  async function completePassThrough(options, fetcher, path, request) {
2652
+ const input = resolveAnthropicInput(request);
2659
2653
  const response = await fetcher(buildURL(options.baseURL, path), {
2660
2654
  method: "POST",
2661
2655
  headers: buildHeaders2(options),
@@ -2663,12 +2657,13 @@ async function completePassThrough(options, fetcher, path, request) {
2663
2657
  ...options.defaultBody,
2664
2658
  ...request.body,
2665
2659
  model: options.model,
2666
- system: request.systemPrompt,
2667
- messages: [{ role: "user", content: request.prompt }],
2660
+ system: input.systemPrompt,
2661
+ messages: input.messages,
2668
2662
  temperature: request.temperature,
2669
2663
  max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2670
2664
  stream: false
2671
- }))
2665
+ })),
2666
+ signal: request.signal
2672
2667
  });
2673
2668
  if (!response.ok) {
2674
2669
  const message = await response.text();
@@ -2690,7 +2685,8 @@ async function completePassThrough(options, fetcher, path, request) {
2690
2685
  }
2691
2686
  async function completeWithMCPToolLoop(options, fetcher, path, request) {
2692
2687
  const maxToolRounds = normalizeMaxToolRounds(request.maxToolRounds ?? options.defaultMaxToolRounds);
2693
- let messages = [{ role: "user", content: request.prompt }];
2688
+ const input = resolveAnthropicInput(request);
2689
+ let messages = input.messages;
2694
2690
  let aggregatedUsage;
2695
2691
  let finishReason;
2696
2692
  let lastPayload;
@@ -2706,14 +2702,15 @@ async function completeWithMCPToolLoop(options, fetcher, path, request) {
2706
2702
  ...options.defaultBody,
2707
2703
  ...request.body,
2708
2704
  model: options.model,
2709
- system: request.systemPrompt,
2705
+ system: input.systemPrompt,
2710
2706
  messages,
2711
2707
  temperature: request.temperature,
2712
2708
  max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2713
2709
  tools,
2714
2710
  tool_choice: toAnthropicToolChoice(request.toolChoice),
2715
2711
  stream: false
2716
- }))
2712
+ })),
2713
+ signal: request.signal
2717
2714
  });
2718
2715
  if (!response.ok) {
2719
2716
  const message = await response.text();
@@ -2772,7 +2769,8 @@ async function completeWithMCPToolLoop(options, fetcher, path, request) {
2772
2769
  }
2773
2770
  async function streamWithMCPToolLoop(options, fetcher, path, request, callbacks) {
2774
2771
  const maxToolRounds = normalizeMaxToolRounds(request.maxToolRounds ?? options.defaultMaxToolRounds);
2775
- let messages = [{ role: "user", content: request.prompt }];
2772
+ const input = resolveAnthropicInput(request);
2773
+ let messages = input.messages;
2776
2774
  let aggregatedUsage;
2777
2775
  let finishReason;
2778
2776
  let lastPayload;
@@ -2789,14 +2787,15 @@ async function streamWithMCPToolLoop(options, fetcher, path, request, callbacks)
2789
2787
  ...options.defaultBody,
2790
2788
  ...request.body,
2791
2789
  model: options.model,
2792
- system: request.systemPrompt,
2790
+ system: input.systemPrompt,
2793
2791
  messages,
2794
2792
  temperature: request.temperature,
2795
2793
  max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2796
2794
  tools,
2797
2795
  tool_choice: toAnthropicToolChoice(request.toolChoice),
2798
2796
  stream: true
2799
- }))
2797
+ })),
2798
+ signal: request.signal
2800
2799
  });
2801
2800
  if (!response.ok) {
2802
2801
  const message = await response.text();
@@ -2899,6 +2898,59 @@ function buildHeaders2(options) {
2899
2898
  ...options.headers
2900
2899
  };
2901
2900
  }
2901
+ function resolveAnthropicInput(request) {
2902
+ if (Array.isArray(request.messages) && request.messages.length > 0) {
2903
+ return toAnthropicInput(request.messages);
2904
+ }
2905
+ if (typeof request.prompt !== "string" || request.prompt.trim().length === 0) {
2906
+ throw new Error("LLMRequest must include a prompt or messages.");
2907
+ }
2908
+ return {
2909
+ systemPrompt: request.systemPrompt,
2910
+ messages: [{ role: "user", content: request.prompt }]
2911
+ };
2912
+ }
2913
+ function toAnthropicInput(messages) {
2914
+ const systemParts = [];
2915
+ const normalizedMessages = [];
2916
+ let sawNonSystem = false;
2917
+ for (const message of messages) {
2918
+ if (message.role === "system") {
2919
+ if (sawNonSystem) {
2920
+ throw new Error('Anthropic-compatible messages only support "system" turns at the beginning.');
2921
+ }
2922
+ systemParts.push(stringifyAnthropicSystemContent(message.content));
2923
+ continue;
2924
+ }
2925
+ sawNonSystem = true;
2926
+ normalizedMessages.push({
2927
+ role: message.role,
2928
+ content: message.content
2929
+ });
2930
+ }
2931
+ if (normalizedMessages.length === 0) {
2932
+ throw new Error("Anthropic-compatible requests require at least one non-system message.");
2933
+ }
2934
+ return {
2935
+ systemPrompt: systemParts.length > 0 ? systemParts.join(`
2936
+
2937
+ `) : undefined,
2938
+ messages: normalizedMessages
2939
+ };
2940
+ }
2941
+ function stringifyAnthropicSystemContent(content) {
2942
+ if (typeof content === "string") {
2943
+ return content;
2944
+ }
2945
+ if (content === null || content === undefined) {
2946
+ return "";
2947
+ }
2948
+ try {
2949
+ return JSON.stringify(content, null, 2) ?? "";
2950
+ } catch {
2951
+ return String(content);
2952
+ }
2953
+ }
2902
2954
  function resolveMaxTokens(value, fallback) {
2903
2955
  const requested = toFiniteNumber(value);
2904
2956
  if (requested !== undefined && requested > 0) {
@@ -3785,17 +3837,15 @@ async function structured(adapter, schemaOrOptions, promptInput, callOptions) {
3785
3837
  const useOutdent = normalized.outdent ?? true;
3786
3838
  const resolvedPrompt = applyPromptOutdent(resolvePrompt(normalized.prompt, { mode }), useOutdent);
3787
3839
  const resolvedSystemPrompt = applyOutdentToOptionalPrompt(normalized.systemPrompt, useOutdent);
3788
- const prompt = shouldInjectFormat(resolvedPrompt.prompt, normalized.schemaInstruction) ? formatPrompt(normalized.schema, resolvedPrompt.prompt, {
3789
- schemaInstruction: normalized.schemaInstruction
3790
- }) : resolvedPrompt.prompt.trim();
3791
- const systemPrompt = mergeSystemPrompts(resolvedPrompt.systemPrompt, resolvedSystemPrompt);
3840
+ const preparedPrompt = prepareStructuredPromptPayload(resolvedPrompt, resolvedSystemPrompt, normalized.schema, normalized.schemaInstruction);
3792
3841
  const first = await executeAttempt(adapter, {
3793
- prompt,
3842
+ prompt: preparedPrompt.prompt,
3843
+ messages: preparedPrompt.messages,
3794
3844
  schema: normalized.schema,
3795
3845
  parseOptions,
3796
3846
  stream: streamConfig,
3797
3847
  request: normalized.request,
3798
- systemPrompt,
3848
+ systemPrompt: preparedPrompt.systemPrompt,
3799
3849
  observe: normalized.observe,
3800
3850
  debug: debugConfig,
3801
3851
  attemptNumber: 1,
@@ -3855,7 +3905,7 @@ async function structured(adapter, schemaOrOptions, promptInput, callOptions) {
3855
3905
  parseOptions,
3856
3906
  stream: streamConfig,
3857
3907
  request: normalized.request,
3858
- systemPrompt,
3908
+ systemPrompt: preparedPrompt.systemPrompt,
3859
3909
  observe: normalized.observe,
3860
3910
  debug: debugConfig,
3861
3911
  attemptNumber,
@@ -3917,12 +3967,15 @@ function isPromptResolver(value) {
3917
3967
  return typeof value === "object" && value !== null && "resolvePrompt" in value && typeof value.resolvePrompt === "function";
3918
3968
  }
3919
3969
  function normalizePromptPayload(value) {
3920
- if (typeof value.prompt !== "string") {
3921
- throw new Error("Structured prompt payload must include a string prompt.");
3970
+ const prompt = typeof value.prompt === "string" ? value.prompt : undefined;
3971
+ const messages = Array.isArray(value.messages) ? value.messages.filter(isLLMMessage) : undefined;
3972
+ if ((!prompt || prompt.trim().length === 0) && (!messages || messages.length === 0)) {
3973
+ throw new Error("Structured prompt payload must include a non-empty prompt or messages.");
3922
3974
  }
3923
3975
  return {
3924
- prompt: value.prompt,
3925
- systemPrompt: typeof value.systemPrompt === "string" ? value.systemPrompt : undefined
3976
+ prompt,
3977
+ systemPrompt: typeof value.systemPrompt === "string" ? value.systemPrompt : undefined,
3978
+ messages: messages && messages.length > 0 ? messages.map((message) => ({ ...message })) : undefined
3926
3979
  };
3927
3980
  }
3928
3981
  function applyPromptOutdent(payload, enabled) {
@@ -3930,10 +3983,24 @@ function applyPromptOutdent(payload, enabled) {
3930
3983
  return payload;
3931
3984
  }
3932
3985
  return {
3933
- prompt: structuredOutdent.string(payload.prompt),
3934
- systemPrompt: applyOutdentToOptionalPrompt(payload.systemPrompt, enabled)
3986
+ prompt: typeof payload.prompt === "string" ? structuredOutdent.string(payload.prompt) : undefined,
3987
+ systemPrompt: applyOutdentToOptionalPrompt(payload.systemPrompt, enabled),
3988
+ messages: payload.messages?.map((message) => ({
3989
+ ...message,
3990
+ content: typeof message.content === "string" ? structuredOutdent.string(message.content) : message.content
3991
+ }))
3935
3992
  };
3936
3993
  }
3994
+ function isLLMMessage(value) {
3995
+ if (typeof value !== "object" || value === null) {
3996
+ return false;
3997
+ }
3998
+ const candidate = value;
3999
+ if (candidate.role !== "system" && candidate.role !== "user" && candidate.role !== "assistant" && candidate.role !== "tool") {
4000
+ return false;
4001
+ }
4002
+ return "content" in candidate;
4003
+ }
3937
4004
  function applyOutdentToOptionalPrompt(value, enabled) {
3938
4005
  if (!enabled || typeof value !== "string") {
3939
4006
  return value;
@@ -3949,6 +4016,60 @@ function mergeSystemPrompts(primary, secondary) {
3949
4016
 
3950
4017
  `);
3951
4018
  }
4019
+ function prepareStructuredPromptPayload(payload, systemPrompt, schema, schemaInstruction) {
4020
+ if (Array.isArray(payload.messages) && payload.messages.length > 0) {
4021
+ const messages = payload.messages.map((message) => ({ ...message }));
4022
+ const mergedSystemPrompt = mergeSystemPrompts(payload.systemPrompt, systemPrompt);
4023
+ const systemMessages = mergedSystemPrompt ? [{ role: "system", content: mergedSystemPrompt }] : [];
4024
+ return {
4025
+ messages: injectStructuredFormatIntoMessages([...systemMessages, ...messages], schema, schemaInstruction)
4026
+ };
4027
+ }
4028
+ const resolvedPrompt = payload.prompt?.trim();
4029
+ if (!resolvedPrompt) {
4030
+ throw new Error("Structured prompt payload must include a non-empty prompt or messages.");
4031
+ }
4032
+ return {
4033
+ prompt: shouldInjectFormat(resolvedPrompt, schemaInstruction) ? formatPrompt(schema, resolvedPrompt, {
4034
+ schemaInstruction
4035
+ }) : resolvedPrompt,
4036
+ systemPrompt: mergeSystemPrompts(payload.systemPrompt, systemPrompt)
4037
+ };
4038
+ }
4039
+ function injectStructuredFormatIntoMessages(messages, schema, schemaInstruction) {
4040
+ const lastUserIndex = findLastUserMessageIndex(messages);
4041
+ if (lastUserIndex === -1) {
4042
+ throw new Error("Structured prompts with messages must include at least one user message.");
4043
+ }
4044
+ const target = messages[lastUserIndex];
4045
+ const content = typeof target?.content === "string" ? target.content.trim() : stringifyPromptContent(target?.content);
4046
+ const formatted = shouldInjectFormat(content, schemaInstruction) ? formatPrompt(schema, content, { schemaInstruction }) : content.trim();
4047
+ return messages.map((message, index) => index === lastUserIndex ? {
4048
+ ...message,
4049
+ content: formatted
4050
+ } : message);
4051
+ }
4052
+ function findLastUserMessageIndex(messages) {
4053
+ for (let index = messages.length - 1;index >= 0; index -= 1) {
4054
+ if (messages[index]?.role === "user") {
4055
+ return index;
4056
+ }
4057
+ }
4058
+ return -1;
4059
+ }
4060
+ function stringifyPromptContent(content) {
4061
+ if (typeof content === "string") {
4062
+ return content;
4063
+ }
4064
+ if (content === null || content === undefined) {
4065
+ return "";
4066
+ }
4067
+ try {
4068
+ return JSON.stringify(content, null, 2) ?? "";
4069
+ } catch {
4070
+ return String(content);
4071
+ }
4072
+ }
3952
4073
  function shouldInjectFormat(prompt, schemaInstruction) {
3953
4074
  const instruction = resolveSchemaInstruction(schemaInstruction);
3954
4075
  return !prompt.trimStart().startsWith(instruction);
@@ -4127,6 +4248,7 @@ function normalizeDebugConfig(option) {
4127
4248
  async function executeAttempt(adapter, input) {
4128
4249
  const response = await callModel(adapter, {
4129
4250
  prompt: input.prompt,
4251
+ messages: input.messages,
4130
4252
  systemPrompt: input.systemPrompt,
4131
4253
  request: input.request,
4132
4254
  stream: input.stream,
@@ -4164,6 +4286,7 @@ async function executeAttempt(adapter, input) {
4164
4286
  async function callModel(adapter, options) {
4165
4287
  const requestPayload = {
4166
4288
  prompt: options.prompt,
4289
+ messages: options.messages,
4167
4290
  systemPrompt: options.systemPrompt,
4168
4291
  temperature: options.request?.temperature,
4169
4292
  maxTokens: options.request?.maxTokens,
@@ -4173,7 +4296,8 @@ async function callModel(adapter, options) {
4173
4296
  maxToolRounds: options.request?.maxToolRounds,
4174
4297
  onToolExecution: options.request?.onToolExecution,
4175
4298
  toolDebug: options.request?.toolDebug,
4176
- body: options.request?.body
4299
+ body: options.request?.body,
4300
+ signal: options.request?.signal
4177
4301
  };
4178
4302
  emitDebugRequest(options.debug, {
4179
4303
  provider: adapter.provider,
@@ -4473,6 +4597,7 @@ function emitObserve(observe, event) {
4473
4597
  }
4474
4598
  function emitDebugRequest(config, input) {
4475
4599
  const requestBody = input.requestPayload.body !== undefined ? JSON.stringify(input.requestPayload.body, null, 2) : "(none)";
4600
+ const requestMessages = input.requestPayload.messages !== undefined ? JSON.stringify(input.requestPayload.messages, null, 2) : "(none)";
4476
4601
  const lines = [
4477
4602
  color(config, title(config, [
4478
4603
  "[structured][request]",
@@ -4486,7 +4611,9 @@ function emitDebugRequest(config, input) {
4486
4611
  `stream=${input.stream}`
4487
4612
  ].join(" ")),
4488
4613
  color(config, "prompt:", "yellow"),
4489
- input.requestPayload.prompt,
4614
+ input.requestPayload.prompt ?? "(none)",
4615
+ color(config, "messages:", "yellow"),
4616
+ requestMessages,
4490
4617
  color(config, "systemPrompt:", "yellow"),
4491
4618
  input.requestPayload.systemPrompt ?? "(none)",
4492
4619
  color(config, "request.body:", "yellow"),
@@ -4707,35 +4834,28 @@ function toPromptMessage(input, values) {
4707
4834
  }
4708
4835
  return renderPromptTemplate(input, values);
4709
4836
  }
4710
- function joinMessages(messages) {
4711
- return messages.join(`
4712
-
4713
- `);
4714
- }
4715
4837
 
4716
4838
  class PromptMessageBuilderImpl {
4717
- systemMessages = [];
4718
- userMessages = [];
4839
+ messages = [];
4719
4840
  system(input, ...values) {
4720
- const message = toPromptMessage(input, values);
4721
- if (message.length > 0) {
4722
- this.systemMessages.push(message);
4723
- }
4724
- return this;
4841
+ return this.pushMessage("system", input, values);
4725
4842
  }
4726
4843
  user(input, ...values) {
4844
+ return this.pushMessage("user", input, values);
4845
+ }
4846
+ assistant(input, ...values) {
4847
+ return this.pushMessage("assistant", input, values);
4848
+ }
4849
+ pushMessage(role, input, values) {
4727
4850
  const message = toPromptMessage(input, values);
4728
4851
  if (message.length > 0) {
4729
- this.userMessages.push(message);
4852
+ this.messages.push({ role, content: message });
4730
4853
  }
4731
4854
  return this;
4732
4855
  }
4733
4856
  build() {
4734
- const prompt = joinMessages(this.userMessages);
4735
- const systemPrompt = joinMessages(this.systemMessages);
4736
4857
  return {
4737
- prompt,
4738
- systemPrompt: systemPrompt.length > 0 ? systemPrompt : undefined
4858
+ messages: this.messages.map((message) => ({ ...message }))
4739
4859
  };
4740
4860
  }
4741
4861
  resolvePrompt(_context) {
@@ -4845,8 +4965,8 @@ function inferSchemaExample(schema) {
4845
4965
  }
4846
4966
  function getObjectShape(schema) {
4847
4967
  const unwrapped = unwrap2(schema).schema;
4848
- const typeName = unwrapped._def?.typeName;
4849
- if (typeName !== "ZodObject") {
4968
+ const typeName = unwrapped._def?.type;
4969
+ if (typeName !== "object") {
4850
4970
  return null;
4851
4971
  }
4852
4972
  const rawShape = unwrapped._def?.shape;
@@ -4857,33 +4977,25 @@ function getObjectShape(schema) {
4857
4977
  }
4858
4978
  function readDefaultValue(schema) {
4859
4979
  let current = schema;
4860
- while (current?._def?.typeName) {
4861
- const typeName = current._def.typeName;
4862
- if (typeName === "ZodDefault") {
4863
- const raw = current._def.defaultValue;
4864
- if (typeof raw === "function") {
4865
- try {
4980
+ while (current?._def?.type) {
4981
+ const typeName = current._def.type;
4982
+ if (typeName === "default") {
4983
+ try {
4984
+ const raw = current._def.defaultValue;
4985
+ if (typeof raw === "function") {
4866
4986
  return raw();
4867
- } catch {
4868
- return;
4869
4987
  }
4988
+ return raw;
4989
+ } catch {
4990
+ return;
4870
4991
  }
4871
- return raw;
4872
4992
  }
4873
- if (typeName === "ZodOptional" || typeName === "ZodNullable" || typeName === "ZodCatch" || typeName === "ZodReadonly") {
4993
+ if (typeName === "optional" || typeName === "nullable" || typeName === "catch" || typeName === "readonly") {
4874
4994
  current = current._def.innerType ?? current;
4875
4995
  continue;
4876
4996
  }
4877
- if (typeName === "ZodEffects") {
4878
- current = current._def.schema ?? current;
4879
- continue;
4880
- }
4881
- if (typeName === "ZodBranded") {
4882
- current = current._def.type ?? current;
4883
- continue;
4884
- }
4885
- if (typeName === "ZodPipeline") {
4886
- current = current._def.out ?? current;
4997
+ if (typeName === "pipe") {
4998
+ current = current._def.in ?? current;
4887
4999
  continue;
4888
5000
  }
4889
5001
  return;
@@ -4892,34 +5004,22 @@ function readDefaultValue(schema) {
4892
5004
  }
4893
5005
  function readSchemaDescription2(schema) {
4894
5006
  let current = schema;
4895
- while (current?._def?.typeName) {
4896
- const raw = current._def.description;
4897
- if (typeof raw === "string" && raw.trim().length > 0) {
4898
- return raw.trim();
4899
- }
4900
- const fallback = current.description;
4901
- if (typeof fallback === "string" && fallback.trim().length > 0) {
4902
- return fallback.trim();
5007
+ while (current?._def?.type) {
5008
+ const desc = current.description;
5009
+ if (typeof desc === "string" && desc.trim().length > 0) {
5010
+ return desc.trim();
4903
5011
  }
4904
- const typeName = current._def.typeName;
4905
- if (typeName === "ZodOptional" || typeName === "ZodDefault" || typeName === "ZodNullable") {
5012
+ const typeName = current._def.type;
5013
+ if (typeName === "optional" || typeName === "default" || typeName === "nullable") {
4906
5014
  current = current._def.innerType ?? current;
4907
5015
  continue;
4908
5016
  }
4909
- if (typeName === "ZodCatch" || typeName === "ZodReadonly") {
5017
+ if (typeName === "catch" || typeName === "readonly") {
4910
5018
  current = current._def.innerType ?? current;
4911
5019
  continue;
4912
5020
  }
4913
- if (typeName === "ZodEffects") {
4914
- current = current._def.schema ?? current;
4915
- continue;
4916
- }
4917
- if (typeName === "ZodBranded") {
4918
- current = current._def.type ?? current;
4919
- continue;
4920
- }
4921
- if (typeName === "ZodPipeline") {
4922
- current = current._def.out ?? current;
5021
+ if (typeName === "pipe") {
5022
+ current = current._def.in ?? current;
4923
5023
  continue;
4924
5024
  }
4925
5025
  break;
@@ -4929,27 +5029,19 @@ function readSchemaDescription2(schema) {
4929
5029
  function unwrap2(schema) {
4930
5030
  let current = schema;
4931
5031
  let optional = false;
4932
- while (current?._def?.typeName) {
4933
- const typeName = current._def.typeName;
4934
- if (typeName === "ZodOptional" || typeName === "ZodDefault") {
5032
+ while (current?._def?.type) {
5033
+ const typeName = current._def.type;
5034
+ if (typeName === "optional" || typeName === "default") {
4935
5035
  optional = true;
4936
5036
  current = current._def.innerType ?? current;
4937
5037
  continue;
4938
5038
  }
4939
- if (typeName === "ZodNullable" || typeName === "ZodCatch" || typeName === "ZodReadonly") {
5039
+ if (typeName === "nullable" || typeName === "catch" || typeName === "readonly") {
4940
5040
  current = current._def.innerType ?? current;
4941
5041
  continue;
4942
5042
  }
4943
- if (typeName === "ZodEffects") {
4944
- current = current._def.schema ?? current;
4945
- continue;
4946
- }
4947
- if (typeName === "ZodBranded") {
4948
- current = current._def.type ?? current;
4949
- continue;
4950
- }
4951
- if (typeName === "ZodPipeline") {
4952
- current = current._def.out ?? current;
5043
+ if (typeName === "pipe") {
5044
+ current = current._def.in ?? current;
4953
5045
  continue;
4954
5046
  }
4955
5047
  break;