@openhoo/hoopilot 2.1.2 → 2.1.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/cli.js CHANGED
@@ -688,7 +688,7 @@ function normalizeRequestedModel(model) {
688
688
  }
689
689
  function responsesCompactionResult(upstreamText, isSse) {
690
690
  const summary = compactionSummaryText(upstreamText, isSse);
691
- return { output: [compactionSummaryMessageItem(summary)] };
691
+ return { output: [compactionSummaryOutputMessageItem(summary)] };
692
692
  }
693
693
  function isResponsesCompactionRequest(request) {
694
694
  return responseInputItems(request.input).some(
@@ -975,8 +975,14 @@ function contentToText(content) {
975
975
  }
976
976
  return "";
977
977
  }
978
- function compactionSummaryMessageItem(text, id = `msg_${randomId()}`) {
979
- return {
978
+ function compactionSummaryOutputMessageItem(text) {
979
+ return compactionSummaryMessageItem(text, `msg_${randomId()}`);
980
+ }
981
+ function compactionSummaryInputMessageItem(text) {
982
+ return compactionSummaryMessageItem(text);
983
+ }
984
+ function compactionSummaryMessageItem(text, id) {
985
+ return removeUndefined({
980
986
  content: [
981
987
  {
982
988
  text: `${COMPACTION_SUMMARY_PREFIX}
@@ -987,7 +993,7 @@ ${text}`,
987
993
  id,
988
994
  role: "user",
989
995
  type: "message"
990
- };
996
+ });
991
997
  }
992
998
  function compactionOutputItem(text, id = `cmpct_${randomId()}`) {
993
999
  return {
@@ -1011,7 +1017,7 @@ function normalizeCompactionInputForCopilot(input, options) {
1011
1017
  if (type === "compaction" || type === "compaction_summary" || type === "context_compaction") {
1012
1018
  const text = contentToText(record.encrypted_content);
1013
1019
  if (text) {
1014
- normalized.push(compactionSummaryMessageItem(text));
1020
+ normalized.push(compactionSummaryInputMessageItem(text));
1015
1021
  }
1016
1022
  continue;
1017
1023
  }
@@ -1056,6 +1062,7 @@ function extractTokenUsage(usage) {
1056
1062
  asRecord(record.output_tokens_details).reasoning_tokens
1057
1063
  );
1058
1064
  const cached = firstNumber(
1065
+ record.cache_read_input_tokens,
1059
1066
  asRecord(record.prompt_tokens_details).cached_tokens,
1060
1067
  asRecord(record.input_tokens_details).cached_tokens
1061
1068
  );
@@ -1201,9 +1208,10 @@ var AnthropicCompatibilityError = class extends Error {
1201
1208
  }
1202
1209
  };
1203
1210
  function anthropicMessagesToResponsesRequest(request) {
1204
- return removeUndefined({
1205
- input: anthropicMessagesToResponsesInput(request.messages),
1206
- instructions: anthropicSystemToInstructions(request.system),
1211
+ const system = anthropicSystemToResponses(request.system);
1212
+ const response = removeUndefined({
1213
+ input: [...system.input, ...anthropicMessagesToResponsesInput(request.messages)],
1214
+ instructions: system.instructions,
1207
1215
  max_output_tokens: typeof request.max_tokens === "number" && Number.isFinite(request.max_tokens) ? request.max_tokens : void 0,
1208
1216
  metadata: request.metadata,
1209
1217
  model: normalizeRequestedModel(request.model),
@@ -1216,6 +1224,8 @@ function anthropicMessagesToResponsesRequest(request) {
1216
1224
  tools: anthropicTools(request.tools),
1217
1225
  top_p: request.top_p
1218
1226
  });
1227
+ applyCacheControlToLastBlock(response, anthropicCacheControl(request.cache_control));
1228
+ return response;
1219
1229
  }
1220
1230
  function responsesResponseToAnthropicMessage(response, fallbackModel) {
1221
1231
  const content = anthropicContentFromResponsesOutput(response);
@@ -1312,6 +1322,7 @@ function anthropicMessagesToResponsesInput(messages) {
1312
1322
  throw new AnthropicCompatibilityError("Anthropic Messages requests require messages[].");
1313
1323
  }
1314
1324
  const input = [];
1325
+ let fallbackToolCallIndex = 0;
1315
1326
  for (const message of messages) {
1316
1327
  const record = asRecord(message);
1317
1328
  const role = anthropicRole(record.role);
@@ -1333,10 +1344,13 @@ function anthropicMessagesToResponsesInput(messages) {
1333
1344
  if (type === "text") {
1334
1345
  const text = textValue(part.text);
1335
1346
  if (text) {
1336
- messageParts.push({
1337
- text,
1338
- type: role === "assistant" ? "output_text" : "input_text"
1339
- });
1347
+ messageParts.push(
1348
+ removeUndefined({
1349
+ cache_control: anthropicCacheControl(part.cache_control),
1350
+ text,
1351
+ type: role === "assistant" ? "output_text" : "input_text"
1352
+ })
1353
+ );
1340
1354
  }
1341
1355
  continue;
1342
1356
  }
@@ -1351,21 +1365,27 @@ function anthropicMessagesToResponsesInput(messages) {
1351
1365
  }
1352
1366
  if (type === "tool_use") {
1353
1367
  flushMessage();
1354
- input.push({
1355
- arguments: JSON.stringify(asRecord(part.input)),
1356
- call_id: textValue(part.id) || `call_${randomId()}`,
1357
- name: textValue(part.name),
1358
- type: "function_call"
1359
- });
1368
+ input.push(
1369
+ removeUndefined({
1370
+ arguments: JSON.stringify(asRecord(part.input)),
1371
+ cache_control: anthropicCacheControl(part.cache_control),
1372
+ call_id: textValue(part.id) || `call_hoopilot_${fallbackToolCallIndex++}`,
1373
+ name: textValue(part.name),
1374
+ type: "function_call"
1375
+ })
1376
+ );
1360
1377
  continue;
1361
1378
  }
1362
1379
  if (type === "tool_result") {
1363
1380
  flushMessage();
1364
- input.push({
1365
- call_id: textValue(part.tool_use_id),
1366
- output: anthropicToolResultOutput(part.content),
1367
- type: "function_call_output"
1368
- });
1381
+ input.push(
1382
+ removeUndefined({
1383
+ cache_control: anthropicCacheControl(part.cache_control),
1384
+ call_id: textValue(part.tool_use_id),
1385
+ output: anthropicToolResultOutput(part.content),
1386
+ type: "function_call_output"
1387
+ })
1388
+ );
1369
1389
  continue;
1370
1390
  }
1371
1391
  if (type === "thinking" || type === "redacted_thinking") {
@@ -1412,22 +1432,24 @@ function anthropicImageToResponsesPart(part) {
1412
1432
  if (!data) {
1413
1433
  throw new AnthropicCompatibilityError("Anthropic base64 image content requires source.data.");
1414
1434
  }
1415
- return {
1435
+ return removeUndefined({
1436
+ cache_control: anthropicCacheControl(part.cache_control),
1416
1437
  detail: "auto",
1417
1438
  image_url: `data:${mediaType};base64,${data}`,
1418
1439
  type: "input_image"
1419
- };
1440
+ });
1420
1441
  }
1421
1442
  if (sourceType === "url") {
1422
1443
  const url = textValue(source.url);
1423
1444
  if (!url) {
1424
1445
  throw new AnthropicCompatibilityError("Anthropic URL image content requires source.url.");
1425
1446
  }
1426
- return {
1447
+ return removeUndefined({
1448
+ cache_control: anthropicCacheControl(part.cache_control),
1427
1449
  detail: "auto",
1428
1450
  image_url: url,
1429
1451
  type: "input_image"
1430
- };
1452
+ });
1431
1453
  }
1432
1454
  throw new AnthropicCompatibilityError(
1433
1455
  `Anthropic image source type "${sourceType || "unknown"}" is not supported.`
@@ -1448,15 +1470,42 @@ function anthropicToolResultOutput(content) {
1448
1470
  }
1449
1471
  return typeof content === "object" ? JSON.stringify(content) : String(content);
1450
1472
  }
1451
- function anthropicSystemToInstructions(system) {
1473
+ function anthropicSystemToResponses(system) {
1452
1474
  if (typeof system === "string") {
1453
- return system || void 0;
1475
+ return { input: [], instructions: system || void 0 };
1454
1476
  }
1455
1477
  if (!Array.isArray(system)) {
1478
+ return { input: [] };
1479
+ }
1480
+ const parts = system.map((part) => anthropicSystemPartToResponsesPart(part)).filter((part) => part !== void 0);
1481
+ if (parts.length === 0) {
1482
+ return { input: [] };
1483
+ }
1484
+ if (parts.some((part) => part.cache_control !== void 0)) {
1485
+ return {
1486
+ input: [
1487
+ {
1488
+ content: parts,
1489
+ role: "system",
1490
+ type: "message"
1491
+ }
1492
+ ]
1493
+ };
1494
+ }
1495
+ const text = parts.map((part) => textValue(part.text)).filter(Boolean).join("\n");
1496
+ return { input: [], instructions: text || void 0 };
1497
+ }
1498
+ function anthropicSystemPartToResponsesPart(part) {
1499
+ const record = asRecord(part);
1500
+ const text = textValue(record.text) || textValue(part);
1501
+ if (!text) {
1456
1502
  return void 0;
1457
1503
  }
1458
- const text = system.map((part) => textValue(asRecord(part).text) || textValue(part)).filter(Boolean).join("\n");
1459
- return text || void 0;
1504
+ return removeUndefined({
1505
+ cache_control: anthropicCacheControl(record.cache_control),
1506
+ text,
1507
+ type: "input_text"
1508
+ });
1460
1509
  }
1461
1510
  function anthropicTools(tools) {
1462
1511
  if (!Array.isArray(tools)) {
@@ -1465,6 +1514,7 @@ function anthropicTools(tools) {
1465
1514
  const converted = tools.map((tool) => {
1466
1515
  const record = asRecord(tool);
1467
1516
  return removeUndefined({
1517
+ cache_control: anthropicCacheControl(record.cache_control),
1468
1518
  description: record.description,
1469
1519
  name: record.name,
1470
1520
  parameters: record.input_schema,
@@ -1474,6 +1524,55 @@ function anthropicTools(tools) {
1474
1524
  });
1475
1525
  return converted.length > 0 ? converted : void 0;
1476
1526
  }
1527
+ function anthropicCacheControl(value) {
1528
+ if (value === void 0 || value === null) {
1529
+ return void 0;
1530
+ }
1531
+ const record = asRecord(value);
1532
+ const type = textValue(record.type);
1533
+ if (type !== "ephemeral") {
1534
+ throw new AnthropicCompatibilityError(
1535
+ `Anthropic cache_control type "${type || "unknown"}" is not supported.`
1536
+ );
1537
+ }
1538
+ const ttl = textValue(record.ttl);
1539
+ if (ttl && ttl !== "5m" && ttl !== "1h") {
1540
+ throw new AnthropicCompatibilityError(`Anthropic cache_control ttl "${ttl}" is not supported.`);
1541
+ }
1542
+ return removeUndefined({
1543
+ ttl: ttl || void 0,
1544
+ type
1545
+ });
1546
+ }
1547
+ function applyCacheControlToLastBlock(request, cacheControl) {
1548
+ if (!cacheControl) {
1549
+ return;
1550
+ }
1551
+ const input = Array.isArray(request.input) ? request.input : [];
1552
+ for (let itemIndex = input.length - 1; itemIndex >= 0; itemIndex -= 1) {
1553
+ const item = asRecord(input[itemIndex]);
1554
+ const content = Array.isArray(item.content) ? item.content : [];
1555
+ for (let partIndex = content.length - 1; partIndex >= 0; partIndex -= 1) {
1556
+ const part = asRecord(content[partIndex]);
1557
+ if (part.cache_control === void 0 && isCacheableResponsesPart(part)) {
1558
+ part.cache_control = cacheControl;
1559
+ return;
1560
+ }
1561
+ }
1562
+ }
1563
+ const tools = Array.isArray(request.tools) ? request.tools : [];
1564
+ for (let index = tools.length - 1; index >= 0; index -= 1) {
1565
+ const tool = asRecord(tools[index]);
1566
+ if (tool.cache_control === void 0) {
1567
+ tool.cache_control = cacheControl;
1568
+ return;
1569
+ }
1570
+ }
1571
+ }
1572
+ function isCacheableResponsesPart(part) {
1573
+ const type = textValue(part.type);
1574
+ return type === "input_text" || type === "output_text" || type === "text" || type === "input_image";
1575
+ }
1477
1576
  function anthropicToolChoice(toolChoice) {
1478
1577
  if (toolChoice === void 0 || toolChoice === null) {
1479
1578
  return void 0;