@nick3/copilot-api 1.4.9 → 1.5.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 (40) hide show
  1. package/README.md +5 -3
  2. package/dist/account-BMFr8t9b.js +362 -0
  3. package/dist/account-BMFr8t9b.js.map +1 -0
  4. package/dist/{accounts-manager-Cjrd_el_.js → accounts-manager-DgQH4KtO.js} +114 -13
  5. package/dist/accounts-manager-DgQH4KtO.js.map +1 -0
  6. package/dist/admin/assets/index-519a65q_.js +66 -0
  7. package/dist/admin/assets/index-ChMaMig2.css +1 -0
  8. package/dist/admin/index.html +2 -2
  9. package/dist/{auth-1gAffrpI.js → auth-DipSy-jV.js} +6 -12
  10. package/dist/auth-DipSy-jV.js.map +1 -0
  11. package/dist/{check-usage-CsRu467P.js → check-usage-Dbjs73E0.js} +5 -5
  12. package/dist/check-usage-Dbjs73E0.js.map +1 -0
  13. package/dist/{debug-BzR5ZQUk.js → debug-BJfZVBB7.js} +2 -2
  14. package/dist/{debug-BzR5ZQUk.js.map → debug-BJfZVBB7.js.map} +1 -1
  15. package/dist/{get-copilot-token-BbpphnmV.js → get-copilot-token-DoK8Ia3u.js} +2 -2
  16. package/dist/{get-copilot-token-BbpphnmV.js.map → get-copilot-token-DoK8Ia3u.js.map} +1 -1
  17. package/dist/main.js +4 -4
  18. package/dist/{paths-Cvzy-eLX.js → paths-DGlr310R.js} +2 -2
  19. package/dist/{paths-Cvzy-eLX.js.map → paths-DGlr310R.js.map} +1 -1
  20. package/dist/{utils-DY-jLXwO.js → poll-access-token-BzenaGHn.js} +352 -52
  21. package/dist/poll-access-token-BzenaGHn.js.map +1 -0
  22. package/dist/{server-DqwhClJ-.js → server-DzE_zmUf.js} +498 -136
  23. package/dist/server-DzE_zmUf.js.map +1 -0
  24. package/dist/{start-B1_Ols5Z.js → start-DEugVHqn.js} +26 -15
  25. package/dist/start-DEugVHqn.js.map +1 -0
  26. package/package.json +1 -1
  27. package/dist/account-CipKmikF.js +0 -17
  28. package/dist/account-CipKmikF.js.map +0 -1
  29. package/dist/accounts-manager-Cjrd_el_.js.map +0 -1
  30. package/dist/accounts-registry-CQYvRe65.js +0 -180
  31. package/dist/accounts-registry-CQYvRe65.js.map +0 -1
  32. package/dist/admin/assets/index-BFvCJZIK.js +0 -57
  33. package/dist/admin/assets/index-CsAeel_7.css +0 -1
  34. package/dist/auth-1gAffrpI.js.map +0 -1
  35. package/dist/check-usage-CsRu467P.js.map +0 -1
  36. package/dist/poll-access-token-CGfLFzMq.js +0 -52
  37. package/dist/poll-access-token-CGfLFzMq.js.map +0 -1
  38. package/dist/server-DqwhClJ-.js.map +0 -1
  39. package/dist/start-B1_Ols5Z.js.map +0 -1
  40. package/dist/utils-DY-jLXwO.js.map +0 -1
@@ -1,13 +1,13 @@
1
- import { t as PATHS } from "./paths-Cvzy-eLX.js";
2
- import { i as listAccountsFromRegistry } from "./accounts-registry-CQYvRe65.js";
3
- import { C as prepareInteractionHeaders, D as state, E as accountFromState, S as prepareForCompact, T as resolveTraceId, _ as copilotHeaders, a as generateRequestIdFromPayload, c as isNullish, g as copilotBaseUrl, h as forwardError, l as parseUserIdMetadata, m as HTTPError, n as cacheModels, o as getRootSessionId, p as getCopilotUsage, s as getUUID, u as sleep, w as requestContext } from "./utils-DY-jLXwO.js";
4
- import "./get-copilot-token-BbpphnmV.js";
5
- import { _ as isMessagesApiEnabled, a as getClaudeTokenMultiplier, b as mergeConfigWithDefaults, c as getModelAliases, d as getProviderConfig, f as getReasoningEffortForModel, g as isMessageStartInputTokensFallbackEnabled, h as isForceAgentEnabled, i as getAnthropicApiKey, l as getModelAliasesInfo, m as isAccountAffinityEnabled, n as PROVIDER_TYPE_ANTHROPIC, o as getConfig, p as getSmallModel, r as getAliasTargetSet, s as getExtraPromptForModel, t as accountsManager, u as getModelRefreshIntervalMs, v as isResponsesApiContextManagementModel, x as shouldCompactUseSmallModel, y as isResponsesApiWebSearchEnabled } from "./accounts-manager-Cjrd_el_.js";
1
+ import { A as resolveTraceId, C as normalizeDomain, D as accountFromState, E as prepareMessageProxyHeaders, O as state, T as prepareInteractionHeaders, _ as HTTPError, b as copilotHeaders, c as getRootSessionId, d as parseUserIdMetadata, f as sleep, g as getCopilotUsage, h as getDeviceCode, k as requestContext, l as getUUID, m as getGitHubUser, r as cacheModels, s as generateRequestIdFromPayload, t as pollAccessToken, u as isNullish, v as forwardError, w as prepareForCompact, y as copilotBaseUrl } from "./poll-access-token-BzenaGHn.js";
2
+ import { a as getAccountClientIdentityByLoginAndApp, c as listAccountsFromRegistry, f as removeAccountFromRegistry, g as DEFAULT_IDENTITY_ENTERPRISE_DOMAIN, h as saveRegistry, m as saveAccountToken, p as removeAccountToken, r as addAccountToRegistry, t as isAccountType, u as loadRegistry, y as getCurrentIdentityEnvironment } from "./account-BMFr8t9b.js";
3
+ import { r as ensurePaths, t as PATHS } from "./paths-DGlr310R.js";
4
+ import "./get-copilot-token-DoK8Ia3u.js";
5
+ import { _ as isMessagesApiEnabled, a as getClaudeTokenMultiplier, b as mergeConfigWithDefaults, c as getModelAliases, d as getProviderConfig, f as getReasoningEffortForModel, g as isMessageStartInputTokensFallbackEnabled, h as isForceAgentEnabled, i as getAnthropicApiKey, l as getModelAliasesInfo, m as isAccountAffinityEnabled, n as PROVIDER_TYPE_ANTHROPIC, o as getConfig, p as getSmallModel, r as getAliasTargetSet, s as getExtraPromptForModel, t as accountsManager, u as getModelRefreshIntervalMs, v as isResponsesApiContextManagementModel, x as shouldCompactUseSmallModel, y as isResponsesApiWebSearchEnabled } from "./accounts-manager-DgQH4KtO.js";
6
6
  import consola from "consola";
7
7
  import fs, { readFile } from "node:fs/promises";
8
+ import { randomUUID, timingSafeEqual } from "node:crypto";
8
9
  import * as path$1 from "node:path";
9
10
  import path from "node:path";
10
- import { randomUUID, timingSafeEqual } from "node:crypto";
11
11
  import { Hono } from "hono";
12
12
  import { cors } from "hono/cors";
13
13
  import { logger } from "hono/logger";
