@tonyclaw/agent-inspector 2.0.36 → 2.0.38

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 (86) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-Bg2mo0NZ.js → CompareDrawer-hc5OoAls.js} +1 -1
  3. package/.output/public/assets/{ProxyViewerContainer-C_Lq5T5V.js → ProxyViewerContainer-BMKBs8Qz.js} +35 -35
  4. package/.output/public/assets/{ReplayDialog-Bns-ayOg.js → ReplayDialog-CN-KM2nu.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-BBcPAIWx.js → RequestAnatomy-B1kTlAUk.js} +1 -1
  6. package/.output/public/assets/{ResponseView-DSRS3rHt.js → ResponseView-BchUjKjt.js} +1 -1
  7. package/.output/public/assets/{StreamingChunkSequence-CzZxKE5-.js → StreamingChunkSequence-BQOxI9Hi.js} +1 -1
  8. package/.output/public/assets/_sessionId-CVw5e8TK.js +1 -0
  9. package/.output/public/assets/index-BdUTMQL6.js +1 -0
  10. package/.output/public/assets/{main-BVKRHBUl.js → main-Blykwzsn.js} +2 -2
  11. package/.output/server/_libs/lucide-react.mjs +114 -94
  12. package/.output/server/{_sessionId-Dsd36Yhc.mjs → _sessionId-BUNZz2zZ.mjs} +2 -2
  13. package/.output/server/_ssr/{CompareDrawer-BbJ5UdYD.mjs → CompareDrawer-VaDYPM5G.mjs} +3 -3
  14. package/.output/server/_ssr/{ProxyViewerContainer-7igCY291.mjs → ProxyViewerContainer-CpdWs7Pk.mjs} +801 -785
  15. package/.output/server/_ssr/{ReplayDialog-CgWweshq.mjs → ReplayDialog-DbfIjJhb.mjs} +4 -4
  16. package/.output/server/_ssr/{RequestAnatomy-BAyM_j7a.mjs → RequestAnatomy-CrD8h6As.mjs} +3 -3
  17. package/.output/server/_ssr/{ResponseView-iZQH7EYu.mjs → ResponseView-BalvDwtU.mjs} +3 -3
  18. package/.output/server/_ssr/{StreamingChunkSequence-BU6hyHMg.mjs → StreamingChunkSequence-RxatDbPV.mjs} +2 -2
  19. package/.output/server/_ssr/{index-D7QF4E6v.mjs → index-11qAtV9d.mjs} +2 -2
  20. package/.output/server/_ssr/index.mjs +2 -2
  21. package/.output/server/_ssr/{router-DLLY6gv_.mjs → router-C4OdRnqX.mjs} +138 -138
  22. package/.output/server/{_tanstack-start-manifest_v-CHmIZaVV.mjs → _tanstack-start-manifest_v-F6bwcl33.mjs} +1 -1
  23. package/.output/server/index.mjs +60 -60
  24. package/README.md +1 -1
  25. package/package.json +1 -1
  26. package/src/components/ProxyViewer.tsx +43 -9
  27. package/src/components/ProxyViewerContainer.tsx +1 -1
  28. package/src/components/providers/ProviderForm.tsx +2 -2
  29. package/src/components/proxy-viewer/AgentTraceSummary.tsx +1 -1
  30. package/src/components/proxy-viewer/CompareDrawer.tsx +1 -1
  31. package/src/components/proxy-viewer/ConversationGroup.tsx +1 -1
  32. package/src/components/proxy-viewer/ConversationGroupList.tsx +1 -1
  33. package/src/components/proxy-viewer/ConversationHeader.tsx +11 -7
  34. package/src/components/proxy-viewer/LogEntry.tsx +1 -1
  35. package/src/components/proxy-viewer/LogEntryHeader.tsx +1 -1
  36. package/src/components/proxy-viewer/ReplayDialog.tsx +1 -1
  37. package/src/components/proxy-viewer/ResponseView.tsx +2 -2
  38. package/src/components/proxy-viewer/StreamingChunkSequence.tsx +1 -1
  39. package/src/components/proxy-viewer/TurnGroup.tsx +1 -1
  40. package/src/components/proxy-viewer/anatomy/sessionContextSummary.ts +1 -1
  41. package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +1 -1
  42. package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +2 -2
  43. package/src/components/proxy-viewer/formats/index.tsx +5 -3
  44. package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +1 -1
  45. package/src/components/proxy-viewer/log-formats/anthropic.ts +1 -4
  46. package/src/components/proxy-viewer/log-formats/index.ts +6 -6
  47. package/src/components/proxy-viewer/log-formats/openai.ts +1 -1
  48. package/src/components/proxy-viewer/log-formats/types.ts +2 -2
  49. package/src/components/proxy-viewer/viewerState.ts +1 -1
  50. package/src/contracts/anthropic.ts +235 -0
  51. package/src/contracts/index.ts +27 -0
  52. package/src/contracts/json.ts +32 -0
  53. package/src/contracts/log.ts +72 -0
  54. package/src/contracts/openai.ts +176 -0
  55. package/src/knowledge/distiller.ts +1 -1
  56. package/src/lib/export-logs.ts +1 -1
  57. package/src/lib/groupContract.ts +1 -1
  58. package/src/lib/objectUtils.ts +3 -3
  59. package/src/lib/providerTestContract.ts +1 -1
  60. package/src/lib/runContract.ts +1 -1
  61. package/src/lib/stopReason.ts +1 -1
  62. package/src/mcp/previewExtractor.ts +4 -7
  63. package/src/mcp/server.ts +1 -1
  64. package/src/mcp/toolHandlers.ts +1 -1
  65. package/src/proxy/formats/anthropic/anthropicProvider.ts +2 -2
  66. package/src/proxy/formats/anthropic/schemas.ts +12 -235
  67. package/src/proxy/formats/handler.ts +2 -2
  68. package/src/proxy/formats/index.ts +1 -1
  69. package/src/proxy/formats/jsonSchema.ts +2 -36
  70. package/src/proxy/formats/openai/alibabaProvider.ts +2 -2
  71. package/src/proxy/formats/openai/provider.ts +2 -2
  72. package/src/proxy/formats/openai/schemas.ts +14 -187
  73. package/src/proxy/formats/openai/zhipuProvider.ts +2 -2
  74. package/src/proxy/formats/{protocol.ts → providerAdapter.ts} +5 -5
  75. package/src/proxy/formats/providerRegistry.ts +7 -7
  76. package/src/proxy/formats/providers/index.ts +1 -1
  77. package/src/proxy/formats/registry.ts +20 -11
  78. package/src/proxy/handler.ts +1 -1
  79. package/src/proxy/openaiOrphanToolStrip.ts +1 -1
  80. package/src/proxy/providers.ts +1 -1
  81. package/src/proxy/schemas.ts +18 -80
  82. package/src/proxy/store.ts +14 -11
  83. package/src/proxy/upstream.ts +1 -1
  84. package/src/routes/api/logs.stream.ts +1 -1
  85. package/.output/public/assets/_sessionId-DurHDwM1.js +0 -1
  86. package/.output/public/assets/index-sGphugFR.js +0 -1
