@code-yeongyu/senpi-ai 2026.7.25-2 → 2026.7.26
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/api/anthropic-messages.d.ts.map +1 -1
- package/dist/api/anthropic-messages.js +135 -16
- package/dist/api/anthropic-messages.js.map +1 -1
- package/dist/api/azure-openai-responses.js +1 -1
- package/dist/api/azure-openai-responses.js.map +1 -1
- package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
- package/dist/api/bedrock-converse-stream.js +1 -4
- package/dist/api/bedrock-converse-stream.js.map +1 -1
- package/dist/api/google-shared.d.ts.map +1 -1
- package/dist/api/google-shared.js +4 -3
- package/dist/api/google-shared.js.map +1 -1
- package/dist/api/openai-codex-responses.js +2 -2
- package/dist/api/openai-codex-responses.js.map +1 -1
- package/dist/api/openai-responses-shared.d.ts +1 -0
- package/dist/api/openai-responses-shared.d.ts.map +1 -1
- package/dist/api/openai-responses-shared.js +67 -31
- package/dist/api/openai-responses-shared.js.map +1 -1
- package/dist/api/openai-responses.js +1 -1
- package/dist/api/openai-responses.js.map +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/utils/retry.d.ts.map +1 -1
- package/dist/utils/retry.js +10 -0
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/stop-details.d.ts +1 -1
- package/dist/utils/stop-details.d.ts.map +1 -1
- package/dist/utils/stop-details.js +7 -3
- package/dist/utils/stop-details.js.map +1 -1
- package/dist/utils/tool-call-id.d.ts +9 -0
- package/dist/utils/tool-call-id.d.ts.map +1 -0
- package/dist/utils/tool-call-id.js +16 -0
- package/dist/utils/tool-call-id.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../src/api/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAU1C,OAAO,KAAK,EAYX,mBAAmB,EAEnB,cAAc,EACd,aAAa,
|
|
1
|
+
{"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../src/api/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAU1C,OAAO,KAAK,EAYX,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAOb,MAAM,aAAa,CAAC;AAiMrB,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,CAAC;AAoHhE,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACtD;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;CACnB;AA+pBD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,gBAAgB,CAoYzE,CAAC;AA0FF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CA2ClF,CAAC"}
|
|
@@ -10,6 +10,7 @@ import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
|
10
10
|
import { retryProviderRequest } from "../utils/provider-retry.js";
|
|
11
11
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
12
12
|
import { applyServerFallbackAbort, parseServerFallbackReceipt, parseStickyFallbackReceipt, } from "../utils/server-fallback-receipt.js";
|
|
13
|
+
import { normalizeToolCallId } from "../utils/tool-call-id.js";
|
|
13
14
|
import { isForcedToolChoiceUnsupportedError, omitToolChoiceParam } from "../utils/tool-choice-fallback.js";
|
|
14
15
|
import { resolveCloudflareBaseUrl } from "./cloudflare.js";
|
|
15
16
|
import { resolveJsonSchemaStrictSampling } from "./constrained-sampling.js";
|
|
@@ -309,6 +310,97 @@ function isAnthropicWebSearchReplayBlock(raw) {
|
|
|
309
310
|
return true;
|
|
310
311
|
return raw.type === "server_tool_use" && raw.name === "web_search";
|
|
311
312
|
}
|
|
313
|
+
// The user turn a pending server tool can survive is one that carries only
|
|
314
|
+
// tool results. Anything else the wire would emit — real text, an image —
|
|
315
|
+
// closes the assistant turn (the API then 400s the still-open use). A blank
|
|
316
|
+
// message serializes to nothing, so it closes nothing.
|
|
317
|
+
function userMessageClosesServerTurn(message) {
|
|
318
|
+
if (typeof message.content === "string")
|
|
319
|
+
return message.content.trim().length > 0;
|
|
320
|
+
return message.content.some((block) => (block.type === "text" && block.text.trim().length > 0) || block.type === "image");
|
|
321
|
+
}
|
|
322
|
+
function collectProviderNativeToolPairing(messages, model, deferredToolNames, normalizeToolName, discardedFallbackToolCallIds) {
|
|
323
|
+
const resolvedUseIds = new Set();
|
|
324
|
+
const validResultIds = new Set();
|
|
325
|
+
// Uses whose turn can still be resumed. A same-model assistant resets the
|
|
326
|
+
// set: its own result blocks may answer the prior pending uses, and any use
|
|
327
|
+
// it leaves pending becomes the open set. Anything that closes the turn —
|
|
328
|
+
// user text, a tool result whose deferred-tool references serialize sibling
|
|
329
|
+
// text after the results, or another model's assistant — empties it.
|
|
330
|
+
let pendingUseIds = new Set();
|
|
331
|
+
const loadedReferenceNames = new Set();
|
|
332
|
+
for (const message of messages) {
|
|
333
|
+
if (message.role === "assistant") {
|
|
334
|
+
const priorUseIds = pendingUseIds;
|
|
335
|
+
pendingUseIds = new Set();
|
|
336
|
+
if (!isSameAnthropicModel(message, model))
|
|
337
|
+
continue;
|
|
338
|
+
for (const block of message.content) {
|
|
339
|
+
if (block.type !== "providerNative" || !isRecord(block.raw))
|
|
340
|
+
continue;
|
|
341
|
+
const raw = block.raw;
|
|
342
|
+
if (typeof raw.type !== "string" || !REPLAYABLE_ANTHROPIC_PROVIDER_NATIVE_TYPES.has(raw.type))
|
|
343
|
+
continue;
|
|
344
|
+
if (isProviderNativeToolUseBlock(raw) && typeof raw.id === "string")
|
|
345
|
+
pendingUseIds.add(raw.id);
|
|
346
|
+
}
|
|
347
|
+
for (const block of message.content) {
|
|
348
|
+
if (block.type !== "providerNative" || !isRecord(block.raw))
|
|
349
|
+
continue;
|
|
350
|
+
const raw = block.raw;
|
|
351
|
+
if (typeof raw.type !== "string" || !REPLAYABLE_ANTHROPIC_PROVIDER_NATIVE_TYPES.has(raw.type))
|
|
352
|
+
continue;
|
|
353
|
+
const toolUseId = raw.tool_use_id;
|
|
354
|
+
if (typeof toolUseId !== "string")
|
|
355
|
+
continue;
|
|
356
|
+
if (priorUseIds.has(toolUseId) || pendingUseIds.has(toolUseId)) {
|
|
357
|
+
resolvedUseIds.add(toolUseId);
|
|
358
|
+
validResultIds.add(toolUseId);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
if (message.role === "toolResult") {
|
|
364
|
+
// Conversion drops a discarded pre-fallback result without touching
|
|
365
|
+
// loadedToolNames, so it must not load the name here either.
|
|
366
|
+
if (discardedFallbackToolCallIds.has(message.toolCallId))
|
|
367
|
+
continue;
|
|
368
|
+
// convertToolResult emits sibling text after the tool_result blocks only
|
|
369
|
+
// for names that survive the deferred/loaded filter, so only those names
|
|
370
|
+
// close the turn; a stale or already-loaded name leaves the result plain
|
|
371
|
+
// and the pending use resumable.
|
|
372
|
+
let emitsReferences = false;
|
|
373
|
+
for (const name of message.addedToolNames ?? []) {
|
|
374
|
+
const normalizedName = normalizeToolName(name);
|
|
375
|
+
if (!deferredToolNames.has(normalizedName) || loadedReferenceNames.has(normalizedName))
|
|
376
|
+
continue;
|
|
377
|
+
loadedReferenceNames.add(normalizedName);
|
|
378
|
+
emitsReferences = true;
|
|
379
|
+
}
|
|
380
|
+
if (emitsReferences)
|
|
381
|
+
pendingUseIds = new Set();
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
if (message.role === "user" && userMessageClosesServerTurn(message)) {
|
|
385
|
+
pendingUseIds = new Set();
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
// Whatever is still pending at the end of history belongs to the last
|
|
389
|
+
// assistant message and can still resume, so it is live rather than unpaired.
|
|
390
|
+
return { resolvedUseIds, liveUseIds: pendingUseIds, validResultIds };
|
|
391
|
+
}
|
|
392
|
+
// True for a server-tool block whose counterpart can never arrive: a use that
|
|
393
|
+
// is neither answered nor resumable, or a result whose use is nowhere.
|
|
394
|
+
// Blocks that pair nothing (`fallback`, `container_upload`) are never unpaired.
|
|
395
|
+
function isUnpairedProviderNativeToolBlock(raw, pairing) {
|
|
396
|
+
if (!isRecord(raw))
|
|
397
|
+
return false;
|
|
398
|
+
if (isProviderNativeToolUseBlock(raw)) {
|
|
399
|
+
return typeof raw.id !== "string" || !(pairing.resolvedUseIds.has(raw.id) || pairing.liveUseIds.has(raw.id));
|
|
400
|
+
}
|
|
401
|
+
const toolUseId = raw.tool_use_id;
|
|
402
|
+
return typeof toolUseId === "string" && !pairing.validResultIds.has(toolUseId);
|
|
403
|
+
}
|
|
312
404
|
// tool_use ids referenced by server-tool result blocks in content[0, boundary).
|
|
313
405
|
// A pre-boundary `server_tool_use` whose id is absent here is unpaired — the
|
|
314
406
|
// fallback interrupted the declined attempt before its result arrived — so
|
|
@@ -1055,6 +1147,18 @@ function cannotDisableThinking(model, compat) {
|
|
|
1055
1147
|
return true;
|
|
1056
1148
|
return matchesModelMarker(model, DISABLED_THINKING_REJECTING_MODEL_MARKERS);
|
|
1057
1149
|
}
|
|
1150
|
+
function disableThinkingForRequest(params, model, compat) {
|
|
1151
|
+
// A degraded/disabled turn must not retain the caller's higher effort.
|
|
1152
|
+
delete params.output_config;
|
|
1153
|
+
if (cannotDisableThinking(model, compat)) {
|
|
1154
|
+
delete params.thinking;
|
|
1155
|
+
if (supportsAdaptiveThinking(model)) {
|
|
1156
|
+
params.output_config = { effort: "low" };
|
|
1157
|
+
}
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
params.thinking = { type: "disabled" };
|
|
1161
|
+
}
|
|
1058
1162
|
function supportsAdaptiveThinking(model) {
|
|
1059
1163
|
if (model.compat?.forceAdaptiveThinking !== undefined) {
|
|
1060
1164
|
return model.compat.forceAdaptiveThinking;
|
|
@@ -1288,20 +1392,18 @@ function buildParams(model, context, isOAuthToken, options, unsignedThinkingRepl
|
|
|
1288
1392
|
}
|
|
1289
1393
|
}
|
|
1290
1394
|
else if (options?.thinkingEnabled === false) {
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
// effort: the request stays valid and reasoning stays at the documented minimum.
|
|
1296
|
-
if (supportsAdaptiveThinking(model)) {
|
|
1297
|
-
params.output_config = { effort: "low" };
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
else {
|
|
1301
|
-
params.thinking = { type: "disabled" };
|
|
1302
|
-
}
|
|
1395
|
+
// Some adaptive families reject `thinking.type: "disabled"` and default
|
|
1396
|
+
// to reasoning when omitted. Keep their request valid at the cheapest
|
|
1397
|
+
// legal effort; use an explicit disabled block everywhere else.
|
|
1398
|
+
disableThinkingForRequest(params, model, compat);
|
|
1303
1399
|
}
|
|
1304
1400
|
}
|
|
1401
|
+
// Anthropic rejects a thinking-enabled request whose final assistant turn
|
|
1402
|
+
// contains tool_use but does not begin with a thinking block. Cross-model
|
|
1403
|
+
// histories lose their signed thinking blocks (demoted to text or dropped),
|
|
1404
|
+
// so degrade thinking for this request instead of failing every turn.
|
|
1405
|
+
if (params.thinking && params.thinking.type !== "disabled" && finalAssistantTurnStartsWithToolUse(params.messages))
|
|
1406
|
+
disableThinkingForRequest(params, model, compat);
|
|
1305
1407
|
if (options?.metadata) {
|
|
1306
1408
|
const userId = options.metadata.user_id;
|
|
1307
1409
|
if (typeof userId === "string") {
|
|
@@ -1331,9 +1433,24 @@ function applyExtraBodyToAnthropicParams(params, extraBody) {
|
|
|
1331
1433
|
Object.defineProperty(params, key, { value, writable: true, enumerable: true, configurable: true });
|
|
1332
1434
|
}
|
|
1333
1435
|
}
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1436
|
+
/**
|
|
1437
|
+
* Whether the final assistant turn contains tool_use without a leading
|
|
1438
|
+
* thinking/redacted_thinking block. Anthropic requires thinking-enabled
|
|
1439
|
+
* requests to start that turn with a thinking block.
|
|
1440
|
+
*/
|
|
1441
|
+
function finalAssistantTurnStartsWithToolUse(messages) {
|
|
1442
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
1443
|
+
const message = messages[index];
|
|
1444
|
+
if (message.role !== "assistant")
|
|
1445
|
+
continue;
|
|
1446
|
+
if (!Array.isArray(message.content) || message.content.length === 0)
|
|
1447
|
+
return false;
|
|
1448
|
+
const first = message.content[0];
|
|
1449
|
+
if (first.type === "thinking" || first.type === "redacted_thinking")
|
|
1450
|
+
return false;
|
|
1451
|
+
return message.content.some((block) => block.type === "tool_use");
|
|
1452
|
+
}
|
|
1453
|
+
return false;
|
|
1337
1454
|
}
|
|
1338
1455
|
function convertToolResult(msg, isOAuthToken, deferredToolNames, loadedToolNames, normalizeToolName) {
|
|
1339
1456
|
const references = [];
|
|
@@ -1372,6 +1489,7 @@ function convertMessages(transformedMessages, model, isOAuthToken, cacheControl,
|
|
|
1372
1489
|
// assistant turn below; drop their tool_results in lockstep so none dangle.
|
|
1373
1490
|
const discardedFallbackToolCallIds = collectDiscardedFallbackToolCallIds(transformedMessages, model);
|
|
1374
1491
|
const rejectsNativeWebSearchReplay = !getAnthropicCompat(model).supportsWebSearch;
|
|
1492
|
+
const providerNativeToolPairing = collectProviderNativeToolPairing(transformedMessages, model, deferredToolNames, normalizeToolName, discardedFallbackToolCallIds);
|
|
1375
1493
|
for (let i = 0; i < transformedMessages.length; i++) {
|
|
1376
1494
|
const msg = transformedMessages[i];
|
|
1377
1495
|
if (msg.role === "user") {
|
|
@@ -1505,7 +1623,8 @@ function convertMessages(transformedMessages, model, isOAuthToken, cacheControl,
|
|
|
1505
1623
|
else if (block.type === "providerNative") {
|
|
1506
1624
|
if (isSameModel &&
|
|
1507
1625
|
isReplayableAnthropicProviderNativeBlock(block.raw) &&
|
|
1508
|
-
!(rejectsNativeWebSearchReplay && isAnthropicWebSearchReplayBlock(block.raw))
|
|
1626
|
+
!(rejectsNativeWebSearchReplay && isAnthropicWebSearchReplayBlock(block.raw)) &&
|
|
1627
|
+
!isUnpairedProviderNativeToolBlock(block.raw, providerNativeToolPairing)) {
|
|
1509
1628
|
blocks.push(block.raw);
|
|
1510
1629
|
}
|
|
1511
1630
|
}
|