@tonyclaw/agent-inspector 2.0.37 → 2.0.39

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 (88) hide show
  1. package/.output/cli.js +528 -24
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/{CompareDrawer-nEHCEVP4.js → CompareDrawer-Jfe6M6DQ.js} +1 -1
  4. package/.output/public/assets/{ProxyViewerContainer-BstBIX2B.js → ProxyViewerContainer-CQKV0Bqq.js} +15 -15
  5. package/.output/public/assets/{ReplayDialog-CUnBdt1Q.js → ReplayDialog-B58TbTtY.js} +1 -1
  6. package/.output/public/assets/{RequestAnatomy-BU9VT2Sw.js → RequestAnatomy-d4P6JNiP.js} +1 -1
  7. package/.output/public/assets/{ResponseView-amxuKPKY.js → ResponseView-Bum1a3tG.js} +1 -1
  8. package/.output/public/assets/{StreamingChunkSequence-DpscrQM2.js → StreamingChunkSequence-CjBDp5E9.js} +1 -1
  9. package/.output/public/assets/_sessionId-BupV2gtf.js +1 -0
  10. package/.output/public/assets/index-DHSww5em.js +1 -0
  11. package/.output/public/assets/{main-D56QvEyw.js → main-DK9PoBjx.js} +2 -2
  12. package/.output/server/{_sessionId-ChwEDyI4.mjs → _sessionId-DjarbXpT.mjs} +2 -2
  13. package/.output/server/_ssr/{CompareDrawer-Ce2590rK.mjs → CompareDrawer-C5Z6AlUk.mjs} +2 -2
  14. package/.output/server/_ssr/{ProxyViewerContainer-D6xM8A0S.mjs → ProxyViewerContainer-4pXsBywn.mjs} +37 -9
  15. package/.output/server/_ssr/{ReplayDialog-CB4KOlLe.mjs → ReplayDialog-w1vc1p5e.mjs} +3 -3
  16. package/.output/server/_ssr/{RequestAnatomy-CsWV3W03.mjs → RequestAnatomy-2HaBhsNV.mjs} +2 -2
  17. package/.output/server/_ssr/{ResponseView-BuCCV3LU.mjs → ResponseView-SO_Y_W85.mjs} +2 -2
  18. package/.output/server/_ssr/{StreamingChunkSequence-C5dE7V1d.mjs → StreamingChunkSequence-CXEa2DkO.mjs} +2 -2
  19. package/.output/server/_ssr/{index-BeIi0CPv.mjs → index-DuCGt4a2.mjs} +2 -2
  20. package/.output/server/_ssr/index.mjs +2 -2
  21. package/.output/server/_ssr/{router-Ca2MCyUX.mjs → router-D0BaSzkZ.mjs} +69 -76
  22. package/.output/server/{_tanstack-start-manifest_v-CBAJfSAX.mjs → _tanstack-start-manifest_v-6N4SODyd.mjs} +1 -1
  23. package/.output/server/index.mjs +62 -62
  24. package/README.md +8 -1
  25. package/package.json +1 -1
  26. package/src/cli/onboard.ts +629 -21
  27. package/src/components/ProxyViewer.tsx +1 -1
  28. package/src/components/ProxyViewerContainer.tsx +1 -1
  29. package/src/components/providers/ProviderForm.tsx +2 -2
  30. package/src/components/providers/SettingsDialog.tsx +30 -0
  31. package/src/components/proxy-viewer/AgentTraceSummary.tsx +1 -1
  32. package/src/components/proxy-viewer/CompareDrawer.tsx +1 -1
  33. package/src/components/proxy-viewer/ConversationGroup.tsx +1 -1
  34. package/src/components/proxy-viewer/ConversationGroupList.tsx +1 -1
  35. package/src/components/proxy-viewer/ConversationHeader.tsx +1 -1
  36. package/src/components/proxy-viewer/LogEntry.tsx +1 -1
  37. package/src/components/proxy-viewer/LogEntryHeader.tsx +1 -1
  38. package/src/components/proxy-viewer/ReplayDialog.tsx +1 -1
  39. package/src/components/proxy-viewer/ResponseView.tsx +2 -2
  40. package/src/components/proxy-viewer/StreamingChunkSequence.tsx +1 -1
  41. package/src/components/proxy-viewer/TurnGroup.tsx +1 -1
  42. package/src/components/proxy-viewer/anatomy/sessionContextSummary.ts +1 -1
  43. package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +1 -1
  44. package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +2 -2
  45. package/src/components/proxy-viewer/formats/index.tsx +5 -3
  46. package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +1 -1
  47. package/src/components/proxy-viewer/log-formats/anthropic.ts +1 -4
  48. package/src/components/proxy-viewer/log-formats/index.ts +6 -6
  49. package/src/components/proxy-viewer/log-formats/openai.ts +1 -1
  50. package/src/components/proxy-viewer/log-formats/types.ts +2 -2
  51. package/src/components/proxy-viewer/viewerState.ts +1 -1
  52. package/src/contracts/anthropic.ts +235 -0
  53. package/src/contracts/index.ts +27 -0
  54. package/src/contracts/json.ts +32 -0
  55. package/src/contracts/log.ts +72 -0
  56. package/src/contracts/openai.ts +176 -0
  57. package/src/knowledge/distiller.ts +1 -1
  58. package/src/lib/export-logs.ts +1 -1
  59. package/src/lib/groupContract.ts +1 -1
  60. package/src/lib/objectUtils.ts +3 -3
  61. package/src/lib/providerTestContract.ts +1 -1
  62. package/src/lib/runContract.ts +1 -1
  63. package/src/lib/stopReason.ts +1 -1
  64. package/src/mcp/previewExtractor.ts +4 -7
  65. package/src/mcp/server.ts +1 -1
  66. package/src/mcp/toolHandlers.ts +1 -1
  67. package/src/proxy/formats/anthropic/anthropicProvider.ts +2 -2
  68. package/src/proxy/formats/anthropic/schemas.ts +12 -235
  69. package/src/proxy/formats/handler.ts +2 -2
  70. package/src/proxy/formats/index.ts +1 -1
  71. package/src/proxy/formats/jsonSchema.ts +2 -36
  72. package/src/proxy/formats/openai/alibabaProvider.ts +2 -2
  73. package/src/proxy/formats/openai/provider.ts +2 -2
  74. package/src/proxy/formats/openai/schemas.ts +14 -187
  75. package/src/proxy/formats/openai/zhipuProvider.ts +2 -2
  76. package/src/proxy/formats/{protocol.ts → providerAdapter.ts} +5 -5
  77. package/src/proxy/formats/providerRegistry.ts +7 -7
  78. package/src/proxy/formats/providers/index.ts +1 -1
  79. package/src/proxy/formats/registry.ts +16 -13
  80. package/src/proxy/handler.ts +1 -1
  81. package/src/proxy/openaiOrphanToolStrip.ts +1 -1
  82. package/src/proxy/providers.ts +1 -1
  83. package/src/proxy/schemas.ts +18 -80
  84. package/src/proxy/store.ts +2 -2
  85. package/src/proxy/upstream.ts +1 -1
  86. package/src/routes/api/logs.stream.ts +1 -1
  87. package/.output/public/assets/_sessionId-7c9bsOFT.js +0 -1
  88. package/.output/public/assets/index-B7a5OmIO.js +0 -1
