# How MemoryProxy Handles OpenAI and Anthropic Protocols

> Discover how MemoryProxy unifies OpenAI and Anthropic protocols, normalizes requests, handles authentication, and ensures seamless response compatibility for LLM providers.

- Repository: [Tencent Cloud/TencentDB-Agent-Memory](https://github.com/TencentCloud/TencentDB-Agent-Memory)
- Tags: internals
- Published: 2026-09-01

---

**MemoryProxy normalizes incoming OpenAI and Anthropic requests into a unified internal schema, routes them to upstream LLM providers with protocol-specific authentication headers, and re-encodes responses to maintain wire-protocol compatibility with the original client.**

MemoryProxy, a core component of the TencentDB-Agent-Memory repository, functions as a bidirectional protocol adapter that transparently supports both OpenAI Chat Completions (including the Responses API) and Anthropic Messages formats. The implementation eliminates vendor lock-in by converting all traffic to a canonical internal representation before processing, enabling seamless integration with heterogeneous LLM backends.

## Protocol Whitelist and Routing

Before normalization occurs, MemoryProxy validates incoming requests against a static whitelist of supported endpoints. The whitelist definition resides in [`src/routes/whitelist.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/routes/whitelist.ts), which enumerates the specific OpenAI- and Anthropic-compatible paths that the proxy will accept.

When a request arrives, the handler invokes `matchWhitelistEndpoint` (implemented in [`src/handler.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/handler.ts)) to verify that the URL path belongs to one of the supported protocols. This gatekeeping ensures that only recognized OpenAI or Anthropic endpoints proceed to the normalization stage, rejecting malformed or unsupported routes before any payload processing occurs.

## Unified Internal Message Model

At the heart of the dual-protocol support is a normalized data structure defined in [`src/types.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/types.ts). The **NormalizedMessage** type serves as the universal intermediary format, decoupling downstream business logic from provider-specific JSON schemas.

### AgentUpstreamEntry Configuration

The routing and authentication logic relies on the `AgentUpstreamEntry` interface (lines 4–13 in [`src/types.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/types.ts)):

```typescript
// src/types.ts
export interface AgentUpstreamEntry {
  /** Target upstream base URL. Required. */
  url: string;
  /**
   * Per-agent apiKey. When set (non-empty):
   *   - OpenAI: `Authorization: Bearer <apiKey>` is injected
   *   - Anthropic: `x-api-key: <apiKey>` is injected
   */
  apiKey?: string;
}

```

Each entry maps an agent to its target upstream base URL and optionally stores a per-agent API key. The proxy uses this configuration to inject the correct authentication header—`Authorization: Bearer <token>` for OpenAI or `x-api-key: <token>` for Anthropic—when forwarding requests through `resolveForwardTarget` in [`src/handler.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/handler.ts).

### Normalization Logic

The heavy lifting of protocol conversion happens in [`src/skill/normalize-conversation.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/skill/normalize-conversation.ts). This module transforms provider-specific payloads into the `NormalizedMessage[]` array used throughout the system.

**OpenAI Conversion:** The `convertOpenAIMessage` function handles the four standard roles (`system`, `user`, `assistant`, `tool`) and extracts tool calls from the `tool_calls` array (lines 70–80):

```typescript
// src/skill/normalize-conversation.ts
function convertOpenAIMessage(msg: RawMessage, agentSource: string): NormalizedMessage[] {
  const role = msg.role;
  const content = msg.content;

  if (role === "assistant") return convertOpenAIAssistant(content, msg.tool_calls);
  // …handles user, tool, system roles…
}

```

**Anthropic Conversion:** For Anthropic traffic, the system invokes `anthropicToolResultContentToString` to map content blocks into the unified schema (lines 53–66):

```typescript
function anthropicToolResultContentToString(rc: unknown): string {
  if (Array.isArray(rc)) {
    const parts: string[] = [];
    for (const b of rc) {
      const bb = b as Record<string, unknown>;
      if (bb.type === "text") parts.push(bb.text as string);
    }
    return parts.join("\n");
  }
  return contentToString(rc);
}

```

Both conversion paths return identical `NormalizedMessage` structures, allowing downstream components—such as session management, skill extraction, and credit reporting—to operate without awareness of the original protocol.

