@caupulican/pi-agent-core 0.93.1 → 0.93.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.
Files changed (38) hide show
  1. package/dist/agent-loop.d.ts.map +1 -1
  2. package/dist/agent-loop.js +10 -8
  3. package/dist/agent-loop.js.map +1 -1
  4. package/dist/agent.d.ts +1 -1
  5. package/dist/agent.d.ts.map +1 -1
  6. package/dist/agent.js +2 -2
  7. package/dist/agent.js.map +1 -1
  8. package/dist/compaction/compaction.d.ts.map +1 -1
  9. package/dist/compaction/compaction.js +1 -1
  10. package/dist/compaction/compaction.js.map +1 -1
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/provider-request-estimator.d.ts +9 -3
  16. package/dist/provider-request-estimator.d.ts.map +1 -1
  17. package/dist/provider-request-estimator.js +75 -14
  18. package/dist/provider-request-estimator.js.map +1 -1
  19. package/dist/provider-request-image-budget.d.ts +30 -0
  20. package/dist/provider-request-image-budget.d.ts.map +1 -0
  21. package/dist/provider-request-image-budget.js +194 -0
  22. package/dist/provider-request-image-budget.js.map +1 -0
  23. package/dist/provider-request-planner.d.ts.map +1 -1
  24. package/dist/provider-request-planner.js +6 -1
  25. package/dist/provider-request-planner.js.map +1 -1
  26. package/dist/tool-failure-memory.d.ts +2 -0
  27. package/dist/tool-failure-memory.d.ts.map +1 -1
  28. package/dist/tool-failure-memory.js +14 -0
  29. package/dist/tool-failure-memory.js.map +1 -1
  30. package/dist/tool-failure-recovery-gate.d.ts +17 -8
  31. package/dist/tool-failure-recovery-gate.d.ts.map +1 -1
  32. package/dist/tool-failure-recovery-gate.js +162 -121
  33. package/dist/tool-failure-recovery-gate.js.map +1 -1
  34. package/dist/types.d.ts +12 -9
  35. package/dist/types.d.ts.map +1 -1
  36. package/dist/types.js +2 -2
  37. package/dist/types.js.map +1 -1
  38. package/package.json +7 -2
@@ -1,6 +1,11 @@
1
+ import { projectMessagesForModelImageSupport } from "@caupulican/pi-ai";
1
2
  const CHARS_PER_TOKEN_ESTIMATE = 4;