@@ -11,7 +11,7 @@ import {
11
11
  Trash2,
12
12
  } from "lucide-react";
13
13
 
14
- import type { CapturedLog } from "../proxy/schemas";
14
+ import type { CapturedLog } from "../contracts";
15
15
  import { exportLogsAsZip, type ExportMode } from "../lib/export-logs";
16
16
  import type { CaptureMode, TimeDisplayFormat } from "../lib/runtimeConfig";
17
17
  import { formatTimestampRange } from "../lib/timeDisplay";
@@ -1,6 +1,6 @@
1
1
  import { useState, useEffect, useCallback, useRef, useMemo, type JSX } from "react";
2
2
  import { z } from "zod";
3
- import { CapturedLogSchema, type CapturedLog } from "../proxy/schemas";
3
+ import { CapturedLogSchema, type CapturedLog } from "../contracts";
4
4
  import { useStripConfig } from "../lib/useStripConfig";
5
5
  import { OnboardingBanner } from "./OnboardingBanner";
6
6
  import { ProxyViewer } from "./ProxyViewer";
@@ -845,7 +845,7 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
845
845
  Anthropic Format
846
846
  </button>
847
847
  </TooltipTrigger>
848
- <TooltipContent>Anthropic Messages API protocol</TooltipContent>
848
+ <TooltipContent>Anthropic Messages API format</TooltipContent>
849
849
  </Tooltip>