@@ -112,7 +112,9 @@ const traceIdMiddleware = async (c, next) => {
112
112
  const context = {
113
113
  traceId,
114
114
  startTime: Date.now(),
115
- userAgent: c.req.header("user-agent") || ""
115
+ userAgent: c.req.header("user-agent") || "",
116
+ sessionAffinity: c.req.header("x-session-affinity"),
117
+ parentSessionId: c.req.header("x-parent-session-id")
116
118
  };
117
119
  await requestContext.run(context, async () => {
118
120
  await next();
@@ -690,6 +692,162 @@ function extractResponsesUsageFromResult(result) {
690
692
  return normalizeResponsesUsage(result.usage);
691
693
  }
692
694
 
695
+ //#endregion
696
+ //#region src/routes/admin-api/auth-sessions.ts
697
+ function buildOauthUrls(enterpriseDomain) {
698
+ if (!enterpriseDomain) return void 0;
699
+ const domain = normalizeDomain(enterpriseDomain);
700
+ if (!domain) return void 0;
701
+ return {
702
+ deviceCodeUrl: `https://${domain}/login/device/code`,
703
+ accessTokenUrl: `https://${domain}/login/oauth/access_token`
704
+ };
705
+ }
706
+ const CLEANUP_INTERVAL_MS$1 = 6e4;
707
+ var AuthSessionManager = class {
708
+ sessions = /* @__PURE__ */ new Map();
709
+ cleanupTimer = null;
710
+ start() {
711
+ if (this.cleanupTimer) return;
712
+ this.cleanupTimer = setInterval(() => this.cleanupExpired(), CLEANUP_INTERVAL_MS$1);
713
+ }
714
+ stop() {
715
+ if (this.cleanupTimer) {
716
+ clearInterval(this.cleanupTimer);
717
+ this.cleanupTimer = null;
718
+ }
719
+ for (const session of this.sessions.values()) session.abortController.abort();
720
+ this.sessions.clear();
721
+ }
722
+ async startAuth(params) {
723
+ const enterpriseDomain = params.enterpriseDomain ? normalizeDomain(params.enterpriseDomain) : null;
724
+ const overrideUrls = buildOauthUrls(enterpriseDomain);
725
+ await ensurePaths();
726
+ const deviceResponse = await getDeviceCode({ overrideUrls });
727
+ const sessionId = randomUUID();
728
+ const abortController = new AbortController();
729
+ const expiresAt = Date.now() + deviceResponse.expires_in * 1e3;
730
+ const session = {
731
+ sessionId,
732
+ accountType: params.accountType,
733
+ enterpriseDomain,
734
+ status: "pending",
735
+ userCode: deviceResponse.user_code,
736
+ verificationUri: deviceResponse.verification_uri,
737
+ expiresAt,
738
+ interval: deviceResponse.interval,
739
+ abortController,
740
+ reauthAccountId: params.reauthAccountId ?? null
741
+ };
742
+ this.sessions.set(sessionId, session);
743
+ this.runAuthFlow(session, deviceResponse, overrideUrls);
744
+ return {
745
+ sessionId,
746
+ userCode: deviceResponse.user_code,
747
+ verificationUri: deviceResponse.verification_uri,
748
+ expiresIn: deviceResponse.expires_in,
749
+ interval: deviceResponse.interval
750
+ };
751
+ }
752
+ getStatus(sessionId) {
753
+ const session = this.sessions.get(sessionId);
754
+ if (!session) return null;
755
+ if (session.status === "pending" && Date.now() >= session.expiresAt) {
756
+ session.status = "expired";
757
+ session.abortController.abort();
758
+ }
759
+ return {
760
+ status: session.status,
761
+ accountId: session.accountId,
762
+ error: session.error
763
+ };
764
+ }
765
+ cancel(sessionId) {
766
+ const session = this.sessions.get(sessionId);
767
+ if (!session) return false;
768
+ session.abortController.abort();
769
+ this.sessions.delete(sessionId);
770
+ return true;
771
+ }
772
+ getLiveSession(sessionId) {
773
+ const session = this.sessions.get(sessionId);
774
+ if (!session || session.abortController.signal.aborted) return null;
775
+ return session;
776
+ }
777
+ async runAuthFlow(session, deviceResponse, overrideUrls) {
778
+ try {
779
+ const sessionId = session.sessionId;
780
+ const signal = session.abortController.signal;
781
+ const token = await pollAccessToken(deviceResponse, {
782
+ overrideUrls,
783
+ signal
784
+ });
785
+ if (!this.getLiveSession(sessionId)) return;
786
+ const user = await getGitHubUser({
787
+ githubToken: token,
788
+ accountType: session.accountType
789
+ });
790
+ if (!this.getLiveSession(sessionId)) return;
791
+ const accountId = user.login;
792
+ if (session.reauthAccountId && session.reauthAccountId !== accountId) {
793
+ this.failSession(sessionId, `Authenticated as "${accountId}" but expected "${session.reauthAccountId}". Use "Add Account" to add a different account.`);
794
+ return;
795
+ }
796
+ if (!this.getLiveSession(sessionId)) return;
797
+ await saveAccountToken(accountId, token);
798
+ if (!this.getLiveSession(sessionId)) return;
799
+ if (!this.getLiveSession(sessionId)) return;
800
+ const existingAccounts = await listAccountsFromRegistry();
801
+ if (!this.getLiveSession(sessionId)) return;
802
+ if (existingAccounts.some((acc) => acc.id === accountId)) {
803
+ const registry = await loadRegistry();
804
+ if (!this.getLiveSession(sessionId)) return;
805
+ await saveRegistry(registry);
806
+ } else {
807
+ if (!this.getLiveSession(sessionId)) return;
808
+ await addAccountToRegistry({
809
+ id: accountId,
810
+ accountType: session.accountType,
811
+ addedAt: Date.now()
812
+ });
813
+ }
814
+ if (!this.getLiveSession(sessionId)) return;
815
+ this.completeSession(sessionId, accountId);
816
+ } catch (error) {
817
+ if (session.abortController.signal.aborted) return;
818
+ this.failSession(session.sessionId, error instanceof Error ? error.message : String(error));
819
+ consola.error(`Auth session ${session.sessionId} failed:`, error);
820
+ }
821
+ }
822
+ completeSession(sessionId, accountId) {
823
+ const session = this.sessions.get(sessionId);
824
+ if (!session || session.abortController.signal.aborted) return;
825
+ session.status = "completed";
826
+ session.accountId = accountId;
827
+ }
828
+ failSession(sessionId, error) {
829
+ const session = this.sessions.get(sessionId);
830
+ if (!session || session.abortController.signal.aborted) return;
831
+ session.status = "failed";
832
+ session.error = error;
833
+ }
834
+ cleanupExpired() {
835
+ const now = Date.now();
836
+ const cleanupThreshold = 5 * 6e4;
837
+ for (const [id, session] of this.sessions) {
838
+ if (session.status !== "pending" && now - session.expiresAt > cleanupThreshold) {
839
+ session.abortController.abort();
840
+ this.sessions.delete(id);
841
+ }
842
+ if (session.status === "pending" && now >= session.expiresAt) {
843
+ session.status = "expired";
844
+ session.abortController.abort();
845
+ }
846
+ }
847
+ }
848
+ };
849
+ const authSessionManager = new AuthSessionManager();
850
+
693
851
  //#endregion
694
852
  //#region src/routes/admin-api/route.ts
695
853
  const ADMIN_TOKEN = process.env.ADMIN_TOKEN?.trim() || void 0;
@@ -1166,6 +1324,7 @@ adminApiRoutes.use("*", async (c, next) => {
1166
1324
  } }, decision.status);
1167
1325
  await next();
1168
1326
  });