@@ -0,0 +1,235 @@
1
+ import { z } from "zod";
2
+ import { JsonValueSchema } from "./json";
3
+
4
+ const CacheControl = z.object({
5
+ type: z.string(),
6
+ ttl: z.string().optional(),
7
+ scope: z.string().optional(),
8
+ });
9
+
10
+ const TextContentBlock = z.object({
11
+ type: z.literal("text"),
12
+ text: z.string(),
13
+ cache_control: CacheControl.optional(),
14
+ });
15
+
16
+ const ThinkingContentBlock = z.object({
17
+ type: z.literal("thinking"),
18
+ thinking: z.string(),
19
+ signature: z.string().optional(),
20
+ });
21
+
22
+ const ThinkContentBlock = z.object({
23
+ type: z.literal("think"),
24
+ thinking: z.string(),
25
+ signature: z.string().optional(),
26
+ });
27
+
28
+ const ImageSourceBlock = z.object({
29
+ type: z.literal("base64"),
30
+ media_type: z.string(),
31
+ data: z.string(),
32
+ });
33
+
34
+ const ImageContentBlock = z.object({
35
+ type: z.literal("image"),
36
+ source: ImageSourceBlock,
37
+ });
38
+
39
+ const ToolUseContentBlock = z.object({
40
+ type: z.literal("tool_use"),
41
+ id: z.string(),
42
+ name: z.string(),
43
+ input: z.record(z.string(), JsonValueSchema),
44
+ });
45
+
46
+ const ToolResultContentItem = z.discriminatedUnion("type", [TextContentBlock, ImageContentBlock]);
47
+
48
+ const ToolResultContentBlock = z.object({
49
+ type: z.literal("tool_result"),
50
+ tool_use_id: z.string().optional(),
51
+ content: z.union([z.string(), z.array(ToolResultContentItem)]),
52
+ is_error: z.boolean().optional(),
53
+ });
54
+
55
+ const ContentBlock = z.discriminatedUnion("type", [
56
+ TextContentBlock,
57
+ ThinkingContentBlock,
58
+ ImageContentBlock,
59
+ ToolUseContentBlock,
60
+ ToolResultContentBlock,
61
+ ]);
62
+
63
+ const MessageContent = z.union([z.string(), z.array(ContentBlock)]);
64
+
65
+ const Message = z.object({
66
+ role: z.enum(["user", "assistant"]),
67
+ content: MessageContent,
68
+ });
69
+
70
+ const SystemBlock = z.object({
71
+ type: z.literal("text"),
72
+ text: z.string(),
73
+ cache_control: CacheControl.optional(),
74
+ });
75
+
76
+ const InputSchema = z.object({
77
+ type: z.string(),
78
+ properties: z.record(z.string(), z.record(z.string(), JsonValueSchema)).optional(),
79
+ required: z.array(z.string()).optional(),
80
+ additionalProperties: z.boolean().optional(),
81
+ $schema: z.string().optional(),
82
+ });
83
+
84
+ const ToolDefinition = z.object({
85
+ name: z.string(),
86
+ description: z.string().optional(),
87
+ input_schema: InputSchema.optional(),
88
+ cache_control: CacheControl.optional(),
89
+ });
90
+
91
+ const ThinkingConfig = z.discriminatedUnion("type", [
92
+ z.object({ type: z.literal("enabled"), budget_tokens: z.number() }),
93
+ z.object({ type: z.literal("disabled") }),
94
+ z.object({ type: z.literal("adaptive") }),
95
+ ]);
96
+
97
+ export const AnthropicRequestSchema = z.object({
98
+ model: z.string(),
99
+ messages: z.array(Message),
100
+ system: z.array(SystemBlock).optional(),
101
+ tools: z.array(ToolDefinition).optional(),
102
+ max_tokens: z.number().optional(),
103
+ temperature: z.number().optional(),
104
+ stream: z.boolean().optional(),
105
+ thinking: ThinkingConfig.optional(),
106
+ metadata: z
107
+ .object({
108
+ user_id: z.string().optional(),
109
+ })
110
+ .optional(),
111
+ });
112
+
113
+ const ResponseContentBlock = z.discriminatedUnion("type", [
114
+ TextContentBlock,
115
+ ThinkingContentBlock,
116
+ ThinkContentBlock,
117
+ ToolUseContentBlock,
118
+ ]);
119
+
120
+ const ResponseUsageSchema = z
121
+ .object({
122
+ input_tokens: z.number().nullable().optional(),
123
+ output_tokens: z.number().nullable().optional(),
124
+ cache_creation_input_tokens: z.number().nullable().optional(),
125
+ cache_read_input_tokens: z.number().nullable().optional(),
126
+ })
127
+ .passthrough();
128
+
129
+ export const AnthropicResponseSchema = z
130
+ .object({
131
+ id: z.string(),
132
+ type: z.literal("message"),
133
+ model: z.string(),
134
+ role: z.literal("assistant"),
135
+ content: z.array(ResponseContentBlock),
136
+ stop_reason: z.string().nullable(),
137
+ stop_sequence: z.string().nullable().optional(),
138
+ usage: ResponseUsageSchema,
139
+ })
140
+ .passthrough();
141
+
142
+ const SseMessageStartEvent = z.object({
143
+ type: z.literal("message_start"),
144
+ message: z.object({
145
+ id: z.string(),
146
+ type: z.literal("message"),
147
+ model: z.string(),
148
+ role: z.literal("assistant"),
149
+ content: z.array(ResponseContentBlock),
150
+ stop_reason: z.null(),
151
+ stop_sequence: z.null(),
152
+ usage: z
153
+ .object({
154
+ input_tokens: z.number(),
155
+ cache_creation_input_tokens: z.number().optional(),
156
+ cache_read_input_tokens: z.number().optional(),
157
+ })
158
+ .passthrough(),
159
+ }),
160
+ });
161
+
162
+ const SseContentBlockStartEvent = z.object({
163
+ type: z.literal("content_block_start"),
164
+ index: z.number(),
165
+ content_block: ResponseContentBlock,
166
+ });
167
+
168
+ const SseDeltaBlock = z.discriminatedUnion("type", [
169
+ z.object({ type: z.literal("text_delta"), text: z.string() }),
170
+ z.object({ type: z.literal("input_json_delta"), partial_json: z.string() }),
171
+ z.object({ type: z.literal("thinking_delta"), thinking: z.string() }),
172
+ z.object({ type: z.literal("signature_delta"), signature: z.string() }),
173
+ ]);
174
+
175
+ const SseContentBlockDeltaEvent = z.object({
176
+ type: z.literal("content_block_delta"),
177
+ index: z.number(),
178
+ delta: SseDeltaBlock,
179
+ });
180
+
181
+ const SseContentBlockStopEvent = z.object({
182
+ type: z.literal("content_block_stop"),
183
+ index: z.number(),
184
+ });
185
+
186
+ const SseMessageDeltaEvent = z.object({
187
+ type: z.literal("message_delta"),
188
+ delta: z.object({
189
+ stop_reason: z.string().nullable(),
190
+ stop_sequence: z.string().nullable().optional(),
191
+ }),
192
+ usage: z
193
+ .object({
194
+ output_tokens: z.number(),
195
+ input_tokens: z.number().optional(),
196
+ cache_creation_input_tokens: z.number().optional(),
197
+ cache_read_input_tokens: z.number().optional(),
198
+ })
199
+ .passthrough(),
200
+ });
201
+
202
+ const SseMessageStopEvent = z.object({
203
+ type: z.literal("message_stop"),
204
+ });
205
+
206
+ const SsePingEvent = z.object({
207
+ type: z.literal("ping"),
208
+ });
209
+
210
+ const SseErrorEvent = z.object({
211
+ type: z.literal("error"),
212
+ error: z.object({
213
+ type: z.string(),
214
+ message: z.string(),
215
+ }),
216
+ });
217
+
218
+ export const SseEventSchema = z.discriminatedUnion("type", [
219
+ SseMessageStartEvent,
220
+ SseContentBlockStartEvent,
221
+ SseContentBlockDeltaEvent,
222
+ SseContentBlockStopEvent,
223
+ SseMessageDeltaEvent,
224
+ SseMessageStopEvent,
225
+ SsePingEvent,
226
+ SseErrorEvent,
227
+ ]);
228
+
229
+ export type AnthropicResponse = z.infer<typeof AnthropicResponseSchema>;
230
+ export type ResponseContentBlockType = z.infer<typeof ResponseContentBlock>;
231
+
232
+ // Backward-compatible aliases (originally named Inspector*)
233
+ export const InspectorRequestSchema = AnthropicRequestSchema;
234
+ export const InspectorResponseSchema = AnthropicResponseSchema;
235
+ export type InspectorResponse = AnthropicResponse;
@@ -0,0 +1,27 @@
1
+ export { JsonValueSchema, trustAsJsonValue } from "./json";
2
+ export type { JsonValue } from "./json";
3
+
4
+ export { CapturedLogSchema, StreamingChunkSchema } from "./log";
5
+ export type { ApiFormat, CapturedLog, RequestFormat, StreamingChunk, TokenUsage } from "./log";
6
+
7
+ export {
8
+ AnthropicRequestSchema,
9
+ AnthropicResponseSchema,
10
+ SseEventSchema,
11
+ } from "./anthropic";
12
+ export type { AnthropicResponse, ResponseContentBlockType } from "./anthropic";
13
+
14
+ export {
15
+ OpenAIChoice,
16
+ OpenAIChoiceDelta,
17
+ OpenAIFunctionCall,
18
+ OpenAIMessage,
19
+ OpenAIMessageContent,
20
+ OpenAIRequestSchema,
21
+ OpenAIResponseSchema,
22
+ OpenAISSERawChunkSchema,
23
+ OpenAIToolCallSchema,
24
+ OpenAIToolDefinition,
25
+ parseOpenAIResponse,
26
+ } from "./openai";
27
+ export type { OpenAIResponse, OpenAIToolCall } from "./openai";
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * Shared JSON value type for API payload fragments and streaming chunks.
5
+ */
6
+ export type JsonValue =
7
+ | string
8
+ | number
9
+ | boolean
10
+ | null
11
+ | JsonValue[]
12
+ | { [key: string]: JsonValue };
13
+
14
+ export const JsonValueSchema: z.ZodType<JsonValue> = z.lazy(() =>
15
+ z.union([
16
+ z.string(),
17
+ z.number(),
18
+ z.boolean(),
19
+ z.null(),
20
+ z.array(JsonValueSchema),
21
+ z.record(z.string(), JsonValueSchema),
22
+ ]),
23
+ );
24
+
25
+ /**
26
+ * Re-types a value as `JsonValue` without re-walking it. Use this ONLY when
27
+ * the value has already been validated and originated from `JSON.parse`.
28
+ */
29
+ export function trustAsJsonValue<T>(value: T): JsonValue {
30
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
31
+ return value as unknown as JsonValue;
32
+ }
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ import { JsonValueSchema } from "./json";
3
+
4
+ export type ApiFormat = "anthropic" | "openai" | "unknown";
5
+ export type RequestFormat = ApiFormat;
6
+
7
+ /**
8
+ * A single SSE event from a streaming response.
9
+ */
10
+ export const StreamingChunkSchema = z.object({
11
+ index: z.number(),
12
+ timestamp: z.number(),
13
+ type: z.string(),
14
+ data: JsonValueSchema,
15
+ });
16
+
17
+ export type StreamingChunk = z.infer<typeof StreamingChunkSchema>;
18
+
19
+ const StreamingChunksArraySchema = z.object({
20
+ chunks: z.array(StreamingChunkSchema),
21
+ truncated: z.boolean().optional().default(false),
22
+ });
23
+
24
+ export const CapturedLogSchema = z.object({
25
+ id: z.number(),
26
+ timestamp: z.string(),
27
+ method: z.string(),
28
+ path: z.string(),
29
+ model: z.string().nullable(),
30
+ sessionId: z.string().nullable(),
31
+ rawRequestBody: z.string().nullable(),
32
+ responseStatus: z.number().nullable(),
33
+ responseText: z.string().nullable(),
34
+ inputTokens: z.number().nullable(),
35
+ outputTokens: z.number().nullable(),
36
+ cacheCreationInputTokens: z.number().nullable(),
37
+ cacheReadInputTokens: z.number().nullable(),
38
+ elapsedMs: z.number().nullable(),
39
+ firstChunkMs: z.number().nullable().optional(),
40
+ totalStreamMs: z.number().nullable().optional(),
41
+ tokensPerSecond: z.number().nullable().optional(),
42
+ streaming: z.boolean(),
43
+ userAgent: z.string().nullable(),
44
+ origin: z.string().nullable(),
45
+ rawHeaders: z.record(z.string(), z.string()).optional(),
46
+ /** Headers sent to the upstream LLM */
47
+ headers: z.record(z.string(), z.string()).optional(),
48
+ apiFormat: z.enum(["anthropic", "openai", "unknown"]).default("unknown"),
49
+ isTest: z.boolean().optional().default(false),
50
+ replayOfLogId: z.number().nullable().optional(),
51
+ providerName: z.string().nullable().optional(),
52
+ clientPort: z.number().nullable().optional(),
53
+ clientPid: z.number().nullable().optional(),
54
+ clientCwd: z.string().nullable().optional(),
55
+ clientProjectFolder: z.string().nullable().optional(),
56
+ streamingChunks: StreamingChunksArraySchema.optional(),
57
+ streamingChunksPath: z.string().nullable().optional(),
58
+ rawRequestBodyBytes: z.number().int().nonnegative().nullable().optional(),
59
+ responseTextBytes: z.number().int().nonnegative().nullable().optional(),
60
+ bodyContentMode: z.enum(["full", "compact", "truncated"]).optional(),
61
+ /** Error message from streaming response (e.g., SSE error event) */
62
+ error: z.string().nullable().optional(),
63
+ });
64
+
65
+ export type CapturedLog = z.infer<typeof CapturedLogSchema>;
66
+
67
+ export type TokenUsage = {
68
+ inputTokens: number | null;
69
+ outputTokens: number | null;
70
+ cacheCreationInputTokens: number | null;
71
+ cacheReadInputTokens: number | null;
72
+ };
@@ -0,0 +1,176 @@
1
+ import { z } from "zod";
2
+ import { JsonValueSchema } from "./json";
3
+
4
+ export const OpenAIMessageContent = z.union([
5
+ z.string(),
6
+ z.array(
7
+ z.discriminatedUnion("type", [
8
+ z.object({ type: z.literal("text"), text: z.string() }),
9
+ z.object({
10
+ type: z.literal("image_url"),
11
+ image_url: z.object({ url: z.string(), detail: z.string().optional() }),
12
+ }),
13
+ ]),
14
+ ),
15
+ ]);
16
+
17
+ export const OpenAIMessage = z.object({
18
+ role: z.enum(["system", "user", "assistant", "tool"]),
19
+ content: OpenAIMessageContent,
20
+ name: z.string().optional(),
21
+ reasoning_content: z.string().optional(),
22
+ thinking: z.string().optional(),
23
+ think: z.string().optional(),
24
+ });
25
+
26
+ export const OpenAIFunctionCall = z.object({
27
+ name: z.string(),
28
+ arguments: z.string(),
29
+ });
30
+
31
+ export const OpenAIToolCallSchema = z.object({
32
+ index: z.number().optional(),
33
+ id: z.string().optional(),
34
+ type: z.literal("function").optional(),
35
+ function: z.object({
36
+ name: z.string().optional(),
37
+ arguments: z.string().optional(),
38
+ }),
39
+ });
40
+
41
+ export type OpenAIToolCall = z.infer<typeof OpenAIToolCallSchema>;
42
+
43
+ const OpenAIMessageWithFunctionCall = OpenAIMessage.extend({
44
+ content: z
45
+ .union([z.string(), z.array(z.object({ type: z.literal("text"), text: z.string() }))])
46
+ .optional(),
47
+ function_call: OpenAIFunctionCall.optional(),
48
+ tool_calls: z.array(OpenAIToolCallSchema).optional(),
49
+ });
50
+
51
+ export const OpenAIToolDefinition = z.object({
52
+ type: z.literal("function"),
53
+ function: z.object({
54
+ name: z.string(),
55
+ description: z.string().optional(),
56
+ parameters: z.record(z.string(), JsonValueSchema),
57
+ }),
58
+ });
59
+
60
+ export const OpenAIRequestSchema = z.object({
61
+ model: z.string(),
62
+ messages: z.array(OpenAIMessage),
63
+ temperature: z.number().optional(),
64
+ max_tokens: z.number().optional(),
65
+ stream: z.boolean().optional(),
66
+ tools: z.array(OpenAIToolDefinition).optional(),
67
+ tool_choice: z
68
+ .union([
69
+ z.enum(["auto", "none", "required"]),
70
+ z.object({ type: z.literal("auto") }),
71
+ z.object({ type: z.literal("none") }),
72
+ z.object({ type: z.literal("function"), function: z.object({ name: z.string() }) }),
73
+ ])
74
+ .optional(),
75
+ user: z.string().optional(),
76
+ });
77
+
78
+ export const OpenAIChoiceDelta = z.object({
79
+ role: z.enum(["assistant"]).optional(),
80
+ content: z.string().nullable().optional(),
81
+ reasoning_content: z.string().nullable().optional(),
82
+ thinking: z.string().nullable().optional(),
83
+ think: z.string().nullable().optional(),
84
+ function_call: z
85
+ .object({ name: z.string().optional(), arguments: z.string().optional() })
86
+ .nullable()
87
+ .optional(),
88
+ tool_calls: z
89
+ .array(
90
+ z.object({
91
+ index: z.number(),
92
+ id: z.string().optional(),
93
+ type: z.literal("function").optional(),
94
+ function: z.object({
95
+ name: z.string().optional(),
96
+ arguments: z.string().optional(),
97
+ }),
98
+ }),
99
+ )
100
+ .nullable()
101
+ .optional(),
102
+ });
103
+
104
+ export const OpenAIChoice = z.object({
105
+ index: z.number(),
106
+ message: z
107
+ .object({
108
+ role: z.enum(["assistant"]),
109
+ content: z.string().nullable(),
110
+ reasoning_content: z.string().optional(),
111
+ thinking: z.string().optional(),
112
+ think: z.string().optional(),
113
+ function_call: z.object({ name: z.string(), arguments: z.string() }).nullable().optional(),
114
+ tool_calls: z.array(OpenAIToolCallSchema).optional(),
115
+ })
116
+ .optional(),
117
+ delta: OpenAIChoiceDelta.optional(),
118
+ finish_reason: z.string().nullable(),
119
+ });
120
+
121
+ export const OpenAIResponseSchema = z
122
+ .object({
123
+ id: z.string(),
124
+ object: z.literal("chat.completion"),
125
+ created: z.number(),
126
+ model: z.string(),
127
+ choices: z.array(OpenAIChoice),
128
+ usage: z
129
+ .object({
130
+ prompt_tokens: z.number().nullable().optional(),
131
+ completion_tokens: z.number().nullable().optional(),
132
+ total_tokens: z.number().nullable().optional(),
133
+ })
134
+ .passthrough(),
135
+ service_tier: z.string().nullable().optional(),
136
+ system_fingerprint: z.string().nullable().optional(),
137
+ })
138
+ .passthrough();
139
+
140
+ export const OpenAISSERawChunkSchema = z
141
+ .object({
142
+ id: z.string(),
143
+ object: z.literal("chat.completion.chunk"),
144
+ created: z.number(),
145
+ model: z.string(),
146
+ choices: z.array(
147
+ z.object({
148
+ index: z.number(),
149
+ delta: OpenAIChoiceDelta,
150
+ finish_reason: z.string().nullable().optional(),
151
+ }),
152
+ ),
153
+ usage: z
154
+ .object({
155
+ prompt_tokens: z.number().nullable().optional(),
156
+ completion_tokens: z.number().nullable().optional(),
157
+ total_tokens: z.number().nullable().optional(),
158
+ })
159
+ .passthrough()
160
+ .nullable()
161
+ .optional(),
162
+ })
163
+ .passthrough();
164
+
165
+ export type OpenAIResponse = z.infer<typeof OpenAIResponseSchema>;
166
+
167
+ export function parseOpenAIResponse(rawBody: string): OpenAIResponse | null {
168
+ try {
169
+ const json: unknown = JSON.parse(rawBody);
170
+ const result = OpenAIResponseSchema.safeParse(json);
171
+ if (result.success) return result.data;
172
+ return null;
173
+ } catch {
174
+ return null;
175
+ }
176
+ }
@@ -1,5 +1,5 @@
1
1
  import { extractLastUserMessagePreview, extractResponsePreview } from "../mcp/previewExtractor";