850
850
  </TooltipProvider>
851
851
  <TooltipProvider>
@@ -863,7 +863,7 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
863
863
  OpenAI Format
864
864
  </button>
865
865
  </TooltipTrigger>
866
- <TooltipContent>OpenAI Chat Completions API protocol</TooltipContent>
866
+ <TooltipContent>OpenAI Chat Completions API format</TooltipContent>
867
867
  </Tooltip>
868
868
  </TooltipProvider>
869
869
  </div>
@@ -293,6 +293,18 @@ function OnboardingSettingsTab(): JSX.Element {
293
293
  label: "Codex prompt",
294
294
  value: "Use the agent-inspector-onboard skill",
295
295
  },
296
+ {
297
+ id: "opencode-config",
298
+ label: "OpenCode config",
299
+ value: "agent-inspector onboard --opencode-only",
300
+ },
301
+ {
302
+ id: "opencode-status",
303
+ label: "OpenCode status",
304
+ value: "agent-inspector onboard --status --opencode-only",
305
+ },
306
+ { id: "opencode-verify", label: "OpenCode verify", value: "opencode mcp list" },
307
+ { id: "opencode-proxy", label: "OpenCode proxy", value: `LLM_BASE_URL=${origin}/proxy` },
296
308
  { id: "mcp", label: "MCP URL", value: `${origin}/api/mcp` },
297
309
  { id: "proxy", label: "Proxy URL", value: `${origin}/proxy` },
298
310
  { id: "anthropic", label: "Anthropic base", value: `ANTHROPIC_BASE_URL=${origin}/proxy` },
