Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 37 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,42 +268,43 @@ agentsview stats --include-git-outcomes

agentsview auto-discovers sessions from all of these:

| Agent | Session Directory |
| ------------------ | ------------------------------------------------------ |
| Amp | `~/.local/share/amp/threads/` |
| Antigravity | `~/.gemini/antigravity/` |
| Antigravity CLI | `~/.gemini/antigravity-cli/` (see note below) |
| Claude Code | `~/.claude/projects/` |
| Claude Cowork | `~/Library/Application Support/Claude/local-agent-mode-sessions/` (macOS) |
| Codex | `~/.codex/sessions/` |
| Copilot CLI | `~/.copilot/` |
| Cortex Code | `~/.snowflake/cortex/conversations/` |
| Cursor | `~/.cursor/projects/` |
| DeepSeek TUI | `~/.codewhale/sessions/`, `~/.deepseek/sessions/` |
| Forge | `~/.forge/` |
| Gemini CLI | `~/.gemini/` |
| gptme | `~/.local/share/gptme/logs/` |
| Hermes Agent | `~/.hermes/sessions/` |
| iFlow | `~/.iflow/projects/` |
| Kilo | `~/.local/share/kilo/` |
| Kimi | `~/.kimi/sessions/` |
| Kiro CLI | `~/.kiro/sessions/cli/`, `~/.local/share/kiro-cli/` |
| Kiro IDE | `~/Library/Application Support/Kiro/` (macOS) |
| MiMoCode | `~/.local/share/mimocode/` |
| OpenClaw | `~/.openclaw/agents/` |
| OpenCode | `~/.local/share/opencode/` |
| OpenHands CLI | `~/.openhands/conversations/` |
| Pi | `~/.pi/agent/sessions/` |
| Piebald | `~/.local/share/piebald/` |
| Positron Assistant | `~/Library/Application Support/Positron/User/` (macOS) |
| QClaw | `~/.qclaw/agents/` |
| Qwen Code | `~/.qwen/projects/` |
| QwenPaw | `~/.copaw/workspaces/`, `~/.qwenpaw/workspaces/` |
| VSCode Copilot | `~/Library/Application Support/Code/User/` (macOS) |
| Warp | `~/.warp/` (platform-dependent) |
| WorkBuddy | `~/.workbuddy/projects/` |
| Zed | `~/Library/Application Support/Zed/` (macOS) |
| Zencoder | `~/.zencoder/sessions/` |
| Agent | Session Directory |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Amp | `~/.local/share/amp/threads/` |
| Antigravity | `~/.gemini/antigravity/` |
| Antigravity CLI | `~/.gemini/antigravity-cli/` (see note below) |
| Claude Code | `~/.claude/projects/` |
| Claude Cowork | `~/Library/Application Support/Claude/local-agent-mode-sessions/` (macOS) |
| Codex | `~/.codex/sessions/` |
| Copilot CLI | `~/.copilot/` |
| Cortex Code | `~/.snowflake/cortex/conversations/` |
| Cursor | `~/.cursor/projects/` |
| DeepSeek TUI | `~/.codewhale/sessions/`, `~/.deepseek/sessions/` |
| Forge | `~/.forge/` |
| Gemini CLI | `~/.gemini/` |
| gptme | `~/.local/share/gptme/logs/` |
| Hermes Agent | `~/.hermes/sessions/` |
| iFlow | `~/.iflow/projects/` |
| Kilo | `~/.local/share/kilo/` |
| Kimi | `~/.kimi/sessions/` |
| Kiro CLI | `~/.kiro/sessions/cli/`, `~/.local/share/kiro-cli/` |
| Kiro IDE | `~/Library/Application Support/Kiro/` (macOS) |
| MiMoCode | `~/.local/share/mimocode/` |
| OpenClaw | `~/.openclaw/agents/` |
| OpenCode | `~/.local/share/opencode/` |
| OpenHands CLI | `~/.openhands/conversations/` |
| Pi | `~/.pi/agent/sessions/` |
| Piebald | `~/.local/share/piebald/` |
| Positron Assistant | `~/Library/Application Support/Positron/User/` (macOS) |
| QClaw | `~/.qclaw/agents/` |
| Qwen Code | `~/.qwen/projects/` |
| QwenPaw | `~/.copaw/workspaces/`, `~/.qwenpaw/workspaces/` |
| VSCode Copilot | `~/Library/Application Support/Code/User/` (macOS) |
| Visual Studio Copilot | `%LOCALAPPDATA%\\Temp\\VSGitHubCopilotLogs\\traces\\` (Windows), `~/Library/Caches/VSGitHubCopilotLogs/traces/` (macOS), `~/.cache/VSGitHubCopilotLogs/traces/` (Linux) |
| Warp | `~/.warp/` (platform-dependent) |
| WorkBuddy | `~/.workbuddy/projects/` |
| Zed | `~/Library/Application Support/Zed/` (macOS) |
| Zencoder | `~/.zencoder/sessions/` |

