cc-transcript 14.17.0__tar.gz → 14.18.0__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.
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/PKG-INFO +1 -1
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/__init__.py +1 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/__init__.pyi +2 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/_native.pyi +3 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/activity.py +174 -60
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/pyproject.toml +1 -1
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/benches/parse.rs +10 -1
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/activity.rs +90 -7
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/python.rs +68 -22
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/Cargo.lock +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/Cargo.toml +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/LICENSE +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/README.md +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/activity_probe.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/builders.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/codex.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/command.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/context.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/corrections.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/cost.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/decision_store.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/decisions.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/discovery.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/disktruth.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/evidence.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/extract/__init__.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/extract/correct.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/facts.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/filterspec.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/heartbeats.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/ids.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/judge/__init__.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/judge/llm.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/judge/similar.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/judge/verdicts.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/ledger.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/literals.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/mining/__init__.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/mining/candidates.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/mining/confidence.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/mining/engine.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/mining/formats.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/mining/sampling.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/mining/signals.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/mining/sourcekind.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/mining/spec.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/mining/store.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/models.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/nlp.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/notifications.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/parser.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/py.typed +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/query.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/render.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/sentiment/__init__.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/sentiment/buckets.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/sentiment/data/afinn-en-165.tsv +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/sentiment/data/domain_overrides.tsv +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/sentiment/data/en-ewt.udpipe +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/sentiment/engine.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/sentiment/lexicon.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/sentiment/scorespec.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/synthetic.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/tools.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/watch.py +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/Cargo.toml +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/commands/blame.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/commands/corrections.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/commands/digest.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/commands/facts.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/commands/grep.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/commands/list.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/commands/mod.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/commands/scratchpad.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/commands/show.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/commands/slice.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/commands/stats.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/commands/watch.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/lib.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/main.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/output.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/target.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/cli/src/timearg.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/Cargo.toml +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/benches/render.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/benches/toolcall.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/actor.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/blame.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/buckets.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/codex/discovery.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/codex/lower.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/codex/mod.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/codex/parse.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/codex/probe.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/codex/protocol.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/codex/types.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/command.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/context.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/corrections.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/cost.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/discovery.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/facts.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/feedback.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/filter.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/gateway.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/ids.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/judge.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/lib.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/literals/command.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/literals/corrections.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/literals/feedback.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/literals/mining.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/literals/mod.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/literals/protocol.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/notifications.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/parse.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/protocol.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/pystr.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/query.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/render.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/rng.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/schema.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/sqlite.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/toolcall.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/types.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/value.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/watch.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/Cargo.toml +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/build.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/data/command_prefix_pins.tsv +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/actor_bridge.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/bin/stub_gen.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/codex.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/command.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/context.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/corrections.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/discovery.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/feedback.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/judge.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/lexicon.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/lib.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/mining.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/nlp.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/render.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/score.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/sqlite.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/toolcall.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/attachment.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/blocks.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/command.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/convert.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/dunder.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/events.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/meta.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/mod.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/print.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/store.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/system.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/toolcall.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/toolresult.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/views/transcript.rs +0 -0
- {cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/py/src/watch.rs +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# isort: off
|
|
3
3
|
|
|
4
4
|
from cc_transcript.activity import (
|
|
5
|
+
ActivityLift as ActivityLift,
|
|
5
6
|
Edit as Edit,
|
|
6
7
|
SessionActivity as SessionActivity,
|
|
7
8
|
ToolUse as ToolUse,
|
|
@@ -305,6 +306,7 @@ EXPORTS: dict[str, str]
|
|
|
305
306
|
__all__ = [
|
|
306
307
|
"ASSISTANTS",
|
|
307
308
|
"Action",
|
|
309
|
+
"ActivityLift",
|
|
308
310
|
"ApiError",
|
|
309
311
|
"ApplyPatchCall",
|
|
310
312
|
"AskUserQuestionResult",
|
|
@@ -108,6 +108,7 @@ __all__ = [
|
|
|
108
108
|
"activity_hunk_overlap",
|
|
109
109
|
"activity_lift",
|
|
110
110
|
"activity_lift_from_events",
|
|
111
|
+
"activity_lift_tail",
|
|
111
112
|
"activity_overlap_between",
|
|
112
113
|
"activity_parse_show_hunks",
|
|
113
114
|
"bucket_events_from_events",
|
|
@@ -2295,6 +2296,8 @@ def activity_lift(path: builtins.str, max_events: builtins.int) -> dict[str, typ
|
|
|
2295
2296
|
|
|
2296
2297
|
def activity_lift_from_events(events: list[models.TranscriptEvent], opener_flags: typing.Optional[typing.Sequence[builtins.bool]] = None) -> list[dict[str, typing.Any]]: ...
|
|
2297
2298
|
|
|
2299
|
+
def activity_lift_tail(events: list[models.TranscriptEvent], opener_flags: typing.Optional[typing.Sequence[builtins.bool]] = None, open_turn: builtins.bool = False) -> dict[str, typing.Any]: ...
|
|
2300
|
+
|
|
2298
2301
|
def activity_overlap_between(incorrect: typing.Sequence[tuple[builtins.str, builtins.str]], correction: typing.Sequence[tuple[builtins.str, builtins.str]]) -> builtins.float: ...
|
|
2299
2302
|
|
|
2300
2303
|
def activity_parse_show_hunks(diff: builtins.str) -> builtins.list[tuple[builtins.str, builtins.str]]: ...
|
|
@@ -13,8 +13,8 @@ products.
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
15
|
from collections.abc import Callable
|
|
16
|
-
from dataclasses import dataclass
|
|
17
|
-
from typing import TYPE_CHECKING
|
|
16
|
+
from dataclasses import dataclass, replace
|
|
17
|
+
from typing import TYPE_CHECKING, Any
|
|
18
18
|
|
|
19
19
|
from cc_transcript import _native
|
|
20
20
|
from cc_transcript.discovery import TranscriptExpiredError, resolve
|
|
@@ -25,7 +25,7 @@ from cc_transcript.parser import parse
|
|
|
25
25
|
from cc_transcript.tools import edits_of, parse_tool_call, parse_tool_result
|
|
26
26
|
|
|
27
27
|
if TYPE_CHECKING:
|
|
28
|
-
from collections.abc import Sequence
|
|
28
|
+
from collections.abc import Mapping, Sequence
|
|
29
29
|
from datetime import datetime
|
|
30
30
|
from pathlib import Path
|
|
31
31
|
|
|
@@ -181,64 +181,10 @@ class SessionActivity:
|
|
|
181
181
|
turn; everything else folds into the current one. Events before the
|
|
182
182
|
first qualifying prompt form turn 0 with prompt ``""``.
|
|
183
183
|
"""
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if user_classifier is native_user_classifier
|
|
188
|
-
else [bool(user_classifier(event)) if isinstance(event, UserEvent) else False for event in evs]
|
|
184
|
+
return cls(
|
|
185
|
+
session_id=session_id,
|
|
186
|
+
turns=ActivityLift(session_id, user_classifier=user_classifier).extend(events).turns,
|
|
189
187
|
)
|
|
190
|
-
tool_blocks = {
|
|
191
|
-
event_idx: tuple(block for block in event.blocks if isinstance(block, ToolUseBlock))
|
|
192
|
-
for event_idx, event in enumerate(evs)
|
|
193
|
-
if isinstance(event, AssistantEvent)
|
|
194
|
-
}
|
|
195
|
-
tool_block_positions: dict[int, int] = {}
|
|
196
|
-
turns: list[Turn] = []
|
|
197
|
-
for index, skeleton in enumerate(_native.activity_lift_from_events(evs, opener_flags)):
|
|
198
|
-
tool_uses: list[ToolUse] = []
|
|
199
|
-
for use in skeleton["tool_uses"]:
|
|
200
|
-
event_idx = use["event_idx"]
|
|
201
|
-
event = evs[event_idx]
|
|
202
|
-
block_position = tool_block_positions.get(event_idx, 0)
|
|
203
|
-
block = tool_blocks[event_idx][block_position]
|
|
204
|
-
tool_block_positions[event_idx] = block_position + 1
|
|
205
|
-
result_event_idx = use["result_event_idx"]
|
|
206
|
-
if result_event_idx is None:
|
|
207
|
-
result = None
|
|
208
|
-
result_ts = None
|
|
209
|
-
else:
|
|
210
|
-
result_event = evs[result_event_idx]
|
|
211
|
-
result = next(
|
|
212
|
-
candidate
|
|
213
|
-
for candidate in reversed(result_event.blocks)
|
|
214
|
-
if isinstance(candidate, ToolResultBlock) and candidate.tool_use_id == use["tool_use_id"]
|
|
215
|
-
)
|
|
216
|
-
result_ts = result_event.meta.timestamp
|
|
217
|
-
call = parse_tool_call(block.name, block.input, on_error="other")
|
|
218
|
-
tool_uses.append(
|
|
219
|
-
ToolUse(
|
|
220
|
-
ref=EventRef(session_id, event.meta.uuid, block.id),
|
|
221
|
-
call=call,
|
|
222
|
-
result=result,
|
|
223
|
-
result_ts=result_ts,
|
|
224
|
-
edits=edits_of(call),
|
|
225
|
-
turn_index=index,
|
|
226
|
-
ts=event.meta.timestamp,
|
|
227
|
-
)
|
|
228
|
-
)
|
|
229
|
-
started_idx = skeleton["started_idx"]
|
|
230
|
-
ended_idx = skeleton["ended_idx"]
|
|
231
|
-
turns.append(
|
|
232
|
-
Turn(
|
|
233
|
-
index=index,
|
|
234
|
-
prompt=skeleton["prompt"],
|
|
235
|
-
started_at=None if started_idx is None else evs[started_idx].meta.timestamp,
|
|
236
|
-
ended_at=None if ended_idx is None else evs[ended_idx].meta.timestamp,
|
|
237
|
-
events=tuple(evs[skeleton["start"] : skeleton["end"]]),
|
|
238
|
-
tool_uses=tuple(tool_uses),
|
|
239
|
-
)
|
|
240
|
-
)
|
|
241
|
-
return cls(session_id=session_id, turns=tuple(turns))
|
|
242
188
|
|
|
243
189
|
@classmethod
|
|
244
190
|
def from_session(
|
|
@@ -326,6 +272,174 @@ class SessionActivity:
|
|
|
326
272
|
return tuple(same_turn + later)
|
|
327
273
|
|
|
328
274
|
|
|
275
|
+
class ActivityLift:
|
|
276
|
+
"""A session's lift that grows with its transcript.
|
|
277
|
+
|
|
278
|
+
Each :meth:`extend` folds the events appended since the previous call into
|
|
279
|
+
the activity lifted so far: closed turns are kept, the open turn grows by
|
|
280
|
+
the appended events alone, and a tool use whose result arrives in the tail
|
|
281
|
+
is re-paired wherever it sits. The result always equals
|
|
282
|
+
:meth:`SessionActivity.from_events` over every event fed so far. A step
|
|
283
|
+
costs the appended events, the tool uses they re-pair, and copies of the
|
|
284
|
+
turn tuple and of the open turn's event and tool-use tuples; it never
|
|
285
|
+
re-derives the session.
|
|
286
|
+
|
|
287
|
+
Feed only the events appended since the previous call: nothing checks
|
|
288
|
+
provenance, so events fed twice lift twice. A transcript rewritten in
|
|
289
|
+
place, rather than appended to, needs a new cursor.
|
|
290
|
+
|
|
291
|
+
The classifier is read once, at construction, and must be deterministic
|
|
292
|
+
and event-only: its answer for an event has to stay the same as later
|
|
293
|
+
events are appended, since turns lifted under it are never revisited.
|
|
294
|
+
|
|
295
|
+
Example:
|
|
296
|
+
>>> lift = ActivityLift(session_id)
|
|
297
|
+
>>> activity = lift.extend(events)
|
|
298
|
+
>>> lift.extend(appended) == SessionActivity.from_events(session_id, [*events, *appended])
|
|
299
|
+
True
|
|
300
|
+
"""
|
|
301
|
+
|
|
302
|
+
__slots__ = ("_activity", "_results", "_session_id", "_user_classifier", "_uses")
|
|
303
|
+
|
|
304
|
+
def __init__(self, session_id: SessionId, *, user_classifier: UserClassifier = native_user_classifier) -> None:
|
|
305
|
+
self._session_id = session_id
|
|
306
|
+
self._user_classifier = user_classifier
|
|
307
|
+
self._activity = SessionActivity(session_id=session_id, turns=())
|
|
308
|
+
self._uses: dict[ToolUseId, tuple[tuple[int, int], ...]] = {}
|
|
309
|
+
self._results: dict[ToolUseId, UserEvent] = {}
|
|
310
|
+
|
|
311
|
+
@property
|
|
312
|
+
def session_id(self) -> SessionId:
|
|
313
|
+
"""The session being lifted."""
|
|
314
|
+
return self._session_id
|
|
315
|
+
|
|
316
|
+
@property
|
|
317
|
+
def user_classifier(self) -> UserClassifier:
|
|
318
|
+
"""Decides which user events open turns."""
|
|
319
|
+
return self._user_classifier
|
|
320
|
+
|
|
321
|
+
@property
|
|
322
|
+
def activity(self) -> SessionActivity:
|
|
323
|
+
"""Everything lifted so far."""
|
|
324
|
+
return self._activity
|
|
325
|
+
|
|
326
|
+
def extend(self, events: Sequence[TranscriptEvent]) -> SessionActivity:
|
|
327
|
+
"""Lifts ``events``, appended after everything fed so far, into :attr:`activity`."""
|
|
328
|
+
tail = list(events)
|
|
329
|
+
if not tail:
|
|
330
|
+
return self._activity
|
|
331
|
+
opener_flags = (
|
|
332
|
+
None
|
|
333
|
+
if self._user_classifier is native_user_classifier
|
|
334
|
+
else [bool(self._user_classifier(event)) if isinstance(event, UserEvent) else False for event in tail]
|
|
335
|
+
)
|
|
336
|
+
turns = list(self._activity.turns)
|
|
337
|
+
lifted = _native.activity_lift_tail(tail, opener_flags, open_turn=bool(turns))
|
|
338
|
+
first = len(turns) - 1 if lifted["continued"] else len(turns)
|
|
339
|
+
grown = [
|
|
340
|
+
lift_turn(self._session_id, first + offset, skeleton, tail, self._results)
|
|
341
|
+
for offset, skeleton in enumerate(lifted["turns"])
|
|
342
|
+
]
|
|
343
|
+
if lifted["continued"]:
|
|
344
|
+
turns[-1] = continued(turns[-1], grown[0])
|
|
345
|
+
turns.extend(grown[1:])
|
|
346
|
+
else:
|
|
347
|
+
turns.extend(grown)
|
|
348
|
+
repairs: dict[int, dict[int, UserEvent]] = {}
|
|
349
|
+
for tool_use_id, result_idx in lifted["results"]:
|
|
350
|
+
for turn_index, position in self._uses.get(tool_use_id, ()):
|
|
351
|
+
repairs.setdefault(turn_index, {})[position] = tail[result_idx]
|
|
352
|
+
self._results[tool_use_id] = tail[result_idx]
|
|
353
|
+
for turn_index, at in repairs.items():
|
|
354
|
+
turns[turn_index] = repaired(turns[turn_index], at)
|
|
355
|
+
for turn in grown:
|
|
356
|
+
base = len(turns[turn.index].tool_uses) - len(turn.tool_uses)
|
|
357
|
+
for position, use in enumerate(turn.tool_uses, base):
|
|
358
|
+
self._uses[use.ref.tool_use_id] = (*self._uses.get(use.ref.tool_use_id, ()), (turn.index, position))
|
|
359
|
+
self._activity = SessionActivity(session_id=self._session_id, turns=tuple(turns))
|
|
360
|
+
return self._activity
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def lift_turn(
|
|
364
|
+
session_id: SessionId,
|
|
365
|
+
index: int,
|
|
366
|
+
skeleton: dict[str, Any],
|
|
367
|
+
evs: Sequence[TranscriptEvent],
|
|
368
|
+
prior_results: Mapping[ToolUseId, UserEvent],
|
|
369
|
+
) -> Turn:
|
|
370
|
+
events = tuple(evs[skeleton["start"] : skeleton["end"]])
|
|
371
|
+
calls = [
|
|
372
|
+
(event, block)
|
|
373
|
+
for event in events
|
|
374
|
+
if isinstance(event, AssistantEvent)
|
|
375
|
+
for block in event.blocks
|
|
376
|
+
if isinstance(block, ToolUseBlock)
|
|
377
|
+
]
|
|
378
|
+
started_idx = skeleton["started_idx"]
|
|
379
|
+
ended_idx = skeleton["ended_idx"]
|
|
380
|
+
return Turn(
|
|
381
|
+
index=index,
|
|
382
|
+
prompt=skeleton["prompt"],
|
|
383
|
+
started_at=None if started_idx is None else evs[started_idx].meta.timestamp,
|
|
384
|
+
ended_at=None if ended_idx is None else evs[ended_idx].meta.timestamp,
|
|
385
|
+
events=events,
|
|
386
|
+
tool_uses=tuple(
|
|
387
|
+
lift_tool_use(
|
|
388
|
+
session_id,
|
|
389
|
+
index,
|
|
390
|
+
event,
|
|
391
|
+
block,
|
|
392
|
+
prior_results.get(block.id) if (result_idx := use["result_event_idx"]) is None else evs[result_idx],
|
|
393
|
+
)
|
|
394
|
+
for (event, block), use in zip(calls, skeleton["tool_uses"], strict=True)
|
|
395
|
+
),
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def lift_tool_use(
|
|
400
|
+
session_id: SessionId, turn_index: int, event: AssistantEvent, block: ToolUseBlock, result_event: UserEvent | None
|
|
401
|
+
) -> ToolUse:
|
|
402
|
+
call = parse_tool_call(block.name, block.input, on_error="other")
|
|
403
|
+
return ToolUse(
|
|
404
|
+
ref=EventRef(session_id, event.meta.uuid, block.id),
|
|
405
|
+
call=call,
|
|
406
|
+
result=None if result_event is None else result_block(result_event, block.id),
|
|
407
|
+
result_ts=None if result_event is None else result_event.meta.timestamp,
|
|
408
|
+
edits=edits_of(call),
|
|
409
|
+
turn_index=turn_index,
|
|
410
|
+
ts=event.meta.timestamp,
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def result_block(event: UserEvent, tool_use_id: ToolUseId) -> ToolResultBlock:
|
|
415
|
+
return next(
|
|
416
|
+
candidate
|
|
417
|
+
for candidate in reversed(event.blocks)
|
|
418
|
+
if isinstance(candidate, ToolResultBlock) and candidate.tool_use_id == tool_use_id
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def continued(turn: Turn, tail: Turn) -> Turn:
|
|
423
|
+
return replace(
|
|
424
|
+
turn,
|
|
425
|
+
started_at=tail.started_at if turn.started_at is None else turn.started_at,
|
|
426
|
+
ended_at=turn.ended_at if tail.ended_at is None else tail.ended_at,
|
|
427
|
+
events=turn.events + tail.events,
|
|
428
|
+
tool_uses=turn.tool_uses + tail.tool_uses,
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def repaired(turn: Turn, at: Mapping[int, UserEvent]) -> Turn:
|
|
433
|
+
uses = list(turn.tool_uses)
|
|
434
|
+
for position, event in at.items():
|
|
435
|
+
uses[position] = replace(
|
|
436
|
+
uses[position],
|
|
437
|
+
result=result_block(event, uses[position].ref.tool_use_id),
|
|
438
|
+
result_ts=event.meta.timestamp,
|
|
439
|
+
)
|
|
440
|
+
return replace(turn, tool_uses=tuple(uses))
|
|
441
|
+
|
|
442
|
+
|
|
329
443
|
def hunk_overlap(a: Hunk, b: Hunk) -> float:
|
|
330
444
|
"""The fraction of ``a.new``'s non-empty lines present in ``b.old``.
|
|
331
445
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "cc-transcript"
|
|
3
|
-
version = "14.
|
|
3
|
+
version = "14.18.0" # informational — releases stamp the version from the git tag
|
|
4
4
|
description = "Grep every Claude Code session you've ever run."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "PolyForm-Noncommercial-1.0.0"
|
|
@@ -6,9 +6,12 @@ use std::path::{Path, PathBuf};
|
|
|
6
6
|
|
|
7
7
|
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
|
|
8
8
|
|
|
9
|
-
use cc_transcript_core::activity::{
|
|
9
|
+
use cc_transcript_core::activity::{
|
|
10
|
+
lift_session, lift_session_index, lift_session_index_tail, session_activity, ActivityOpts,
|
|
11
|
+
};
|
|
10
12
|
use cc_transcript_core::filter::{compile_spec, spec_keep, SIGNAL_SPEC_JSON};
|
|
11
13
|
use cc_transcript_core::parse::parse_bytes;
|
|
14
|
+
use cc_transcript_core::types::Entry;
|
|
12
15
|
|
|
13
16
|
fn corpus_dir() -> PathBuf {
|
|
14
17
|
std::env::var_os("CC_BENCH_CORPUS")
|
|
@@ -80,6 +83,12 @@ fn bench_activity(c: &mut Criterion) {
|
|
|
80
83
|
group.bench_function("full_lift", |b| {
|
|
81
84
|
b.iter(|| lift_session(&session_id, &entries))
|
|
82
85
|
});
|
|
86
|
+
let refs: Vec<&Entry> = entries.iter().collect();
|
|
87
|
+
group.bench_function("lift_index", |b| b.iter(|| lift_session_index(&refs, None)));
|
|
88
|
+
let appended = &refs[refs.len().saturating_sub(8)..];
|
|
89
|
+
group.bench_function("lift_index_tail_8", |b| {
|
|
90
|
+
b.iter(|| lift_session_index_tail(appended, None, true))
|
|
91
|
+
});
|
|
83
92
|
group.finish();
|
|
84
93
|
}
|
|
85
94
|
|
|
@@ -500,17 +500,17 @@ struct Segment {
|
|
|
500
500
|
end: usize,
|
|
501
501
|
}
|
|
502
502
|
|
|
503
|
+
fn opens(entry: &Entry, index: usize, openers: Option<&[bool]>) -> bool {
|
|
504
|
+
matches!(entry, Entry::User(user) if openers.map_or_else(|| opens_turn(user), |flags| flags[index]))
|
|
505
|
+
}
|
|
506
|
+
|
|
503
507
|
// activity.py from_events segmentation: a turn-opening user entry starts a contiguous
|
|
504
508
|
// segment, else folds into the current one; `Some(openers)` replaces that per-entry decision.
|
|
505
509
|
fn segments(entries: &[&Entry], openers: Option<&[bool]>) -> Vec<Segment> {
|
|
506
510
|
let mut segments: Vec<Segment> = Vec::new();
|
|
507
511
|
for (index, &entry) in entries.iter().enumerate() {
|
|
508
|
-
let opens = openers.map_or_else(
|
|
509
|
-
|| matches!(entry, Entry::User(user) if opens_turn(user)),
|
|
510
|
-
|flags| flags[index],
|
|
511
|
-
);
|
|
512
512
|
match entry {
|
|
513
|
-
Entry::User(user) if opens => segments.push(Segment {
|
|
513
|
+
Entry::User(user) if opens(entry, index, openers) => segments.push(Segment {
|
|
514
514
|
prompt: user.content.text(),
|
|
515
515
|
start: index,
|
|
516
516
|
end: index + 1,
|
|
@@ -711,7 +711,42 @@ pub fn lift_session_index<'a>(
|
|
|
711
711
|
entries: &[&'a Entry],
|
|
712
712
|
openers: Option<&[bool]>,
|
|
713
713
|
) -> Vec<TurnIndex<'a>> {
|
|
714
|
-
|
|
714
|
+
turn_indexes(entries, openers, &result_positions(entries))
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/// The tail of an incremental lift (activity.py ActivityLift.extend): skeletons over the
|
|
718
|
+
/// appended entries alone, `continued` when the first is the rest of the prior open turn,
|
|
719
|
+
/// and every tool result the tail carries as `(tool_use_id, position)` for re-pairing.
|
|
720
|
+
#[derive(Debug, PartialEq, Eq)]
|
|
721
|
+
pub struct LiftTail<'a> {
|
|
722
|
+
pub turns: Vec<TurnIndex<'a>>,
|
|
723
|
+
pub continued: bool,
|
|
724
|
+
pub results: Vec<(&'a str, usize)>,
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/// `lift_session_index` over the entries appended since a prior lift whose last turn
|
|
728
|
+
/// is open when `open_turn`. Turn boundaries never look ahead, so prior turns are final.
|
|
729
|
+
pub fn lift_session_index_tail<'a>(
|
|
730
|
+
entries: &[&'a Entry],
|
|
731
|
+
openers: Option<&[bool]>,
|
|
732
|
+
open_turn: bool,
|
|
733
|
+
) -> LiftTail<'a> {
|
|
734
|
+
let result_pos = result_positions(entries);
|
|
735
|
+
let mut results: Vec<(&'a str, usize)> =
|
|
736
|
+
result_pos.iter().map(|(&id, &pos)| (id, pos)).collect();
|
|
737
|
+
results.sort_unstable_by_key(|&(_, pos)| pos);
|
|
738
|
+
LiftTail {
|
|
739
|
+
turns: turn_indexes(entries, openers, &result_pos),
|
|
740
|
+
continued: open_turn
|
|
741
|
+
&& entries
|
|
742
|
+
.first()
|
|
743
|
+
.is_some_and(|&entry| !opens(entry, 0, openers)),
|
|
744
|
+
results,
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
fn result_positions<'a>(entries: &[&'a Entry]) -> HashMap<&'a str, usize> {
|
|
749
|
+
entries
|
|
715
750
|
.iter()
|
|
716
751
|
.enumerate()
|
|
717
752
|
.filter_map(|(index, &entry)| match entry {
|
|
@@ -722,7 +757,14 @@ pub fn lift_session_index<'a>(
|
|
|
722
757
|
user.tool_results()
|
|
723
758
|
.map(move |block| (block.tool_use_id.as_str(), index))
|
|
724
759
|
})
|
|
725
|
-
.collect()
|
|
760
|
+
.collect()
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
fn turn_indexes<'a>(
|
|
764
|
+
entries: &[&'a Entry],
|
|
765
|
+
openers: Option<&[bool]>,
|
|
766
|
+
result_pos: &HashMap<&'a str, usize>,
|
|
767
|
+
) -> Vec<TurnIndex<'a>> {
|
|
726
768
|
segments(entries, openers)
|
|
727
769
|
.into_iter()
|
|
728
770
|
.map(|segment| {
|
|
@@ -1553,6 +1595,47 @@ mod tests {
|
|
|
1553
1595
|
);
|
|
1554
1596
|
}
|
|
1555
1597
|
|
|
1598
|
+
#[test]
|
|
1599
|
+
fn tail_continues_an_open_turn_only_through_a_non_opener() {
|
|
1600
|
+
let entries = vec![
|
|
1601
|
+
tool_use("Bash", "t1", r#"{"command":"ls"}"#),
|
|
1602
|
+
tool_result("t1"),
|
|
1603
|
+
user("next ask"),
|
|
1604
|
+
];
|
|
1605
|
+
let refs: Vec<&Entry> = entries.iter().collect();
|
|
1606
|
+
|
|
1607
|
+
let continued = lift_session_index_tail(&refs, None, true);
|
|
1608
|
+
assert!(continued.continued);
|
|
1609
|
+
assert_eq!(continued.turns, lift_session_index(&refs, None));
|
|
1610
|
+
assert_eq!(continued.results, [("t1", 1)]);
|
|
1611
|
+
|
|
1612
|
+
assert!(!lift_session_index_tail(&refs, None, false).continued);
|
|
1613
|
+
assert!(!lift_session_index_tail(&refs[2..], None, true).continued);
|
|
1614
|
+
assert!(!lift_session_index_tail(&[], None, true).continued);
|
|
1615
|
+
assert!(lift_session_index_tail(&refs, Some(&[false, false, false]), true).continued);
|
|
1616
|
+
assert!(
|
|
1617
|
+
lift_session_index_tail(&refs, Some(&[true, false, false]), true).continued,
|
|
1618
|
+
"a flag on a non-user entry opens nothing, exactly as segments() ignores it"
|
|
1619
|
+
);
|
|
1620
|
+
assert!(lift_session_index_tail(&refs[2..], Some(&[false]), true).continued);
|
|
1621
|
+
assert!(!lift_session_index_tail(&refs[2..], Some(&[true]), true).continued);
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
#[test]
|
|
1625
|
+
fn tail_results_keep_the_last_position_per_id_in_tail_order() {
|
|
1626
|
+
let entries = vec![
|
|
1627
|
+
tool_result("t2"),
|
|
1628
|
+
tool_result("t1"),
|
|
1629
|
+
user("interrupting ask"),
|
|
1630
|
+
tool_result("t2"),
|
|
1631
|
+
];
|
|
1632
|
+
let refs: Vec<&Entry> = entries.iter().collect();
|
|
1633
|
+
assert_eq!(
|
|
1634
|
+
lift_session_index_tail(&refs, None, true).results,
|
|
1635
|
+
[("t1", 1), ("t2", 3)]
|
|
1636
|
+
);
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1556
1639
|
#[test]
|
|
1557
1640
|
fn hunk_overlap_matches_reference() {
|
|
1558
1641
|
let hunk = |old: &str, new: &str| Hunk {
|
|
@@ -15,8 +15,8 @@ use crate::views::print::print_result_view;
|
|
|
15
15
|
use crate::views::transcript::TranscriptView;
|
|
16
16
|
use crate::{command, lexicon, mining, score};
|
|
17
17
|
use cc_transcript_core::activity::{
|
|
18
|
-
hunk_overlap, lift_session, lift_session_index,
|
|
19
|
-
result_index, ActivityOpts, Hunk, SessionActivity,
|
|
18
|
+
hunk_overlap, lift_session, lift_session_index, lift_session_index_tail, overlap_between,
|
|
19
|
+
parse_show_hunks, result_index, ActivityOpts, Hunk, SessionActivity, TurnIndex,
|
|
20
20
|
};
|
|
21
21
|
use cc_transcript_core::buckets;
|
|
22
22
|
use cc_transcript_core::command::CommandLine;
|
|
@@ -310,28 +310,73 @@ fn activity_lift_from_events<'py>(
|
|
|
310
310
|
.collect::<PyResult<Vec<_>>>()?;
|
|
311
311
|
lift_session_index(&entries, opener_flags.as_deref())
|
|
312
312
|
.iter()
|
|
313
|
-
.map(|turn|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
313
|
+
.map(|turn| turn_index_dict(py, turn))
|
|
314
|
+
.collect()
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// activity.ActivityLift.extend: the tail skeleton over the appended events alone, plus
|
|
318
|
+
// whether its first turn continues the open one and every result the tail carries.
|
|
319
|
+
#[pyo3_stub_gen::derive::gen_stub_pyfunction]
|
|
320
|
+
#[pyfunction]
|
|
321
|
+
#[pyo3(signature = (events, opener_flags=None, open_turn=false))]
|
|
322
|
+
#[gen_stub(override_return_type(type_repr = "dict[str, typing.Any]", imports = ("typing",)))]
|
|
323
|
+
fn activity_lift_tail<'py>(
|
|
324
|
+
py: Python<'py>,
|
|
325
|
+
#[gen_stub(override_type(type_repr = "list[cc_transcript.models.TranscriptEvent]", imports = ("cc_transcript.models",)))]
|
|
326
|
+
events: Vec<Bound<'py, PyAny>>,
|
|
327
|
+
opener_flags: Option<Vec<bool>>,
|
|
328
|
+
open_turn: bool,
|
|
329
|
+
) -> PyResult<Bound<'py, PyDict>> {
|
|
330
|
+
if let Some(flags) = &opener_flags {
|
|
331
|
+
if flags.len() != events.len() {
|
|
332
|
+
return Err(PyValueError::new_err(format!(
|
|
333
|
+
"activity_lift_tail() got {} opener_flags for {} events",
|
|
334
|
+
flags.len(),
|
|
335
|
+
events.len()
|
|
336
|
+
)));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
let entries = events
|
|
340
|
+
.iter()
|
|
341
|
+
.map(|event| mining::view_entry(event, "activity_lift_tail"))
|
|
342
|
+
.collect::<PyResult<Vec<_>>>()?;
|
|
343
|
+
let tail = lift_session_index_tail(&entries, opener_flags.as_deref(), open_turn);
|
|
344
|
+
let dict = PyDict::new(py);
|
|
345
|
+
dict.set_item(
|
|
346
|
+
"turns",
|
|
347
|
+
PyList::new(
|
|
348
|
+
py,
|
|
349
|
+
tail.turns
|
|
322
350
|
.iter()
|
|
323
|
-
.map(|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
351
|
+
.map(|turn| turn_index_dict(py, turn))
|
|
352
|
+
.collect::<PyResult<Vec<_>>>()?,
|
|
353
|
+
)?,
|
|
354
|
+
)?;
|
|
355
|
+
dict.set_item("continued", tail.continued)?;
|
|
356
|
+
dict.set_item("results", tail.results)?;
|
|
357
|
+
Ok(dict)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
fn turn_index_dict<'py>(py: Python<'py>, turn: &TurnIndex<'_>) -> PyResult<Bound<'py, PyDict>> {
|
|
361
|
+
let td = PyDict::new(py);
|
|
362
|
+
td.set_item("prompt", &turn.prompt)?;
|
|
363
|
+
td.set_item("start", turn.start)?;
|
|
364
|
+
td.set_item("end", turn.end)?;
|
|
365
|
+
td.set_item("started_idx", turn.started_idx)?;
|
|
366
|
+
td.set_item("ended_idx", turn.ended_idx)?;
|
|
367
|
+
let tool_uses = turn
|
|
368
|
+
.tool_uses
|
|
369
|
+
.iter()
|
|
370
|
+
.map(|use_| {
|
|
371
|
+
let ud = PyDict::new(py);
|
|
372
|
+
ud.set_item("event_idx", use_.event_idx)?;
|
|
373
|
+
ud.set_item("tool_use_id", use_.tool_use_id)?;
|
|
374
|
+
ud.set_item("result_event_idx", use_.result_event_idx)?;
|
|
375
|
+
Ok(ud)
|
|
333
376
|
})
|
|
334
|
-
.collect()
|
|
377
|
+
.collect::<PyResult<Vec<_>>>()?;
|
|
378
|
+
td.set_item("tool_uses", PyList::new(py, tool_uses)?)?;
|
|
379
|
+
Ok(td)
|
|
335
380
|
}
|
|
336
381
|
|
|
337
382
|
#[pyo3_stub_gen::derive::gen_stub_pyfunction]
|
|
@@ -1023,6 +1068,7 @@ fn _native(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
|
1023
1068
|
m.add_function(wrap_pyfunction!(cli_main, m)?)?;
|
|
1024
1069
|
m.add_function(wrap_pyfunction!(activity_lift, m)?)?;
|
|
1025
1070
|
m.add_function(wrap_pyfunction!(activity_lift_from_events, m)?)?;
|
|
1071
|
+
m.add_function(wrap_pyfunction!(activity_lift_tail, m)?)?;
|
|
1026
1072
|
m.add_function(wrap_pyfunction!(activity_hunk_overlap, m)?)?;
|
|
1027
1073
|
m.add_function(wrap_pyfunction!(activity_overlap_between, m)?)?;
|
|
1028
1074
|
m.add_function(wrap_pyfunction!(activity_parse_show_hunks, m)?)?;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/sentiment/data/afinn-en-165.tsv
RENAMED
|
File without changes
|
{cc_transcript-14.17.0 → cc_transcript-14.18.0}/cc_transcript/sentiment/data/domain_overrides.tsv
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cc_transcript-14.17.0 → cc_transcript-14.18.0}/rust/crates/core/src/literals/corrections.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|