@townco/debugger 0.1.3 → 0.1.5
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@townco/debugger",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"bun": ">=1.3.0"
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"check": "tsc --noEmit"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@townco/otlp-server": "0.1.
|
|
17
|
+
"@townco/otlp-server": "0.1.5",
|
|
18
18
|
"@radix-ui/react-label": "^2.1.7",
|
|
19
19
|
"@radix-ui/react-select": "^2.2.6",
|
|
20
20
|
"@radix-ui/react-slot": "^1.2.3",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"tailwind-merge": "^3.3.1"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@townco/tsconfig": "0.1.
|
|
30
|
+
"@townco/tsconfig": "0.1.47",
|
|
31
31
|
"@types/bun": "latest",
|
|
32
32
|
"@types/react": "^19",
|
|
33
33
|
"@types/react-dom": "^19",
|
|
@@ -1,14 +1,34 @@
|
|
|
1
1
|
interface AttributeViewerProps {
|
|
2
2
|
label: string;
|
|
3
3
|
data: string | null;
|
|
4
|
+
excludeKeys?: string[];
|
|
4
5
|
}
|
|
5
6
|
|
|
6
|
-
export function AttributeViewer({
|
|
7
|
+
export function AttributeViewer({
|
|
8
|
+
label,
|
|
9
|
+
data,
|
|
10
|
+
excludeKeys = [],
|
|
11
|
+
}: AttributeViewerProps) {
|
|
7
12
|
if (!data || data === "{}" || data === "[]") return null;
|
|
8
13
|
|
|
9
14
|
let parsed: unknown;
|
|
10
15
|
try {
|
|
11
16
|
parsed = JSON.parse(data);
|
|
17
|
+
|
|
18
|
+
// Filter out excluded keys
|
|
19
|
+
if (
|
|
20
|
+
excludeKeys.length > 0 &&
|
|
21
|
+
typeof parsed === "object" &&
|
|
22
|
+
parsed !== null
|
|
23
|
+
) {
|
|
24
|
+
const filtered = { ...parsed } as Record<string, unknown>;
|
|
25
|
+
for (const key of excludeKeys) {
|
|
26
|
+
delete filtered[key];
|
|
27
|
+
}
|
|
28
|
+
// Return null if no keys left after filtering
|
|
29
|
+
if (Object.keys(filtered).length === 0) return null;
|
|
30
|
+
parsed = filtered;
|
|
31
|
+
}
|
|
12
32
|
} catch {
|
|
13
33
|
parsed = data;
|
|
14
34
|
}
|
|
@@ -2,6 +2,31 @@ import { useState } from "react";
|
|
|
2
2
|
import type { Log } from "../types";
|
|
3
3
|
import { AttributeViewer } from "./AttributeViewer";
|
|
4
4
|
|
|
5
|
+
function LogMetadataViewer({ attributes }: { attributes: string | null }) {
|
|
6
|
+
if (!attributes) return null;
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
const parsed = JSON.parse(attributes);
|
|
10
|
+
const metadataStr = parsed["log.metadata"];
|
|
11
|
+
if (!metadataStr) return null;
|
|
12
|
+
|
|
13
|
+
const metadata = JSON.parse(metadataStr);
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div className="mb-2">
|
|
17
|
+
<div className="text-xs text-muted-foreground uppercase font-medium">
|
|
18
|
+
Metadata
|
|
19
|
+
</div>
|
|
20
|
+
<pre className="text-xs bg-muted p-2 rounded overflow-x-auto whitespace-pre-wrap">
|
|
21
|
+
{JSON.stringify(metadata, null, 2)}
|
|
22
|
+
</pre>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
5
30
|
function getSeverityColor(severityNumber: number): string {
|
|
6
31
|
if (severityNumber >= 17) return "text-red-500"; // ERROR/FATAL
|
|
7
32
|
if (severityNumber >= 13) return "text-yellow-500"; // WARN
|
|
@@ -40,7 +65,12 @@ function LogRow({ log }: { log: Log }) {
|
|
|
40
65
|
{expanded && (
|
|
41
66
|
<div className="py-2 px-4 bg-muted/50 rounded mb-1 ml-14">
|
|
42
67
|
<AttributeViewer label="Body" data={log.body} />
|
|
43
|
-
<
|
|
68
|
+
<LogMetadataViewer attributes={log.attributes} />
|
|
69
|
+
<AttributeViewer
|
|
70
|
+
label="Attributes"
|
|
71
|
+
data={log.attributes}
|
|
72
|
+
excludeKeys={["log.metadata"]}
|
|
73
|
+
/>
|
|
44
74
|
<AttributeViewer label="Resource" data={log.resource_attributes} />
|
|
45
75
|
{log.span_id && (
|
|
46
76
|
<div className="text-xs text-muted-foreground">
|
|
@@ -57,9 +57,28 @@ function SpanRow({ span }: { span: SpanNode }) {
|
|
|
57
57
|
span.name.startsWith("chat") && "gen_ai.input.messages" in attrs;
|
|
58
58
|
const isSpecialSpan = isToolCall || isChatSpan;
|
|
59
59
|
|
|
60
|
+
// Helper to get display name for tool calls (with special handling for Task/subagent)
|
|
61
|
+
const getToolDisplayName = (): string => {
|
|
62
|
+
const toolName = attrs["tool.name"] as string;
|
|
63
|
+
if (toolName !== "Task") return toolName || span.name;
|
|
64
|
+
|
|
65
|
+
// Parse tool.input to extract agentName for subagent spans
|
|
66
|
+
try {
|
|
67
|
+
const toolInput = attrs["tool.input"];
|
|
68
|
+
const input =
|
|
69
|
+
typeof toolInput === "string" ? JSON.parse(toolInput) : toolInput;
|
|
70
|
+
if (input?.agentName) {
|
|
71
|
+
return `Subagent (${input.agentName})`;
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
// Fall back to "Task" if parsing fails
|
|
75
|
+
}
|
|
76
|
+
return toolName || span.name;
|
|
77
|
+
};
|
|
78
|
+
|
|
60
79
|
// Get display name based on span type
|
|
61
80
|
const displayName = isToolCall
|
|
62
|
-
? (
|
|
81
|
+
? getToolDisplayName()
|
|
63
82
|
: isChatSpan
|
|
64
83
|
? (attrs["gen_ai.request.model"] as string) || span.name
|
|
65
84
|
: span.name;
|