## Request Forwarding and Authentication

After normalization, `resolveForwardTarget` in [`src/handler.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/handler.ts) determines the appropriate upstream URL from the agent configuration. The proxy establishes the outbound HTTP connection using the base URL stored in `AgentUpstreamEntry.url`.

Authentication header injection occurs at this stage based on the presence of `apiKey` in the selected upstream entry. The system conditionally sets:
- **`Authorization: Bearer <apiKey>`** for OpenAI-compatible endpoints
- **`x-api-key: <apiKey>`** for Anthropic-compatible endpoints

This per-agent key management enables a single MemoryProxy instance to route traffic to multiple LLM providers simultaneously while maintaining proper credential isolation.

## Response Encoding and Protocol Compliance

Downstream processing complete, the proxy must return data in the format expected by the original client. The [`src/mem-command/response-builder.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/mem-command/response-builder.ts) module handles bidirectional protocol encoding with functions like `buildOpenAIResponse`, `buildOpenAIStreamResponse`, and their Anthropic counterparts (lines 97–120):

```typescript
// src/mem-command/response-builder.ts
export function buildOpenAIResponse(text: string, requestId: string): Response {
  return new Response(JSON.stringify({ id: requestId, object: "chat.completion", ... }), {
    headers: { "Content-Type": "application/json" },
  });
}

```

The same file generates both OpenAI-compatible and Anthropic-compatible fake LLM responses when necessary, ensuring protocol consistency even for synthetic or cached replies.

Additionally, [`src/handler.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/handler.ts) captures usage metrics through protocol-specific helpers such as `langfuseReportGeneration` and `opikCreateLlmSpan`, ensuring that token consumption and latency data are recorded in the format expected by the originating provider's observability stack.

## Summary

- **Whitelist validation** in [`src/routes/whitelist.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/routes/whitelist.ts) and `matchWhitelistEndpoint` ensures only recognized OpenAI or Anthropic endpoints enter the pipeline.
- **Unified normalization** via [`src/skill/normalize-conversation.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/skill/normalize-conversation.ts) converts both OpenAI Chat Completions and Anthropic Messages into a canonical `NormalizedMessage` format.
- **Per-agent routing** using `AgentUpstreamEntry` in [`src/types.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/types.ts) supports simultaneous multi-provider configurations with automatic header injection (`Authorization` vs. `x-api-key`).
- **Protocol-specific response building** in [`src/mem-command/response-builder.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/mem-command/response-builder.ts) guarantees that clients receive syntactically correct replies matching their original request format.

## Frequently Asked Questions

### Does MemoryProxy support streaming responses for both OpenAI and Anthropic protocols?

Yes. According to the source code in [`src/mem-command/response-builder.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/mem-command/response-builder.ts), the proxy implements both `buildOpenAIStreamResponse` and Anthropic streaming equivalents. These functions construct Server-Sent Events (SSE) or chunked transfer responses that conform to each provider's streaming specification, allowing real-time token delivery regardless of the upstream LLM.

### How does MemoryProxy handle authentication differences between OpenAI and Anthropic?

The proxy inspects the `AgentUpstreamEntry.apiKey` field defined in [`src/types.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/types.ts). When present, the system injects `Authorization: Bearer <apiKey>` for OpenAI upstreams and `x-api-key: <apiKey>` for Anthropic upstreams during the forwarding stage in [`src/handler.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/handler.ts). This abstraction allows a single deployment to manage credentials for heterogeneous LLM backends without code changes.

### What specific OpenAI message roles are supported during normalization?

The `convertOpenAIMessage` function in [`src/skill/normalize-conversation.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/src/skill/normalize-conversation.ts) explicitly handles four roles: `system`, `user`, `assistant`, and `tool`. For assistant messages, the function additionally extracts the `tool_calls` array (lines 70–80) to preserve function-calling context within the normalized representation.

### Can MemoryProxy route tool results back to clients using different protocols?

Yes. The normalization pipeline includes bidirectional conversion for tool results. For Anthropic, `anthropicToolResultContentToString` processes `type: "text"` content blocks (lines 53–66), while OpenAI tool results are handled through the standard `convertOpenAIMessage` path. This ensures that tool outputs generated by one provider can be seamlessly returned to clients expecting the other protocol's format.