2
- import type { CapturedLog } from "../proxy/schemas";
2
+ import type { CapturedLog } from "../contracts";
3
3
  import type { KnowledgeCandidate, KnowledgeCandidateType } from "./types";
4
4
  import { redactCandidate } from "./redactor";
5
5
 
@@ -1,5 +1,5 @@
1
1
  import JSZip from "jszip";
2
- import type { CapturedLog } from "../proxy/schemas";
2
+ import type { CapturedLog } from "../contracts";
3
3
 
4
4
  export type ExportMode = "redacted" | "raw";
5
5
  export type ExportLogsResult =
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { JsonValueSchema } from "../proxy/schemas";
2
+ import { JsonValueSchema } from "../contracts";
3
3
  import { EvidenceReportSchema, InspectorRunSchema, InspectorRunStatusSchema } from "./runContract";
4
4
  import { SessionInfoSchema, SessionTokenUsageSchema } from "./sessionInfoContract";
5
5
 
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Generic object utilities shared across protocol modules.
3
- * Only truly protocol-agnostic helpers belong here Anthropic/OpenAI-specific
4
- * checks stay in their respective format modules.
2
+ * Generic object utilities shared across API format modules.
3
+ * Only truly format-agnostic helpers belong here; Anthropic/OpenAI-specific
4
+ * checks stay in their respective API format modules.
5
5
  */
