kimi-proxy 0.1.3 → 0.1.4

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.
@@ -9,7 +9,7 @@ export declare class OpenAIChatClientAdapter implements ClientAdapter {
9
9
  export declare class AnthropicMessagesClientAdapter implements ClientAdapter {
10
10
  clientFormat: ClientFormat;
11
11
  toUlx(body: ClientRequest, headers: Record<string, string>): Request;
12
- fromUlx(ulxResponse: Response): JsonValue;
12
+ fromUlx(ulxResponse: Response, _ulxRequest: Request): JsonValue;
13
13
  }
14
14
  export declare class OpenAIResponsesClientAdapter implements ClientAdapter {
15
15
  clientFormat: ClientFormat;
package/dist/index.js CHANGED
@@ -1554,33 +1554,36 @@ class OpenAIChatClientAdapter {
1554
1554
  };
1555
1555
  }
1556
1556
  fromUlx(ulxResponse, _ulxRequest) {
1557
- const contentBlocks = ulxResponse.output.find((entry) => entry.type === "message");
1558
- let content = null;
1559
- let reasoning_content = undefined;
1560
- if (contentBlocks?.type === "message") {
1561
- const textParts = [];
1562
- const reasoningParts = [];
1563
- for (const entry of contentBlocks.content) {
1564
- if (entry.type === "text") {
1565
- textParts.push(entry.text ?? "");
1566
- } else if (entry.type === "reasoning") {
1567
- reasoningParts.push(entry.text ?? "");
1557
+ const textParts = [];
1558
+ const reasoningParts = [];
1559
+ let toolCalls = undefined;
1560
+ for (const block of ulxResponse.output) {
1561
+ if (block.type === "message") {
1562
+ for (const entry of block.content) {
1563
+ if (entry.type === "reasoning") {
1564
+ reasoningParts.push(entry.text ?? "");
1565
+ }
1566
+ }
1567
+ const meaningfulContent = block.content.filter((c) => c.type !== "reasoning");
1568
+ if (meaningfulContent.length > 0) {
1569
+ const mixed = contentToText(meaningfulContent);
1570
+ textParts.push(typeof mixed === "string" ? mixed : JSON.stringify(mixed));
1571
+ }
1572
+ if (block.tool_calls) {
1573
+ toolCalls = [...toolCalls ?? [], ...block.tool_calls];
1574
+ }
1575
+ } else if (block.type === "reasoning") {
1576
+ for (const entry of block.content) {
1577
+ if (entry.type === "reasoning") {
1578
+ reasoningParts.push(entry.text ?? "");
1579
+ }
1568
1580
  }
1569
- }
1570
- if (textParts.length > 0) {
1571
- content = textParts.join("");
1572
- } else if (contentBlocks.content.some((c) => c.type === "image_url" || c.type === "json")) {
1573
- const mixed = contentToText(contentBlocks.content.filter((c) => c.type !== "reasoning"));
1574
- content = typeof mixed === "string" ? mixed : JSON.stringify(mixed);
1575
- } else {
1576
- content = null;
1577
- }
1578
- if (reasoningParts.length > 0) {
1579
- reasoning_content = reasoningParts.join(`
1580
-
1581
- `);
1582
1581
  }
1583
1582
  }
1583
+ const content = textParts.join("") || null;
1584
+ const reasoning_content = reasoningParts.join(`
1585
+
1586
+ `) || undefined;
1584
1587
  return {
1585
1588
  id: ulxResponse.id,
1586
1589
  object: "chat.completion",
@@ -1591,9 +1594,9 @@ class OpenAIChatClientAdapter {
1591
1594
  index: 0,
1592
1595
  message: {
1593
1596
  role: "assistant",
1594
- content,
1595
1597
  ...reasoning_content ? { reasoning_content } : {},
1596
- tool_calls: contentBlocks?.type === "message" && contentBlocks.tool_calls ? contentBlocks.tool_calls.map((tc) => ({
1598
+ content,
1599
+ tool_calls: toolCalls ? toolCalls.map((tc) => ({
1597
1600
  id: tc.id,
1598
1601
  type: "function",
1599
1602
  function: {
@@ -1683,7 +1686,11 @@ class AnthropicMessagesClientAdapter {
1683
1686
  function anthropicBlockToUlxContent(block) {
1684
1687
  const declaredType = typeof block.type === "string" ? block.type : "";
1685
1688
  if (declaredType === "thinking" || declaredType === "redacted_thinking" || typeof block.thinking === "string") {
1686
- return;
1689
+ return {
1690
+ type: "reasoning",
1691
+ text: block.thinking ?? block.text ?? "",
1692
+ data: block.signature ? { signature: block.signature } : declaredType === "redacted_thinking" ? { redacted: true } : undefined
1693
+ };
1687
1694
  }
1688
1695
  if (typeof block.text === "string") {
1689
1696
  return { type: "text", text: block.text };
@@ -1799,37 +1806,57 @@ class AnthropicMessagesClientAdapter {
1799
1806
  metadata: { clientFormat: this.clientFormat, headers }
1800
1807
  };
1801
1808
  }
1802
- fromUlx(ulxResponse) {
1803
- const contentBlocks = ulxResponse.output.find((entry) => entry.type === "message");
1804
- const messageContent = contentBlocks?.type === "message" ? contentToText(contentBlocks.content) : "";
1805
- const content = [];
1806
- if (typeof messageContent === "string") {
1807
- if (messageContent)
1808
- content.push({ type: "text", text: messageContent });
1809
- } else if (Array.isArray(messageContent)) {
1810
- for (const item of messageContent) {
1811
- if (item && typeof item === "object") {
1812
- const block = item;
1813
- if (block.type === "thinking") {
1814
- content.push(block);
1815
- } else if (block.type === "text") {
1816
- content.push(block);
1809
+ fromUlx(ulxResponse, _ulxRequest) {
1810
+ const thinkingBlocks = [];
1811
+ const textBlocks = [];
1812
+ const toolUseBlocks = [];
1813
+ for (const block of ulxResponse.output) {
1814
+ if (block.type === "reasoning") {
1815
+ for (const entry of block.content) {
1816
+ if (entry.type === "reasoning") {
1817
+ thinkingBlocks.push({
1818
+ type: "thinking",
1819
+ thinking: entry.text ?? "",
1820
+ signature: entry.data?.signature
1821
+ });
1822
+ }
1823
+ }
1824
+ } else if (block.type === "message") {
1825
+ const messageContent = contentToText(block.content);
1826
+ if (typeof messageContent === "string") {
1827
+ if (messageContent)
1828
+ textBlocks.push({ type: "text", text: messageContent });
1829
+ } else if (Array.isArray(messageContent)) {
1830
+ for (const item of messageContent) {
1831
+ if (item && typeof item === "object") {
1832
+ const b = item;
1833
+ if (b.type === "thinking") {
1834
+ thinkingBlocks.push(b);
1835
+ } else if (b.type === "text") {
1836
+ textBlocks.push(b);
1837
+ }
1838
+ }
1839
+ }
1840
+ } else if (typeof messageContent === "object" && messageContent !== null && "text" in messageContent) {
1841
+ textBlocks.push(messageContent);
1842
+ }
1843
+ if (block.tool_calls) {
1844
+ for (const tc of block.tool_calls) {
1845
+ toolUseBlocks.push({
1846
+ type: "tool_use",
1847
+ id: tc.id,
1848
+ name: tc.name,
1849
+ input: JSON.parse(tc.arguments)
1850
+ });
1817
1851
  }
1818
1852
  }
1819
- }
1820
- } else if (typeof messageContent === "object" && messageContent !== null && "text" in messageContent) {
1821
- content.push(messageContent);
1822
- }
1823
- if (contentBlocks?.type === "message" && contentBlocks.tool_calls) {
1824
- for (const tc of contentBlocks.tool_calls) {
1825
- content.push({
1826
- type: "tool_use",
1827
- id: tc.id,
1828
- name: tc.name,
1829
- input: JSON.parse(tc.arguments)
1830
- });
1831
1853
  }
1832
1854
  }
1855
+ const content = [
1856
+ ...thinkingBlocks,
1857
+ ...textBlocks,
1858
+ ...toolUseBlocks
1859
+ ];
1833
1860
  return {
1834
1861
  id: ulxResponse.id,
1835
1862
  type: "message",
@@ -2089,18 +2116,19 @@ class OpenAIResponsesClientAdapter {
2089
2116
  }
2090
2117
  fromUlx(ulxResponse, ulxRequest) {
2091
2118
  const outputBlocks = ulxResponse.output;
2092
- const output = [];
2093
2119
  const textParts = [];
2094
2120
  const createdAt = Math.floor(Date.now() / 1000);
2095
2121
  let messageIndex = 0;
2096
2122
  let functionCallIndex = 0;
2097
2123
  let reasoningIndex = 0;
2124
+ const collectedReasoning = [];
2125
+ const collectedMessages = [];
2126
+ const collectedFunctionCalls = [];
2098
2127
  for (const block of outputBlocks) {
2099
2128
  if (block.type === "message") {
2100
2129
  const messageId = `msg_${ulxResponse.id}_${messageIndex++}`;
2101
2130
  const status = block.status === "incomplete" ? "incomplete" : "completed";
2102
2131
  const content = [];
2103
- const reasoningContent = [];
2104
2132
  for (const entry of block.content) {
2105
2133
  if (entry.type === "text") {
2106
2134
  const text = entry.text ?? "";
@@ -2119,22 +2147,16 @@ class OpenAIResponsesClientAdapter {
2119
2147
  }
2120
2148
  content.push({ type: "output_text", text, annotations: [] });
2121
2149
  } else if (entry.type === "reasoning") {
2122
- reasoningContent.push({
2123
- type: "reasoning_text",
2124
- text: entry.text ?? ""
2150
+ collectedReasoning.push({
2151
+ type: "reasoning",
2152
+ id: `rsn_${ulxResponse.id}_${reasoningIndex++}`,
2153
+ status: "completed",
2154
+ content: [{ type: "reasoning_text", text: entry.text ?? "" }],
2155
+ summary: []
2125
2156
  });
2126
2157
  }
2127
2158
  }
2128
- if (reasoningContent.length > 0) {
2129
- output.push({
2130
- type: "reasoning",
2131
- id: `rsn_${ulxResponse.id}_${reasoningIndex++}`,
2132
- status: "completed",
2133
- content: reasoningContent,
2134
- summary: []
2135
- });
2136
- }
2137
- output.push({
2159
+ collectedMessages.push({
2138
2160
  type: "message",
2139
2161
  id: messageId,
2140
2162
  role: "assistant",
@@ -2143,7 +2165,7 @@ class OpenAIResponsesClientAdapter {
2143
2165
  });
2144
2166
  if (block.tool_calls) {
2145
2167
  for (const call of block.tool_calls) {
2146
- output.push({
2168
+ collectedFunctionCalls.push({
2147
2169
  type: "function_call",
2148
2170
  id: `fc_${ulxResponse.id}_${functionCallIndex++}`,
2149
2171
  call_id: call.id,
@@ -2154,7 +2176,7 @@ class OpenAIResponsesClientAdapter {
2154
2176
  }
2155
2177
  }
2156
2178
  } else if (block.type === "tool_call") {
2157
- output.push({
2179
+ collectedFunctionCalls.push({
2158
2180
  type: "function_call",
2159
2181
  id: `fc_${ulxResponse.id}_${functionCallIndex++}`,
2160
2182
  call_id: block.call_id,
@@ -2163,7 +2185,7 @@ class OpenAIResponsesClientAdapter {
2163
2185
  status: block.status === "pending" ? "in_progress" : "completed"
2164
2186
  });
2165
2187
  } else if (block.type === "reasoning") {
2166
- output.push({
2188
+ collectedReasoning.push({
2167
2189
  type: "reasoning",
2168
2190
  id: `rsn_${ulxResponse.id}_${reasoningIndex++}`,
2169
2191
  status: "completed",
@@ -2178,6 +2200,11 @@ class OpenAIResponsesClientAdapter {
2178
2200
  });
2179
2201
  }
2180
2202
  }
2203
+ const output = [
2204
+ ...collectedReasoning,
2205
+ ...collectedMessages,
2206
+ ...collectedFunctionCalls
2207
+ ];
2181
2208
  const inputTokens = ulxResponse.usage?.input_tokens ?? 0;
2182
2209
  const outputTokens = ulxResponse.usage?.output_tokens ?? 0;
2183
2210
  const totalTokens = ulxResponse.usage?.total_tokens ?? inputTokens + outputTokens;
@@ -2387,7 +2414,9 @@ function createCapturingFetch(originalFetch = globalThis.fetch) {
2387
2414
  // src/core/providers/anthropic.ts
2388
2415
  var AnthropicContentSchema = z6.object({
2389
2416
  type: z6.string(),
2390
- text: z6.string().optional()
2417
+ text: z6.string().optional(),
2418
+ thinking: z6.string().optional(),
2419
+ signature: z6.string().optional()
2391
2420
  }).passthrough();
2392
2421
  var AnthropicResponseSchema = z6.object({
2393
2422
  id: z6.string(),
@@ -2428,6 +2457,13 @@ function toAnthropicContent(blocks) {
2428
2457
  return blocks.map((entry) => {
2429
2458
  if (entry.type === "text")
2430
2459
  return { type: "text", text: entry.text ?? "" };
2460
+ if (entry.type === "reasoning") {
2461
+ return {
2462
+ type: "thinking",
2463
+ thinking: entry.text ?? "",
2464
+ signature: entry.data?.signature
2465
+ };
2466
+ }
2431
2467
  if (entry.type === "image_url") {
2432
2468
  if (typeof entry.url === "string") {
2433
2469
  const match = entry.url.match(/^data:([^;]+);base64,(.+)$/);
@@ -2468,7 +2504,8 @@ function anthropicResponseToUlx(body, request) {
2468
2504
  type: "reasoning",
2469
2505
  content: reasoning.map((part) => ({
2470
2506
  type: "reasoning",
2471
- text: part.text ?? ""
2507
+ text: part.thinking ?? part.text ?? "",
2508
+ data: part.signature ? { signature: part.signature } : undefined
2472
2509
  })),
2473
2510
  summary: []
2474
2511
  });
@@ -2953,32 +2990,31 @@ function toOpenAITool(tool) {
2953
2990
  }
2954
2991
  function toOpenAIMessages(messages) {
2955
2992
  return messages.map((msg) => {
2993
+ const reasoningBlocks = msg.content.filter((c) => c.type === "reasoning");
2994
+ const nonReasoningBlocks = msg.content.filter((c) => c.type !== "reasoning");
2995
+ const res = {
2996
+ role: msg.role === "assistant" ? "assistant" : msg.role,
2997
+ content: toOpenAIContent(nonReasoningBlocks)
2998
+ };
2999
+ if (reasoningBlocks.length > 0) {
3000
+ res.reasoning_content = reasoningBlocks.map((b) => b.text).join(`
3001
+
3002
+ `);
3003
+ }
2956
3004
  if (msg.role === "tool") {
2957
- return {
2958
- role: "tool",
2959
- tool_call_id: msg.tool_call_id,
2960
- content: toOpenAIContent(msg.content)
2961
- };
3005
+ res.tool_call_id = msg.tool_call_id;
2962
3006
  }
2963
3007
  if (msg.tool_calls) {
2964
- return {
2965
- role: msg.role,
2966
- content: toOpenAIContent(msg.content),
2967
- tool_calls: msg.tool_calls.map((call) => ({
2968
- id: call.id,
2969
- type: "function",
2970
- function: {
2971
- name: call.name,
2972
- arguments: call.arguments
2973
- }
2974
- }))
2975
- };
3008
+ res.tool_calls = msg.tool_calls.map((call) => ({
3009
+ id: call.id,
3010
+ type: "function",
3011
+ function: {
3012
+ name: call.name,
3013
+ arguments: call.arguments
3014
+ }
3015
+ }));
2976
3016
  }
2977
- return {
2978
- role: msg.role === "assistant" ? "assistant" : msg.role,
2979
- content: toOpenAIContent(msg.content),
2980
- name: undefined
2981
- };
3017
+ return res;
2982
3018
  });
2983
3019
  }
2984
3020
  function normalizeOpenAIProviderResponse(payload, request) {
@@ -3817,13 +3853,53 @@ class VertexProviderAdapter {
3817
3853
  toVertexTools(tools) {
3818
3854
  if (!tools?.length)
3819
3855
  return;
3856
+ function flattenJsonSchema(schema) {
3857
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
3858
+ return schema;
3859
+ }
3860
+ const obj = { ...schema };
3861
+ const definitions = obj.definitions;
3862
+ delete obj.definitions;
3863
+ function resolveRef(target, path4) {
3864
+ if (!target || typeof target !== "object" || Array.isArray(target)) {
3865
+ return target;
3866
+ }
3867
+ const copy = { ...target };
3868
+ for (const key in copy) {
3869
+ const value = copy[key];
3870
+ if (key === "$ref" && typeof value === "string" && value.startsWith("#/definitions/")) {
3871
+ const defName = value.slice(14);
3872
+ const definition = definitions?.[defName];
3873
+ if (definition) {
3874
+ delete copy.$ref;
3875
+ const resolved = resolveRef(definition, [...path4, defName]);
3876
+ if (resolved && typeof resolved === "object" && !Array.isArray(resolved)) {
3877
+ Object.assign(copy, resolved);
3878
+ }
3879
+ }
3880
+ } else if (key === "$ref" && typeof value === "string") {
3881
+ delete copy.$ref;
3882
+ } else {
3883
+ copy[key] = resolveRef(value, path4);
3884
+ }
3885
+ }
3886
+ return copy;
3887
+ }
3888
+ return resolveRef(obj, []);
3889
+ }
3820
3890
  return [
3821
3891
  {
3822
- functionDeclarations: tools.map((tool) => ({
3823
- name: tool.name,
3824
- description: tool.description,
3825
- parameters: tool.parameters
3826
- }))
3892
+ functionDeclarations: tools.map((tool) => {
3893
+ let parameters = tool.parameters;
3894
+ if (parameters && typeof parameters === "object" && !Array.isArray(parameters)) {
3895
+ parameters = flattenJsonSchema(parameters);
3896
+ }
3897
+ return {
3898
+ name: tool.name,
3899
+ description: tool.description,
3900
+ parameters
3901
+ };
3902
+ })
3827
3903
  }
3828
3904
  ];
3829
3905
  }
@@ -5774,6 +5850,31 @@ async function createServer(config) {
5774
5850
  timestamp: meta.timestamp
5775
5851
  });
5776
5852
  });
5853
+ server.get("/api/config", (_req, reply) => {
5854
+ reply.send({
5855
+ blobRoot: config.logging.blobRoot
5856
+ });
5857
+ });
5858
+ server.get("/api/logs/:id/path", (req, reply) => {
5859
+ const { id } = req.params;
5860
+ const meta = logStore.readMetadata(Number(id));
5861
+ if (!meta) {
5862
+ reply.status(404).send({ error: { message: "Log not found" } });
5863
+ return;
5864
+ }
5865
+ const date = new Date(meta.timestamp);
5866
+ const year = date.getUTCFullYear();
5867
+ const month = String(date.getUTCMonth() + 1).padStart(2, "0");
5868
+ const day = String(date.getUTCDate()).padStart(2, "0");
5869
+ const dirPath = `${config.logging.blobRoot}/${year}/${month}/${day}/${meta.request_id}/`;
5870
+ reply.send({
5871
+ directory: dirPath,
5872
+ request: meta.request_path ? `${config.logging.blobRoot}/${meta.request_path}` : null,
5873
+ response: meta.response_path ? `${config.logging.blobRoot}/${meta.response_path}` : null,
5874
+ providerRequest: meta.provider_request_path ? `${config.logging.blobRoot}/${meta.provider_request_path}` : null,
5875
+ providerResponse: meta.provider_response_path ? `${config.logging.blobRoot}/${meta.provider_response_path}` : null
5876
+ });
5877
+ });
5777
5878
  return server;
5778
5879
  }
5779
5880
  async function handleRequest(req, reply, body, modelRegistry, pipeline, logStore, liveStoreRuntime, config, options) {
@@ -6045,5 +6146,5 @@ async function bootstrap() {
6045
6146
  }
6046
6147
  bootstrap();
6047
6148
 
6048
- //# debugId=49E2D016D6E3465664756E2164756E21
6149
+ //# debugId=58CB00416A249CAB64756E2164756E21
6049
6150
  //# sourceMappingURL=index.js.map