2
- function jsonStringLength(value) {
3
+ export const ESTIMATED_IMAGE_TOKENS = 1_200;
4
+ export const ESTIMATED_IMAGE_CHARS = ESTIMATED_IMAGE_TOKENS * CHARS_PER_TOKEN_ESTIMATE;
5
+ function measureJsonString(value, utf8, maximumLength) {
3
6
  let length = 2;
7
+ if (length > maximumLength)
8
+ return maximumLength + 1;
4
9
  for (let index = 0; index < value.length; index++) {
5
10
  const code = value.charCodeAt(index);
6
11
  if (code === 0x22 ||
@@ -18,7 +23,7 @@ function jsonStringLength(value) {
18
23
  else if (code >= 0xd800 && code <= 0xdbff) {
19
24
  const next = value.charCodeAt(index + 1);
20
25
  if (next >= 0xdc00 && next <= 0xdfff) {
21
- length += 2;
26
+ length += utf8 ? 4 : 2;
22
27
  index++;
23
28
  }
24
29
  else {
@@ -28,13 +33,28 @@ function jsonStringLength(value) {
28
33
  else if (code >= 0xdc00 && code <= 0xdfff) {
29
34
  length += 6;
30
35
  }
31
- else {
36
+ else if (!utf8 || code <= 0x7f) {
32
37
  length++;
33
38
  }
39
+ else if (code <= 0x7ff) {
40
+ length += 2;
41
+ }
42
+ else {
43
+ length += 3;
44
+ }
45
+ if (length > maximumLength)
46
+ return maximumLength + 1;
34
47
  }
35
48
  return length;
36
49
  }
37
- function measuredJsonValue(value, key, active) {
50
+ function jsonStringUtf16Length(value) {
51
+ return measureJsonString(value, false, Number.POSITIVE_INFINITY);
52
+ }
53
+ /** Exact UTF-8 byte length of a JSON string, or `maximumBytes + 1` once its bound is exceeded. */
54
+ export function measureJsonStringUtf8Bytes(value, maximumBytes = Number.POSITIVE_INFINITY) {
55
+ return measureJsonString(value, true, maximumBytes);
56
+ }
57
+ function measuredJsonValue(value, key, active, measureString) {
38
58
  if (typeof value === "object" && value !== null) {
39
59
  const toJSON = Reflect.get(value, "toJSON");
40
60
  if (typeof toJSON === "function")
@@ -42,7 +62,7 @@ function measuredJsonValue(value, key, active) {
42
62
  }
43
63
  switch (typeof value) {
44
64
  case "string":
45
- return jsonStringLength(value);
65
+ return measureString(value);
46
66
  case "number":
47
67
  return Number.isFinite(value) ? (Object.is(value, -0) ? 1 : String(value).length) : 4;
48
68
  case "boolean":
@@ -59,7 +79,7 @@ function measuredJsonValue(value, key, active) {
59
79
  if (value === null)
60
80
  return 4;
61
81
  if (value instanceof String || value instanceof Number || value instanceof Boolean) {
62
- return measuredJsonValue(value.valueOf(), key, active);
82
+ return measuredJsonValue(value.valueOf(), key, active, measureString);
63
83
  }
64
84
  if (active.has(value))
65
85
  throw new TypeError("Converting circular structure to JSON");
@@ -68,19 +88,19 @@ function measuredJsonValue(value, key, active) {
68
88
  if (Array.isArray(value)) {
69
89
  let length = 2 + Math.max(0, value.length - 1);
70
90
  for (let index = 0; index < value.length; index++) {
71
- length += measuredJsonValue(value[index], String(index), active) ?? 4;
91
+ length += measuredJsonValue(value[index], String(index), active, measureString) ?? 4;
72
92
  }
73
93
  return length;
74
94
  }
75
95
  let length = 2;
76
96
  let fields = 0;
77
97
  for (const field of Object.keys(value)) {
78
- const fieldLength = measuredJsonValue(Reflect.get(value, field), field, active);
98
+ const fieldLength = measuredJsonValue(Reflect.get(value, field), field, active, measureString);
79
99
  if (fieldLength === undefined)
80
100
  continue;
81
101
  if (fields > 0)
82
102
  length++;
83
- length += jsonStringLength(field) + 1 + fieldLength;
103
+ length += measureString(field) + 1 + fieldLength;
84
104
  fields++;
85
105
  }
86
106
  return length;
@@ -91,15 +111,56 @@ function measuredJsonValue(value, key, active) {
91
111
  }
92
112
  /** Exact UTF-16 length of standard JSON-compatible data without allocating its serialized copy. */
93
113
  export function measureJsonLength(value) {
94
- return measuredJsonValue(value, "", new Set());
114
+ return measuredJsonValue(value, "", new Set(), jsonStringUtf16Length);
115
+ }
116
+ /** Exact UTF-8 byte length of standard JSON-compatible data without allocating its serialized copy. */
117
+ export function measureJsonUtf8Bytes(value) {
118
+ return measuredJsonValue(value, "", new Set(), measureJsonStringUtf8Bytes);
95
119
  }
96
- /** Bounded planning estimate over the complete, already-materialized provider Context. */
97
- export function estimateProviderRequestTokens(context) {
120
+ function semanticImageContent(content, addImageChars) {
121
+ let changed = false;
122
+ const projected = content.map((block) => {
123
+ if (block.type !== "image")
124
+ return block;
125
+ changed = true;
126
+ addImageChars();
127
+ return { type: "image", data: "", mimeType: block.mimeType };
128
+ });
129
+ return changed ? projected : content;
130
+ }
131
+ function semanticMessages(messages, addImageChars) {
132
+ let changed = false;
133
+ const projected = messages.map((message) => {
134
+ if (message.role === "user" && Array.isArray(message.content)) {
135
+ const content = semanticImageContent(message.content, addImageChars);
136
+ if (content === message.content)
137
+ return message;
138
+ changed = true;
139
+ return { ...message, content };
140
+ }
141
+ if (message.role === "toolResult") {
142
+ const content = semanticImageContent(message.content, addImageChars);
143
+ if (content === message.content)
144
+ return message;
145
+ changed = true;
146
+ return { ...message, content };
147
+ }
148
+ return message;
149
+ });
150
+ return changed ? projected : messages;
151
+ }
152
+ /** Bounded semantic planning estimate over the complete, already-materialized provider Context. */
153
+ export function estimateProviderRequestTokens(context, model) {
154
+ let imageChars = 0;
155
+ const imageAwareMessages = model ? projectMessagesForModelImageSupport(context.messages, model) : context.messages;
156
+ const messages = semanticMessages(imageAwareMessages, () => {
157
+ imageChars += ESTIMATED_IMAGE_CHARS;
158
+ });
98
159
  const serializedLength = measureJsonLength({
99
160
  systemPrompt: context.systemPrompt,
100
- messages: context.messages,
161
+ messages,
101
162
  tools: context.tools,
102
163
  });
103
- return serializedLength === undefined ? 0 : Math.ceil(serializedLength / CHARS_PER_TOKEN_ESTIMATE);
164
+ return serializedLength === undefined ? 0 : Math.ceil((serializedLength + imageChars) / CHARS_PER_TOKEN_ESTIMATE);
104
165
  }
105
166
  //# sourceMappingURL=provider-request-estimator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider-request-estimator.js","sourceRoot":"","sources":["../src/provider-request-estimator.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from \"@caupulican/pi-ai/types\";\n\nconst CHARS_PER_TOKEN_ESTIMATE = 4;\n\nfunction jsonStringLength(value: string): number {\n\tlet length = 2;\n\tfor (let index = 0; index < value.length; index++) {\n\t\tconst code = value.charCodeAt(index);\n\t\tif (\n\t\t\tcode === 0x22 ||\n\t\t\tcode === 0x5c ||\n\t\t\tcode === 0x08 ||\n\t\t\tcode === 0x09 ||\n\t\t\tcode === 0x0a ||\n\t\t\tcode === 0x0c ||\n\t\t\tcode === 0x0d\n\t\t) {\n\t\t\tlength += 2;\n\t\t} else if (code < 0x20) {\n\t\t\tlength += 6;\n\t\t} else if (code >= 0xd800 && code <= 0xdbff) {\n\t\t\tconst next = value.charCodeAt(index + 1);\n\t\t\tif (next >= 0xdc00 && next <= 0xdfff) {\n\t\t\t\tlength += 2;\n\t\t\t\tindex++;\n\t\t\t} else {\n\t\t\t\tlength += 6;\n\t\t\t}\n\t\t} else if (code >= 0xdc00 && code <= 0xdfff) {\n\t\t\tlength += 6;\n\t\t} else {\n\t\t\tlength++;\n\t\t}\n\t}\n\treturn length;\n}\n\nfunction measuredJsonValue(value: unknown, key: string, active: Set<object>): number | undefined {\n\tif (typeof value === \"object\" && value !== null) {\n\t\tconst toJSON = Reflect.get(value, \"toJSON\");\n\t\tif (typeof toJSON === \"function\") value = Reflect.apply(toJSON, value, [key]) as unknown;\n\t}\n\n\tswitch (typeof value) {\n\t\tcase \"string\":\n\t\t\treturn jsonStringLength(value);\n\t\tcase \"number\":\n\t\t\treturn Number.isFinite(value) ? (Object.is(value, -0) ? 1 : String(value).length) : 4;\n\t\tcase \"boolean\":\n\t\t\treturn value ? 4 : 5;\n\t\tcase \"bigint\":\n\t\t\tthrow new TypeError(\"Do not know how to serialize a BigInt\");\n\t\tcase \"undefined\":\n\t\tcase \"function\":\n\t\tcase \"symbol\":\n\t\t\treturn undefined;\n\t\tcase \"object\":\n\t\t\tbreak;\n\t}\n\n\tif (value === null) return 4;\n\tif (value instanceof String || value instanceof Number || value instanceof Boolean) {\n\t\treturn measuredJsonValue(value.valueOf(), key, active);\n\t}\n\tif (active.has(value)) throw new TypeError(\"Converting circular structure to JSON\");\n\tactive.add(value);\n\ttry {\n\t\tif (Array.isArray(value)) {\n\t\t\tlet length = 2 + Math.max(0, value.length - 1);\n\t\t\tfor (let index = 0; index < value.length; index++) {\n\t\t\t\tlength += measuredJsonValue(value[index], String(index), active) ?? 4;\n\t\t\t}\n\t\t\treturn length;\n\t\t}\n\n\t\tlet length = 2;\n\t\tlet fields = 0;\n\t\tfor (const field of Object.keys(value)) {\n\t\t\tconst fieldLength = measuredJsonValue(Reflect.get(value, field), field, active);\n\t\t\tif (fieldLength === undefined) continue;\n\t\t\tif (fields > 0) length++;\n\t\t\tlength += jsonStringLength(field) + 1 + fieldLength;\n\t\t\tfields++;\n\t\t}\n\t\treturn length;\n\t} finally {\n\t\tactive.delete(value);\n\t}\n}\n\n/** Exact UTF-16 length of standard JSON-compatible data without allocating its serialized copy. */\nexport function measureJsonLength(value: unknown): number | undefined {\n\treturn measuredJsonValue(value, \"\", new Set());\n}\n\n/** Bounded planning estimate over the complete, already-materialized provider Context. */\nexport function estimateProviderRequestTokens(context: Context): number {\n\tconst serializedLength = measureJsonLength({\n\t\tsystemPrompt: context.systemPrompt,\n\t\tmessages: context.messages,\n\t\ttools: context.tools,\n\t});\n\treturn serializedLength === undefined ? 0 : Math.ceil(serializedLength / CHARS_PER_TOKEN_ESTIMATE);\n}\n"]}
1
+ {"version":3,"file":"provider-request-estimator.js","sourceRoot":"","sources":["../src/provider-request-estimator.ts"],"names":[],"mappings":"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","sourcesContent":["import { projectMessagesForModelImageSupport } from \"@caupulican/pi-ai\";\nimport type { Api, Context, ImageContent, Message, Model, TextContent } from \"@caupulican/pi-ai/types\";\n\nconst CHARS_PER_TOKEN_ESTIMATE = 4;\nexport const ESTIMATED_IMAGE_TOKENS = 1_200;\nexport const ESTIMATED_IMAGE_CHARS = ESTIMATED_IMAGE_TOKENS * CHARS_PER_TOKEN_ESTIMATE;\n\ntype JsonStringMeasure = (value: string) => number;\n\nfunction measureJsonString(value: string, utf8: boolean, maximumLength: number): number {\n\tlet length = 2;\n\tif (length > maximumLength) return maximumLength + 1;\n\tfor (let index = 0; index < value.length; index++) {\n\t\tconst code = value.charCodeAt(index);\n\t\tif (\n\t\t\tcode === 0x22 ||\n\t\t\tcode === 0x5c ||\n\t\t\tcode === 0x08 ||\n\t\t\tcode === 0x09 ||\n\t\t\tcode === 0x0a ||\n\t\t\tcode === 0x0c ||\n\t\t\tcode === 0x0d\n\t\t) {\n\t\t\tlength += 2;\n\t\t} else if (code < 0x20) {\n\t\t\tlength += 6;\n\t\t} else if (code >= 0xd800 && code <= 0xdbff) {\n\t\t\tconst next = value.charCodeAt(index + 1);\n\t\t\tif (next >= 0xdc00 && next <= 0xdfff) {\n\t\t\t\tlength += utf8 ? 4 : 2;\n\t\t\t\tindex++;\n\t\t\t} else {\n\t\t\t\tlength += 6;\n\t\t\t}\n\t\t} else if (code >= 0xdc00 && code <= 0xdfff) {\n\t\t\tlength += 6;\n\t\t} else if (!utf8 || code <= 0x7f) {\n\t\t\tlength++;\n\t\t} else if (code <= 0x7ff) {\n\t\t\tlength += 2;\n\t\t} else {\n\t\t\tlength += 3;\n\t\t}\n\t\tif (length > maximumLength) return maximumLength + 1;\n\t}\n\treturn length;\n}\n\nfunction jsonStringUtf16Length(value: string): number {\n\treturn measureJsonString(value, false, Number.POSITIVE_INFINITY);\n}\n\n/** Exact UTF-8 byte length of a JSON string, or `maximumBytes + 1` once its bound is exceeded. */\nexport function measureJsonStringUtf8Bytes(value: string, maximumBytes = Number.POSITIVE_INFINITY): number {\n\treturn measureJsonString(value, true, maximumBytes);\n}\n\nfunction measuredJsonValue(\n\tvalue: unknown,\n\tkey: string,\n\tactive: Set<object>,\n\tmeasureString: JsonStringMeasure,\n): number | undefined {\n\tif (typeof value === \"object\" && value !== null) {\n\t\tconst toJSON = Reflect.get(value, \"toJSON\");\n\t\tif (typeof toJSON === \"function\") value = Reflect.apply(toJSON, value, [key]) as unknown;\n\t}\n\n\tswitch (typeof value) {\n\t\tcase \"string\":\n\t\t\treturn measureString(value);\n\t\tcase \"number\":\n\t\t\treturn Number.isFinite(value) ? (Object.is(value, -0) ? 1 : String(value).length) : 4;\n\t\tcase \"boolean\":\n\t\t\treturn value ? 4 : 5;\n\t\tcase \"bigint\":\n\t\t\tthrow new TypeError(\"Do not know how to serialize a BigInt\");\n\t\tcase \"undefined\":\n\t\tcase \"function\":\n\t\tcase \"symbol\":\n\t\t\treturn undefined;\n\t\tcase \"object\":\n\t\t\tbreak;\n\t}\n\n\tif (value === null) return 4;\n\tif (value instanceof String || value instanceof Number || value instanceof Boolean) {\n\t\treturn measuredJsonValue(value.valueOf(), key, active, measureString);\n\t}\n\tif (active.has(value)) throw new TypeError(\"Converting circular structure to JSON\");\n\tactive.add(value);\n\ttry {\n\t\tif (Array.isArray(value)) {\n\t\t\tlet length = 2 + Math.max(0, value.length - 1);\n\t\t\tfor (let index = 0; index < value.length; index++) {\n\t\t\t\tlength += measuredJsonValue(value[index], String(index), active, measureString) ?? 4;\n\t\t\t}\n\t\t\treturn length;\n\t\t}\n\n\t\tlet length = 2;\n\t\tlet fields = 0;\n\t\tfor (const field of Object.keys(value)) {\n\t\t\tconst fieldLength = measuredJsonValue(Reflect.get(value, field), field, active, measureString);\n\t\t\tif (fieldLength === undefined) continue;\n\t\t\tif (fields > 0) length++;\n\t\t\tlength += measureString(field) + 1 + fieldLength;\n\t\t\tfields++;\n\t\t}\n\t\treturn length;\n\t} finally {\n\t\tactive.delete(value);\n\t}\n}\n\n/** Exact UTF-16 length of standard JSON-compatible data without allocating its serialized copy. */\nexport function measureJsonLength(value: unknown): number | undefined {\n\treturn measuredJsonValue(value, \"\", new Set(), jsonStringUtf16Length);\n}\n\n/** Exact UTF-8 byte length of standard JSON-compatible data without allocating its serialized copy. */\nexport function measureJsonUtf8Bytes(value: unknown): number | undefined {\n\treturn measuredJsonValue(value, \"\", new Set(), measureJsonStringUtf8Bytes);\n}\n\nfunction semanticImageContent(\n\tcontent: (TextContent | ImageContent)[],\n\taddImageChars: () => void,\n): (TextContent | ImageContent)[] {\n\tlet changed = false;\n\tconst projected = content.map((block) => {\n\t\tif (block.type !== \"image\") return block;\n\t\tchanged = true;\n\t\taddImageChars();\n\t\treturn { type: \"image\" as const, data: \"\", mimeType: block.mimeType };\n\t});\n\treturn changed ? projected : content;\n}\n\nfunction semanticMessages(messages: Message[], addImageChars: () => void): Message[] {\n\tlet changed = false;\n\tconst projected = messages.map((message) => {\n\t\tif (message.role === \"user\" && Array.isArray(message.content)) {\n\t\t\tconst content = semanticImageContent(message.content, addImageChars);\n\t\t\tif (content === message.content) return message;\n\t\t\tchanged = true;\n\t\t\treturn { ...message, content };\n\t\t}\n\t\tif (message.role === \"toolResult\") {\n\t\t\tconst content = semanticImageContent(message.content, addImageChars);\n\t\t\tif (content === message.content) return message;\n\t\t\tchanged = true;\n\t\t\treturn { ...message, content };\n\t\t}\n\t\treturn message;\n\t});\n\treturn changed ? projected : messages;\n}\n\n/** Bounded semantic planning estimate over the complete, already-materialized provider Context. */\nexport function estimateProviderRequestTokens(context: Context, model?: Model<Api>): number {\n\tlet imageChars = 0;\n\tconst imageAwareMessages = model ? projectMessagesForModelImageSupport(context.messages, model) : context.messages;\n\tconst messages = semanticMessages(imageAwareMessages, () => {\n\t\timageChars += ESTIMATED_IMAGE_CHARS;\n\t});\n\tconst serializedLength = measureJsonLength({\n\t\tsystemPrompt: context.systemPrompt,\n\t\tmessages,\n\t\ttools: context.tools,\n\t});\n\treturn serializedLength === undefined ? 0 : Math.ceil((serializedLength + imageChars) / CHARS_PER_TOKEN_ESTIMATE);\n}\n"]}
@@ -0,0 +1,30 @@
1
+ import type { Api, Context, Model } from "@caupulican/pi-ai/types";
2
+ export declare const USER_IMAGE_BUDGET_PLACEHOLDER = "[An earlier image was removed to keep the request within its size limit and is no longer visible. Do not describe or reason about its contents from memory; ask the user to re-share it if you need to see it again.]";
3
+ export declare const TOOL_IMAGE_BUDGET_NOTE = "[One or more images from this tool result were removed to keep the request within its size limit and are no longer visible. Do not describe or reason about their contents from memory.]";
4
+ export interface ProviderRequestImageBudgetPolicy {
5
+ readonly hardLimitBytes: number;
6
+ readonly triggerBytes: number;
7
+ readonly reclaimTargetBytes: number;
8
+ }
9
+ export declare const XAI_PROVIDER_REQUEST_IMAGE_BUDGET: ProviderRequestImageBudgetPolicy;
10
+ export declare const BEDROCK_PROVIDER_REQUEST_IMAGE_BUDGET: ProviderRequestImageBudgetPolicy;
11
+ /** Safe provider-neutral ceiling for APIs without a tighter transport-specific policy. */
12
+ export declare const GENERIC_PROVIDER_REQUEST_IMAGE_BUDGET: ProviderRequestImageBudgetPolicy;
13
+ export interface ProviderRequestImageBudgetOutcome extends ProviderRequestImageBudgetPolicy {
14
+ bodyBytes: number;
15
+ bodyBytesAfter: number;
16
+ inlineImages: number;
17
+ needsImageCompaction: boolean;
18
+ evicted: number;
19
+ }
20
+ export interface BudgetedProviderRequestContext {
21
+ context: Context;
22
+ outcome?: ProviderRequestImageBudgetOutcome;
23
+ }
24
+ export declare function resolveProviderRequestImageBudget(model: Model<Api>): ProviderRequestImageBudgetPolicy;
25
+ /**
26
+ * Applies high-water/low-water image eviction to a request-local Context copy. Durable history is
27
+ * never mutated; evicted images are replaced with explicit anti-hallucination notices.
28
+ */
29
+ export declare function applyProviderRequestImageBudget(context: Context, model: Model<Api>, policy?: ProviderRequestImageBudgetPolicy): BudgetedProviderRequestContext;
30
+ //# sourceMappingURL=provider-request-image-budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-request-image-budget.d.ts","sourceRoot":"","sources":["../src/provider-request-image-budget.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAyB,KAAK,EAAe,MAAM,yBAAyB,CAAC;AAGvG,eAAO,MAAM,6BAA6B,0NAC8K,CAAC;AACzN,eAAO,MAAM,sBAAsB,6LACwJ,CAAC;AAI5L,MAAM,WAAW,gCAAgC;IAChD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACpC;AAED,eAAO,MAAM,iCAAiC,EAAE,gCAI9C,CAAC;AAEH,eAAO,MAAM,qCAAqC,EAAE,gCAIlD,CAAC;AAEH,0FAA0F;AAC1F,eAAO,MAAM,qCAAqC,EAAE,gCAIlD,CAAC;AAEH,MAAM,WAAW,iCAAkC,SAAQ,gCAAgC;IAC1F,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,8BAA8B;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,iCAAiC,CAAC;CAC5C;AAcD,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,gCAAgC,CAMrG;AAyFD;;;GAGG;AACH,wBAAgB,+BAA+B,CAC9C,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,MAAM,GAAE,gCAA2E,GACjF,8BAA8B,CA6EhC"}
@@ -0,0 +1,194 @@
1
+ import { projectMessagesForModelImageSupport } from "@caupulican/pi-ai";
2
+ import { measureJsonUtf8Bytes } from "./provider-request-estimator.js";
3
+ export const USER_IMAGE_BUDGET_PLACEHOLDER = "[An earlier image was removed to keep the request within its size limit and is no longer visible. Do not describe or reason about its contents from memory; ask the user to re-share it if you need to see it again.]";
4
+ export const TOOL_IMAGE_BUDGET_NOTE = "[One or more images from this tool result were removed to keep the request within its size limit and are no longer visible. Do not describe or reason about their contents from memory.]";
5
+ const MEBIBYTE = 1024 * 1024;
6
+ export const XAI_PROVIDER_REQUEST_IMAGE_BUDGET = Object.freeze({
7
+ hardLimitBytes: 50 * MEBIBYTE,
8
+ triggerBytes: 47 * MEBIBYTE,
9
+ reclaimTargetBytes: 25 * MEBIBYTE,
10
+ });
11
+ export const BEDROCK_PROVIDER_REQUEST_IMAGE_BUDGET = Object.freeze({
12
+ hardLimitBytes: 25_000_000,
13
+ triggerBytes: 22_000_000,
14
+ reclaimTargetBytes: 12_500_000,
15
+ });
16
+ /** Safe provider-neutral ceiling for APIs without a tighter transport-specific policy. */
17
+ export const GENERIC_PROVIDER_REQUEST_IMAGE_BUDGET = Object.freeze({
18
+ hardLimitBytes: 32 * MEBIBYTE,
19
+ triggerBytes: 29 * MEBIBYTE,
20
+ reclaimTargetBytes: 16 * MEBIBYTE,
21
+ });
22
+ export function resolveProviderRequestImageBudget(model) {
23
+ if (model.api === "bedrock-converse-stream" || model.provider === "amazon-bedrock") {
24
+ return BEDROCK_PROVIDER_REQUEST_IMAGE_BUDGET;
25
+ }
26
+ if (model.provider === "xai")
27
+ return XAI_PROVIDER_REQUEST_IMAGE_BUDGET;
28
+ return GENERIC_PROVIDER_REQUEST_IMAGE_BUDGET;
29
+ }
30
+ function validatePolicy(policy) {
31
+ if (!Number.isSafeInteger(policy.hardLimitBytes) ||
32
+ !Number.isSafeInteger(policy.triggerBytes) ||
33
+ !Number.isSafeInteger(policy.reclaimTargetBytes) ||
34
+ policy.reclaimTargetBytes < 0 ||
35
+ policy.reclaimTargetBytes >= policy.triggerBytes ||
36
+ policy.triggerBytes >= policy.hardLimitBytes) {
37
+ throw new TypeError("provider request image budget must satisfy 0 <= reclaim target < trigger < hard limit");
38
+ }
39
+ }
40
+ function measureContent(content, messageIndex, role, locations) {
41
+ let changed = false;
42
+ let dataBytes = 0;
43
+ const projected = content.map((block) => {
44
+ if (block.type !== "image")
45
+ return block;
46
+ changed = true;
47
+ // ImageContent.data is base64 by contract, so every code unit is one unescaped JSON byte.
48
+ const bytes = block.data.length;
49
+ const blank = { type: "image", data: "", mimeType: block.mimeType };
50
+ const blankBytes = measureJsonUtf8Bytes(blank);
51
+ if (blankBytes === undefined)
52
+ throw new TypeError("image content must be JSON serializable");
53
+ locations.push({ messageIndex, role, block, serializedBytes: blankBytes + bytes });
54
+ dataBytes += bytes;
55
+ return blank;
56
+ });
57
+ return { content: changed ? projected : content, dataBytes };
58
+ }
59
+ function measureContextImages(context) {
60
+ const locations = [];
61
+ let dataBytes = 0;
62
+ let changed = false;
63
+ const messages = context.messages.map((message, messageIndex) => {
64
+ if (message.role === "user" && Array.isArray(message.content)) {
65
+ const measured = measureContent(message.content, messageIndex, "user", locations);
66
+ dataBytes += measured.dataBytes;
67
+ if (measured.content === message.content)
68
+ return message;
69
+ changed = true;
70
+ return { ...message, content: measured.content };
71
+ }
72
+ if (message.role === "toolResult") {
73
+ const measured = measureContent(message.content, messageIndex, "toolResult", locations);
74
+ dataBytes += measured.dataBytes;
75
+ if (measured.content === message.content)
76
+ return message;
77
+ changed = true;
78
+ return { ...message, content: measured.content };
79
+ }
80
+ return message;
81
+ });
82
+ const blankBytes = measureJsonUtf8Bytes({
83
+ systemPrompt: context.systemPrompt,
84
+ messages: changed ? messages : context.messages,
85
+ tools: context.tools,
86
+ });
87
+ if (blankBytes === undefined)
88
+ throw new TypeError("provider request context must be JSON serializable");
89
+ return { bodyBytes: blankBytes + dataBytes, locations };
90
+ }
91
+ function cloneImageBearingMessages(messages) {
92
+ return messages.map((message) => {
93
+ if (message.role === "user" && Array.isArray(message.content)) {
94
+ return { ...message, content: message.content.slice() };
95
+ }
96
+ if (message.role === "toolResult")
97
+ return { ...message, content: message.content.slice() };
98
+ return message;
99
+ });
100
+ }
101
+ function hasInlineImages(messages) {
102
+ for (const message of messages) {
103
+ if (message.role === "user" && Array.isArray(message.content)) {
104
+ if (message.content.some((block) => block.type === "image"))
105
+ return true;
106
+ }
107
+ else if (message.role === "toolResult" && message.content.some((block) => block.type === "image")) {
108
+ return true;
109
+ }
110
+ }
111
+ return false;
112
+ }
113
+ /**
114
+ * Applies high-water/low-water image eviction to a request-local Context copy. Durable history is
115
+ * never mutated; evicted images are replaced with explicit anti-hallucination notices.
116
+ */
117
+ export function applyProviderRequestImageBudget(context, model, policy = resolveProviderRequestImageBudget(model)) {
118
+ validatePolicy(policy);
119
+ if (!hasInlineImages(context.messages))
120
+ return { context };
121
+ const projectedMessages = projectMessagesForModelImageSupport(context.messages, model);
122
+ const projectedContext = projectedMessages === context.messages ? context : { ...context, messages: projectedMessages };
123
+ if (!hasInlineImages(projectedMessages))
124
+ return { context: projectedContext };
125
+ const measurement = measureContextImages(projectedContext);
126
+ const needsImageCompaction = measurement.bodyBytes >= policy.triggerBytes;
127
+ if (!needsImageCompaction || measurement.bodyBytes <= policy.reclaimTargetBytes) {
128
+ return {
129
+ context: projectedContext,
130
+ outcome: {
131
+ ...policy,
132
+ bodyBytes: measurement.bodyBytes,
133
+ bodyBytesAfter: measurement.bodyBytes,
134
+ inlineImages: measurement.locations.length,
135
+ needsImageCompaction,
136
+ evicted: 0,
137
+ },
138
+ };
139
+ }
140
+ const messages = cloneImageBearingMessages(projectedContext.messages);
141
+ const budgetedContext = { ...projectedContext, messages };
142
+ const userPlaceholder = { type: "text", text: USER_IMAGE_BUDGET_PLACEHOLDER };
143
+ const toolNote = { type: "text", text: TOOL_IMAGE_BUDGET_NOTE };
144
+ const userPlaceholderBytes = measureJsonUtf8Bytes(userPlaceholder);
145
+ const toolNoteBytes = measureJsonUtf8Bytes(toolNote);
146
+ if (userPlaceholderBytes === undefined || toolNoteBytes === undefined) {
147
+ throw new TypeError("image budget placeholders must be JSON serializable");
148
+ }
149
+ let bodyBytesAfter = measurement.bodyBytes;
150
+ let evicted = 0;
151
+ for (const location of measurement.locations) {
152
+ if (bodyBytesAfter <= policy.reclaimTargetBytes)
153
+ break;
154
+ const message = messages[location.messageIndex];
155
+ if (location.role === "user") {
156
+ if (message?.role !== "user" || !Array.isArray(message.content)) {
157
+ throw new TypeError("provider request image location changed during budgeting");
158
+ }
159
+ const blockIndex = message.content.indexOf(location.block);
160
+ if (blockIndex < 0)
161
+ throw new TypeError("provider request user image disappeared during budgeting");
162
+ message.content[blockIndex] = userPlaceholder;
163
+ bodyBytesAfter -= location.serializedBytes - userPlaceholderBytes;
164
+ }
165
+ else {
166
+ if (message?.role !== "toolResult") {
167
+ throw new TypeError("provider request image location changed during budgeting");
168
+ }
169
+ const blockIndex = message.content.indexOf(location.block);
170
+ if (blockIndex < 0)
171
+ throw new TypeError("provider request tool image disappeared during budgeting");
172
+ const hasNote = message.content.some((block) => block.type === "text" && block.text === TOOL_IMAGE_BUDGET_NOTE);
173
+ if (!hasNote) {
174
+ bodyBytesAfter += toolNoteBytes + (message.content.length > 0 ? 1 : 0);
175
+ message.content.push(toolNote);
176
+ }
177
+ message.content.splice(blockIndex, 1);
178
+ bodyBytesAfter -= location.serializedBytes + 1;
179
+ }
180
+ evicted++;
181
+ }
182
+ return {
183
+ context: budgetedContext,
184
+ outcome: {
185
+ ...policy,
186
+ bodyBytes: measurement.bodyBytes,
187
+ bodyBytesAfter,
188
+ inlineImages: measurement.locations.length,
189
+ needsImageCompaction,
190
+ evicted,
191
+ },
192
+ };
193
+ }
194
+ //# sourceMappingURL=provider-request-image-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-request-image-budget.js","sourceRoot":"","sources":["../src/provider-request-image-budget.ts"],"names":[],"mappings":"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","sourcesContent":["import { projectMessagesForModelImageSupport } from \"@caupulican/pi-ai\";\nimport type { Api, Context, ImageContent, Message, Model, TextContent } from \"@caupulican/pi-ai/types\";\nimport { measureJsonUtf8Bytes } from \"./provider-request-estimator.ts\";\n\nexport const USER_IMAGE_BUDGET_PLACEHOLDER =\n\t\"[An earlier image was removed to keep the request within its size limit and is no longer visible. Do not describe or reason about its contents from memory; ask the user to re-share it if you need to see it again.]\";\nexport const TOOL_IMAGE_BUDGET_NOTE =\n\t\"[One or more images from this tool result were removed to keep the request within its size limit and are no longer visible. Do not describe or reason about their contents from memory.]\";\n\nconst MEBIBYTE = 1024 * 1024;\n\nexport interface ProviderRequestImageBudgetPolicy {\n\treadonly hardLimitBytes: number;\n\treadonly triggerBytes: number;\n\treadonly reclaimTargetBytes: number;\n}\n\nexport const XAI_PROVIDER_REQUEST_IMAGE_BUDGET: ProviderRequestImageBudgetPolicy = Object.freeze({\n\thardLimitBytes: 50 * MEBIBYTE,\n\ttriggerBytes: 47 * MEBIBYTE,\n\treclaimTargetBytes: 25 * MEBIBYTE,\n});\n\nexport const BEDROCK_PROVIDER_REQUEST_IMAGE_BUDGET: ProviderRequestImageBudgetPolicy = Object.freeze({\n\thardLimitBytes: 25_000_000,\n\ttriggerBytes: 22_000_000,\n\treclaimTargetBytes: 12_500_000,\n});\n\n/** Safe provider-neutral ceiling for APIs without a tighter transport-specific policy. */\nexport const GENERIC_PROVIDER_REQUEST_IMAGE_BUDGET: ProviderRequestImageBudgetPolicy = Object.freeze({\n\thardLimitBytes: 32 * MEBIBYTE,\n\ttriggerBytes: 29 * MEBIBYTE,\n\treclaimTargetBytes: 16 * MEBIBYTE,\n});\n\nexport interface ProviderRequestImageBudgetOutcome extends ProviderRequestImageBudgetPolicy {\n\tbodyBytes: number;\n\tbodyBytesAfter: number;\n\tinlineImages: number;\n\tneedsImageCompaction: boolean;\n\tevicted: number;\n}\n\nexport interface BudgetedProviderRequestContext {\n\tcontext: Context;\n\toutcome?: ProviderRequestImageBudgetOutcome;\n}\n\ninterface ImageLocation {\n\tmessageIndex: number;\n\trole: \"user\" | \"toolResult\";\n\tblock: ImageContent;\n\tserializedBytes: number;\n}\n\ninterface ContextImageMeasurement {\n\tbodyBytes: number;\n\tlocations: ImageLocation[];\n}\n\nexport function resolveProviderRequestImageBudget(model: Model<Api>): ProviderRequestImageBudgetPolicy {\n\tif (model.api === \"bedrock-converse-stream\" || model.provider === \"amazon-bedrock\") {\n\t\treturn BEDROCK_PROVIDER_REQUEST_IMAGE_BUDGET;\n\t}\n\tif (model.provider === \"xai\") return XAI_PROVIDER_REQUEST_IMAGE_BUDGET;\n\treturn GENERIC_PROVIDER_REQUEST_IMAGE_BUDGET;\n}\n\nfunction validatePolicy(policy: ProviderRequestImageBudgetPolicy): void {\n\tif (\n\t\t!Number.isSafeInteger(policy.hardLimitBytes) ||\n\t\t!Number.isSafeInteger(policy.triggerBytes) ||\n\t\t!Number.isSafeInteger(policy.reclaimTargetBytes) ||\n\t\tpolicy.reclaimTargetBytes < 0 ||\n\t\tpolicy.reclaimTargetBytes >= policy.triggerBytes ||\n\t\tpolicy.triggerBytes >= policy.hardLimitBytes\n\t) {\n\t\tthrow new TypeError(\"provider request image budget must satisfy 0 <= reclaim target < trigger < hard limit\");\n\t}\n}\n\nfunction measureContent(\n\tcontent: (TextContent | ImageContent)[],\n\tmessageIndex: number,\n\trole: ImageLocation[\"role\"],\n\tlocations: ImageLocation[],\n): { content: (TextContent | ImageContent)[]; dataBytes: number } {\n\tlet changed = false;\n\tlet dataBytes = 0;\n\tconst projected = content.map((block) => {\n\t\tif (block.type !== \"image\") return block;\n\t\tchanged = true;\n\t\t// ImageContent.data is base64 by contract, so every code unit is one unescaped JSON byte.\n\t\tconst bytes = block.data.length;\n\t\tconst blank = { type: \"image\" as const, data: \"\", mimeType: block.mimeType };\n\t\tconst blankBytes = measureJsonUtf8Bytes(blank);\n\t\tif (blankBytes === undefined) throw new TypeError(\"image content must be JSON serializable\");\n\t\tlocations.push({ messageIndex, role, block, serializedBytes: blankBytes + bytes });\n\t\tdataBytes += bytes;\n\t\treturn blank;\n\t});\n\treturn { content: changed ? projected : content, dataBytes };\n}\n\nfunction measureContextImages(context: Context): ContextImageMeasurement {\n\tconst locations: ImageLocation[] = [];\n\tlet dataBytes = 0;\n\tlet changed = false;\n\tconst messages = context.messages.map((message, messageIndex) => {\n\t\tif (message.role === \"user\" && Array.isArray(message.content)) {\n\t\t\tconst measured = measureContent(message.content, messageIndex, \"user\", locations);\n\t\t\tdataBytes += measured.dataBytes;\n\t\t\tif (measured.content === message.content) return message;\n\t\t\tchanged = true;\n\t\t\treturn { ...message, content: measured.content };\n\t\t}\n\t\tif (message.role === \"toolResult\") {\n\t\t\tconst measured = measureContent(message.content, messageIndex, \"toolResult\", locations);\n\t\t\tdataBytes += measured.dataBytes;\n\t\t\tif (measured.content === message.content) return message;\n\t\t\tchanged = true;\n\t\t\treturn { ...message, content: measured.content };\n\t\t}\n\t\treturn message;\n\t});\n\tconst blankBytes = measureJsonUtf8Bytes({\n\t\tsystemPrompt: context.systemPrompt,\n\t\tmessages: changed ? messages : context.messages,\n\t\ttools: context.tools,\n\t});\n\tif (blankBytes === undefined) throw new TypeError(\"provider request context must be JSON serializable\");\n\treturn { bodyBytes: blankBytes + dataBytes, locations };\n}\n\nfunction cloneImageBearingMessages(messages: Message[]): Message[] {\n\treturn messages.map((message) => {\n\t\tif (message.role === \"user\" && Array.isArray(message.content)) {\n\t\t\treturn { ...message, content: message.content.slice() };\n\t\t}\n\t\tif (message.role === \"toolResult\") return { ...message, content: message.content.slice() };\n\t\treturn message;\n\t});\n}\n\nfunction hasInlineImages(messages: Message[]): boolean {\n\tfor (const message of messages) {\n\t\tif (message.role === \"user\" && Array.isArray(message.content)) {\n\t\t\tif (message.content.some((block) => block.type === \"image\")) return true;\n\t\t} else if (message.role === \"toolResult\" && message.content.some((block) => block.type === \"image\")) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Applies high-water/low-water image eviction to a request-local Context copy. Durable history is\n * never mutated; evicted images are replaced with explicit anti-hallucination notices.\n */\nexport function applyProviderRequestImageBudget(\n\tcontext: Context,\n\tmodel: Model<Api>,\n\tpolicy: ProviderRequestImageBudgetPolicy = resolveProviderRequestImageBudget(model),\n): BudgetedProviderRequestContext {\n\tvalidatePolicy(policy);\n\tif (!hasInlineImages(context.messages)) return { context };\n\tconst projectedMessages = projectMessagesForModelImageSupport(context.messages, model);\n\tconst projectedContext =\n\t\tprojectedMessages === context.messages ? context : { ...context, messages: projectedMessages };\n\tif (!hasInlineImages(projectedMessages)) return { context: projectedContext };\n\tconst measurement = measureContextImages(projectedContext);\n\n\tconst needsImageCompaction = measurement.bodyBytes >= policy.triggerBytes;\n\tif (!needsImageCompaction || measurement.bodyBytes <= policy.reclaimTargetBytes) {\n\t\treturn {\n\t\t\tcontext: projectedContext,\n\t\t\toutcome: {\n\t\t\t\t...policy,\n\t\t\t\tbodyBytes: measurement.bodyBytes,\n\t\t\t\tbodyBytesAfter: measurement.bodyBytes,\n\t\t\t\tinlineImages: measurement.locations.length,\n\t\t\t\tneedsImageCompaction,\n\t\t\t\tevicted: 0,\n\t\t\t},\n\t\t};\n\t}\n\n\tconst messages = cloneImageBearingMessages(projectedContext.messages);\n\tconst budgetedContext = { ...projectedContext, messages };\n\tconst userPlaceholder: TextContent = { type: \"text\", text: USER_IMAGE_BUDGET_PLACEHOLDER };\n\tconst toolNote: TextContent = { type: \"text\", text: TOOL_IMAGE_BUDGET_NOTE };\n\tconst userPlaceholderBytes = measureJsonUtf8Bytes(userPlaceholder);\n\tconst toolNoteBytes = measureJsonUtf8Bytes(toolNote);\n\tif (userPlaceholderBytes === undefined || toolNoteBytes === undefined) {\n\t\tthrow new TypeError(\"image budget placeholders must be JSON serializable\");\n\t}\n\tlet bodyBytesAfter = measurement.bodyBytes;\n\tlet evicted = 0;\n\n\tfor (const location of measurement.locations) {\n\t\tif (bodyBytesAfter <= policy.reclaimTargetBytes) break;\n\t\tconst message = messages[location.messageIndex];\n\t\tif (location.role === \"user\") {\n\t\t\tif (message?.role !== \"user\" || !Array.isArray(message.content)) {\n\t\t\t\tthrow new TypeError(\"provider request image location changed during budgeting\");\n\t\t\t}\n\t\t\tconst blockIndex = message.content.indexOf(location.block);\n\t\t\tif (blockIndex < 0) throw new TypeError(\"provider request user image disappeared during budgeting\");\n\t\t\tmessage.content[blockIndex] = userPlaceholder;\n\t\t\tbodyBytesAfter -= location.serializedBytes - userPlaceholderBytes;\n\t\t} else {\n\t\t\tif (message?.role !== \"toolResult\") {\n\t\t\t\tthrow new TypeError(\"provider request image location changed during budgeting\");\n\t\t\t}\n\t\t\tconst blockIndex = message.content.indexOf(location.block);\n\t\t\tif (blockIndex < 0) throw new TypeError(\"provider request tool image disappeared during budgeting\");\n\t\t\tconst hasNote = message.content.some(\n\t\t\t\t(block) => block.type === \"text\" && block.text === TOOL_IMAGE_BUDGET_NOTE,\n\t\t\t);\n\t\t\tif (!hasNote) {\n\t\t\t\tbodyBytesAfter += toolNoteBytes + (message.content.length > 0 ? 1 : 0);\n\t\t\t\tmessage.content.push(toolNote);\n\t\t\t}\n\t\t\tmessage.content.splice(blockIndex, 1);\n\t\t\tbodyBytesAfter -= location.serializedBytes + 1;\n\t\t}\n\t\tevicted++;\n\t}\n\n\treturn {\n\t\tcontext: budgetedContext,\n\t\toutcome: {\n\t\t\t...policy,\n\t\t\tbodyBytes: measurement.bodyBytes,\n\t\t\tbodyBytesAfter,\n\t\t\tinlineImages: measurement.locations.length,\n\t\t\tneedsImageCompaction,\n\t\t\tevicted,\n\t\t},\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"provider-request-planner.d.ts","sourceRoot":"","sources":["../src/provider-request-planner.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACX,YAAY,EAEZ,eAAe,EAEf,uBAAuB,EACvB,sBAAsB,EACtB,QAAQ,EACR,MAAM,YAAY,CAAC;AAKpB,iGAAiG;AACjG,wBAAgB,0BAA0B,CACzC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,SAAS,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,GAAG,SAAS,CAGpB;AAUD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACrC,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,kBAAkB,EAAE,MAAM,GAAG,SAAS,EACtC,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAYpB;AAED,wFAAwF;AACxF,wBAAsB,gCAAgC,CAAC,OAAO,EAAE;IAC/D,gBAAgB,CAAC,EAAE,CAClB,OAAO,EAAE,uBAAuB,EAChC,MAAM,CAAC,EAAE,WAAW,KAChB,sBAAsB,GAAG,SAAS,GAAG,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC,CAAC;IACtF,KAAK,EAAE,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACxC,OAAO,EAAE,uBAAuB,CAAC,SAAS,CAAC,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAO9B;AAiDD;;;GAGG;AACH,wBAAsB,gCAAgC,CACrD,cAAc,EAAE,YAAY,EAC5B,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CA6GxC"}
1
+ {"version":3,"file":"provider-request-planner.d.ts","sourceRoot":"","sources":["../src/provider-request-planner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACX,YAAY,EAEZ,eAAe,EAEf,uBAAuB,EACvB,sBAAsB,EACtB,QAAQ,EACR,MAAM,YAAY,CAAC;AAKpB,iGAAiG;AACjG,wBAAgB,0BAA0B,CACzC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,SAAS,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,GAAG,SAAS,CAGpB;AAUD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACrC,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,kBAAkB,EAAE,MAAM,GAAG,SAAS,EACtC,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAYpB;AAED,wFAAwF;AACxF,wBAAsB,gCAAgC,CAAC,OAAO,EAAE;IAC/D,gBAAgB,CAAC,EAAE,CAClB,OAAO,EAAE,uBAAuB,EAChC,MAAM,CAAC,EAAE,WAAW,KAChB,sBAAsB,GAAG,SAAS,GAAG,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC,CAAC;IACtF,KAAK,EAAE,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACxC,OAAO,EAAE,uBAAuB,CAAC,SAAS,CAAC,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAO9B;AAiDD;;;GAGG;AACH,wBAAsB,gCAAgC,CACrD,cAAc,EAAE,YAAY,EAC5B,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAkHxC"}
@@ -1,4 +1,5 @@
1
1
  import { materializeProviderRequest, startMaterializedProviderStream, streamSimple } from "@caupulican/pi-ai/stream";
2
+ import { applyProviderRequestImageBudget } from "./provider-request-image-budget.js";
2
3
  import { projectToolsForProvider } from "./provider-tool-projection.js";
3
4
  import { sanitizeToolFailureContext } from "./tool-failure-memory.js";
4
5
  const MAX_STALE_PROVIDER_REQUEST_PLANS = 3;
@@ -113,7 +114,11 @@ export async function startPlannedAgentProviderRequest(initialContext, config, s
113
114
  messages: llmMessages,
114
115
  tools: projectToolsForProvider(sourceContext.tools),
115
116
  };
116
- const materialized = materializeProviderRequest(sourceProviderContext, config);
117
+ const protocolMaterialized = materializeProviderRequest(sourceProviderContext, config);
118
+ const budgeted = applyProviderRequestImageBudget(protocolMaterialized.context, config.model);
119
+ const materialized = budgeted.context === protocolMaterialized.context
120
+ ? protocolMaterialized
121
+ : { ...protocolMaterialized, context: budgeted.context };
117
122
  const nonCompactableContext = nonCompactableProviderContext(materialized.context, compactableMessages.length, materialized.usesTextToolProtocol);
118
123
  if (plan.isCurrent?.() === false) {
119
124
  stalePlanCount = nextStalePlanCount(stalePlanCount);
@@ -1 +1 @@
1
- {"version":3,"file":"provider-request-planner.js","sourceRoot":"","sources":["../src/provider-request-planner.ts"],"names":[],"mappings":"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","sourcesContent":["import { materializeProviderRequest, startMaterializedProviderStream, streamSimple } from \"@caupulican/pi-ai/stream\";\nimport type { Context, Message } from \"@caupulican/pi-ai/types\";\nimport { projectToolsForProvider } from \"./provider-tool-projection.ts\";\nimport { sanitizeToolFailureContext } from \"./tool-failure-memory.ts\";\nimport type {\n\tAgentContext,\n\tAgentContextPlan,\n\tAgentLoopConfig,\n\tAgentMessage,\n\tRequestPreflightContext,\n\tRequestPreflightResult,\n\tStreamFn,\n} from \"./types.ts\";\n\nconst MAX_STALE_PROVIDER_REQUEST_PLANS = 3;\nconst MAX_PROVIDER_REQUEST_REPLANS = 2;\n\n/** Compose request-local host instructions without representing them as conversation history. */\nexport function composeRequestSystemPrompt(\n\tbase: string | undefined,\n\ttransient: string | undefined,\n): string | undefined {\n\tif (!transient) return base;\n\treturn base ? `${base}\\n\\n${transient}` : transient;\n}\n\nfunction nextStalePlanCount(count: number): number {\n\tconst next = count + 1;\n\tif (next >= MAX_STALE_PROVIDER_REQUEST_PLANS) {\n\t\tthrow new Error(`Provider request plan stayed stale after ${MAX_STALE_PROVIDER_REQUEST_PLANS} attempts`);\n\t}\n\treturn next;\n}\n\n/**\n * Narrow an owner-selected output cap by one more requested ceiling and the model's own limit,\n * validating each supplied value is a positive safe integer. Exported so hosts computing their own\n * ceiling (e.g. a goal's remaining token budget) can route it through the SAME validated narrowing\n * this module applies just before transport, instead of hand-rolling an unvalidated min-merge that\n * only fails loudly here, several layers away from where the degenerate value was actually computed.\n */\nexport function narrowRequestMaxTokens(\n\townerMaxTokens: number | undefined,\n\trequestedMaxTokens: number | undefined,\n\tmodelMaxTokens: number,\n\tlabel: string,\n): number | undefined {\n\tif (ownerMaxTokens !== undefined && (!Number.isSafeInteger(ownerMaxTokens) || ownerMaxTokens <= 0)) {\n\t\tthrow new TypeError(\"request maxTokens must be a positive safe integer\");\n\t}\n\tif (requestedMaxTokens === undefined) return ownerMaxTokens;\n\tif (!Number.isSafeInteger(requestedMaxTokens) || requestedMaxTokens <= 0) {\n\t\tthrow new TypeError(`${label}.maxTokens must be a positive safe integer`);\n\t}\n\tconst ceilings = [requestedMaxTokens];\n\tif (ownerMaxTokens !== undefined) ceilings.push(ownerMaxTokens);\n\tif (Number.isSafeInteger(modelMaxTokens) && modelMaxTokens > 0) ceilings.push(modelMaxTokens);\n\treturn Math.min(...ceilings);\n}\n\n/** Apply one request-local preflight without mutating persistent loop configuration. */\nexport async function resolveRequestPreflightMaxTokens(options: {\n\trequestPreflight?: (\n\t\tcontext: RequestPreflightContext,\n\t\tsignal?: AbortSignal,\n\t) => RequestPreflightResult | undefined | Promise<RequestPreflightResult | undefined>;\n\tmodel: RequestPreflightContext[\"model\"];\n\tcontext: RequestPreflightContext[\"context\"];\n\tmaxTokens?: number;\n\tsignal?: AbortSignal;\n}): Promise<number | undefined> {\n\tif (!options.requestPreflight) return options.maxTokens;\n\tconst preflight = await options.requestPreflight(\n\t\t{ model: options.model, context: options.context, maxTokens: options.maxTokens },\n\t\toptions.signal,\n\t);\n\treturn narrowRequestMaxTokens(options.maxTokens, preflight?.maxTokens, options.model.maxTokens, \"requestPreflight\");\n}\n\nasync function buildContextPlan(\n\tmessages: AgentMessage[],\n\tattempt: number,\n\tconfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n): Promise<AgentContextPlan> {\n\tif (config.planContext) return await config.planContext({ messages, attempt }, signal);\n\treturn {\n\t\tmessages: config.transformContext ? await config.transformContext(messages, signal) : messages,\n\t};\n}\n\nfunction nonCompactableProviderContext(\n\tcontext: Context,\n\tcompactableMessageCount: number,\n\tusesTextToolProtocol: boolean,\n): Context {\n\tconst protocolGuardCount = usesTextToolProtocol && context.messages.length > 0 ? 1 : 0;\n\treturn {\n\t\t...context,\n\t\tmessages: [\n\t\t\t...context.messages.slice(0, protocolGuardCount),\n\t\t\t...context.messages.slice(protocolGuardCount + compactableMessageCount),\n\t\t],\n\t};\n}\n\nfunction sameToolSurface(left: AgentContext[\"tools\"], right: AgentContext[\"tools\"]): boolean {\n\tif (left === right) return true;\n\tif (!left || !right || left.length !== right.length) return false;\n\treturn left.every((tool, index) => tool === right[index]);\n}\n\nfunction validateReplannedSourceContext(previous: AgentContext, next: AgentContext): void {\n\tif (previous.systemPrompt !== next.systemPrompt || !sameToolSurface(previous.tools, next.tools)) {\n\t\tthrow new TypeError(\"Provider request admission may replan durable messages only\");\n\t}\n}\n\n/** Preserve the loop-owned messages array so shallow response-context projections observe compaction. */\nfunction adoptReplannedMessages(target: AgentContext, accepted: AgentContext): void {\n\tif (target.messages === accepted.messages) return;\n\tconst messages = accepted.messages.slice();\n\ttarget.messages.length = 0;\n\tfor (const message of messages) target.messages.push(message);\n}\n\n/**\n * Canonical two-phase provider boundary: plan replay-safe context, materialize once, admit the exact\n * payload, commit only the accepted plan, then send the admitted object unchanged.\n */\nexport async function startPlannedAgentProviderRequest(\n\tinitialContext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n\tstreamFn?: StreamFn,\n): Promise<Awaited<ReturnType<StreamFn>>> {\n\tlet sourceContext = initialContext;\n\tlet admissionAttempt = 0;\n\tlet stalePlanCount = 0;\n\twhile (true) {\n\t\tsignal?.throwIfAborted();\n\t\tconst sanitized = sanitizeToolFailureContext(sourceContext.messages, sourceContext.systemPrompt);\n\t\tconst plan = await buildContextPlan(sanitized.messages, admissionAttempt, config, signal);\n\t\tlet keepPlan = false;\n\t\ttry {\n\t\t\tsignal?.throwIfAborted();\n\t\t\tif (plan.isCurrent?.() === false) {\n\t\t\t\tstalePlanCount = nextStalePlanCount(stalePlanCount);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst transientMessages = plan.transientMessages ?? [];\n\t\t\tconst compactableMessages = await config.convertToLlm(plan.messages);\n\t\t\tconst providerTransients = transientMessages.length > 0 ? await config.convertToLlm(transientMessages) : [];\n\t\t\tconst llmMessages: Message[] = [...compactableMessages, ...providerTransients];\n\t\t\tsignal?.throwIfAborted();\n\n\t\t\tconst sourceProviderContext: Context = {\n\t\t\t\tsystemPrompt: composeRequestSystemPrompt(sanitized.systemPrompt, plan.transientSystemPrompt),\n\t\t\t\tmessages: llmMessages,\n\t\t\t\ttools: projectToolsForProvider(sourceContext.tools),\n\t\t\t};\n\t\t\tconst materialized = materializeProviderRequest(sourceProviderContext, config);\n\t\t\tconst nonCompactableContext = nonCompactableProviderContext(\n\t\t\t\tmaterialized.context,\n\t\t\t\tcompactableMessages.length,\n\t\t\t\tmaterialized.usesTextToolProtocol,\n\t\t\t);\n\n\t\t\tif (plan.isCurrent?.() === false) {\n\t\t\t\tstalePlanCount = nextStalePlanCount(stalePlanCount);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst admission = await config.admitProviderRequest?.(\n\t\t\t\t{\n\t\t\t\t\tmodel: config.model,\n\t\t\t\t\tcontext: materialized.context,\n\t\t\t\t\tnonCompactableContext,\n\t\t\t\t\tsourceContext,\n\t\t\t\t\tmaxTokens: config.maxTokens,\n\t\t\t\t\tattempt: admissionAttempt,\n\t\t\t\t},\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tsignal?.throwIfAborted();\n\t\t\tif (admission?.action === \"replan\") {\n\t\t\t\tvalidateReplannedSourceContext(sourceContext, admission.context);\n\t\t\t\tif (admissionAttempt >= MAX_PROVIDER_REQUEST_REPLANS) {\n\t\t\t\t\tthrow new Error(`Provider request admission exceeded ${MAX_PROVIDER_REQUEST_REPLANS} replans`);\n\t\t\t\t}\n\t\t\t\tsourceContext = admission.context;\n\t\t\t\tadmissionAttempt++;\n\t\t\t\tstalePlanCount = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet requestMaxTokens = narrowRequestMaxTokens(\n\t\t\t\tconfig.maxTokens,\n\t\t\t\tadmission?.maxTokens,\n\t\t\t\tconfig.model.maxTokens,\n\t\t\t\t\"admitProviderRequest\",\n\t\t\t);\n\t\t\trequestMaxTokens = await resolveRequestPreflightMaxTokens({\n\t\t\t\trequestPreflight: config.requestPreflight,\n\t\t\t\tmodel: config.model,\n\t\t\t\tcontext: materialized.context,\n\t\t\t\tmaxTokens: requestMaxTokens,\n\t\t\t\tsignal,\n\t\t\t});\n\t\t\tsignal?.throwIfAborted();\n\n\t\t\tconst resolvedApiKey =\n\t\t\t\t(config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;\n\t\t\tsignal?.throwIfAborted();\n\t\t\tconst requestReasoning = config.resolveRequestReasoning\n\t\t\t\t? config.resolveRequestReasoning(config.reasoning, {\n\t\t\t\t\t\tmodel: config.model,\n\t\t\t\t\t\tcontext: materialized.context,\n\t\t\t\t\t\tmaxTokens: requestMaxTokens,\n\t\t\t\t\t})\n\t\t\t\t: config.reasoning;\n\t\t\tconst streamFunction = streamFn ?? streamSimple;\n\t\t\tif (plan.isCurrent?.() === false || plan.prepareCommit?.() === false) {\n\t\t\t\tstalePlanCount = nextStalePlanCount(stalePlanCount);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tplan.commit?.();\n\t\t\tadoptReplannedMessages(initialContext, sourceContext);\n\t\t\tkeepPlan = true;\n\t\t\treturn (await startMaterializedProviderStream(\n\t\t\t\tconfig.model,\n\t\t\t\tmaterialized,\n\t\t\t\t{\n\t\t\t\t\t...config,\n\t\t\t\t\tapiKey: resolvedApiKey,\n\t\t\t\t\tmaxTokens: requestMaxTokens,\n\t\t\t\t\treasoning: requestReasoning,\n\t\t\t\t\tsignal,\n\t\t\t\t},\n\t\t\t\t(providerContext, providerOptions) => streamFunction(config.model, providerContext, providerOptions),\n\t\t\t)) as Awaited<ReturnType<StreamFn>>;\n\t\t} finally {\n\t\t\tif (!keepPlan) plan.discard?.();\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"provider-request-planner.js","sourceRoot":"","sources":["../src/provider-request-planner.ts"],"names":[],"mappings":"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","sourcesContent":["import { materializeProviderRequest, startMaterializedProviderStream, streamSimple } from \"@caupulican/pi-ai/stream\";\nimport type { Context, Message } from \"@caupulican/pi-ai/types\";\nimport { applyProviderRequestImageBudget } from \"./provider-request-image-budget.ts\";\nimport { projectToolsForProvider } from \"./provider-tool-projection.ts\";\nimport { sanitizeToolFailureContext } from \"./tool-failure-memory.ts\";\nimport type {\n\tAgentContext,\n\tAgentContextPlan,\n\tAgentLoopConfig,\n\tAgentMessage,\n\tRequestPreflightContext,\n\tRequestPreflightResult,\n\tStreamFn,\n} from \"./types.ts\";\n\nconst MAX_STALE_PROVIDER_REQUEST_PLANS = 3;\nconst MAX_PROVIDER_REQUEST_REPLANS = 2;\n\n/** Compose request-local host instructions without representing them as conversation history. */\nexport function composeRequestSystemPrompt(\n\tbase: string | undefined,\n\ttransient: string | undefined,\n): string | undefined {\n\tif (!transient) return base;\n\treturn base ? `${base}\\n\\n${transient}` : transient;\n}\n\nfunction nextStalePlanCount(count: number): number {\n\tconst next = count + 1;\n\tif (next >= MAX_STALE_PROVIDER_REQUEST_PLANS) {\n\t\tthrow new Error(`Provider request plan stayed stale after ${MAX_STALE_PROVIDER_REQUEST_PLANS} attempts`);\n\t}\n\treturn next;\n}\n\n/**\n * Narrow an owner-selected output cap by one more requested ceiling and the model's own limit,\n * validating each supplied value is a positive safe integer. Exported so hosts computing their own\n * ceiling (e.g. a goal's remaining token budget) can route it through the SAME validated narrowing\n * this module applies just before transport, instead of hand-rolling an unvalidated min-merge that\n * only fails loudly here, several layers away from where the degenerate value was actually computed.\n */\nexport function narrowRequestMaxTokens(\n\townerMaxTokens: number | undefined,\n\trequestedMaxTokens: number | undefined,\n\tmodelMaxTokens: number,\n\tlabel: string,\n): number | undefined {\n\tif (ownerMaxTokens !== undefined && (!Number.isSafeInteger(ownerMaxTokens) || ownerMaxTokens <= 0)) {\n\t\tthrow new TypeError(\"request maxTokens must be a positive safe integer\");\n\t}\n\tif (requestedMaxTokens === undefined) return ownerMaxTokens;\n\tif (!Number.isSafeInteger(requestedMaxTokens) || requestedMaxTokens <= 0) {\n\t\tthrow new TypeError(`${label}.maxTokens must be a positive safe integer`);\n\t}\n\tconst ceilings = [requestedMaxTokens];\n\tif (ownerMaxTokens !== undefined) ceilings.push(ownerMaxTokens);\n\tif (Number.isSafeInteger(modelMaxTokens) && modelMaxTokens > 0) ceilings.push(modelMaxTokens);\n\treturn Math.min(...ceilings);\n}\n\n/** Apply one request-local preflight without mutating persistent loop configuration. */\nexport async function resolveRequestPreflightMaxTokens(options: {\n\trequestPreflight?: (\n\t\tcontext: RequestPreflightContext,\n\t\tsignal?: AbortSignal,\n\t) => RequestPreflightResult | undefined | Promise<RequestPreflightResult | undefined>;\n\tmodel: RequestPreflightContext[\"model\"];\n\tcontext: RequestPreflightContext[\"context\"];\n\tmaxTokens?: number;\n\tsignal?: AbortSignal;\n}): Promise<number | undefined> {\n\tif (!options.requestPreflight) return options.maxTokens;\n\tconst preflight = await options.requestPreflight(\n\t\t{ model: options.model, context: options.context, maxTokens: options.maxTokens },\n\t\toptions.signal,\n\t);\n\treturn narrowRequestMaxTokens(options.maxTokens, preflight?.maxTokens, options.model.maxTokens, \"requestPreflight\");\n}\n\nasync function buildContextPlan(\n\tmessages: AgentMessage[],\n\tattempt: number,\n\tconfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n): Promise<AgentContextPlan> {\n\tif (config.planContext) return await config.planContext({ messages, attempt }, signal);\n\treturn {\n\t\tmessages: config.transformContext ? await config.transformContext(messages, signal) : messages,\n\t};\n}\n\nfunction nonCompactableProviderContext(\n\tcontext: Context,\n\tcompactableMessageCount: number,\n\tusesTextToolProtocol: boolean,\n): Context {\n\tconst protocolGuardCount = usesTextToolProtocol && context.messages.length > 0 ? 1 : 0;\n\treturn {\n\t\t...context,\n\t\tmessages: [\n\t\t\t...context.messages.slice(0, protocolGuardCount),\n\t\t\t...context.messages.slice(protocolGuardCount + compactableMessageCount),\n\t\t],\n\t};\n}\n\nfunction sameToolSurface(left: AgentContext[\"tools\"], right: AgentContext[\"tools\"]): boolean {\n\tif (left === right) return true;\n\tif (!left || !right || left.length !== right.length) return false;\n\treturn left.every((tool, index) => tool === right[index]);\n}\n\nfunction validateReplannedSourceContext(previous: AgentContext, next: AgentContext): void {\n\tif (previous.systemPrompt !== next.systemPrompt || !sameToolSurface(previous.tools, next.tools)) {\n\t\tthrow new TypeError(\"Provider request admission may replan durable messages only\");\n\t}\n}\n\n/** Preserve the loop-owned messages array so shallow response-context projections observe compaction. */\nfunction adoptReplannedMessages(target: AgentContext, accepted: AgentContext): void {\n\tif (target.messages === accepted.messages) return;\n\tconst messages = accepted.messages.slice();\n\ttarget.messages.length = 0;\n\tfor (const message of messages) target.messages.push(message);\n}\n\n/**\n * Canonical two-phase provider boundary: plan replay-safe context, materialize once, admit the exact\n * payload, commit only the accepted plan, then send the admitted object unchanged.\n */\nexport async function startPlannedAgentProviderRequest(\n\tinitialContext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n\tstreamFn?: StreamFn,\n): Promise<Awaited<ReturnType<StreamFn>>> {\n\tlet sourceContext = initialContext;\n\tlet admissionAttempt = 0;\n\tlet stalePlanCount = 0;\n\twhile (true) {\n\t\tsignal?.throwIfAborted();\n\t\tconst sanitized = sanitizeToolFailureContext(sourceContext.messages, sourceContext.systemPrompt);\n\t\tconst plan = await buildContextPlan(sanitized.messages, admissionAttempt, config, signal);\n\t\tlet keepPlan = false;\n\t\ttry {\n\t\t\tsignal?.throwIfAborted();\n\t\t\tif (plan.isCurrent?.() === false) {\n\t\t\t\tstalePlanCount = nextStalePlanCount(stalePlanCount);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst transientMessages = plan.transientMessages ?? [];\n\t\t\tconst compactableMessages = await config.convertToLlm(plan.messages);\n\t\t\tconst providerTransients = transientMessages.length > 0 ? await config.convertToLlm(transientMessages) : [];\n\t\t\tconst llmMessages: Message[] = [...compactableMessages, ...providerTransients];\n\t\t\tsignal?.throwIfAborted();\n\n\t\t\tconst sourceProviderContext: Context = {\n\t\t\t\tsystemPrompt: composeRequestSystemPrompt(sanitized.systemPrompt, plan.transientSystemPrompt),\n\t\t\t\tmessages: llmMessages,\n\t\t\t\ttools: projectToolsForProvider(sourceContext.tools),\n\t\t\t};\n\t\t\tconst protocolMaterialized = materializeProviderRequest(sourceProviderContext, config);\n\t\t\tconst budgeted = applyProviderRequestImageBudget(protocolMaterialized.context, config.model);\n\t\t\tconst materialized =\n\t\t\t\tbudgeted.context === protocolMaterialized.context\n\t\t\t\t\t? protocolMaterialized\n\t\t\t\t\t: { ...protocolMaterialized, context: budgeted.context };\n\t\t\tconst nonCompactableContext = nonCompactableProviderContext(\n\t\t\t\tmaterialized.context,\n\t\t\t\tcompactableMessages.length,\n\t\t\t\tmaterialized.usesTextToolProtocol,\n\t\t\t);\n\n\t\t\tif (plan.isCurrent?.() === false) {\n\t\t\t\tstalePlanCount = nextStalePlanCount(stalePlanCount);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst admission = await config.admitProviderRequest?.(\n\t\t\t\t{\n\t\t\t\t\tmodel: config.model,\n\t\t\t\t\tcontext: materialized.context,\n\t\t\t\t\tnonCompactableContext,\n\t\t\t\t\tsourceContext,\n\t\t\t\t\tmaxTokens: config.maxTokens,\n\t\t\t\t\tattempt: admissionAttempt,\n\t\t\t\t},\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tsignal?.throwIfAborted();\n\t\t\tif (admission?.action === \"replan\") {\n\t\t\t\tvalidateReplannedSourceContext(sourceContext, admission.context);\n\t\t\t\tif (admissionAttempt >= MAX_PROVIDER_REQUEST_REPLANS) {\n\t\t\t\t\tthrow new Error(`Provider request admission exceeded ${MAX_PROVIDER_REQUEST_REPLANS} replans`);\n\t\t\t\t}\n\t\t\t\tsourceContext = admission.context;\n\t\t\t\tadmissionAttempt++;\n\t\t\t\tstalePlanCount = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet requestMaxTokens = narrowRequestMaxTokens(\n\t\t\t\tconfig.maxTokens,\n\t\t\t\tadmission?.maxTokens,\n\t\t\t\tconfig.model.maxTokens,\n\t\t\t\t\"admitProviderRequest\",\n\t\t\t);\n\t\t\trequestMaxTokens = await resolveRequestPreflightMaxTokens({\n\t\t\t\trequestPreflight: config.requestPreflight,\n\t\t\t\tmodel: config.model,\n\t\t\t\tcontext: materialized.context,\n\t\t\t\tmaxTokens: requestMaxTokens,\n\t\t\t\tsignal,\n\t\t\t});\n\t\t\tsignal?.throwIfAborted();\n\n\t\t\tconst resolvedApiKey =\n\t\t\t\t(config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;\n\t\t\tsignal?.throwIfAborted();\n\t\t\tconst requestReasoning = config.resolveRequestReasoning\n\t\t\t\t? config.resolveRequestReasoning(config.reasoning, {\n\t\t\t\t\t\tmodel: config.model,\n\t\t\t\t\t\tcontext: materialized.context,\n\t\t\t\t\t\tmaxTokens: requestMaxTokens,\n\t\t\t\t\t})\n\t\t\t\t: config.reasoning;\n\t\t\tconst streamFunction = streamFn ?? streamSimple;\n\t\t\tif (plan.isCurrent?.() === false || plan.prepareCommit?.() === false) {\n\t\t\t\tstalePlanCount = nextStalePlanCount(stalePlanCount);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tplan.commit?.();\n\t\t\tadoptReplannedMessages(initialContext, sourceContext);\n\t\t\tkeepPlan = true;\n\t\t\treturn (await startMaterializedProviderStream(\n\t\t\t\tconfig.model,\n\t\t\t\tmaterialized,\n\t\t\t\t{\n\t\t\t\t\t...config,\n\t\t\t\t\tapiKey: resolvedApiKey,\n\t\t\t\t\tmaxTokens: requestMaxTokens,\n\t\t\t\t\treasoning: requestReasoning,\n\t\t\t\t\tsignal,\n\t\t\t\t},\n\t\t\t\t(providerContext, providerOptions) => streamFunction(config.model, providerContext, providerOptions),\n\t\t\t)) as Awaited<ReturnType<StreamFn>>;\n\t\t} finally {\n\t\t\tif (!keepPlan) plan.discard?.();\n\t\t}\n\t}\n}\n"]}
@@ -39,6 +39,8 @@ export type ToolFailureResultDetails = ToolFailureMemoryDetails | ToolFailureDir
39
39
  export type ToolFailureMemoryTracker = Map<string, ToolFailureMemoryRecord>;
40
40
  export declare function normalizeToolSignature(pairs: Array<[string, unknown]>): string;
41
41
  export declare function getToolExecutionKey(tool: string, args: unknown): string;
42
+ /** Read the four hash words already encoded by this module's exact execution-key owner. */
43
+ export declare function getToolExecutionKeyHashParts(executionKey: string): readonly [number, number, number, number];
42
44
  export declare function getToolFailureRecordExecutionKey(record: ToolFailureMemoryRecord): string | undefined;
43
45
  export declare function getUnresolvedToolFailure(tracker: ToolFailureMemoryTracker, tool: string, args: unknown): ToolFailureMemoryRecord | undefined;
44
46
  export declare function readVisibleToolFailureCode(result: ToolResultMessage): string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"tool-failure-memory.d.ts","sourceRoot":"","sources":["../src/tool-failure-memory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tool-failure-memory.d.ts","sourceRoot":"","sources":["../src/tool-failure-memory.ts"],"names":[],"mappings":"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"}