Each directory can be overridden with an environment variable. See the
[configuration docs](https://agentsview.io/configuration/) for details.
Expand Down
22 changes: 20 additions & 2 deletions cmd/agentsview/session_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
package main

import (
"errors"
"fmt"
"io"
"os"

"github.com/spf13/cobra"
"go.kenn.io/agentsview/internal/config"
"go.kenn.io/agentsview/internal/db"
"go.kenn.io/agentsview/internal/parser"
)

func newSessionExportCommand() *cobra.Command {
Expand Down Expand Up @@ -55,12 +57,28 @@ func newSessionExportCommand() *cobra.Command {
"session not in local archive: %s", args[0],
)
}
path := d.GetSessionFilePath(id)
if path == "" {
storedPath := d.GetSessionFilePath(id)
if storedPath == "" {
return fmt.Errorf(
"source file not found for session %s", id,
)
}
// A Visual Studio Copilot trace file holds spans for several
// conversations, so streaming the whole file would disclose
// unrelated conversations. Filter to the requested conversation.
if tracePath, conversationID, ok :=
parser.ParseVisualStudioCopilotVirtualPath(storedPath); ok {
err := parser.WriteVisualStudioCopilotConversationJSONL(
cmd.OutOrStdout(), tracePath, conversationID,
)
if errors.Is(err, os.ErrNotExist) {
return fmt.Errorf(
"source file not found: %s", tracePath,
)
}
return err
}
path := parser.ResolveSourceFilePath(storedPath)
f, err := os.Open(path)
if err != nil {
if os.IsNotExist(err) {
Expand Down
184 changes: 184 additions & 0 deletions docs/visualstudio-copilot-traces.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# Visual Studio Copilot Trace Format

Visual Studio Copilot trace data is not the same format as VS Code Copilot chat
sessions.

VS Code Copilot stores app-level chat session documents. Visual Studio Copilot
stores OpenTelemetry-style trace JSONL, where each JSONL line is a trace
envelope containing spans.

## VS Code Copilot Format

VS Code Copilot session files are usually found under paths like:

```text
workspaceStorage/<hash>/chatSessions/<uuid>.json
workspaceStorage/<hash>/chatSessions/<uuid>.jsonl
globalStorage/emptyWindowChatSessions/<uuid>.json
globalStorage/transferredChatSessions/<uuid>.json
```

The top-level shape is a chat session object:

- Session ID is usually `sessionId`.
- Turns are stored in `requests[]`.
- User prompts are stored in `requests[].message.text`.
- Assistant and tool output are stored in `requests[].response[]`.
- One file generally represents one chat session.

Sanitized shape:

```json
{
"version": 3,
"sessionId": "<uuid>",
"creationDate": 1781293600000,
"lastMessageDate": 1781293610000,
"requests": [
{
"requestId": "<uuid>",
"message": {
"text": "<user prompt>"
},
"response": [
{
"kind": "textEditGroup",
"value": "<assistant-or-tool-output>"
}
],
"modelId": "<model>",
"timestamp": 1781293600000
}
]
}
```

## Visual Studio Copilot Format

Visual Studio Copilot trace files are usually found under:

```text
%LOCALAPPDATA%\Temp\VSGitHubCopilotLogs\traces\*_VSGitHubCopilot_traces.jsonl
```

Each line is an OpenTelemetry JSON envelope:

- `resourceSpans[]`
- `scopeSpans[]`
- `spans[]`
- `attributes[]`

Session data is reconstructed from span attributes:

- Conversation ID is `gen_ai.conversation.id`.
- Chat input is `gen_ai.input.messages`.
- Chat output is `gen_ai.output.messages`.
- Tool calls use `gen_ai.tool.name`, `gen_ai.tool.call.id`, and
`gen_ai.tool.call.arguments`.
- Tool results use `gen_ai.tool.call.result`.
- Token usage uses `gen_ai.usage.input_tokens` and `gen_ai.usage.output_tokens`.
- Multiple trace files can contain spans for the same conversation, so the
parser stitches them together by `gen_ai.conversation.id`.

## Sanitized Visual Studio Examples

These examples preserve the structure of real Visual Studio Copilot trace JSONL
spans while redacting prompts, paths, commands, patches, IDs, and results.

### Chat Span

```json
{
"sourceFile": "20260615T234102_b45c44b2_VSGitHubCopilot_traces.jsonl",
"traceId": "<trace-id>",
"spanId": "<span-id>",
"name": "chat gpt-5.5",
"startTimeUnixNano": "<unix-nano>",
"endTimeUnixNano": "<unix-nano>",
"attributes": {
"virtual_parent.genai": "905ec1a433bff543",
"gen_ai.provider.name": "github",
"gen_ai.request.model": "<model>",
"gen_ai.response.model": "<model>",
"gen_ai.response.id": "<redacted>",
"gen_ai.response.finish_reasons": "",
"gen_ai.usage.input_tokens": "94179",
"gen_ai.usage.output_tokens": "218",
"gen_ai.conversation.id": "<uuid-or-call-id>",
"copilot_chat.client_id": "Microsoft.VisualStudio.Conversations.Chat.HelpWindow",
"copilot_chat.root_request_id": "<uuid-or-call-id>",
"server.address": "api.githubcopilot.com",
"gen_ai.tool.definitions": "<redacted>",
"gen_ai.input.messages": "[{\"role\":\"user\",\"parts\":[{\"type\":\"text\",\"content\":\"<user prompt>\"}]}]",
"gen_ai.output.messages": "[{\"role\":\"assistant\",\"parts\":[{\"type\":\"tool_call\",\"id\":\"<call-id>\",\"name\":\"<tool-name>\",\"arguments\":\"<json-encoded-arguments>\"},{\"type\":\"text\",\"content\":\"<assistant text>\"}]}]",
"gen_ai.operation.name": "chat"
}
}
```

### Tool Execution Span

```json
{
"sourceFile": "20260615T234059_b45c44b2_VSGitHubCopilot_traces.jsonl",
"traceId": "<trace-id>",
"spanId": "<span-id>",
"name": "execute_tool get_file",
"startTimeUnixNano": "<unix-nano>",
"endTimeUnixNano": "<unix-nano>",
"attributes": {
"virtual_parent.genai": "26401e75c1171a63",
"gen_ai.conversation.id": "<uuid-or-call-id>",
"gen_ai.tool.call.result": "{\"Value\":\"<tool result>\"}",
"gen_ai.provider.name": "other",
"gen_ai.tool.name": "get_file",
"gen_ai.tool.call.id": "<uuid-or-call-id>",
"gen_ai.tool.type": "extension",
"gen_ai.tool.description": "<redacted>",
"gen_ai.tool.call.arguments": "{\"filename\":\"<path>\",\"command\":\"<command>\",\"patch\":\"<patch>\"}",
"gen_ai.operation.name": "execute_tool"
}
}
```

### Invoke-Agent Span

```json
{
"sourceFile": "20260615T234059_b45c44b2_VSGitHubCopilot_traces.jsonl",
"traceId": "<trace-id>",
"spanId": "<span-id>",
"name": "invoke_agent GitHub Copilot",
"startTimeUnixNano": "<unix-nano>",
"endTimeUnixNano": "<unix-nano>",
"attributes": {
"gen_ai.provider.name": "other",
"gen_ai.agent.name": "GitHub Copilot",
"gen_ai.conversation.id": "<uuid-or-call-id>",
"gen_ai.request.model": "<model>",
"copilot_chat.turn_count": "1",
"copilot_chat.client_id": "Microsoft.VisualStudio.Conversations.Chat.HelpWindow",
"copilot_chat.entry_point": "Microsoft.VisualStudio.Copilot.AgentModeResponder",
"copilot_chat.mode": "Agent",
"copilot_chat.initiator_type": "User",
"copilot_chat.root_request_id": "<uuid-or-call-id>",
"gen_ai.operation.name": "invoke_agent"
}
}
```

## Parser Implications

The Visual Studio parser treats the trace data as telemetry that must be
reconstructed into a transcript:

- It groups spans by `gen_ai.conversation.id`.
- It reads user turns from the stringified `gen_ai.input.messages` payload.
- It reads assistant text and tool-call proposals from the stringified
`gen_ai.output.messages` payload.
- It reads executed tool calls and tool results from separate `execute_tool`
spans.
- It de-duplicates repeated prompt snapshots and duplicate chat/execute tool
records for the same tool call ID.
- It stitches sibling trace files because a single conversation can be split
across multiple `*_VSGitHubCopilot_traces.jsonl` files.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
iflow: "iFlow",
"vscode-copilot": "VSCode Copilot",
pi: "Pi",
"visualstudio-copilot": "Visual Studio Copilot",
qwen: "Qwen Code",
openclaw: "OpenClaw",
qclaw: "QClaw",
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/lib/utils/agents.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ describe("KNOWN_AGENTS", () => {
"zencoder",
"zed",
"vscode-copilot",
"visualstudio-copilot",
"pi",
"qwen",
"qwenpaw",
Expand Down Expand Up @@ -95,6 +96,9 @@ describe("agentColor", () => {
expect(agentColor("vscode-copilot")).toBe(
"var(--accent-teal)",
);
expect(agentColor("visualstudio-copilot")).toBe(
"var(--accent-blue)",
);
expect(agentColor("qclaw")).toBe(
"var(--accent-orange)",
);
Expand All @@ -119,6 +123,9 @@ describe("agentLabel", () => {
expect(agentLabel("vscode-copilot")).toBe(
"VS Code Copilot",
);
expect(agentLabel("visualstudio-copilot")).toBe(
"Visual Studio Copilot",
);
expect(agentLabel("openhands")).toBe("OpenHands");
expect(agentLabel("openclaw")).toBe("OpenClaw");
expect(agentLabel("qclaw")).toBe("QClaw");
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/lib/utils/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export const KNOWN_AGENTS: readonly AgentMeta[] = [
color: "var(--accent-teal)",
label: "VS Code Copilot",
},
{
name: "visualstudio-copilot",
color: "var(--accent-blue)",
label: "Visual Studio Copilot",
},
{ name: "pi", color: "var(--accent-indigo)", label: "Pi" },
{ name: "qwen", color: "var(--accent-cyan)", label: "Qwen Code" },
{ name: "qwenpaw", color: "var(--accent-cyan)", label: "QwenPaw" },
Expand Down
7 changes: 6 additions & 1 deletion internal/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ import (
// trigger a non-destructive re-sync (mtime reset + skip cache
// clear) so existing session data is preserved.
//
// Bumped to 47: the Visual Studio Copilot trace parser now
// persists per-chat model and token usage from gen_ai.usage
// attributes. Existing Visual Studio Copilot rows need re-parsing
// so Usage reports include those sessions.
//
// Bumped to 45: the Codex parser now imports renamed session
// titles from session_index.jsonl. Existing Codex rows need
// re-parsing so their titles reflect later renames.
Expand Down Expand Up @@ -219,7 +224,7 @@ import (
//
// (17: Codex <skill> template filtering.)
// (16: <turn_aborted> system messages.)
const dataVersion = 46
const dataVersion = 47

const tokenCoverageRepairStatsKey = "token_coverage_repair_v1"

Expand Down
Loading