1327
+ authSessionManager.start();
1169
1328
  adminApiRoutes.get("/meta", (c) => {
1170
1329
  const store = getRequestHistoryStore();
1171
1330
  return c.json(store.meta());
@@ -1395,6 +1554,115 @@ adminApiRoutes.get("/requests/:requestId", (c) => {
1395
1554
  const item = getRequestHistoryStore().getByRequestId(requestId);
1396
1555
  return c.json({ item });
1397
1556
  });
1557
+ adminApiRoutes.post("/accounts/auth/start", async (c) => {
1558
+ let payload;
1559
+ try {
1560
+ payload = await c.req.json();
1561
+ } catch {
1562
+ return jsonError(c, 400, {
1563
+ message: "Request body must be valid JSON.",
1564
+ type: "bad_request"
1565
+ });
1566
+ }
1567
+ if (!isPlainObject(payload)) return jsonError(c, 400, {
1568
+ message: "Request body must be an object.",
1569
+ type: "bad_request"
1570
+ });
1571
+ const accountType = payload.accountType;
1572
+ if (!isAccountType(accountType)) return jsonError(c, 400, {
1573
+ message: "accountType must be one of: individual, business, enterprise",
1574
+ type: "bad_request"
1575
+ });
1576
+ const enterpriseDomainRaw = payload.enterpriseDomain;
1577
+ let enterpriseDomain;
1578
+ if (accountType === "enterprise" && typeof enterpriseDomainRaw === "string") enterpriseDomain = enterpriseDomainRaw.trim();
1579
+ if (accountType === "enterprise" && !enterpriseDomain) return jsonError(c, 400, {
1580
+ message: "enterpriseDomain is required for enterprise accounts.",
1581
+ type: "bad_request"
1582
+ });
1583
+ try {
1584
+ const result = await authSessionManager.startAuth({
1585
+ accountType,
1586
+ enterpriseDomain
1587
+ });
1588
+ return c.json(result);
1589
+ } catch (error) {
1590
+ return jsonError(c, 500, {
1591
+ message: `Failed to start auth: ${error instanceof Error ? error.message : String(error)}`,
1592
+ type: "internal_error"
1593
+ });
1594
+ }
1595
+ });
1596
+ adminApiRoutes.get("/accounts/auth/status/:sessionId", (c) => {
1597
+ const sessionId = c.req.param("sessionId");
1598
+ const status = authSessionManager.getStatus(sessionId);
1599
+ if (!status) return jsonError(c, 404, {
1600
+ message: "Session not found.",
1601
+ type: "not_found"
1602
+ });
1603
+ return c.json(status);
1604
+ });
1605
+ adminApiRoutes.post("/accounts/auth/cancel/:sessionId", (c) => {
1606
+ const sessionId = c.req.param("sessionId");
1607
+ if (!authSessionManager.cancel(sessionId)) return jsonError(c, 404, {
1608
+ message: "Session not found.",
1609
+ type: "not_found"
1610
+ });
1611
+ return c.json({ cancelled: true });
1612
+ });
1613
+ adminApiRoutes.delete("/accounts/:id", async (c) => {
1614
+ const accountId = c.req.param("id");
1615
+ try {
1616
+ if (!(await listAccountsFromRegistry()).some((a) => a.id === accountId)) return jsonError(c, 404, {
1617
+ message: "Account not found.",
1618
+ type: "not_found"
1619
+ });
1620
+ await removeAccountFromRegistry(accountId);
1621
+ try {
1622
+ await removeAccountToken(accountId);
1623
+ } catch (error) {
1624
+ console.error(`Account ${accountId} deleted but token cleanup failed.`, error);
1625
+ }
1626
+ return c.json({
1627
+ deleted: true,
1628
+ accountId
1629
+ });
1630
+ } catch (error) {
1631
+ return jsonError(c, 500, {
1632
+ message: `Failed to delete account: ${error instanceof Error ? error.message : String(error)}`,
1633
+ type: "internal_error"
1634
+ });
1635
+ }
1636
+ });
1637
+ adminApiRoutes.post("/accounts/:id/reauth", async (c) => {
1638
+ const accountId = c.req.param("id");
1639
+ try {
1640
+ const account = (await listAccountsFromRegistry()).find((a) => a.id === accountId);
1641
+ if (!account) return jsonError(c, 404, {
1642
+ message: "Account not found.",
1643
+ type: "not_found"
1644
+ });
1645
+ const { oauthApp } = getCurrentIdentityEnvironment();
1646
+ const resolvedEnterpriseDomain = (await getAccountClientIdentityByLoginAndApp(accountId, oauthApp))?.enterpriseDomain;
1647
+ let enterpriseDomain;
1648
+ if (resolvedEnterpriseDomain && resolvedEnterpriseDomain !== DEFAULT_IDENTITY_ENTERPRISE_DOMAIN) enterpriseDomain = resolvedEnterpriseDomain;
1649
+ if (account.accountType === "enterprise" && !enterpriseDomain) return jsonError(c, 400, {
1650
+ message: "Cannot re-authenticate enterprise account: enterprise domain could not be resolved from stored identity.",
1651
+ type: "bad_request"
1652
+ });
1653
+ const result = await authSessionManager.startAuth({
1654
+ accountType: account.accountType,
1655
+ enterpriseDomain,
1656
+ reauthAccountId: accountId
1657
+ });
1658
+ return c.json(result);
1659
+ } catch (error) {
1660
+ return jsonError(c, 500, {
1661
+ message: `Failed to start reauth: ${error instanceof Error ? error.message : String(error)}`,
1662
+ type: "internal_error"
1663
+ });
1664
+ }
1665
+ });
1398
1666
 
1399
1667
  //#endregion
1400
1668
  //#region src/routes/admin/route.ts
@@ -2053,10 +2321,15 @@ function computeDiff(before, after) {
2053
2321
  }
2054
2322
  function toAccountContext(account) {
2055
2323
  return {
2324
+ accountLogin: account.accountLogin,
2056
2325
  githubToken: account.githubToken,
2057
2326
  copilotToken: account.copilotToken,
2327
+ ...account.copilotApiUrl !== void 0 ? { copilotApiUrl: account.copilotApiUrl } : {},
2058
2328
  accountType: account.accountType,
2059
- vsCodeVersion: account.vsCodeVersion
2329
+ vsCodeVersion: account.vsCodeVersion,
2330
+ clientDeviceId: account.clientDeviceId,
2331
+ clientMachineId: account.clientMachineId,
2332
+ clientSessionId: account.clientSessionId
2060
2333
  };
2061
2334
  }
2062
2335
  function extractErrorDetails(error) {
@@ -2081,6 +2354,9 @@ const FLUSH_INTERVAL_MS = 1e3;
2081
2354
  const MAX_BUFFER_SIZE = 100;
2082
2355
  const logStreams = /* @__PURE__ */ new Map();
2083
2356
  const logBuffers = /* @__PURE__ */ new Map();
2357
+ let runtimeInitialized = false;
2358
+ let flushInterval;
2359
+ let cleanupInterval;
2084
2360
  const ensureLogDirectory = () => {
2085
2361
  if (!fs$1.existsSync(LOG_DIR)) fs$1.mkdirSync(LOG_DIR, { recursive: true });
2086
2362
  };
@@ -2111,17 +2387,8 @@ const sanitizeName = (name) => {
2111
2387
  const normalized = name.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replaceAll(/^-+|-+$/g, "");
2112
2388
  return normalized === "" ? "handler" : normalized;
2113
2389
  };
2114
- const getLogStream = (filePath) => {
2115
- let stream = logStreams.get(filePath);
2116
- if (!stream || stream.destroyed) {
2117
- stream = fs$1.createWriteStream(filePath, { flags: "a" });
2118
- logStreams.set(filePath, stream);
2119
- stream.on("error", (error) => {
2120
- console.warn("Log stream error", error);
2121
- logStreams.delete(filePath);
2122
- });
2123
- }
2124
- return stream;
2390
+ const maybeUnref = (timer) => {
2391
+ timer.unref();
2125
2392
  };
2126
2393
  const flushBuffer = (filePath) => {
2127
2394
  const buffer = logBuffers.get(filePath);
@@ -2136,6 +2403,52 @@ const flushBuffer = (filePath) => {
2136
2403
  const flushAllBuffers = () => {
2137
2404
  for (const filePath of logBuffers.keys()) flushBuffer(filePath);
2138
2405
  };
2406
+ const cleanup = () => {
2407
+ if (flushInterval) {
2408
+ clearInterval(flushInterval);
2409
+ flushInterval = void 0;
2410
+ }
2411
+ if (cleanupInterval) {
2412
+ clearInterval(cleanupInterval);
2413
+ cleanupInterval = void 0;
2414
+ }
2415
+ flushAllBuffers();
2416
+ for (const stream of logStreams.values()) stream.end();
2417
+ logStreams.clear();
2418
+ logBuffers.clear();
2419
+ };
2420
+ const initializeLoggerRuntime = () => {
2421
+ if (runtimeInitialized) return;
2422
+ runtimeInitialized = true;
2423
+ ensureLogDirectory();
2424
+ cleanupOldLogs();
2425
+ flushInterval = setInterval(flushAllBuffers, FLUSH_INTERVAL_MS);
2426
+ maybeUnref(flushInterval);
2427
+ cleanupInterval = setInterval(cleanupOldLogs, CLEANUP_INTERVAL_MS);
2428
+ maybeUnref(cleanupInterval);
2429
+ process.once("exit", cleanup);
2430
+ process.once("SIGINT", () => {
2431
+ cleanup();
2432
+ process.exit(0);
2433
+ });
2434
+ process.once("SIGTERM", () => {
2435
+ cleanup();
2436
+ process.exit(0);
2437
+ });
2438
+ };
2439
+ const getLogStream = (filePath) => {
2440
+ initializeLoggerRuntime();
2441
+ let stream = logStreams.get(filePath);
2442
+ if (!stream || stream.destroyed) {
2443
+ stream = fs$1.createWriteStream(filePath, { flags: "a" });
2444
+ logStreams.set(filePath, stream);
2445
+ stream.on("error", (error) => {
2446
+ console.warn("Log stream error", error);
2447
+ logStreams.delete(filePath);
2448
+ });
2449
+ }
2450
+ return stream;
2451
+ };
2139
2452
  const appendLine = (filePath, line) => {
2140
2453
  let buffer = logBuffers.get(filePath);
2141
2454
  if (!buffer) {
@@ -2145,35 +2458,23 @@ const appendLine = (filePath, line) => {
2145
2458
  buffer.push(line);
2146
2459
  if (buffer.length >= MAX_BUFFER_SIZE) flushBuffer(filePath);
2147
2460
  };
2148
- setInterval(flushAllBuffers, FLUSH_INTERVAL_MS);
2149
- const cleanup = () => {
2150
- flushAllBuffers();
2151
- for (const stream of logStreams.values()) stream.end();
2152
- logStreams.clear();
2153
- logBuffers.clear();
2461
+ const debugLazy = (logger$7, factory) => {
2462
+ if (!state.verbose) return;
2463
+ logger$7.debug(...factory());
2464
+ };
2465
+ const debugJson = (logger$7, label, value) => {
2466
+ debugLazy(logger$7, () => [label, JSON.stringify(value)]);
2467
+ };
2468
+ const debugJsonTail = (logger$7, label, { value, tailLength = 400 }) => {
2469
+ debugLazy(logger$7, () => [label, JSON.stringify(value).slice(-tailLength)]);
2154
2470
  };
2155
- process.on("exit", cleanup);
2156
- process.on("SIGINT", () => {
2157
- cleanup();
2158
- process.exit(0);
2159
- });
2160
- process.on("SIGTERM", () => {
2161
- cleanup();
2162
- process.exit(0);
2163
- });
2164
- let lastCleanup = 0;
2165
2471
  const createHandlerLogger = (name) => {
2166
- ensureLogDirectory();
2167
2472
  const sanitizedName = sanitizeName(name);
2168
2473
  const instance = consola.withTag(name);
2169
2474
  if (state.verbose) instance.level = 5;
2170
2475
  instance.setReporters([]);
2171
2476
  instance.addReporter({ log(logObj) {
2172
- ensureLogDirectory();
2173
- if (Date.now() - lastCleanup > CLEANUP_INTERVAL_MS) {
2174
- cleanupOldLogs();
2175
- lastCleanup = Date.now();
2176
- }
2477
+ initializeLoggerRuntime();
2177
2478
  const traceId = requestContext.getStore()?.traceId;
2178
2479
  const date = logObj.date;
2179
2480
  const dateKey = date.toLocaleDateString("sv-SE");
@@ -2503,7 +2804,10 @@ async function handleCompletion$1(c) {
2503
2804
  reason: "MODEL_NOT_SUPPORTED"
2504
2805
  });
2505
2806
  }
2506
- logger$6.debug("Request payload:", JSON.stringify(payload).slice(-400));
2807
+ debugJsonTail(logger$6, "Request payload:", {
2808
+ value: payload,
2809
+ tailLength: 400
2810
+ });
2507
2811
  const upstreamRequestId = generateRequestIdFromPayload(payload, normalizedPromptCacheKey);
2508
2812
  const selection = await accountsManager.selectAccountForRequest([{
2509
2813
  modelId: clientModel,
@@ -2636,7 +2940,7 @@ function applyDefaultMaxTokens(payload, selectedModel) {
2636
2940
  ...payload,
2637
2941
  max_tokens: selectedModel.capabilities.limits.max_output_tokens
2638
2942
  };
2639
- logger$6.debug("Set max_tokens to:", JSON.stringify(updated.max_tokens));
2943
+ debugJson(logger$6, "Set max_tokens to:", updated.max_tokens);
2640
2944
  return updated;
2641
2945
  }
2642
2946
  async function handleStreamingRequest(params) {
@@ -2722,7 +3026,7 @@ async function handleNonStreamingUpstreamResponse(params) {
2722
3026
  let errorMessage;
2723
3027
  const finishedAtMs = Date.now();
2724
3028
  try {
2725
- logger$6.debug("Non-streaming response:", JSON.stringify(response));
3029
+ debugJson(logger$6, "Non-streaming response:", response);
2726
3030
  return c.json(response);
2727
3031
  } catch (error) {
2728
3032
  const details = extractErrorDetails(error);
@@ -2772,7 +3076,7 @@ async function streamChatCompletionsAndLog$1(params) {
2772
3076
  if (ttfbMs === void 0) ttfbMs = Date.now() - request.startedAtMs;
2773
3077
  const usage = await extractUsageFromChunk(chunk);
2774
3078
  if (usage) lastUsage = usage;
2775
- logger$6.debug("Streaming chunk:", JSON.stringify(chunk));
3079
+ debugJson(logger$6, "Streaming chunk:", chunk);
2776
3080
  await stream.writeSSE(chunk);
2777
3081
  }
2778
3082
  } catch (error) {
@@ -2844,7 +3148,7 @@ async function handleNonStreamingRequest(params) {
2844
3148
  });
2845
3149
  }
2846
3150
  usage = normalizeChatCompletionsUsage(response.usage);
2847
- logger$6.debug("Non-streaming response:", JSON.stringify(response));
3151
+ debugJson(logger$6, "Non-streaming response:", response);
2848
3152
  return c.json(response);
2849
3153
  } catch (error) {
2850
3154
  finishedAtMs = Date.now();
@@ -3110,43 +3414,72 @@ const _normalizeSdkModelId = (sdkModelId) => {
3110
3414
  };
3111
3415
 
3112
3416
  //#endregion
3113
- //#region src/routes/messages/utils.ts
3114
- function mapOpenAIStopReasonToAnthropic(finishReason) {
3115
- if (finishReason === null) return null;
3116
- return {
3117
- stop: "end_turn",
3118
- length: "max_tokens",
3119
- tool_calls: "tool_use",
3120
- content_filter: "end_turn"
3121
- }[finishReason];
3122
- }
3123
- const mergeContentWithText = (toolResult, textBlock) => {
3124
- if (typeof toolResult.content === "string") return {
3125
- ...toolResult,
3126
- content: `${toolResult.content}\n\n${textBlock.text}`
3417
+ //#region src/routes/messages/preprocess.ts
3418
+ const compactSystemPromptStart = "You are a helpful AI assistant tasked with summarizing conversations";
3419
+ const compactTextOnlyGuard = "CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.";
3420
+ const compactSummaryPromptStart = "Your task is to create a detailed summary of the conversation so far";
3421
+ const compactMessageSections = ["Pending Tasks:", "Current Work:"];
3422
+ const TOOL_REFERENCE_TURN_BOUNDARY = "Tool loaded.";
3423
+ const getAnthropicEffortForModel = (model) => {
3424
+ const reasoningEffort = getReasoningEffortForModel(model);
3425
+ if (reasoningEffort === "xhigh") return "max";
3426
+ if (reasoningEffort === "none" || reasoningEffort === "minimal") return "low";
3427
+ return reasoningEffort;
3428
+ };
3429
+ const getCompactCandidateText = (message) => {
3430
+ if (message.role !== "user") return "";
3431
+ if (typeof message.content === "string") return message.content;
3432
+ return message.content.filter((block) => block.type === "text").map((block) => block.text.startsWith("<system-reminder>") ? "" : block.text).filter((text) => text.length > 0).join("\n\n");
3433
+ };
3434
+ const isCompactMessage = (lastMessage) => {
3435
+ const text = getCompactCandidateText(lastMessage);
3436
+ if (!text) return false;
3437
+ return text.includes(compactTextOnlyGuard) && text.includes(compactSummaryPromptStart) && compactMessageSections.some((section) => text.includes(section));
3438
+ };
3439
+ const isCompactRequest = (anthropicPayload) => {
3440
+ const lastMessage = anthropicPayload.messages.at(-1);
3441
+ if (lastMessage && isCompactMessage(lastMessage)) return true;
3442
+ const system = anthropicPayload.system;
3443
+ if (typeof system === "string") return system.startsWith(compactSystemPromptStart);
3444
+ if (!Array.isArray(system)) return false;
3445
+ return system.some((msg) => typeof msg.text === "string" && msg.text.startsWith(compactSystemPromptStart));
3446
+ };
3447
+ const mergeContentWithText = (tr, textBlock) => {
3448
+ if (typeof tr.content === "string") return {
3449
+ ...tr,
3450
+ content: `${tr.content}\n\n${textBlock.text}`
3127
3451
  };
3452
+ if (hasToolRef(tr)) return tr;
3128
3453
  return {
3129
- ...toolResult,
3130
- content: [...toolResult.content, textBlock]
3454
+ ...tr,
3455
+ content: [...tr.content, textBlock]
3131
3456
  };
3132
3457
  };
3133
- const mergeContentWithTexts = (toolResult, textBlocks) => {
3134
- if (typeof toolResult.content === "string") {
3458
+ const mergeContentWithTexts = (tr, textBlocks) => {
3459
+ if (typeof tr.content === "string") {
3135
3460
  const appendedTexts = textBlocks.map((tb) => tb.text).join("\n\n");
3136
3461
  return {
3137
- ...toolResult,
3138
- content: `${toolResult.content}\n\n${appendedTexts}`
3462
+ ...tr,
3463
+ content: `${tr.content}\n\n${appendedTexts}`
3139
3464
  };
3140
3465
  }
3466
+ if (hasToolRef(tr)) return tr;
3141
3467
  return {
3142
- ...toolResult,
3143
- content: [...toolResult.content, ...textBlocks]
3468
+ ...tr,
3469
+ content: [...tr.content, ...textBlocks]
3144
3470
  };
3145
3471
  };
3146
3472
  const mergeToolResult = (toolResults, textBlocks) => {
3147
- if (toolResults.length === textBlocks.length) return toolResults.map((toolResult, index) => mergeContentWithText(toolResult, textBlocks[index]));
3473
+ if (toolResults.length === textBlocks.length) return toolResults.map((tr, i) => mergeContentWithText(tr, textBlocks[i]));
3148
3474
  const lastIndex = toolResults.length - 1;
3149
- return toolResults.map((toolResult, index) => index === lastIndex ? mergeContentWithTexts(toolResult, textBlocks) : toolResult);
3475
+ return toolResults.map((tr, i) => i === lastIndex ? mergeContentWithTexts(tr, textBlocks) : tr);
3476
+ };
3477
+ const stripToolReferenceTurnBoundary = (anthropicPayload) => {
3478
+ for (const msg of anthropicPayload.messages) {
3479
+ if (msg.role !== "user" || !Array.isArray(msg.content)) continue;
3480
+ if (!msg.content.some((block) => block.type === "tool_result" && hasToolRef(block))) continue;
3481
+ msg.content = msg.content.filter((block) => block.type !== "text" || block.text.trim() !== TOOL_REFERENCE_TURN_BOUNDARY);
3482
+ }
3150
3483
  };
3151
3484
  const mergeToolResultForClaude = (anthropicPayload) => {
3152
3485
  for (const msg of anthropicPayload.messages) {
@@ -3164,6 +3497,9 @@ const mergeToolResultForClaude = (anthropicPayload) => {
3164
3497
  msg.content = mergeToolResult(toolResults, textBlocks);
3165
3498
  }
3166
3499
  };
3500
+ const hasToolRef = (block) => {
3501
+ return Array.isArray(block.content) && block.content.some((c) => c.type === "tool_reference");
3502
+ };
3167
3503
  const stripUnsupportedCacheControl = (block) => {
3168
3504
  const cacheControl = block.cache_control;
3169
3505
  if (!cacheControl || typeof cacheControl !== "object" || Array.isArray(cacheControl)) return;
@@ -3180,9 +3516,9 @@ const stripTextBlockCacheControl = (block) => {
3180
3516
  if (record.type !== "text") return;
3181
3517
  stripUnsupportedCacheControl(record);
3182
3518
  };
3183
- const stripCacheControl = (anthropicPayload) => {
3184
- if (Array.isArray(anthropicPayload.system)) for (const block of anthropicPayload.system) stripTextBlockCacheControl(block);
3185
- for (const msg of anthropicPayload.messages) {
3519
+ const stripCacheControl = (payload) => {
3520
+ if (Array.isArray(payload.system)) for (const block of payload.system) stripTextBlockCacheControl(block);
3521
+ for (const msg of payload.messages) {
3186
3522
  if (!Array.isArray(msg.content)) continue;
3187
3523
  for (const block of msg.content) {
3188
3524
  stripTextBlockCacheControl(block);
@@ -3190,6 +3526,34 @@ const stripCacheControl = (anthropicPayload) => {
3190
3526
  }
3191
3527
  }
3192
3528
  };
3529
+ const filterAssistantThinkingBlocks = (payload) => {
3530
+ for (const msg of payload.messages) if (msg.role === "assistant" && Array.isArray(msg.content)) msg.content = msg.content.filter((block) => {
3531
+ if (block.type !== "thinking") return true;
3532
+ return block.thinking && block.thinking !== "Thinking..." && block.signature && !block.signature.includes("@");
3533
+ });
3534
+ };
3535
+ const prepareMessagesApiPayload = (payload, selectedModel) => {
3536
+ stripCacheControl(payload);
3537
+ filterAssistantThinkingBlocks(payload);
3538
+ const toolChoice = payload.tool_choice;
3539
+ const disableThink = toolChoice?.type === "any" || toolChoice?.type === "tool";
3540
+ if (selectedModel?.capabilities.supports.adaptive_thinking && !disableThink) {
3541
+ payload.thinking = { type: "adaptive" };
3542
+ payload.output_config = { effort: getAnthropicEffortForModel(payload.model) };
3543
+ }
3544
+ };
3545
+
3546
+ //#endregion
3547
+ //#region src/routes/messages/utils.ts
3548
+ function mapOpenAIStopReasonToAnthropic(finishReason) {
3549
+ if (finishReason === null) return null;
3550
+ return {
3551
+ stop: "end_turn",
3552
+ length: "max_tokens",
3553
+ tool_calls: "tool_use",
3554
+ content_filter: "end_turn"
3555
+ }[finishReason];
3556
+ }
3193
3557
  const estimateInputTokens = async (payload, selectedModel, logger$7) => {
3194
3558
  try {
3195
3559
  return (await getTokenCount(payload, selectedModel)).input;
@@ -3254,21 +3618,6 @@ const maybeBlockOriginalModelName = (context) => {
3254
3618
  }
3255
3619
  });
3256
3620
  };
3257
- const compactSystemPromptStart = "You are a helpful AI assistant tasked with summarizing conversations";
3258
- const compactUserMessageStart = "CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.";
3259
- const hasCompactUserMessage = (messages) => {
3260
- const lastMsg = messages.at(-1);
3261
- if (!lastMsg || lastMsg.role !== "user") return false;
3262
- if (typeof lastMsg.content === "string") return lastMsg.content.startsWith(compactUserMessageStart);
3263
- if (!Array.isArray(lastMsg.content)) return false;
3264
- return lastMsg.content.some((block) => block.type === "text" && typeof block.text === "string" && block.text.startsWith(compactUserMessageStart));
3265
- };
3266
- const isCompactRequest = (anthropicPayload) => {
3267
- const system = anthropicPayload.system;
3268
- if (typeof system === "string" && system.startsWith(compactSystemPromptStart)) return true;
3269
- if (Array.isArray(system) && system.some((msg) => typeof msg.text === "string" && msg.text.startsWith(compactSystemPromptStart))) return true;
3270
- return hasCompactUserMessage(anthropicPayload.messages);
3271
- };
3272
3621
 
3273
3622
  //#endregion
3274
3623
  //#region src/routes/messages/non-stream-translation.ts
@@ -3374,7 +3723,6 @@ function handleAssistantMessage(message, modelId) {
3374
3723
  function mapContent(content) {
3375
3724
  if (typeof content === "string") return content;
3376
3725
  if (!Array.isArray(content)) return null;
3377
- if (!content.some((block) => block.type === "image")) return content.filter((block) => block.type === "text").map((block) => block.text).join("\n\n");
3378
3726
  const contentParts = [];
3379
3727
  for (const block of content) switch (block.type) {
3380
3728
  case "text":
@@ -3389,6 +3737,12 @@ function mapContent(content) {
3389
3737
  image_url: { url: `data:${block.source.media_type};base64,${block.source.data}` }
3390
3738
  });
3391
3739
  break;
3740
+ case "tool_reference":
3741
+ contentParts.push({
3742
+ type: "text",
3743
+ text: `Tool ${block.tool_name} loaded`
3744
+ });
3745
+ break;
3392
3746
  }
3393
3747
  return contentParts;
3394
3748
  }
@@ -3600,7 +3954,7 @@ const translateAnthropicMessagesToResponsesPayload = (payload, modelOverride) =>
3600
3954
  for (const message of payload.messages) input.push(...translateMessage(message, payload.model, applyPhase));
3601
3955
  const translatedTools = convertAnthropicTools(payload.tools);
3602
3956
  const toolChoice = convertAnthropicToolChoice(payload.tool_choice);
3603
- const { safetyIdentifier, sessionId: promptCacheKey } = parseUserIdMetadata(payload.metadata?.user_id);
3957
+ const { sessionId: promptCacheKey } = parseUserIdMetadata(payload.metadata?.user_id);
3604
3958
  return {
3605
3959
  model,
3606
3960
  input,
@@ -3611,7 +3965,6 @@ const translateAnthropicMessagesToResponsesPayload = (payload, modelOverride) =>
3611
3965
  tools: translatedTools,
3612
3966
  tool_choice: toolChoice,
3613
3967
  metadata: payload.metadata ? { ...payload.metadata } : null,
3614
- safety_identifier: safetyIdentifier,
3615
3968
  prompt_cache_key: promptCacheKey,
3616
3969
  stream: payload.stream ?? null,
3617
3970
  store: false,
@@ -3803,7 +4156,7 @@ const translateSystemPrompt = (system, model) => {
3803
4156
  const extraPrompt = getExtraPromptForModel(model);
3804
4157
  if (typeof system === "string") return system + extraPrompt;
3805
4158
  const text = system.map((block, index) => {
3806
- if (index === 0) return block.text + extraPrompt;
4159
+ if (index === 0) return block.text + "\n\n" + extraPrompt + "\n\n";
3807
4160
  return block.text;
3808
4161
  }).join(" ");
3809
4162
  return text.length > 0 ? text : null;
@@ -4002,6 +4355,9 @@ const convertToolResultContent = (content) => {
4002
4355
  case "image":
4003
4356
  result.push(createImageContent(block));
4004
4357
  break;
4358
+ case "tool_reference":
4359
+ result.push(createTextContent(`Tool ${block.tool_name} loaded`));
4360
+ break;
4005
4361
  default: break;
4006
4362
  }
4007
4363
  return result;
@@ -4443,7 +4799,7 @@ const extractFunctionCallDetails = (rawEvent) => {
4443
4799
  //#region src/routes/responses/utils.ts
4444
4800
  const getResponsesRequestOptions = (payload) => {
4445
4801
  return {
4446
- vision: hasVisionInput(payload),
4802
+ vision: hasVisionInput$1(payload),
4447
4803
  initiator: hasAgentInitiator(payload) ? "agent" : "user"
4448
4804
  };
4449
4805
  };
@@ -4458,7 +4814,7 @@ const isAgentRole = (item) => {
4458
4814
  if (!("role" in item) || !item.role) return true;
4459
4815
  return (typeof item.role === "string" ? item.role.toLowerCase() : "") === "assistant";
4460
4816
  };
4461
- const hasVisionInput = (payload) => {
4817
+ const hasVisionInput$1 = (payload) => {
4462
4818
  return getPayloadItems(payload).some((item) => containsVisionContent(item));
4463
4819
  };
4464
4820
  const resolveResponsesCompactThreshold = (maxPromptTokens) => {
@@ -4535,19 +4891,33 @@ const buildAnthropicBetaHeader = (anthropicBetaHeader, thinking) => {
4535
4891
  }
4536
4892
  if (thinking?.budget_tokens && !isAdaptiveThinking) return INTERLEAVED_THINKING_BETA;
4537
4893
  };
4538
- const createMessages = async (payload, account, options) => {
4539
- const ctx = account ?? accountFromState();
4540
- if (!ctx.copilotToken) throw new Error("Copilot token not found");
4541
- const enableVision = payload.messages.some((message) => Array.isArray(message.content) && message.content.some((block) => block.type === "image"));
4542
- const initiator = options?.initiator ?? getMessagesInitiator(payload);
4894
+ const hasVisionInput = (payload) => payload.messages.some((message) => Array.isArray(message.content) && message.content.some((block) => block.type === "image" || block.type === "tool_result" && Array.isArray(block.content) && block.content.some((inner) => inner.type === "image")));
4895
+ const shouldUseMessageProxyHeaders = (payload) => {
4896
+ const { safetyIdentifier, sessionId } = parseUserIdMetadata(payload.metadata?.user_id);
4897
+ return Boolean(safetyIdentifier && sessionId);
4898
+ };
4899
+ const buildMessagesHeaders = ({ ctx, enableVision, initiator, options, payload }) => {
4543
4900
  const headers = {
4544
4901
  ...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
4545
4902
  "x-initiator": options?.subagentMarker ? "agent" : initiator
4546
4903
  };
4547
4904
  prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
4548
4905
  prepareForCompact(headers, options?.isCompact);
4906
+ if (shouldUseMessageProxyHeaders(payload)) prepareMessageProxyHeaders(headers);
4549
4907
  const anthropicBeta = buildAnthropicBetaHeader(options?.anthropicBetaHeader, payload.thinking);
4550
4908
  if (anthropicBeta) headers["anthropic-beta"] = anthropicBeta;
4909
+ return headers;
4910
+ };
4911
+ const createMessages = async (payload, account, options) => {
4912
+ const ctx = account ?? accountFromState();
4913
+ if (!ctx.copilotToken) throw new Error("Copilot token not found");
4914
+ const headers = buildMessagesHeaders({
4915
+ ctx,
4916
+ enableVision: hasVisionInput(payload),
4917
+ initiator: options?.initiator ?? getMessagesInitiator(payload),
4918
+ options,
4919
+ payload
4920
+ });
4551
4921
  const response = await fetch(`${copilotBaseUrl(ctx)}/v1/messages`, {
4552
4922
  method: "POST",
4553
4923
  headers,
@@ -4822,7 +5192,7 @@ function closeThinkingBlockIfOpen(state$1, events$1) {
4822
5192
  //#region src/routes/messages/subagent-marker.ts
4823
5193
  const subagentMarkerPrefix = "__SUBAGENT_MARKER__";
4824
5194
  const parseSubagentMarkerFromFirstUser = (payload) => {
4825
- const firstUserMessage = payload.messages.find((msg) => msg.role === "user");
5195
+ const firstUserMessage = payload.messages.find((msg) => msg.role === "user" && Array.isArray(msg.content));
4826
5196
  if (!firstUserMessage || !Array.isArray(firstUserMessage.content)) return null;
4827
5197
  for (const block of firstUserMessage.content) {
4828
5198
  if (block.type !== "text") continue;
@@ -4879,10 +5249,10 @@ async function handleCompletion(c) {
4879
5249
  const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
4880
5250
  const userAgent = c.req.header("user-agent") ?? void 0;
4881
5251
  const anthropicPayload = await c.req.json();
4882
- logger$5.debug("Anthropic request payload:", JSON.stringify(anthropicPayload));
5252
+ debugJson(logger$5, "Anthropic request payload:", anthropicPayload);
4883
5253
  const subagentMarker = parseSubagentMarkerFromFirstUser(anthropicPayload);
4884
5254
  const initiatorOverride = subagentMarker ? "agent" : void 0;
4885
- if (subagentMarker) logger$5.debug("Detected Subagent marker:", JSON.stringify(subagentMarker));
5255
+ if (subagentMarker) debugJson(logger$5, "Detected Subagent marker:", subagentMarker);
4886
5256
  const sessionId = getRootSessionId(anthropicPayload, c);
4887
5257
  logger$5.debug("Extracted session ID:", sessionId);
4888
5258
  const anthropicBeta = c.req.header("anthropic-beta");
@@ -4891,7 +5261,10 @@ async function handleCompletion(c) {
4891
5261
  if (isCompact) {
4892
5262
  logger$5.debug("Is compact request:", isCompact);
4893
5263
  if (shouldCompactUseSmallModel()) anthropicPayload.model = getSmallModel();
4894
- } else mergeToolResultForClaude(anthropicPayload);
5264
+ } else {
5265
+ stripToolReferenceTurnBoundary(anthropicPayload);
5266
+ mergeToolResultForClaude(anthropicPayload);
5267
+ }
4895
5268
  const upstreamRequestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
4896
5269
  logger$5.debug("Generated request ID:", upstreamRequestId);
4897
5270
  const clientModel = anthropicPayload.model;
@@ -5021,7 +5394,7 @@ async function handleCompletion(c) {
5021
5394
  }
5022
5395
  const handleWithChatCompletions = async (params) => {
5023
5396
  const { c, openAIPayload, initiatorOverride, subagentMarker, sessionId, selectedModel, instr, isCompact } = params;
5024
- logger$5.debug("Translated OpenAI request payload:", JSON.stringify(openAIPayload));
5397
+ debugJson(logger$5, "Translated OpenAI request payload:", openAIPayload);
5025
5398
  const ctx = toAccountContext(instr.account);
5026
5399
  const initiator = initiatorOverride ?? getChatInitiator(openAIPayload.messages);
5027
5400
  instr.initiator = initiator;
@@ -5068,7 +5441,7 @@ const handleWithResponsesApi = async (params) => {
5068
5441
  const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload, selectedModel.id);
5069
5442
  applyResponsesApiContextManagement(responsesPayload, selectedModel.capabilities.limits.max_prompt_tokens);
5070
5443
  compactInputByLatestCompaction(responsesPayload);
5071
- logger$5.debug("Translated Responses payload:", JSON.stringify(responsesPayload));
5444
+ debugJson(logger$5, "Translated Responses payload:", responsesPayload);
5072
5445
  const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
5073
5446
  const resolvedInitiator = initiatorOverride ?? initiator;
5074
5447
  const ctx = toAccountContext(instr.account);
@@ -5182,7 +5555,7 @@ async function handleChatCompletionsNonStreaming(params) {
5182
5555
  try {
5183
5556
  logger$5.debug("Non-streaming response from Copilot:", JSON.stringify(response));
5184
5557
  const anthropicResponse = translateToAnthropic(response);
5185
- logger$5.debug("Translated Anthropic response:", JSON.stringify(anthropicResponse));
5558
+ debugJson(logger$5, "Translated Anthropic response:", anthropicResponse);
5186
5559
  return c.json(anthropicResponse);
5187
5560
  } catch (error) {
5188
5561
  const details = extractErrorDetails(error);
@@ -5304,7 +5677,7 @@ async function handleResponsesNonStreaming(params) {
5304
5677
  usage = extractResponsesUsageFromResult(result);
5305
5678
  logger$5.debug("Non-streaming Responses result:", JSON.stringify(result).slice(-400));
5306
5679
  const anthropicResponse = translateResponsesResultToAnthropic(result);
5307
- logger$5.debug("Translated Anthropic response:", JSON.stringify(anthropicResponse));
5680
+ debugJson(logger$5, "Translated Anthropic response:", anthropicResponse);
5308
5681
  return c.json(anthropicResponse);
5309
5682
  } catch (error) {
5310
5683
  const details = extractErrorDetails(error);
@@ -5535,20 +5908,8 @@ async function streamMessagesAndLog(params) {
5535
5908
  }
5536
5909
  const handleWithMessagesApi = async (params) => {
5537
5910
  const { c, anthropicPayload, anthropicBetaHeader, initiatorOverride, subagentMarker, sessionId, instr, selectedModel, isCompact } = params;
5538
- stripCacheControl(anthropicPayload);
5539
- for (const msg of anthropicPayload.messages) if (msg.role === "assistant" && Array.isArray(msg.content)) msg.content = msg.content.filter((block) => {
5540
- if (block.type !== "thinking") return true;
5541
- return block.thinking && block.thinking !== "Thinking..." && block.signature && !block.signature.includes("@");
5542
- });
5543
- const toolChoice = anthropicPayload.tool_choice;
5544
- if (toolChoice?.type === "any" || toolChoice?.type === "tool") {
5545
- delete anthropicPayload.thinking;
5546
- delete anthropicPayload.output_config;
5547
- } else if (selectedModel.capabilities.supports.adaptive_thinking) {
5548
- anthropicPayload.thinking = { type: "adaptive" };
5549
- anthropicPayload.output_config = { effort: getAnthropicEffortForModel(anthropicPayload.model) };
5550
- }
5551
- logger$5.debug("Translated Messages payload:", JSON.stringify(anthropicPayload));
5911
+ prepareMessagesApiPayload(anthropicPayload, selectedModel);
5912
+ debugJson(logger$5, "Translated Messages payload:", anthropicPayload);
5552
5913
  const ctx = toAccountContext(instr.account);
5553
5914
  const initiator = initiatorOverride ?? getMessagesInitiator(anthropicPayload);
5554
5915
  instr.initiator = initiator;
@@ -5586,12 +5947,6 @@ const handleWithMessagesApi = async (params) => {
5586
5947
  };
5587
5948
  const isNonStreaming = (response) => Object.hasOwn(response, "choices");
5588
5949
  const isAsyncIterable$1 = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
5589
- const getAnthropicEffortForModel = (model) => {
5590
- const reasoningEffort = getReasoningEffortForModel(model);
5591
- if (reasoningEffort === "xhigh") return "max";
5592
- if (reasoningEffort === "none" || reasoningEffort === "minimal") return "low";
5593
- return reasoningEffort;
5594
- };
5595
5950
 
5596
5951
  //#endregion
5597
5952
  //#region src/routes/messages/route.ts
@@ -5772,10 +6127,10 @@ async function handleProviderMessages(c) {
5772
6127
  payload.temperature ??= modelConfig?.temperature;
5773
6128
  payload.top_p ??= modelConfig?.topP;
5774
6129
  payload.top_k ??= modelConfig?.topK;
5775
- logger$3.debug("provider.messages.request", JSON.stringify({
6130
+ debugJson(logger$3, "provider.messages.request", {
5776
6131
  payload,
5777
6132
  provider
5778
- }));
6133
+ });
5779
6134
  const upstreamResponse = await forwardProviderMessages(providerConfig, payload, c.req.raw.headers);
5780
6135
  if (!upstreamResponse.ok) {
5781
6136
  logger$3.error("Failed to create responses", upstreamResponse);
@@ -5818,7 +6173,7 @@ async function handleProviderMessages(c) {
5818
6173
  }
5819
6174
  const jsonBody = await upstreamResponse.json();
5820
6175
  adjustInputTokens(providerConfig, jsonBody.usage);
5821
- logger$3.debug("provider.messages.no_stream result:", JSON.stringify(jsonBody));
6176
+ debugJson(logger$3, "provider.messages.no_stream result:", jsonBody);
5822
6177
  return c.json(jsonBody);
5823
6178
  } catch (error) {
5824
6179
  logger$3.error("provider.messages.error", {
@@ -5831,7 +6186,7 @@ async function handleProviderMessages(c) {
5831
6186
  const adjustInputTokens = (providerConfig, usage) => {
5832
6187
  if (!providerConfig.adjustInputTokens || !usage) return;
5833
6188
  usage.input_tokens = Math.max(0, (usage.input_tokens ?? 0) - (usage.cache_read_input_tokens ?? 0) - (usage.cache_creation_input_tokens ?? 0));
5834
- logger$3.debug("provider.messages.adjusted_usage:", JSON.stringify(usage));
6189
+ debugJson(logger$3, "provider.messages.adjusted_usage:", usage);
5835
6190
  };
5836
6191
 
5837
6192
  //#endregion
@@ -5926,7 +6281,7 @@ const handleResponses = async (c) => {
5926
6281
  const request = buildRequestContext(c);
5927
6282
  const payload = await c.req.json();
5928
6283
  const clientModel = payload.model;
5929
- logger$1.debug("Responses request payload:", JSON.stringify(payload));
6284
+ debugJson(logger$1, "Responses request payload:", payload);
5930
6285
  if (!isResponsesApiWebSearchEnabled()) removeWebSearchTool(payload);
5931
6286
  compactInputByLatestCompaction(payload);
5932
6287
  const streamRequested = Boolean(payload.stream);
@@ -6174,7 +6529,10 @@ async function handleNonStreamingUpstreamResult(params) {
6174
6529
  let errorMessage;
6175
6530
  const finishedAtMs = Date.now();
6176
6531
  try {
6177
- logger$1.debug("Forwarding native Responses result:", JSON.stringify(result).slice(-400));
6532
+ debugJsonTail(logger$1, "Forwarding native Responses result:", {
6533
+ value: result,
6534
+ tailLength: 400
6535
+ });
6178
6536
  return c.json(result);
6179
6537
  } catch (error) {
6180
6538
  const details = extractErrorDetails(error);
@@ -6226,7 +6584,7 @@ async function streamResponsesAndLog(params) {
6226
6584
  const processedData = fixStreamIds(data ?? "", event, idTracker);
6227
6585
  const usage = extractUsageFromChunkData(processedData);
6228
6586
  if (usage) lastUsage = usage;
6229
- logger$1.debug("Responses stream chunk:", JSON.stringify(chunk));
6587
+ debugJson(logger$1, "Responses stream chunk:", chunk);
6230
6588
  await stream.writeSSE({
6231
6589
  id,
6232
6590
  event,
@@ -6290,7 +6648,10 @@ async function handleNonStreamingResponses(params) {
6290
6648
  if (streamResponse) return streamResponse;
6291
6649
  const result = response;
6292
6650
  usage = extractResponsesUsageFromResult(result);
6293
- logger$1.debug("Forwarding native Responses result:", JSON.stringify(result).slice(-400));
6651
+ debugJsonTail(logger$1, "Forwarding native Responses result:", {
6652
+ value: result,
6653
+ tailLength: 400
6654
+ });
6294
6655
  return c.json(result);
6295
6656
  } catch (error) {
6296
6657
  finishedAtMs = Date.now();
@@ -6337,6 +6698,7 @@ function handleUnexpectedResponsesStream(c, response) {
6337
6698
  for await (const chunk of response) {
6338
6699
  const { id, event, data } = getStreamChunkFields(chunk);
6339
6700
  const processedData = fixStreamIds(data ?? "", event, idTracker);
6701
+ debugJson(logger$1, "Responses stream chunk:", chunk);
6340
6702
  await stream.writeSSE({
6341
6703
  id,
6342
6704
  event,
@@ -6469,4 +6831,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
6469
6831
 
6470
6832
  //#endregion
6471
6833
  export { server };
6472
- //# sourceMappingURL=server-DqwhClJ-.js.map
6834
+ //# sourceMappingURL=server-DzE_zmUf.js.map