@@ -345,6 +357,24 @@ function OnboardingSettingsTab(): JSX.Element {
345
357
  instead. Configure only one entry for the same Inspector.
346
358
  </span>
347
359
  </div>
360
+ <div className="flex items-start gap-2">
361
+ <Check className="mt-0.5 size-3.5 text-emerald-500" />
362
+ <span>
363
+ OpenCode onboarding safely merges{" "}
364
+ <code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
365
+ mcp.agent-inspector
366
+ </code>{" "}
367
+ into{" "}
368
+ <code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
369
+ opencode.json
370
+ </code>
371
+ , then verify with{" "}
372
+ <code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
373
+ opencode mcp list
374
+ </code>
375
+ .
376
+ </span>
377
+ </div>
348
378
  <div className="flex items-start gap-2">
349
379
  <Check className="mt-0.5 size-3.5 text-emerald-500" />
350
380
  <span>
@@ -29,7 +29,7 @@ import {
29
29
  type KnowledgeCandidate,
30
30
  type KnowledgeCandidateStatus,
31
31
  } from "../../knowledge/types";
32
- import type { CapturedLog } from "../../proxy/schemas";
32
+ import type { CapturedLog } from "../../contracts";
33
33
  import { Badge } from "../ui/badge";
34
34
  import { Button } from "../ui/button";
35
35
  import { buildTraceSummary, extractToolTraceEvents, type TraceSummary } from "./viewerState";
@@ -13,7 +13,7 @@ import {
13
13
  X,
14
14
  } from "lucide-react";
15
15
  import { cn, formatTokens } from "../../lib/utils";
16
- import type { CapturedLog } from "../../proxy/schemas";
16
+ import type { CapturedLog } from "../../contracts";
17
17
  import {
18
18
  type DiffOp,
19
19
  type JsonNode,
@@ -1,7 +1,7 @@
1
1
  import { useState, memo, useCallback, useEffect, useMemo } from "react";
2
2
  import type { JSX } from "react";
3
3
  import type { TimeDisplayFormat } from "../../lib/runtimeConfig";
4
- import type { CapturedLog } from "../../proxy/schemas";
4
+ import type { CapturedLog } from "../../contracts";
5
5
  import {
6
6
  ConversationHeader,
7
7
  getGroupApiFormat,
@@ -1,6 +1,6 @@
1
1
  import { type JSX, useCallback, useEffect, useMemo, useState } from "react";
2
2
  import { useWindowVirtualizer } from "@tanstack/react-virtual";
3
- import type { CapturedLog } from "../../proxy/schemas";
3
+ import type { CapturedLog } from "../../contracts";
4
4
  import { ConversationGroup, type ConversationGroupProps } from "./ConversationGroup";
5
5
  import type { ConversationGroupData } from "./ConversationHeader";
6
6
  import { LOG_FOCUS_REQUEST_EVENT, readLogFocusRequest } from "./logFocus";
@@ -15,7 +15,7 @@ import { getSessionPath } from "../../lib/sessionUrl";
15
15
  import type { TimeDisplayFormat } from "../../lib/runtimeConfig";
16
16
  import { formatTimestampRange } from "../../lib/timeDisplay";
17
17
  import { cn, formatTokens } from "../../lib/utils";
18
- import type { CapturedLog } from "../../proxy/schemas";
18
+ import type { CapturedLog } from "../../contracts";
19
19
  import { Badge } from "../ui/badge";
20
20
  import { ConfirmDialog } from "../ui/confirm-dialog";
21
21
  import { resolveLogFormat } from "./log-formats";
@@ -1,7 +1,7 @@
1
1
  import { GitCompareArrows } from "lucide-react";
2
2
  import { Suspense, type JSX } from "react";
3
3
  import { useEffect, useMemo, useRef, useState, memo } from "react";
4
- import type { CapturedLog } from "../../proxy/schemas";
4
+ import type { CapturedLog } from "../../contracts";
5
5
  import type { TimeDisplayFormat } from "../../lib/runtimeConfig";
6
6
  import { stripClaudeCodeBillingHeader } from "../../proxy/claudeCodeStrip";
7
7
  import { Button } from "../ui/button";
@@ -27,7 +27,7 @@ import { memo } from "react";
27
27
  import type { TimeDisplayFormat } from "../../lib/runtimeConfig";
28
28
  import { formatTimestamp } from "../../lib/timeDisplay";
29
29
  import { cn, formatTokens, getStatusCategory, type StatusCategory } from "../../lib/utils";
30
- import type { CapturedLog } from "../../proxy/schemas";
30
+ import type { CapturedLog } from "../../contracts";
31
31
  import { Badge } from "../ui/badge";
32
32
  import { Button } from "../ui/button";
33
33
  import { ProviderLogo, detectProvider } from "../providers/ProviderLogo";
@@ -8,7 +8,7 @@ import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "../ui/
8
8
  import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog";
9
9
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
10
10
  import { ResponseView } from "./ResponseView";
11
- import { CapturedLogSchema, type CapturedLog } from "../../proxy/schemas";
11
+ import { CapturedLogSchema, type CapturedLog } from "../../contracts";
12
12
  import { dispatchLogFocusRequest } from "./logFocus";
13
13
  import {
14
14
  buildReplayComparisons,
@@ -3,7 +3,7 @@ import type { JSX } from "react";
3
3
  import { memo } from "react";
4
4
  import { useMemo } from "react";
5
5
  import { cn, formatTokens, getStatusCategory, type StatusCategory } from "../../lib/utils";
6
- import type { RequestFormat } from "../../proxy/schemas";
6
+ import type { ApiFormat } from "../../contracts";
7
7
  import { AnswerMarkdown } from "./AnswerMarkdown";
8
8
  import { formatViewFor } from "./formats";
9
9
  import { getLogFormatAdapter } from "./log-formats";
@@ -16,7 +16,7 @@ export type ResponseViewProps = {
16
16
  outputTokens: number | null;
17
17
  cacheCreationInputTokens?: number | null;
18
18
  cacheReadInputTokens?: number | null;
19
- apiFormat?: RequestFormat;
19
+ apiFormat?: ApiFormat;
20
20
  /** SSE error message from streaming response */
21
21
  error?: string | null;
22
22
  };
@@ -3,7 +3,7 @@ import { ChevronDown, ChevronRight, Loader2 } from "lucide-react";
3
3
  import { Badge } from "../ui/badge";
4
4
  import { JsonViewer } from "../ui/json-viewer";
5
5
  import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "../ui/tooltip";
6
- import type { StreamingChunk } from "../../proxy/schemas";
6
+ import type { StreamingChunk } from "../../contracts";
7
7
 
8
8
  export type StreamingChunkSequenceProps = {
9
9
  logId: number;
@@ -3,7 +3,7 @@ import { AlertTriangle, ChevronRight, Clock, Zap } from "lucide-react";
3
3
  import { isTurnBoundary } from "../../lib/stopReason";
4
4
  import type { TimeDisplayFormat } from "../../lib/runtimeConfig";
5
5
  import { cn, formatTokens } from "../../lib/utils";
6
- import type { CapturedLog } from "../../proxy/schemas";
6
+ import type { CapturedLog } from "../../contracts";
7
7
  import { getCrabVariant } from "../ui/crab-variants";
8
8
  import { ProviderLogo, detectProvider, type Provider } from "../providers/ProviderLogo";
9
9
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip";
@@ -1,5 +1,5 @@
1
1
  import type { ProviderConfig } from "../../../lib/providerContract";
2
- import type { CapturedLog } from "../../../proxy/schemas";
2
+ import type { CapturedLog } from "../../../contracts";
3
3
  import { getLogFormatAdapter, resolveLogFormat } from "../log-formats";
4
4
  import {
5
5
  analyzeContextIntelligence,
@@ -1,6 +1,6 @@
1
1
  import { Brain, ChevronDown, ChevronRight, Terminal } from "lucide-react";
2
2
  import { type JSX, memo, useState } from "react";
3
- import type { ResponseContentBlockType } from "../../../../proxy/schemas";
3
+ import type { ResponseContentBlockType } from "../../../../contracts/anthropic";
4
4
  import { AnswerMarkdown } from "../../AnswerMarkdown";
5
5
  import { Badge } from "../../../ui/badge";
6
6
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../../ui/collapsible";
@@ -1,6 +1,6 @@
1
1
  import { StopCircle, Zap } from "lucide-react";
2
2
  import { memo, type JSX } from "react";
3
- import type { InspectorResponse } from "../../../../proxy/schemas";
3
+ import type { AnthropicResponse } from "../../../../contracts/anthropic";
4
4
  import { formatTokens } from "../../../../lib/utils";
5
5
  import { Badge } from "../../../ui/badge";
6
6
  import { Separator } from "../../../ui/separator";
@@ -9,7 +9,7 @@ import { ResponseContentBlockRenderer } from "./ContentBlocks";
9
9
  export const StructuredResponseViewAnthropic = memo(function StructuredResponseViewAnthropic({
10
10
  response,
11
11
  }: {
12
- response: InspectorResponse;
12
+ response: AnthropicResponse;
13
13
  }): JSX.Element {
14
14
  return (
15
15
  <div className="space-y-3">
@@ -1,5 +1,7 @@
1
1
  import type { JSX } from "react";
2
- import type { InspectorResponse, OpenAIResponse, RequestFormat } from "../../../proxy/schemas";
2
+ import type { ApiFormat } from "../../../contracts";
3
+ import type { AnthropicResponse } from "../../../contracts/anthropic";
4
+ import type { OpenAIResponse } from "../../../contracts/openai";
3
5
  import { StructuredResponseViewAnthropic } from "./anthropic/ResponseView";
4
6
  import { OpenAIResponseView } from "./openai/ResponseView";
5
7
 
@@ -15,12 +17,12 @@ function isOpenAIResponse(response: unknown): response is OpenAIResponse {
15
17
  return isRecord(response) && response.object === "chat.completion";
16
18
  }
17
19
 
18
- function isAnthropicResponse(response: unknown): response is InspectorResponse {
20
+ function isAnthropicResponse(response: unknown): response is AnthropicResponse {
19
21
  return isRecord(response) && response.type === "message" && Array.isArray(response.content);
20
22
  }
21
23
 
22
24
  export function formatViewFor(
23
- apiFormat: RequestFormat | undefined,
25
+ apiFormat: ApiFormat | undefined,
24
26
  response: unknown,
25
27
  ): JSX.Element | null {
26
28
  if (apiFormat === "openai" && isOpenAIResponse(response)) {
@@ -1,6 +1,6 @@
1
1
  import { StopCircle, Terminal, Zap } from "lucide-react";
2
2
  import { memo, useState, type JSX } from "react";
3
- import type { OpenAIResponse, OpenAIToolCall } from "../../../../proxy/schemas";
3
+ import type { OpenAIResponse, OpenAIToolCall } from "../../../../contracts/openai";
4
4
  import { formatTokens } from "../../../../lib/utils";
5
5
  import { AnswerMarkdown } from "../../AnswerMarkdown";
6
6
  import { Badge } from "../../../ui/badge";
@@ -1,7 +1,4 @@
1
- import {
2
- AnthropicRequestSchema,
3
- AnthropicResponseSchema,
4
- } from "../../../proxy/formats/anthropic/schemas";
1
+ import { AnthropicRequestSchema, AnthropicResponseSchema } from "../../../contracts/anthropic";
5
2
  import type { AnatomySegment } from "../anatomy/types";
6
3
  import { countCharacters, estimateTokens } from "../anatomy/tokenEstimate";
7
4
  import type { LogFormatAdapter } from "./types";
@@ -1,22 +1,22 @@
1
- import { requestFormatForPath } from "../../../proxy/formats";
2
- import type { CapturedLog, RequestFormat } from "../../../proxy/schemas";
1
+ import { apiFormatForPath } from "../../../proxy/formats";
2
+ import type { ApiFormat, CapturedLog } from "../../../contracts";
3
3
  import { anthropicLogFormatAdapter } from "./anthropic";
4
4
  import { openAILogFormatAdapter } from "./openai";
5
5
  import type { LogFormatAdapter } from "./types";
6
6
  import { unknownLogFormatAdapter } from "./unknown";
7
7
 
8
- const ADAPTERS: Record<RequestFormat, LogFormatAdapter> = {
8
+ const ADAPTERS: Record<ApiFormat, LogFormatAdapter> = {
9
9
  anthropic: anthropicLogFormatAdapter,
10
10
  openai: openAILogFormatAdapter,
11
11
  unknown: unknownLogFormatAdapter,
12
12
  };
13
13
 
14
- export function getLogFormatAdapter(format: RequestFormat): LogFormatAdapter {
14
+ export function getLogFormatAdapter(format: ApiFormat): LogFormatAdapter {
15
15
  return ADAPTERS[format];
16
16
  }
17
17
 
18
- export function resolveLogFormat(log: Pick<CapturedLog, "path" | "apiFormat">): RequestFormat {
19
- const pathFormat = requestFormatForPath(log.path);
18
+ export function resolveLogFormat(log: Pick<CapturedLog, "path" | "apiFormat">): ApiFormat {
19
+ const pathFormat = apiFormatForPath(log.path);
20
20
  return pathFormat === "unknown" ? log.apiFormat : pathFormat;
21
21
  }
22
22
 
@@ -1,4 +1,4 @@
1
- import { OpenAIRequestSchema, parseOpenAIResponse } from "../../../proxy/formats/openai/schemas";
1
+ import { OpenAIRequestSchema, parseOpenAIResponse } from "../../../contracts/openai";
2
2
  import type { AnatomySegment } from "../anatomy/types";
3
3
  import { countCharacters, estimateTokens } from "../anatomy/tokenEstimate";
4
4
  import type { LogFormatAdapter } from "./types";
@@ -1,4 +1,4 @@
1
- import type { RequestFormat } from "../../../proxy/schemas";
1
+ import type { ApiFormat } from "../../../contracts";
2
2
  import type { AnatomySegment } from "../anatomy/types";
3
3
 
4
4
  export type RequestAnalysis = {
@@ -14,7 +14,7 @@ export type ResponseAnalysis = {
14
14
  };
15
15
 
16
16
  export type LogFormatAdapter = {
17
- readonly format: RequestFormat;
17
+ readonly format: ApiFormat;
18
18
  analyzeRequest(rawBody: string | null): RequestAnalysis;
19
19
  analyzeResponse(responseText: string | null): ResponseAnalysis;
20
20
  /**
@@ -1,6 +1,6 @@
1
1
  import { extractStopReason, isTurnBoundary, type StopReason } from "../../lib/stopReason";
2
2
  import { safeGetOwnProperty } from "../../lib/objectUtils";
3
- import type { CapturedLog } from "../../proxy/schemas";
3
+ import type { CapturedLog } from "../../contracts";
4
4
  import { resolveLogFormat } from "./log-formats";
5
5
 
6
6
  export type TurnEntry = {
@@ -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
+ }