6
6
 
7
7
  /**
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { StreamingChunkSchema } from "../proxy/schemas";
2
+ import { StreamingChunkSchema } from "../contracts";
3
3
 
4
4
  export const ProviderTestErrorTypeSchema = z.enum([
5
5
  "timeout",
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { JsonValueSchema } from "../proxy/schemas";
2
+ import { JsonValueSchema } from "../contracts";
3
3
  import { SessionInfoSchema } from "./sessionInfoContract";
4
4
 
5
5
  export const InspectorRunStatusSchema = z.enum([
@@ -1,4 +1,4 @@
1
- import type { CapturedLog } from "../proxy/schemas";
1
+ import type { CapturedLog } from "../contracts";
2
2
 
3
3
  export type StopReason = "end_turn" | "tool_use" | "stop" | null;
4
4
 
@@ -10,7 +10,7 @@
10
10
  * agent needs to make a "is this the log I care about?" judgment from
11
11
  * `list_logs` alone.
12
12
  *
13
- * Null returns are an expected and frequent outcome they cover:
13
+ * Null returns are an expected and frequent outcome; they cover:
14
14
  * - `apiFormat === "unknown"`
15
15
  * - `rawRequestBody` / `responseText` is null
16
16
  * - JSON.parse failure
@@ -19,12 +19,9 @@
19
19
  * - the relevant content is non-text (e.g., image-only multimodal block)
20
20
  */
