agent-dump 1.2.2__tar.gz → 1.2.4__tar.gz
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.
- {agent_dump-1.2.2 → agent_dump-1.2.4}/Cargo.lock +7 -7
- {agent_dump-1.2.2 → agent_dump-1.2.4}/Cargo.toml +1 -1
- {agent_dump-1.2.2 → agent_dump-1.2.4}/PKG-INFO +21 -3
- {agent_dump-1.2.2 → agent_dump-1.2.4}/README.md +20 -2
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/compat/json/diagnostic.rs +22 -3
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/compat/json.rs +12 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/config.rs +14 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/output/export.rs +9 -38
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/claude/mod.rs +19 -20
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/claude/transcript.rs +5 -1
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/codex/enrichment.rs +4 -1
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/codex/mod.rs +10 -4
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/codex/transcript.rs +11 -3
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/contract.rs +1 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/cursor/mod.rs +5 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/desktop/mod.rs +4 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/desktop/tests.rs +33 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/files.rs +64 -22
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/jsonl.rs +60 -15
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/kimi/mod.rs +10 -4
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/kimi/transcript.rs +13 -1
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/kimi/wire.rs +17 -14
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/pi/mod.rs +10 -4
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/registry.rs +21 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/sqlite/mod.rs +43 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/query/filter.rs +10 -6
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/query/index/tests.rs +17 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/query/index.rs +33 -18
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/query/scanner.rs +5 -4
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/session/cache/tests.rs +5 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/pyproject.toml +1 -1
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/locales/en.json +1 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/locales/zh.json +1 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/insight-handoff.txt +1 -1
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/pm-handoff.txt +1 -1
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/collect/llm.rs +111 -29
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/workflows/collect.rs +9 -20
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/workflows/config.rs +3 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/workflows/interactive.rs +23 -20
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/workflows/list.rs +19 -27
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/workflows/machine.rs +17 -29
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/workflows/maintenance.rs +13 -8
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/workflows/reader.rs +1 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/workflows/uri.rs +3 -4
- {agent_dump-1.2.2 → agent_dump-1.2.4}/LICENSE +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/Cargo.toml +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/compat/json/encoding.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/compat/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/compat/value.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/lib.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/output/diagnostics.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/output/formats.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/output/i18n.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/output/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/output/render.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/parallel.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/codex/patch.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/cursor/transcript.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/desktop/cherry.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/desktop/deepchat.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/desktop/minimax.rs +6 -6
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/error.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/pi/transcript.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/source_tests.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/sqlite/connection.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/sqlite/legacy.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/sqlite/v2.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/title.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/query/context.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/query/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/query/read.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/query/text.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/query/transcript.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/session/assembly.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/session/cache.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/session/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/session/timestamp.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/storage/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/storage/private_files.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/storage/source_io.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/.gitattributes +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/README.md +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/insight-chunk.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/insight-merge.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/insight-report.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/insight-retry.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/pm-chunk.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/pm-merge.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/pm-report.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/pm-retry.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/read-session-en.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/read-session-zh.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/system.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/resources/prompts/uri.txt +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/rust-toolchain.toml +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/rustfmt.toml +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/cli_args.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/collect/events.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/collect/handoff.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/collect/log.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/collect/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/collect/model.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/collect/progress.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/collect/prompts.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/collect/reduction.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/collect/sessions.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/collect/summary.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/command.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/date_input.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/main.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/shortcut.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/terminal/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/terminal/reader.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/terminal/selector.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/terminal/tui.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/workflows/mod.rs +0 -0
- {agent_dump-1.2.2 → agent_dump-1.2.4}/src/workflows/read.rs +0 -0
|
@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
|
|
10
10
|
|
|
11
11
|
[[package]]
|
|
12
12
|
name = "agent-dump"
|
|
13
|
-
version = "1.2.
|
|
13
|
+
version = "1.2.4"
|
|
14
14
|
dependencies = [
|
|
15
15
|
"agent-dump-core",
|
|
16
16
|
"caseless",
|
|
@@ -837,9 +837,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
|
837
837
|
|
|
838
838
|
[[package]]
|
|
839
839
|
name = "jiff"
|
|
840
|
-
version = "0.2.
|
|
840
|
+
version = "0.2.38"
|
|
841
841
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
842
|
-
checksum = "
|
|
842
|
+
checksum = "b2b005715dcbeb0089a3c0dab99f2ff1cc3b2525323552703d648585d342a383"
|
|
843
843
|
dependencies = [
|
|
844
844
|
"defmt",
|
|
845
845
|
"jiff-core",
|
|
@@ -864,9 +864,9 @@ dependencies = [
|
|
|
864
864
|
|
|
865
865
|
[[package]]
|
|
866
866
|
name = "jiff-static"
|
|
867
|
-
version = "0.2.
|
|
867
|
+
version = "0.2.38"
|
|
868
868
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
869
|
-
checksum = "
|
|
869
|
+
checksum = "2cc9817253cf7c7ee4684451bd327e88d6f3658014e54a29198625590650695c"
|
|
870
870
|
dependencies = [
|
|
871
871
|
"jiff-core",
|
|
872
872
|
"proc-macro2",
|
|
@@ -1859,9 +1859,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|
|
1859
1859
|
|
|
1860
1860
|
[[package]]
|
|
1861
1861
|
name = "uuid"
|
|
1862
|
-
version = "1.
|
|
1862
|
+
version = "1.28.0"
|
|
1863
1863
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1864
|
-
checksum = "
|
|
1864
|
+
checksum = "7cc1186384beb7dd8eedea376413fd654937285ea6c9cfbb928dc3043ea4b606"
|
|
1865
1865
|
dependencies = [
|
|
1866
1866
|
"getrandom 0.4.3",
|
|
1867
1867
|
"js-sys",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-dump
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.4
|
|
4
4
|
Classifier: Environment :: Console
|
|
5
5
|
Classifier: License :: OSI Approved :: MIT License
|
|
6
6
|
Classifier: Programming Language :: Rust
|
|
@@ -462,7 +462,7 @@ File discovery failures include partially unreadable providers. Valid sessions r
|
|
|
462
462
|
|
|
463
463
|
When some session reads or summaries fail, collection continues with successful sessions. The saved Markdown includes a fixed incomplete-report notice with failure and included-session counts; an entirely failed run still fails.
|
|
464
464
|
|
|
465
|
-
Collect discovers candidate sessions without a creation-time cutoff and processes user/assistant visible text only within the requested local dates. A session spanning several days is split into separate daily units before summarization; session counts remain unique URI counts. Text without a reliable timestamp (including undated Kimi context and inferred Cursor times) belongs to no date and is excluded without being reported as a coverage gap. No session creation/update time is substituted. Query filters select candidates; limits apply to unique sessions after text-date filtering. Events, including long individual messages, are split into chunks of at most 3,200 Unicode characters including labels. Chunk summaries are merged in groups of at most eight; large final reports are rendered in separate source-preserving groups. Model inputs are limited to 64,000 characters per request. Oversized metadata or derived summaries fail explicitly; source text is never silently truncated. Partial reports list omitted session URIs. Full input coverage does not mean a summary preserves every detail.
|
|
465
|
+
Collect discovers candidate sessions without a creation-time cutoff and processes user/assistant visible text only within the requested local dates. A session spanning several days is split into separate daily units before summarization; session counts remain unique URI counts. Text without a reliable timestamp (including undated Kimi context and inferred Cursor times) belongs to no date and is excluded without being reported as a coverage gap. No session creation/update time is substituted. Query filters select candidates; limits apply to unique sessions after text-date filtering. Events, including long individual messages, are split into chunks of at most 3,200 Unicode characters including labels. Chunk summaries are merged in groups of at most eight; large final reports are rendered in separate source-preserving groups. Model inputs are limited to 64,000 characters per request. Oversized metadata or derived summaries fail explicitly; source text is never silently truncated. A final report or `--summary` reply that stops at the model output token limit is treated as a failed request, not saved as complete. Partial reports list omitted session URIs. Full input coverage does not mean a summary preserves every detail.
|
|
466
466
|
|
|
467
467
|
PM summaries merge sessions only within the same date and known working directory. Sessions without a working directory retain separate attribution.
|
|
468
468
|
|
|
@@ -479,6 +479,7 @@ provider = "openai" # openai | anthropic
|
|
|
479
479
|
base_url = "https://api.openai.com/v1"
|
|
480
480
|
model = "gpt-4.1-mini"
|
|
481
481
|
api_key = "sk-..."
|
|
482
|
+
reasoning = "off" # off | default
|
|
482
483
|
|
|
483
484
|
[collect]
|
|
484
485
|
summary_concurrency = 4 # 1-32
|
|
@@ -501,6 +502,23 @@ deny = [
|
|
|
501
502
|
]
|
|
502
503
|
```
|
|
503
504
|
|
|
505
|
+
`[ai].reasoning` controls the model's thinking mode. `off` (the default) sends `enable_thinking: false` to OpenAI-compatible services and `thinking: {type: "disabled"}` to Anthropic. `default` sends neither and leaves the service default in place. Enabling reasoning or choosing an effort level uses vendor-specific parameters, so set them in `[ai.extra_body]`. The table is deep-merged into every request body: nested tables merge, other values replace.
|
|
506
|
+
|
|
507
|
+
```toml
|
|
508
|
+
# OpenAI reasoning models
|
|
509
|
+
[ai.extra_body]
|
|
510
|
+
reasoning_effort = "low"
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
```toml
|
|
514
|
+
# Anthropic extended thinking; max_tokens must exceed budget_tokens
|
|
515
|
+
[ai.extra_body]
|
|
516
|
+
max_tokens = 8192
|
|
517
|
+
thinking = { type = "enabled", budget_tokens = 2048 }
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
When an OpenAI-compatible service rejects the default `enable_thinking`, `temperature`, or `max_tokens`, agent-dump retries without it; `max_tokens` is renamed to `max_completion_tokens`. Parameters set in `extra_body` are never removed. `--config edit` does not prompt for `reasoning` or `extra_body` and keeps their values.
|
|
521
|
+
|
|
504
522
|
`[agent.<name>].deny` only applies to `--collect`. When a session `cwd` matches one of the configured paths, or is inside that path, the session is ignored during collect.
|
|
505
523
|
|
|
506
524
|
Collect, `--collect --dry-run`, and `--collect --emit-prompt` require valid TOML and exclusion arrays containing only nonempty path strings. Invalid configuration stops the command before session discovery or AI requests; compatibility parsing never disables exclusions for collect.
|
|
@@ -559,7 +577,7 @@ Pass `locations[].locator` from search unchanged to `--message`. Positions are o
|
|
|
559
577
|
|
|
560
578
|
`--locate` requires `--search`. It returns messages containing any search term, respecting role filters, while all terms must still match the session. Title-only matches have empty locations; failed location reads have null locations and partial status. Search without --locate is unchanged.
|
|
561
579
|
|
|
562
|
-
`--message` cannot combine with `--head` or `--summary`. Without `--format`, it prints context; `--json` writes a context envelope to stdout with kind=context and data containing uri, locator, total_messages, start/end and messages (position plus normalized message). Invalid or stale locators exit nonzero; JSON diagnostics go only to stderr.
|
|
580
|
+
`--message` cannot combine with `--head` or `--summary`. Without `--format`, it prints context; `--json` writes a context envelope to stdout with kind=context, status (partial when recoverable source diagnostics occur) and data containing uri, locator, total_messages, start/end and messages (position plus normalized message). Invalid or stale locators exit nonzero; JSON diagnostics go only to stderr.
|
|
563
581
|
|
|
564
582
|
Use `--format json,markdown` to export the selected context. Files are named `<id>.messages-<start>-<end>.json` / `.md` under the Provider's output directory, separate from full-session exports. Both formats retain the canonical Session URI, the locator (revision plus target position), the absolute message range, and status. JSON retains normalized message records; Markdown renders their searchable text. Recoverable source diagnostics mark the file `partial` and are reported on stderr. Stale locators are rejected before file creation. Provider format restrictions still apply; raw/print file formats and `--json` with file-export options are rejected. `--output` requires an explicit `--format`; output-directory defaults follow full-session export rules.
|
|
565
583
|
|
|
@@ -438,7 +438,7 @@ File discovery failures include partially unreadable providers. Valid sessions r
|
|
|
438
438
|
|
|
439
439
|
When some session reads or summaries fail, collection continues with successful sessions. The saved Markdown includes a fixed incomplete-report notice with failure and included-session counts; an entirely failed run still fails.
|
|
440
440
|
|
|
441
|
-
Collect discovers candidate sessions without a creation-time cutoff and processes user/assistant visible text only within the requested local dates. A session spanning several days is split into separate daily units before summarization; session counts remain unique URI counts. Text without a reliable timestamp (including undated Kimi context and inferred Cursor times) belongs to no date and is excluded without being reported as a coverage gap. No session creation/update time is substituted. Query filters select candidates; limits apply to unique sessions after text-date filtering. Events, including long individual messages, are split into chunks of at most 3,200 Unicode characters including labels. Chunk summaries are merged in groups of at most eight; large final reports are rendered in separate source-preserving groups. Model inputs are limited to 64,000 characters per request. Oversized metadata or derived summaries fail explicitly; source text is never silently truncated. Partial reports list omitted session URIs. Full input coverage does not mean a summary preserves every detail.
|
|
441
|
+
Collect discovers candidate sessions without a creation-time cutoff and processes user/assistant visible text only within the requested local dates. A session spanning several days is split into separate daily units before summarization; session counts remain unique URI counts. Text without a reliable timestamp (including undated Kimi context and inferred Cursor times) belongs to no date and is excluded without being reported as a coverage gap. No session creation/update time is substituted. Query filters select candidates; limits apply to unique sessions after text-date filtering. Events, including long individual messages, are split into chunks of at most 3,200 Unicode characters including labels. Chunk summaries are merged in groups of at most eight; large final reports are rendered in separate source-preserving groups. Model inputs are limited to 64,000 characters per request. Oversized metadata or derived summaries fail explicitly; source text is never silently truncated. A final report or `--summary` reply that stops at the model output token limit is treated as a failed request, not saved as complete. Partial reports list omitted session URIs. Full input coverage does not mean a summary preserves every detail.
|
|
442
442
|
|
|
443
443
|
PM summaries merge sessions only within the same date and known working directory. Sessions without a working directory retain separate attribution.
|
|
444
444
|
|
|
@@ -455,6 +455,7 @@ provider = "openai" # openai | anthropic
|
|
|
455
455
|
base_url = "https://api.openai.com/v1"
|
|
456
456
|
model = "gpt-4.1-mini"
|
|
457
457
|
api_key = "sk-..."
|
|
458
|
+
reasoning = "off" # off | default
|
|
458
459
|
|
|
459
460
|
[collect]
|
|
460
461
|
summary_concurrency = 4 # 1-32
|
|
@@ -477,6 +478,23 @@ deny = [
|
|
|
477
478
|
]
|
|
478
479
|
```
|
|
479
480
|
|
|
481
|
+
`[ai].reasoning` controls the model's thinking mode. `off` (the default) sends `enable_thinking: false` to OpenAI-compatible services and `thinking: {type: "disabled"}` to Anthropic. `default` sends neither and leaves the service default in place. Enabling reasoning or choosing an effort level uses vendor-specific parameters, so set them in `[ai.extra_body]`. The table is deep-merged into every request body: nested tables merge, other values replace.
|
|
482
|
+
|
|
483
|
+
```toml
|
|
484
|
+
# OpenAI reasoning models
|
|
485
|
+
[ai.extra_body]
|
|
486
|
+
reasoning_effort = "low"
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
```toml
|
|
490
|
+
# Anthropic extended thinking; max_tokens must exceed budget_tokens
|
|
491
|
+
[ai.extra_body]
|
|
492
|
+
max_tokens = 8192
|
|
493
|
+
thinking = { type = "enabled", budget_tokens = 2048 }
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
When an OpenAI-compatible service rejects the default `enable_thinking`, `temperature`, or `max_tokens`, agent-dump retries without it; `max_tokens` is renamed to `max_completion_tokens`. Parameters set in `extra_body` are never removed. `--config edit` does not prompt for `reasoning` or `extra_body` and keeps their values.
|
|
497
|
+
|
|
480
498
|
`[agent.<name>].deny` only applies to `--collect`. When a session `cwd` matches one of the configured paths, or is inside that path, the session is ignored during collect.
|
|
481
499
|
|
|
482
500
|
Collect, `--collect --dry-run`, and `--collect --emit-prompt` require valid TOML and exclusion arrays containing only nonempty path strings. Invalid configuration stops the command before session discovery or AI requests; compatibility parsing never disables exclusions for collect.
|
|
@@ -535,7 +553,7 @@ Pass `locations[].locator` from search unchanged to `--message`. Positions are o
|
|
|
535
553
|
|
|
536
554
|
`--locate` requires `--search`. It returns messages containing any search term, respecting role filters, while all terms must still match the session. Title-only matches have empty locations; failed location reads have null locations and partial status. Search without --locate is unchanged.
|
|
537
555
|
|
|
538
|
-
`--message` cannot combine with `--head` or `--summary`. Without `--format`, it prints context; `--json` writes a context envelope to stdout with kind=context and data containing uri, locator, total_messages, start/end and messages (position plus normalized message). Invalid or stale locators exit nonzero; JSON diagnostics go only to stderr.
|
|
556
|
+
`--message` cannot combine with `--head` or `--summary`. Without `--format`, it prints context; `--json` writes a context envelope to stdout with kind=context, status (partial when recoverable source diagnostics occur) and data containing uri, locator, total_messages, start/end and messages (position plus normalized message). Invalid or stale locators exit nonzero; JSON diagnostics go only to stderr.
|
|
539
557
|
|
|
540
558
|
Use `--format json,markdown` to export the selected context. Files are named `<id>.messages-<start>-<end>.json` / `.md` under the Provider's output directory, separate from full-session exports. Both formats retain the canonical Session URI, the locator (revision plus target position), the absolute message range, and status. JSON retains normalized message records; Markdown renders their searchable text. Recoverable source diagnostics mark the file `partial` and are reported on stderr. Stale locators are rejected before file creation. Provider format restrictions still apply; raw/print file formats and `--json` with file-export options are rejected. `--output` requires an explicit `--format`; output-directory defaults follow full-session export rules.
|
|
541
559
|
|
|
@@ -39,6 +39,7 @@ pub fn syntax(text: &str, original: &serde_json::Error) -> Error {
|
|
|
39
39
|
let mut parser = Parser {
|
|
40
40
|
chars: text.chars().collect(),
|
|
41
41
|
index: 0,
|
|
42
|
+
depth: 0,
|
|
42
43
|
};
|
|
43
44
|
let failure = if text.starts_with('\u{feff}') {
|
|
44
45
|
Some(("Unexpected UTF-8 BOM (decode using utf-8-sig)", 0))
|
|
@@ -49,7 +50,9 @@ pub fn syntax(text: &str, original: &serde_json::Error) -> Error {
|
|
|
49
50
|
.then_some(("Extra data", parser.index))
|
|
50
51
|
})
|
|
51
52
|
};
|
|
52
|
-
let message = if let Some((message, position)) =
|
|
53
|
+
let message = if let Some((message, position)) =
|
|
54
|
+
failure.filter(|(message, _)| *message != TOO_DEEP)
|
|
55
|
+
{
|
|
53
56
|
let before = &parser.chars[..position];
|
|
54
57
|
let line = before.iter().filter(|c| **c == '\n').count() + 1;
|
|
55
58
|
let column = position
|
|
@@ -70,9 +73,14 @@ pub fn syntax(text: &str, original: &serde_json::Error) -> Error {
|
|
|
70
73
|
|
|
71
74
|
type Failure = (&'static str, usize);
|
|
72
75
|
|
|
76
|
+
// Matches serde_json's recursion limit so deep input cannot overflow the stack.
|
|
77
|
+
const MAX_DEPTH: usize = 128;
|
|
78
|
+
const TOO_DEEP: &str = "recursion limit exceeded";
|
|
79
|
+
|
|
73
80
|
struct Parser {
|
|
74
81
|
chars: Vec<char>,
|
|
75
82
|
index: usize,
|
|
83
|
+
depth: usize,
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
impl Parser {
|
|
@@ -107,8 +115,19 @@ impl Parser {
|
|
|
107
115
|
self.whitespace();
|
|
108
116
|
match self.chars.get(self.index).copied() {
|
|
109
117
|
Some('"') => self.string(),
|
|
110
|
-
Some('{')
|
|
111
|
-
|
|
118
|
+
Some('{' | '[') if self.depth == MAX_DEPTH => {
|
|
119
|
+
Err((TOO_DEEP, self.index))
|
|
120
|
+
}
|
|
121
|
+
Some(open @ ('{' | '[')) => {
|
|
122
|
+
self.depth += 1;
|
|
123
|
+
let result = if open == '{' {
|
|
124
|
+
self.object()
|
|
125
|
+
} else {
|
|
126
|
+
self.array()
|
|
127
|
+
};
|
|
128
|
+
self.depth -= 1;
|
|
129
|
+
result
|
|
130
|
+
}
|
|
112
131
|
_ => {
|
|
113
132
|
for word in
|
|
114
133
|
["null", "true", "false", "NaN", "Infinity", "-Infinity"]
|
|
@@ -156,3 +156,15 @@ impl serde_json::ser::Formatter for Formatter {
|
|
|
156
156
|
writer.write_all(output.as_bytes())
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
|
+
|
|
160
|
+
#[cfg(test)]
|
|
161
|
+
mod tests {
|
|
162
|
+
use super::*;
|
|
163
|
+
|
|
164
|
+
#[test]
|
|
165
|
+
fn deep_nesting_reports_error_without_overflow() {
|
|
166
|
+
let error = from_str(&"[".repeat(100_000)).unwrap_err();
|
|
167
|
+
|
|
168
|
+
assert!(error.to_string().starts_with("recursion limit exceeded"));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -10,6 +10,8 @@ pub struct AiConfig {
|
|
|
10
10
|
pub base_url: String,
|
|
11
11
|
pub model: String,
|
|
12
12
|
pub api_key: String,
|
|
13
|
+
pub reasoning: String,
|
|
14
|
+
pub extra_body: Value,
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
pub struct CollectConfig {
|
|
@@ -183,6 +185,12 @@ impl Config {
|
|
|
183
185
|
base_url: text(&self.data["ai"]["base_url"]),
|
|
184
186
|
model: text(&self.data["ai"]["model"]),
|
|
185
187
|
api_key: text(&self.data["ai"]["api_key"]),
|
|
188
|
+
reasoning: if self.data["ai"]["reasoning"].is_null() {
|
|
189
|
+
"off".into()
|
|
190
|
+
} else {
|
|
191
|
+
text(&self.data["ai"]["reasoning"])
|
|
192
|
+
},
|
|
193
|
+
extra_body: self.data["ai"]["extra_body"].clone(),
|
|
186
194
|
})
|
|
187
195
|
}
|
|
188
196
|
pub fn output(&self) -> String {
|
|
@@ -436,6 +444,12 @@ pub fn validate_ai(
|
|
|
436
444
|
if config.api_key.is_empty() {
|
|
437
445
|
errors.push("api_key");
|
|
438
446
|
}
|
|
447
|
+
if !matches!(config.reasoning.as_str(), "off" | "default") {
|
|
448
|
+
errors.push("reasoning");
|
|
449
|
+
}
|
|
450
|
+
if !config.extra_body.is_null() && !config.extra_body.is_object() {
|
|
451
|
+
errors.push("extra_body");
|
|
452
|
+
}
|
|
439
453
|
if !config.base_url.is_empty() {
|
|
440
454
|
let scheme = config
|
|
441
455
|
.base_url
|
|
@@ -59,25 +59,14 @@ fn filename(id: &str) -> crate::Result<String> {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
fn absolute_existing_ancestor(path: &Path) -> crate::Result<PathBuf> {
|
|
63
|
-
if path.exists() {
|
|
64
|
-
return Ok(path.canonicalize()?);
|
|
65
|
-
}
|
|
66
|
-
let parent = path.parent().ok_or("Cannot resolve output path")?;
|
|
67
|
-
Ok(absolute_existing_ancestor(parent)?
|
|
68
|
-
.join(path.file_name().ok_or("Invalid output path")?))
|
|
69
|
-
}
|
|
70
|
-
|
|
71
62
|
fn write(
|
|
72
63
|
output: &Path,
|
|
73
64
|
session_id: &str,
|
|
74
65
|
suffix: &str,
|
|
75
|
-
source_root: &Path,
|
|
76
66
|
contents: impl FnOnce(&mut fs::File) -> crate::Result<()>,
|
|
77
67
|
) -> crate::Result<PathBuf> {
|
|
78
68
|
let directory = std::path::absolute(output)?;
|
|
79
|
-
|
|
80
|
-
if resolved.starts_with(source_root.canonicalize()?) {
|
|
69
|
+
if crate::providers::registry::inside_source(&directory)? {
|
|
81
70
|
return Err(
|
|
82
71
|
"Export output must be outside the Provider source directory"
|
|
83
72
|
.into(),
|
|
@@ -114,10 +103,9 @@ pub fn json(
|
|
|
114
103
|
session_id: &str,
|
|
115
104
|
data: &impl serde::Serialize,
|
|
116
105
|
output: &Path,
|
|
117
|
-
source_root: &Path,
|
|
118
106
|
suffix: &str,
|
|
119
107
|
) -> crate::Result<PathBuf> {
|
|
120
|
-
write(output, session_id, suffix,
|
|
108
|
+
write(output, session_id, suffix, |file| {
|
|
121
109
|
let mut writer = io::BufWriter::new(file);
|
|
122
110
|
data.serialize(&mut serde_json::Serializer::with_formatter(
|
|
123
111
|
&mut writer,
|
|
@@ -132,19 +120,17 @@ pub fn markdown(
|
|
|
132
120
|
session_id: &str,
|
|
133
121
|
text: &str,
|
|
134
122
|
output: &Path,
|
|
135
|
-
source_root: &Path,
|
|
136
123
|
) -> crate::Result<PathBuf> {
|
|
137
|
-
markdown_with_suffix(session_id, text, output,
|
|
124
|
+
markdown_with_suffix(session_id, text, output, ".md")
|
|
138
125
|
}
|
|
139
126
|
|
|
140
127
|
fn markdown_with_suffix(
|
|
141
128
|
session_id: &str,
|
|
142
129
|
text: &str,
|
|
143
130
|
output: &Path,
|
|
144
|
-
source_root: &Path,
|
|
145
131
|
suffix: &str,
|
|
146
132
|
) -> crate::Result<PathBuf> {
|
|
147
|
-
write(output, session_id, suffix,
|
|
133
|
+
write(output, session_id, suffix, |file| {
|
|
148
134
|
if cfg!(windows) {
|
|
149
135
|
file.write_all(text.replace('\n', "\r\n").as_bytes())?;
|
|
150
136
|
} else {
|
|
@@ -158,9 +144,8 @@ pub fn raw(
|
|
|
158
144
|
session_id: &str,
|
|
159
145
|
source: &Path,
|
|
160
146
|
output: &Path,
|
|
161
|
-
source_root: &Path,
|
|
162
147
|
) -> crate::Result<PathBuf> {
|
|
163
|
-
write(output, session_id, ".raw.jsonl",
|
|
148
|
+
write(output, session_id, ".raw.jsonl", |file| {
|
|
164
149
|
io::copy(&mut fs::File::open(source)?, file)?;
|
|
165
150
|
Ok(())
|
|
166
151
|
})
|
|
@@ -179,7 +164,6 @@ impl Excerpt<'_> {
|
|
|
179
164
|
&self,
|
|
180
165
|
format: crate::output::formats::OutputFormat,
|
|
181
166
|
output: &Path,
|
|
182
|
-
source_root: &Path,
|
|
183
167
|
) -> crate::Result<PathBuf> {
|
|
184
168
|
use crate::output::formats::OutputFormat;
|
|
185
169
|
let suffix =
|
|
@@ -197,7 +181,6 @@ impl Excerpt<'_> {
|
|
|
197
181
|
&self.data.id,
|
|
198
182
|
&document,
|
|
199
183
|
output,
|
|
200
|
-
source_root,
|
|
201
184
|
&format!("{suffix}.json"),
|
|
202
185
|
)
|
|
203
186
|
}
|
|
@@ -211,7 +194,6 @@ impl Excerpt<'_> {
|
|
|
211
194
|
self.incomplete,
|
|
212
195
|
),
|
|
213
196
|
output,
|
|
214
|
-
source_root,
|
|
215
197
|
&format!("{suffix}.md"),
|
|
216
198
|
),
|
|
217
199
|
OutputFormat::Raw | OutputFormat::Print => {
|
|
@@ -239,17 +221,13 @@ impl SessionExport<'_> {
|
|
|
239
221
|
use crate::providers::contract::RawExport;
|
|
240
222
|
match format {
|
|
241
223
|
OutputFormat::Raw => match self.raw.as_ref().unwrap() {
|
|
242
|
-
RawExport::File(source) =>
|
|
243
|
-
&self.session.id,
|
|
244
|
-
|
|
245
|
-
output,
|
|
246
|
-
self.provider.source_root(),
|
|
247
|
-
),
|
|
224
|
+
RawExport::File(source) => {
|
|
225
|
+
raw(&self.session.id, source, output)
|
|
226
|
+
}
|
|
248
227
|
RawExport::Session => json(
|
|
249
228
|
&self.session.id,
|
|
250
229
|
self.data.unwrap(),
|
|
251
230
|
output,
|
|
252
|
-
self.provider.source_root(),
|
|
253
231
|
".raw.json",
|
|
254
232
|
),
|
|
255
233
|
},
|
|
@@ -261,13 +239,7 @@ impl SessionExport<'_> {
|
|
|
261
239
|
{
|
|
262
240
|
object.insert("summary".into(), summary.into());
|
|
263
241
|
}
|
|
264
|
-
json(
|
|
265
|
-
&self.session.id,
|
|
266
|
-
&payload,
|
|
267
|
-
output,
|
|
268
|
-
self.provider.source_root(),
|
|
269
|
-
".json",
|
|
270
|
-
)
|
|
242
|
+
json(&self.session.id, &payload, output, ".json")
|
|
271
243
|
}
|
|
272
244
|
OutputFormat::Markdown => markdown(
|
|
273
245
|
&self.session.id,
|
|
@@ -276,7 +248,6 @@ impl SessionExport<'_> {
|
|
|
276
248
|
self.data.unwrap(),
|
|
277
249
|
),
|
|
278
250
|
output,
|
|
279
|
-
self.provider.source_root(),
|
|
280
251
|
),
|
|
281
252
|
OutputFormat::Print => unreachable!(),
|
|
282
253
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
pub(super) mod transcript;
|
|
2
2
|
|
|
3
|
-
use crate::compat::value::{field, text
|
|
3
|
+
use crate::compat::value::{field, text};
|
|
4
4
|
use crate::providers::contract::{
|
|
5
5
|
DiagnosticSink, Provider, RecoverableDiagnostic,
|
|
6
6
|
};
|
|
7
|
-
use crate::providers::files::{
|
|
7
|
+
use crate::providers::files::{
|
|
8
|
+
self as file_sessions, SourceFiles, SourceRoots,
|
|
9
|
+
};
|
|
8
10
|
use crate::providers::jsonl;
|
|
9
11
|
use crate::providers::title::{basename, normalize_title};
|
|
10
12
|
use crate::session::timestamp::Timestamp;
|
|
@@ -51,7 +53,7 @@ impl Claude {
|
|
|
51
53
|
})
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
fn files(&mut self) -> crate::Result<
|
|
56
|
+
fn files(&mut self) -> crate::Result<SourceFiles> {
|
|
55
57
|
let files = self.roots.files(Some(2), |path, base| {
|
|
56
58
|
path.extension().is_some_and(|ext| ext == "jsonl")
|
|
57
59
|
&& path.parent() != Some(base)
|
|
@@ -112,11 +114,14 @@ impl Claude {
|
|
|
112
114
|
let mut skipped = 0;
|
|
113
115
|
for entry in value["entries"].as_array().into_iter().flatten() {
|
|
114
116
|
let id = text(&entry["sessionId"]);
|
|
115
|
-
|
|
117
|
+
let summary = &entry["summary"];
|
|
118
|
+
if id.trim().is_empty()
|
|
119
|
+
|| !(summary.is_null() || summary.is_string())
|
|
120
|
+
{
|
|
116
121
|
skipped += 1;
|
|
117
122
|
continue;
|
|
118
123
|
}
|
|
119
|
-
titles.insert(id.to_owned(),
|
|
124
|
+
titles.insert(id.to_owned(), summary.clone());
|
|
120
125
|
}
|
|
121
126
|
if skipped > 0 {
|
|
122
127
|
diagnostics(RecoverableDiagnostic::TitleCacheEntriesSkipped {
|
|
@@ -149,21 +154,11 @@ impl Claude {
|
|
|
149
154
|
.into_owned();
|
|
150
155
|
let created_at = parse_timestamp(text(&header["timestamp"]))
|
|
151
156
|
.unwrap_or(Timestamp::try_from(path.metadata()?.modified()?)?);
|
|
152
|
-
let explicit =
|
|
157
|
+
let explicit = self
|
|
153
158
|
.titles(project, diagnostics)?
|
|
154
159
|
.get(&id)
|
|
155
|
-
.
|
|
156
|
-
|
|
157
|
-
Some(Value::String(title)) => normalize_title(title),
|
|
158
|
-
Some(value) => {
|
|
159
|
-
let kind = crate::compat::value::type_name(value);
|
|
160
|
-
return Err(format!(
|
|
161
|
-
"expected string or bytes-like object, got '{kind}'"
|
|
162
|
-
)
|
|
163
|
-
.into());
|
|
164
|
-
}
|
|
165
|
-
None => None,
|
|
166
|
-
};
|
|
160
|
+
.and_then(Value::as_str)
|
|
161
|
+
.and_then(normalize_title);
|
|
167
162
|
let first_user = scan
|
|
168
163
|
.records
|
|
169
164
|
.iter()
|
|
@@ -244,7 +239,7 @@ impl Provider for Claude {
|
|
|
244
239
|
) -> crate::Result<crate::providers::contract::Discovery> {
|
|
245
240
|
self.titles.clear();
|
|
246
241
|
file_sessions::discover(
|
|
247
|
-
|
|
242
|
+
self.files()?,
|
|
248
243
|
days,
|
|
249
244
|
true,
|
|
250
245
|
Self::scan,
|
|
@@ -261,7 +256,7 @@ impl Provider for Claude {
|
|
|
261
256
|
let files = self.files()?;
|
|
262
257
|
file_sessions::find(
|
|
263
258
|
self.roots.base.clone().as_deref(),
|
|
264
|
-
|
|
259
|
+
files,
|
|
265
260
|
id,
|
|
266
261
|
|path| path.file_stem().is_some_and(|name| name == id),
|
|
267
262
|
|path| self.parse(path, Self::scan(path)?, diagnostics),
|
|
@@ -296,6 +291,10 @@ impl Provider for Claude {
|
|
|
296
291
|
fn source_root(&self) -> &Path {
|
|
297
292
|
self.roots.owned()
|
|
298
293
|
}
|
|
294
|
+
|
|
295
|
+
fn select_source(&mut self) -> crate::Result<Option<&Path>> {
|
|
296
|
+
self.roots.select()
|
|
297
|
+
}
|
|
299
298
|
}
|
|
300
299
|
|
|
301
300
|
#[cfg(test)]
|
{agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/claude/transcript.rs
RENAMED
|
@@ -255,12 +255,16 @@ impl Decoder {
|
|
|
255
255
|
continue;
|
|
256
256
|
}
|
|
257
257
|
let parts = output_parts(&item["content"], timestamp);
|
|
258
|
+
let mut updates = updates.clone();
|
|
259
|
+
if item["is_error"] == true {
|
|
260
|
+
updates.insert("status".into(), "error".into());
|
|
261
|
+
}
|
|
258
262
|
if let Some(tool) = backfill(
|
|
259
263
|
&mut self.messages,
|
|
260
264
|
&self.pending,
|
|
261
265
|
&call_id,
|
|
262
266
|
&parts,
|
|
263
|
-
Some(updates
|
|
267
|
+
Some(updates),
|
|
264
268
|
)? {
|
|
265
269
|
if !parts.is_empty() {
|
|
266
270
|
tool.state
|
{agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/codex/enrichment.rs
RENAMED
|
@@ -79,7 +79,10 @@ pub fn subagent_notification(
|
|
|
79
79
|
if !payload.is_object() {
|
|
80
80
|
return None;
|
|
81
81
|
}
|
|
82
|
-
let agent_id = field(&payload, "agent_id").trim()
|
|
82
|
+
let agent_id = match field(&payload, "agent_id").trim() {
|
|
83
|
+
"" => field(&payload, "agent_path").trim().to_owned(),
|
|
84
|
+
agent_id => agent_id.to_owned(),
|
|
85
|
+
};
|
|
83
86
|
let nickname = field(&payload, "nickname").trim().to_owned();
|
|
84
87
|
let completed = if payload["status"].is_object() {
|
|
85
88
|
field(&payload["status"], "completed").trim().to_owned()
|
|
@@ -6,7 +6,9 @@ use crate::compat::value::text;
|
|
|
6
6
|
use crate::providers::contract::{
|
|
7
7
|
DiagnosticSink, Provider, RecoverableDiagnostic,
|
|
8
8
|
};
|
|
9
|
-
use crate::providers::files::{
|
|
9
|
+
use crate::providers::files::{
|
|
10
|
+
self as file_sessions, SourceFiles, SourceRoots,
|
|
11
|
+
};
|
|
10
12
|
use crate::providers::jsonl;
|
|
11
13
|
use crate::providers::title::{basename, normalize_title};
|
|
12
14
|
use crate::session::timestamp::Timestamp;
|
|
@@ -87,7 +89,7 @@ impl Codex {
|
|
|
87
89
|
.cloned())
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
fn files(&mut self) -> crate::Result<
|
|
92
|
+
fn files(&mut self) -> crate::Result<SourceFiles> {
|
|
91
93
|
self.roots.files(None, |path, _| {
|
|
92
94
|
path.extension().is_some_and(|ext| ext == "jsonl")
|
|
93
95
|
})
|
|
@@ -219,7 +221,7 @@ impl Provider for Codex {
|
|
|
219
221
|
) -> crate::Result<crate::providers::contract::Discovery> {
|
|
220
222
|
self.titles = None;
|
|
221
223
|
file_sessions::discover(
|
|
222
|
-
|
|
224
|
+
self.files()?,
|
|
223
225
|
days,
|
|
224
226
|
true,
|
|
225
227
|
Self::scan,
|
|
@@ -237,7 +239,7 @@ impl Provider for Codex {
|
|
|
237
239
|
let files = self.files()?;
|
|
238
240
|
file_sessions::find(
|
|
239
241
|
self.roots.base.clone().as_deref(),
|
|
240
|
-
|
|
242
|
+
files,
|
|
241
243
|
id,
|
|
242
244
|
|path| {
|
|
243
245
|
path.file_name().is_some_and(|name| {
|
|
@@ -280,6 +282,10 @@ impl Provider for Codex {
|
|
|
280
282
|
fn source_root(&self) -> &Path {
|
|
281
283
|
self.roots.owned()
|
|
282
284
|
}
|
|
285
|
+
|
|
286
|
+
fn select_source(&mut self) -> crate::Result<Option<&Path>> {
|
|
287
|
+
self.roots.select()
|
|
288
|
+
}
|
|
283
289
|
}
|
|
284
290
|
|
|
285
291
|
#[cfg(test)]
|
{agent_dump-1.2.2 → agent_dump-1.2.4}/crates/agent-dump-core/src/providers/codex/transcript.rs
RENAMED
|
@@ -154,13 +154,17 @@ impl Decoder {
|
|
|
154
154
|
})
|
|
155
155
|
.collect::<Vec<_>>()
|
|
156
156
|
.join("\n\n");
|
|
157
|
+
let is_notification = user_text.starts_with("<subagent_notification>")
|
|
158
|
+
&& user_text.ends_with("</subagent_notification>");
|
|
157
159
|
if self.pending_plan.is_some()
|
|
158
160
|
&& role == "user"
|
|
159
161
|
&& !user_text.is_empty()
|
|
162
|
+
&& !is_notification
|
|
160
163
|
{
|
|
161
164
|
if user_text
|
|
162
165
|
.trim_start()
|
|
163
166
|
.starts_with("PLEASE IMPLEMENT THIS PLAN")
|
|
167
|
+
|| user_text == "Implement the plan."
|
|
164
168
|
{
|
|
165
169
|
self.finish_plan("success", None);
|
|
166
170
|
} else {
|
|
@@ -343,10 +347,13 @@ pub fn read(
|
|
|
343
347
|
) -> crate::Result<SessionData> {
|
|
344
348
|
let mut decoder = Decoder::default();
|
|
345
349
|
let mut stats = Stats::default();
|
|
350
|
+
let mut usage = Value::Null;
|
|
346
351
|
jsonl::scan(&session.source_path, diagnostics, |record, diagnostics| {
|
|
347
|
-
let result = decoder.record(&record, zh).
|
|
348
|
-
let
|
|
349
|
-
|
|
352
|
+
let result = decoder.record(&record, zh).map(|()| {
|
|
353
|
+
let snapshot = &record["payload"]["info"]["total_token_usage"];
|
|
354
|
+
if snapshot.is_object() {
|
|
355
|
+
usage = snapshot.clone();
|
|
356
|
+
}
|
|
350
357
|
});
|
|
351
358
|
if let Err(error) = result {
|
|
352
359
|
diagnostics(RecoverableDiagnostic::MessageConvertFailed(
|
|
@@ -356,6 +363,7 @@ pub fn read(
|
|
|
356
363
|
Ok(())
|
|
357
364
|
})?;
|
|
358
365
|
decoder.finish_plan("fail", None);
|
|
366
|
+
stats.add_tokens(&usage["input_tokens"], &usage["output_tokens"])?;
|
|
359
367
|
stats.message_count = decoder.messages.len();
|
|
360
368
|
let mut data = session.payload(decoder.messages, stats);
|
|
361
369
|
data.directory = session.source_metadata["cwd"].clone();
|
|
@@ -98,6 +98,7 @@ pub trait Provider: Send + Sync {
|
|
|
98
98
|
diagnostics: &mut DiagnosticSink<'_>,
|
|
99
99
|
) -> crate::Result<SessionData>;
|
|
100
100
|
fn source_root(&self) -> &Path;
|
|
101
|
+
fn select_source(&mut self) -> crate::Result<Option<&Path>>;
|
|
101
102
|
fn search_roots(&self) -> crate::Result<Vec<(&'static str, PathBuf)>>;
|
|
102
103
|
|
|
103
104
|
fn change_sources(&self, session: &Session) -> Vec<PathBuf> {
|
|
@@ -163,6 +163,11 @@ impl Provider for Cursor {
|
|
|
163
163
|
fn source_root(&self) -> &Path {
|
|
164
164
|
self.database.parent().unwrap()
|
|
165
165
|
}
|
|
166
|
+
|
|
167
|
+
fn select_source(&mut self) -> crate::Result<Option<&Path>> {
|
|
168
|
+
self.database = (self.resolve_database)()?;
|
|
169
|
+
Ok(self.database.exists().then(|| self.source_root()))
|
|
170
|
+
}
|
|
166
171
|
fn supports_format(&self, format: OutputFormat) -> bool {
|
|
167
172
|
matches!(format, OutputFormat::Json | OutputFormat::Print)
|
|
168
173
|
}
|