@heripo/ledger-extractor 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1139,6 +1139,72 @@ function detectProvider(model) {
1139
1139
  if (providerId.includes("lmstudio")) return "lmstudio";
1140
1140
  return "unknown";
1141
1141
  }
1142
+ function withSystemPromptCache(model, systemPrompt, providerOptions) {
1143
+ const unchanged = {
1144
+ ...systemPrompt === void 0 ? {} : { instructions: systemPrompt },
1145
+ ...providerOptions === void 0 ? {} : { providerOptions }
1146
+ };
1147
+ const provider = detectProvider(model);
1148
+ if (provider === "anthropic")
1149
+ return systemPrompt ? {
1150
+ ...unchanged,
1151
+ instructions: cachedSystem(systemPrompt, {
1152
+ anthropic: { cacheControl: { type: "ephemeral" } }
1153
+ })
1154
+ } : unchanged;
1155
+ if (provider !== "openai" || !supportsOpenAICacheBreakpoints(modelIdOf(model)) || providerOptions?.openai?.promptCacheOptions !== void 0)
1156
+ return unchanged;
1157
+ return {
1158
+ ...systemPrompt ? {
1159
+ instructions: cachedSystem(systemPrompt, {
1160
+ openai: { promptCacheBreakpoint: { mode: "explicit" } }
1161
+ })
1162
+ } : unchanged,
1163
+ providerOptions: {
1164
+ ...providerOptions,
1165
+ openai: {
1166
+ ...providerOptions?.openai,
1167
+ promptCacheOptions: { mode: "explicit" }
1168
+ }
1169
+ }
1170
+ };
1171
+ }
1172
+ function withRepeatedRequestCache(model, systemPrompt, userPrompt, providerOptions) {
1173
+ const anthropicBreakpoint = {
1174
+ anthropic: { cacheControl: { type: "ephemeral" } }
1175
+ };
1176
+ if (detectProvider(model) === "anthropic")
1177
+ return {
1178
+ ...providerOptions === void 0 ? {} : { providerOptions },
1179
+ instructions: cachedSystem(systemPrompt, anthropicBreakpoint),
1180
+ messages: [
1181
+ {
1182
+ role: "user",
1183
+ content: userPrompt,
1184
+ providerOptions: anthropicBreakpoint
1185
+ }
1186
+ ]
1187
+ };
1188
+ return {
1189
+ instructions: systemPrompt,
1190
+ prompt: userPrompt,
1191
+ ...providerOptions === void 0 ? {} : { providerOptions }
1192
+ };
1193
+ }
1194
+ function cachedSystem(content, providerOptions) {
1195
+ return { role: "system", content, providerOptions };
1196
+ }
1197
+ function modelIdOf(model) {
1198
+ const modelId = model.modelId;
1199
+ return typeof modelId === "string" ? modelId : "";
1200
+ }
1201
+ function supportsOpenAICacheBreakpoints(modelId) {
1202
+ const version = /^(?:openai\/)?gpt-(\d+)(?:\.(\d+))?(?:-.+)?$/u.exec(modelId);
1203
+ if (!version) return false;
1204
+ const major = Number(version[1]);
1205
+ const minor = Number(version[2] ?? 0);
1206
+ return major > 5 || major === 5 && minor >= 6;
1207
+ }
1142
1208
  function cacheWrite1hTokens(steps) {
1143
1209
  let total;
1144
1210
  for (const step of steps ?? []) {
@@ -1340,7 +1406,8 @@ var LLMCaller = class {
1340
1406
  * 2. If all fail and fallbackModel provided, try fallback up to maxRetries times
1341
1407
  * 3. Throw error if all attempts exhausted
1342
1408
  *
1343
- * Provider-aware strategy is automatically applied based on the model's provider field.
1409
+ * Provider-aware strategy is automatically applied based on the model's provider field, and the prompt cache
1410
+ * breakpoint is placed only at the end of the system prompt (see `withSystemPromptCache`).
1344
1411
  *
1345
1412
  * @template TOutput - Output type from schema validation
1346
1413
  * @param config - LLM call configuration
@@ -1351,17 +1418,12 @@ var LLMCaller = class {
1351
1418
  return this.executeWithFallback(
1352
1419
  config,
1353
1420
  (model) => this.generateStructuredOutput(model, config.schema, {
1354
- instructions: config.cacheSystemPrompt ? {
1355
- role: "system",
1356
- content: config.systemPrompt,
1357
- providerOptions: {
1358
- anthropic: { cacheControl: { type: "ephemeral" } }
1359
- }
1360
- } : config.systemPrompt,
1421
+ ...withSystemPromptCache(
1422
+ model,
1423
+ config.systemPrompt,
1424
+ config.providerOptions
1425
+ ),
1361
1426
  prompt: config.userPrompt,
1362
- ...config.providerOptions && {
1363
- providerOptions: config.providerOptions
1364
- },
1365
1427
  temperature: config.temperature,
1366
1428
  maxRetries: config.maxRetries,
1367
1429
  abortSignal: config.abortSignal
@@ -1384,6 +1446,7 @@ var LLMCaller = class {
1384
1446
  config,
1385
1447
  (model) => this.generateStructuredOutput(model, config.schema, {
1386
1448
  messages: config.messages,
1449
+ ...withSystemPromptCache(model, void 0, void 0),
1387
1450
  temperature: config.temperature,
1388
1451
  maxRetries: config.maxRetries,
1389
1452
  abortSignal: config.abortSignal
@@ -1906,7 +1969,6 @@ async function discoverCandidateUnit(unit, options) {
1906
1969
  schema: request.schema,
1907
1970
  systemPrompt: request.systemPrompt,
1908
1971
  userPrompt: request.userPrompt,
1909
- cacheSystemPrompt: true,
1910
1972
  primaryModel: options.model,
1911
1973
  maxRetries: options.maxRetries,
1912
1974
  abortSignal: options.abortSignal,
@@ -2099,7 +2161,6 @@ async function deduplicateCandidateBlocks(plan, discovery, options) {
2099
2161
  systemPrompt: request.systemPrompt,
2100
2162
  userPrompt: request.userPrompt,
2101
2163
  // every block shares the system prompt, so later blocks read it from the provider's prompt cache
2102
- cacheSystemPrompt: true,
2103
2164
  providerOptions: CANDIDATE_DEDUPLICATION_BLOCK_PROVIDER_OPTIONS,
2104
2165
  primaryModel: options.model,
2105
2166
  maxRetries: options.maxRetries,
@@ -8831,11 +8892,15 @@ async function attachContentThinUnit(plan, unit, options) {
8831
8892
  request.providerOutputSchema
8832
8893
  )
8833
8894
  }),
8834
- system: request.systemPrompt,
8835
- prompt: request.userPrompt,
8895
+ // r2 and later runs repeat r1's request once its answer returns
8896
+ ...withRepeatedRequestCache(
8897
+ audited.model,
8898
+ request.systemPrompt,
8899
+ request.userPrompt,
8900
+ providerOptions
8901
+ ),
8836
8902
  maxRetries: options.maxRetries ?? 0,
8837
- abortSignal: options.abortSignal,
8838
- providerOptions
8903
+ abortSignal: options.abortSignal
8839
8904
  });
8840
8905
  result = recordContentAttachmentThinCall(plan, unit, {
8841
8906
  run,
@@ -9894,7 +9959,7 @@ async function routeReport(index, signals, options) {
9894
9959
  request.providerOutputSchema
9895
9960
  )
9896
9961
  }),
9897
- system: request.systemPrompt,
9962
+ ...withSystemPromptCache(audited.model, request.systemPrompt, void 0),
9898
9963
  prompt: request.userPrompt,
9899
9964
  maxRetries: options.maxRetries ?? 0,
9900
9965
  abortSignal: options.abortSignal
@@ -13217,8 +13282,13 @@ async function judgeRelationParentBatch(request, options) {
13217
13282
  request.providerOutputSchema
13218
13283
  )
13219
13284
  }),
13220
- system: request.systemPrompt,
13221
- prompt: request.userPrompt,
13285
+ // r2 and later runs repeat r1's request once its answer returns
13286
+ ...withRepeatedRequestCache(
13287
+ audited.model,
13288
+ request.systemPrompt,
13289
+ request.userPrompt,
13290
+ void 0
13291
+ ),
13222
13292
  maxRetries: options.maxRetries ?? 0,
13223
13293
  abortSignal: options.abortSignal
13224
13294
  });
@@ -13498,7 +13568,12 @@ async function proposePlaceAliases(plan, ledger, request, options) {
13498
13568
  request.providerOutputSchema
13499
13569
  )
13500
13570
  }),
13501
- system: request.systemPrompt,
13571
+ // r1 and r2 are sent together, so neither can read the other's user prompt from the cache
13572
+ ...withSystemPromptCache(
13573
+ audited.model,
13574
+ request.systemPrompt,
13575
+ void 0
13576
+ ),
13502
13577
  prompt: request.userPrompt,
13503
13578
  maxRetries: options.maxRetries ?? 0,
13504
13579
  abortSignal: options.abortSignal