21
21
 
22
- import type { CapturedLog } from "../proxy/schemas";
23
- import {
24
- AnthropicRequestSchema,
25
- AnthropicResponseSchema,
26
- } from "../proxy/formats/anthropic/schemas";
27
- import { OpenAIRequestSchema, OpenAIResponseSchema } from "../proxy/formats/openai/schemas";
22
+ import type { CapturedLog } from "../contracts";
23
+ import { AnthropicRequestSchema, AnthropicResponseSchema } from "../contracts/anthropic";
24
+ import { OpenAIRequestSchema, OpenAIResponseSchema } from "../contracts/openai";
28
25
 
29
26
  /** Preview length cap, per design D5. */
30
27
  const PREVIEW_MAX_CHARS = 500;
package/src/mcp/server.ts CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  } from "../lib/groupContract";
35
35
  import { InspectorRunStatusSchema, UpdateInspectorRunInputSchema } from "../lib/runContract";
36
36
  import { setCurrentPort } from "../lib/serverPort";
37
- import { JsonValueSchema } from "../proxy/schemas";
37
+ import { JsonValueSchema } from "../contracts";
38
38
  import {
39
39
  getInspectorGroup,
40
40
  listInspectorGroups,
@@ -28,7 +28,7 @@ import {
28
28
  } from "../lib/groupContract";
29
29
  import { type CreateInspectorRunInput, type UpdateInspectorRunInput } from "../lib/runContract";
30
30
  import { SessionInfoSchema } from "../lib/sessionInfoContract";
31
- import { CapturedLogSchema, type CapturedLog } from "../proxy/schemas";
31
+ import { CapturedLogSchema, type CapturedLog } from "../contracts";
32
32
  import {
33
33
  addInspectorGroupSession,
34
34
  createInspectorGroup,
@@ -1,5 +1,5 @@
1
1
  import type { CapturedLog } from "../../schemas";
2
- import type { ProviderProtocol } from "../protocol";
2
+ import type { ProviderAdapter } from "../providerAdapter";
3
3
  import { registry } from "../providers";
4
4
  import { extractAnthropicStream } from "./stream";
5
5
 
@@ -27,7 +27,7 @@ function getUpstreamForModel(model: string): string {
27
27
  /**
28
28
  * Anthropic Provider Implementation
29
29
  */
30
- export const anthropicProvider: ProviderProtocol = {
30
+ export const anthropicProvider: ProviderAdapter = {
31
31
  name: "anthropic",
32
32
 
33
33
  matches(model: string): boolean {