axios+telemetry cleanup

This commit is contained in:
2026-04-02 15:19:11 +03:00
parent a3cbca1e11
commit 7e1eac8002
100 changed files with 3048 additions and 4491 deletions

View File

@@ -1,4 +1,4 @@
import axios from 'axios'
import { nativeRequest } from '../utils/http.js'
import { debugBody, extractErrorDetail } from './debugUtils.js'
import {
@@ -148,38 +148,26 @@ export function createBridgeApiClient(deps: BridgeApiDeps): BridgeApiClient {
const response = await withOAuthRetry(
(token: string) =>
axios.post<{
nativeRequest<{
environment_id: string
environment_secret: string
}>(
`${deps.baseUrl}/v1/environments/bridge`,
{
machine_name: config.machineName,
directory: config.dir,
branch: config.branch,
git_repo_url: config.gitRepoUrl,
// Advertise session capacity so claude.ai/code can show
// "2/4 sessions" badges and only block the picker when
// actually at capacity. Backends that don't yet accept
// this field will silently ignore it.
max_sessions: config.maxSessions,
// worker_type lets claude.ai filter environments by origin
// (e.g. assistant picker only shows assistant-mode workers).
// Desktop cowork app sends "cowork"; we send a distinct value.
metadata: { worker_type: config.workerType },
// Idempotent re-registration: if we have a backend-issued
// environment_id from a prior session (--session-id resume),
// send it back so the backend reattaches instead of creating
// a new env. The backend may still hand back a fresh ID if
// the old one expired — callers must compare the response.
...(config.reuseEnvironmentId && {
environment_id: config.reuseEnvironmentId,
}),
},
{
method: 'POST',
body: {
machine_name: config.machineName,
directory: config.dir,
branch: config.branch,
git_repo_url: config.gitRepoUrl,
max_sessions: config.maxSessions,
metadata: { worker_type: config.workerType },
...(config.reuseEnvironmentId && {
environment_id: config.reuseEnvironmentId,
}),
},
headers: getHeaders(token),
timeout: 15_000,
validateStatus: status => status < 500,
},
),
'Registration',
@@ -209,17 +197,16 @@ export function createBridgeApiClient(deps: BridgeApiDeps): BridgeApiClient {
const prevEmptyPolls = consecutiveEmptyPolls
consecutiveEmptyPolls = 0
const response = await axios.get<WorkResponse | null>(
`${deps.baseUrl}/v1/environments/${environmentId}/work/poll`,
const pollUrl = reclaimOlderThanMs !== undefined
? `${deps.baseUrl}/v1/environments/${environmentId}/work/poll?reclaim_older_than_ms=${reclaimOlderThanMs}`
: `${deps.baseUrl}/v1/environments/${environmentId}/work/poll`
const response = await nativeRequest<WorkResponse | null>(
pollUrl,
{
method: 'GET',
headers: getHeaders(environmentSecret),
params:
reclaimOlderThanMs !== undefined
? { reclaim_older_than_ms: reclaimOlderThanMs }
: undefined,
timeout: 10_000,
signal,
validateStatus: status => status < 500,
timeout: 10_000,
},
)
@@ -256,13 +243,13 @@ export function createBridgeApiClient(deps: BridgeApiDeps): BridgeApiClient {
debug(`[bridge:api] POST .../work/${workId}/ack`)
const response = await axios.post(
const response = await nativeRequest(
`${deps.baseUrl}/v1/environments/${environmentId}/work/${workId}/ack`,
{},
{
method: 'POST',
body: {},
headers: getHeaders(sessionToken),
timeout: 10_000,
validateStatus: s => s < 500,
},
)
@@ -282,13 +269,13 @@ export function createBridgeApiClient(deps: BridgeApiDeps): BridgeApiClient {
const response = await withOAuthRetry(
(token: string) =>
axios.post(
nativeRequest(
`${deps.baseUrl}/v1/environments/${environmentId}/work/${workId}/stop`,
{ force },
{
method: 'POST',
body: { force },
headers: getHeaders(token),
timeout: 10_000,
validateStatus: s => s < 500,
},
),
'StopWork',
@@ -305,12 +292,12 @@ export function createBridgeApiClient(deps: BridgeApiDeps): BridgeApiClient {
const response = await withOAuthRetry(
(token: string) =>
axios.delete(
nativeRequest(
`${deps.baseUrl}/v1/environments/bridge/${environmentId}`,
{
method: 'DELETE',
headers: getHeaders(token),
timeout: 10_000,
validateStatus: s => s < 500,
},
),
'Deregister',
@@ -329,13 +316,13 @@ export function createBridgeApiClient(deps: BridgeApiDeps): BridgeApiClient {
const response = await withOAuthRetry(
(token: string) =>
axios.post(
nativeRequest(
`${deps.baseUrl}/v1/sessions/${sessionId}/archive`,
{},
{
method: 'POST',
body: {},
headers: getHeaders(token),
timeout: 10_000,
validateStatus: s => s < 500,
},
),
'ArchiveSession',
@@ -368,13 +355,13 @@ export function createBridgeApiClient(deps: BridgeApiDeps): BridgeApiClient {
const response = await withOAuthRetry(
(token: string) =>
axios.post(
nativeRequest(
`${deps.baseUrl}/v1/environments/${environmentId}/bridge/reconnect`,
{ session_id: sessionId },
{
method: 'POST',
body: { session_id: sessionId },
headers: getHeaders(token),
timeout: 10_000,
validateStatus: s => s < 500,
},
),
'ReconnectSession',
@@ -394,18 +381,18 @@ export function createBridgeApiClient(deps: BridgeApiDeps): BridgeApiClient {
debug(`[bridge:api] POST .../work/${workId}/heartbeat`)
const response = await axios.post<{
const response = await nativeRequest<{
lease_extended: boolean
state: string
last_heartbeat: string
ttl_seconds: number
}>(
`${deps.baseUrl}/v1/environments/${environmentId}/work/${workId}/heartbeat`,
{},
{
method: 'POST',
body: {},
headers: getHeaders(sessionToken),
timeout: 10_000,
validateStatus: s => s < 500,
},
)
@@ -427,13 +414,13 @@ export function createBridgeApiClient(deps: BridgeApiDeps): BridgeApiClient {
`[bridge:api] POST /v1/sessions/${sessionId}/events type=${event.type}`,
)
const response = await axios.post(
const response = await nativeRequest(
`${deps.baseUrl}/v1/sessions/${sessionId}/events`,
{ events: [event] },
{
method: 'POST',
body: { events: [event] },
headers: getHeaders(sessionToken),
timeout: 10_000,
validateStatus: s => s < 500,
},
)

View File

@@ -7,7 +7,7 @@
* accessToken + baseUrl — no implicit auth or config reads.
*/
import axios from 'axios'
import { isHttpError, nativeRequest } from '../utils/http.js'
import { logForDebugging } from '../utils/debug.js'
import { errorMessage } from '../utils/errors.js'
import { jsonStringify } from '../utils/slowOperations.js'
@@ -33,16 +33,13 @@ export async function createCodeSession(
const url = `${baseUrl}/v1/code/sessions`
let response
try {
response = await axios.post(
response = await nativeRequest(
url,
// bridge: {} is the positive signal for the oneof runner — omitting it
// (or sending environment_id: "") now 400s. BridgeRunner is an empty
// message today; it's a placeholder for future bridge-specific options.
{ title, bridge: {}, ...(tags?.length ? { tags } : {}) },
{
method: 'POST',
body: { title, bridge: {}, ...(tags?.length ? { tags } : {}) },
headers: oauthHeaders(accessToken),
timeout: timeoutMs,
validateStatus: s => s < 500,
},
)
} catch (err: unknown) {
@@ -104,13 +101,13 @@ export async function fetchRemoteCredentials(
}
let response
try {
response = await axios.post(
response = await nativeRequest(
url,
{},
{
method: 'POST',
body: {},
headers,
timeout: timeoutMs,
validateStatus: s => s < 500,
},
)
} catch (err: unknown) {

View File

@@ -1,4 +1,5 @@
import type { SDKMessage } from '../entrypoints/agentSdkTypes.js'
import { nativeRequest } from '../utils/http.js'
import { logForDebugging } from '../utils/debug.js'
import { errorMessage } from '../utils/errors.js'
import { extractErrorDetail } from './debugUtils.js'
@@ -59,7 +60,6 @@ export async function createBridgeSession({
const { parseGitHubRepository } = await import('../utils/detectRepository.js')
const { getDefaultBranch } = await import('../utils/git.js')
const { getMainLoopModel } = await import('../utils/model/model.js')
const { default: axios } = await import('axios')
const accessToken =
getAccessToken?.() ?? getClaudeAIOAuthTokens()?.accessToken
@@ -144,10 +144,11 @@ export async function createBridgeSession({
const url = `${baseUrlOverride ?? getOauthConfig().BASE_API_URL}/v1/sessions`
let response
try {
response = await axios.post(url, requestBody, {
response = await nativeRequest(url, {
method: 'POST',
body: requestBody,
headers,
signal,
validateStatus: s => s < 500,
})
} catch (err: unknown) {
logForDebugging(
@@ -195,7 +196,6 @@ export async function getBridgeSession(
const { getOrganizationUUID } = await import('../services/oauth/client.js')
const { getOauthConfig } = await import('../constants/oauth.js')
const { getOAuthHeaders } = await import('../utils/teleport/api.js')
const { default: axios } = await import('axios')
const accessToken =
opts?.getAccessToken?.() ?? getClaudeAIOAuthTokens()?.accessToken
@@ -221,9 +221,9 @@ export async function getBridgeSession(
let response
try {
response = await axios.get<{ environment_id?: string; title?: string }>(
response = await nativeRequest<{ environment_id?: string; title?: string }>(
url,
{ headers, timeout: 10_000, validateStatus: s => s < 500 },
{ headers, timeout: 10_000 },
)
} catch (err: unknown) {
logForDebugging(
@@ -272,7 +272,6 @@ export async function archiveBridgeSession(
const { getOrganizationUUID } = await import('../services/oauth/client.js')
const { getOauthConfig } = await import('../constants/oauth.js')
const { getOAuthHeaders } = await import('../utils/teleport/api.js')
const { default: axios } = await import('axios')
const accessToken =
opts?.getAccessToken?.() ?? getClaudeAIOAuthTokens()?.accessToken
@@ -296,13 +295,13 @@ export async function archiveBridgeSession(
const url = `${opts?.baseUrl ?? getOauthConfig().BASE_API_URL}/v1/sessions/${sessionId}/archive`
logForDebugging(`[bridge] Archiving session ${sessionId}`)
const response = await axios.post(
const response = await nativeRequest(
url,
{},
{
method: 'POST',
body: {},
headers,
timeout: opts?.timeoutMs ?? 10_000,
validateStatus: s => s < 500,
},
)
@@ -333,7 +332,6 @@ export async function updateBridgeSessionTitle(
const { getOrganizationUUID } = await import('../services/oauth/client.js')
const { getOauthConfig } = await import('../constants/oauth.js')
const { getOAuthHeaders } = await import('../utils/teleport/api.js')
const { default: axios } = await import('axios')
const accessToken =
opts?.getAccessToken?.() ?? getClaudeAIOAuthTokens()?.accessToken
@@ -362,10 +360,14 @@ export async function updateBridgeSessionTitle(
logForDebugging(`[bridge] Updating session title: ${compatId}${title}`)
try {
const response = await axios.patch(
const response = await nativeRequest(
url,
{ title },
{ headers, timeout: 10_000, validateStatus: s => s < 500 },
{
method: 'PATCH',
body: { title },
headers,
timeout: 10_000,
},
)
if (response.status === 200) {

View File

@@ -11,7 +11,7 @@
*/
import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.mjs'
import axios from 'axios'
import { isHttpError, nativeRequest } from '../utils/http.js'
import { randomUUID } from 'crypto'
import { mkdir, writeFile } from 'fs/promises'
import { basename, join } from 'path'
@@ -79,11 +79,10 @@ async function resolveOne(att: InboundAttachment): Promise<string | undefined> {
// FedStart URL degrades to "no @path" instead of crashing print.ts's
// reader loop (which has no catch around the await).
const url = `${getBridgeBaseUrl()}/api/oauth/files/${encodeURIComponent(att.file_uuid)}/content`
const response = await axios.get(url, {
const response = await nativeRequest<ArrayBuffer>(url, {
headers: { Authorization: `Bearer ${token}` },
responseType: 'arraybuffer',
timeout: DOWNLOAD_TIMEOUT_MS,
validateStatus: () => true,
})
if (response.status !== 200) {
debug(`fetch ${att.file_uuid} failed: status=${response.status}`)

View File

@@ -29,7 +29,7 @@
*/
import { feature } from 'bun:bundle'
import axios from 'axios'
import { isHttpError, nativeRequest } from '../utils/http.js'
import {
createV2ReplTransport,
type ReplBridgeTransport,
@@ -981,17 +981,17 @@ async function archiveSession(
// cse_* and we correctly send it.
const compatId = toCompatSessionId(sessionId)
try {
const response = await axios.post(
const response = await nativeRequest(
`${baseUrl}/v1/sessions/${compatId}/archive`,
{},
{
method: 'POST',
body: {},
headers: {
...oauthHeaders(accessToken),
'anthropic-beta': 'ccr-byoc-2025-07-29',
'x-organization-uuid': orgUUID,
},
timeout: timeoutMs,
validateStatus: () => true,
},
)
logForDebugging(
@@ -1001,7 +1001,7 @@ async function archiveSession(
} catch (err) {
const msg = errorMessage(err)
logForDebugging(`[remote-bridge] Archive failed: ${msg}`)
return axios.isAxiosError(err) && err.code === 'ECONNABORTED'
return isHttpError(err) && err.code === 'ECONNABORTED'
? 'timeout'
: 'error'
}

View File

@@ -1,4 +1,4 @@
import axios from 'axios'
import { nativeRequest } from '../utils/http.js'
import memoize from 'lodash-es/memoize.js'
import { hostname } from 'os'
import { getOauthConfig } from '../constants/oauth.js'
@@ -142,19 +142,19 @@ export async function enrollTrustedDevice(): Promise<void> {
const baseUrl = getOauthConfig().BASE_API_URL
let response
try {
response = await axios.post<{
response = await nativeRequest<{
device_token?: string
device_id?: string
}>(
`${baseUrl}/api/auth/trusted_devices`,
{ display_name: `Claude Code on ${hostname()} · ${process.platform}` },
{
method: 'POST',
body: { display_name: `Claude Code on ${hostname()} · ${process.platform}` },
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
timeout: 10_000,
validateStatus: s => s < 500,
},
)
} catch (err: unknown) {

View File

@@ -1,4 +1,4 @@
import axios from 'axios'
import { nativeRequest } from '../utils/http.js'
import { jsonParse, jsonStringify } from '../utils/slowOperations.js'
import type { WorkSecret } from './types.js'
@@ -98,10 +98,11 @@ export async function registerWorker(
sessionUrl: string,
accessToken: string,
): Promise<number> {
const response = await axios.post(
const response = await nativeRequest(
`${sessionUrl}/worker/register`,
{},
{
method: 'POST',
body: {},
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',