fix: always populate user-agent (#708)
This commit is contained in:
24
src/agent/http-headers.ts
Normal file
24
src/agent/http-headers.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import packageJson from "../../package.json";
|
||||
|
||||
/**
|
||||
* Get standard headers for manual HTTP calls to Letta API.
|
||||
* Use this for any direct fetch() calls (not SDK calls).
|
||||
*/
|
||||
export function getLettaCodeHeaders(apiKey?: string): Record<string, string> {
|
||||
return {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": `letta-code/${packageJson.version}`,
|
||||
"X-Letta-Source": "letta-code",
|
||||
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get headers for MCP OAuth connections (includes Accept header for SSE).
|
||||
*/
|
||||
export function getMcpOAuthHeaders(apiKey: string): Record<string, string> {
|
||||
return {
|
||||
...getLettaCodeHeaders(apiKey),
|
||||
Accept: "text/event-stream",
|
||||
};
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import { getResumeData } from "../agent/check-approval";
|
||||
import { getClient } from "../agent/client";
|
||||
import { getCurrentAgentId, setCurrentAgentId } from "../agent/context";
|
||||
import { type AgentProvenance, createAgent } from "../agent/create";
|
||||
import { getLettaCodeHeaders } from "../agent/http-headers";
|
||||
import { ISOLATED_BLOCK_LABELS } from "../agent/memory";
|
||||
import {
|
||||
detachMemoryFilesystemBlock,
|
||||
@@ -1099,11 +1100,7 @@ export default function App({
|
||||
const apiKey = process.env.LETTA_API_KEY || settings.env?.LETTA_API_KEY;
|
||||
|
||||
const response = await fetch(`${baseURL}/v1/metadata/balance`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
"X-Letta-Source": "letta-code",
|
||||
},
|
||||
headers: getLettaCodeHeaders(apiKey),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
@@ -5113,11 +5110,7 @@ export default function App({
|
||||
const balanceResponse = await fetch(
|
||||
`${baseURL}/v1/metadata/balance`,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
"X-Letta-Source": "letta-code",
|
||||
},
|
||||
headers: getLettaCodeHeaders(apiKey),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -8754,9 +8747,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
|
||||
"X-Letta-Source": "letta-code",
|
||||
...getLettaCodeHeaders(apiKey),
|
||||
"X-Letta-Code-Device-ID": settingsManager.getOrCreateDeviceId(),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import { getServerUrl } from "../../agent/client";
|
||||
import { getMcpOAuthHeaders } from "../../agent/http-headers";
|
||||
import { settingsManager } from "../../settings-manager";
|
||||
|
||||
// Match backend's OauthStreamEvent enum
|
||||
@@ -76,12 +77,7 @@ export async function connectMcpServer(
|
||||
|
||||
const response = await fetch(`${baseUrl}/v1/tools/mcp/servers/connect`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "text/event-stream",
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
"X-Letta-Source": "letta-code",
|
||||
},
|
||||
headers: getMcpOAuthHeaders(apiKey),
|
||||
body: JSON.stringify(config),
|
||||
signal: abortSignal,
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
setConversationId as setContextConversationId,
|
||||
} from "./agent/context";
|
||||
import type { AgentProvenance } from "./agent/create";
|
||||
|
||||
import { getLettaCodeHeaders } from "./agent/http-headers";
|
||||
import { ensureSkillsBlocks, ISOLATED_BLOCK_LABELS } from "./agent/memory";
|
||||
import { LETTA_CLOUD_API_URL } from "./auth/oauth";
|
||||
import { ConversationSelector } from "./cli/components/ConversationSelector";
|
||||
@@ -1478,7 +1478,7 @@ async function main(): Promise<void> {
|
||||
const apiKey =
|
||||
process.env.LETTA_API_KEY || settings.env?.LETTA_API_KEY;
|
||||
const response = await fetch(`${baseURL}/v1/metadata/balance`, {
|
||||
headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : {},
|
||||
headers: getLettaCodeHeaders(apiKey),
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = (await response.json()) as {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Unified module for managing custom LLM provider connections
|
||||
*/
|
||||
|
||||
import { getLettaCodeHeaders } from "../agent/http-headers";
|
||||
import { LETTA_CLOUD_API_URL } from "../auth/oauth";
|
||||
import { settingsManager } from "../settings-manager";
|
||||
|
||||
@@ -113,11 +114,7 @@ async function providersRequest<T>(
|
||||
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
"X-Letta-Source": "letta-code",
|
||||
},
|
||||
headers: getLettaCodeHeaders(apiKey),
|
||||
...(body && { body: JSON.stringify(body) }),
|
||||
});
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Direct API calls to Letta for managing MiniMax provider
|
||||
*/
|
||||
|
||||
import { getLettaCodeHeaders } from "../agent/http-headers";
|
||||
import { LETTA_CLOUD_API_URL } from "../auth/oauth";
|
||||
import { settingsManager } from "../settings-manager";
|
||||
|
||||
@@ -42,11 +43,7 @@ async function providersRequest<T>(
|
||||
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
"X-Letta-Source": "letta-code",
|
||||
},
|
||||
headers: getLettaCodeHeaders(apiKey),
|
||||
...(body && { body: JSON.stringify(body) }),
|
||||
});
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* (transforms OpenAI API format → ChatGPT backend API format)
|
||||
*/
|
||||
|
||||
import { getLettaCodeHeaders } from "../agent/http-headers";
|
||||
import { LETTA_CLOUD_API_URL } from "../auth/oauth";
|
||||
import { settingsManager } from "../settings-manager";
|
||||
|
||||
@@ -72,11 +73,7 @@ async function providersRequest<T>(
|
||||
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
"X-Letta-Source": "letta-code",
|
||||
},
|
||||
headers: getLettaCodeHeaders(apiKey),
|
||||
...(body && { body: JSON.stringify(body) }),
|
||||
});
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Direct API calls to Letta for managing Zai provider
|
||||
*/
|
||||
|
||||
import { getLettaCodeHeaders } from "../agent/http-headers";
|
||||
import { LETTA_CLOUD_API_URL } from "../auth/oauth";
|
||||
import { settingsManager } from "../settings-manager";
|
||||
|
||||
@@ -42,11 +43,7 @@ async function providersRequest<T>(
|
||||
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
"X-Letta-Source": "letta-code",
|
||||
},
|
||||
headers: getLettaCodeHeaders(apiKey),
|
||||
...(body && { body: JSON.stringify(body) }),
|
||||
});
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import { createRequire } from "node:module";
|
||||
import { homedir } from "node:os";
|
||||
import { extname, join, relative } from "node:path";
|
||||
|
||||
import { getLettaCodeHeaders } from "../../../../agent/http-headers";
|
||||
import type { BackupManifest } from "./backup-memory";
|
||||
|
||||
// Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
|
||||
@@ -119,7 +120,7 @@ async function restoreMemory(
|
||||
const blocksResp = await fetch(
|
||||
`${baseUrl}/v1/agents/${agentId}/core-memory`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${getApiKey()}` },
|
||||
headers: getLettaCodeHeaders(getApiKey()),
|
||||
},
|
||||
);
|
||||
if (!blocksResp.ok) {
|
||||
@@ -180,10 +181,7 @@ async function restoreMemory(
|
||||
const url = `${baseUrl}/v1/blocks/${existingBlock.id}`;
|
||||
const resp = await fetch(url, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${getApiKey()}`,
|
||||
},
|
||||
headers: getLettaCodeHeaders(getApiKey()),
|
||||
body: JSON.stringify({ value: newValue }),
|
||||
});
|
||||
if (!resp.ok) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { getLettaCodeHeaders } from "../agent/http-headers";
|
||||
import { settingsManager } from "../settings-manager";
|
||||
|
||||
export interface TelemetryEvent {
|
||||
@@ -399,9 +400,7 @@ class TelemetryManager {
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
|
||||
"X-Letta-Source": "letta-code",
|
||||
...getLettaCodeHeaders(apiKey),
|
||||
"X-Letta-Code-Device-ID": this.deviceId || "",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
|
||||
Reference in New Issue
Block a user