cc-transcript 14.20.1__tar.gz → 14.22.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.

Potentially problematic release.


This version of cc-transcript might be problematic. Click here for more details.

Files changed (162) hide show
  1. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/PKG-INFO +1 -1
  2. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/_native.pyi +1 -1
  3. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/render.py +25 -6
  4. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/pyproject.toml +1 -1
  5. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/context.rs +1 -1
  6. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/render.rs +96 -18
  7. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/render.rs +2 -0
  8. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/Cargo.lock +0 -0
  9. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/Cargo.toml +0 -0
  10. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/LICENSE +0 -0
  11. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/README.md +0 -0
  12. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/__init__.py +0 -0
  13. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/__init__.pyi +0 -0
  14. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/activity.py +0 -0
  15. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/activity_probe.py +0 -0
  16. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/builders.py +0 -0
  17. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/codex.py +0 -0
  18. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/command.py +0 -0
  19. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/context.py +0 -0
  20. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/corrections.py +0 -0
  21. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/cost.py +0 -0
  22. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/decision_store.py +0 -0
  23. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/decisions.py +0 -0
  24. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/discovery.py +0 -0
  25. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/disktruth.py +0 -0
  26. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/evidence.py +0 -0
  27. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/extract/__init__.py +0 -0
  28. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/extract/correct.py +0 -0
  29. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/facts.py +0 -0
  30. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/filterspec.py +0 -0
  31. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/heartbeats.py +0 -0
  32. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/ids.py +0 -0
  33. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/judge/__init__.py +0 -0
  34. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/judge/llm.py +0 -0
  35. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/judge/similar.py +0 -0
  36. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/judge/verdicts.py +0 -0
  37. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/ledger.py +0 -0
  38. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/literals.py +0 -0
  39. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/mining/__init__.py +0 -0
  40. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/mining/candidates.py +0 -0
  41. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/mining/confidence.py +0 -0
  42. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/mining/engine.py +0 -0
  43. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/mining/formats.py +0 -0
  44. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/mining/sampling.py +0 -0
  45. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/mining/signals.py +0 -0
  46. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/mining/sourcekind.py +0 -0
  47. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/mining/spec.py +0 -0
  48. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/mining/store.py +0 -0
  49. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/models.py +0 -0
  50. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/nlp.py +0 -0
  51. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/notifications.py +0 -0
  52. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/parser.py +0 -0
  53. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/py.typed +0 -0
  54. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/query.py +0 -0
  55. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/sentiment/__init__.py +0 -0
  56. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/sentiment/buckets.py +0 -0
  57. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/sentiment/data/afinn-en-165.tsv +0 -0
  58. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/sentiment/data/domain_overrides.tsv +0 -0
  59. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/sentiment/data/en-ewt.udpipe +0 -0
  60. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/sentiment/engine.py +0 -0
  61. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/sentiment/lexicon.py +0 -0
  62. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/sentiment/scorespec.py +0 -0
  63. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/synthetic.py +0 -0
  64. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/tools.py +0 -0
  65. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/cc_transcript/watch.py +0 -0
  66. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/Cargo.toml +0 -0
  67. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/commands/blame.rs +0 -0
  68. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/commands/corrections.rs +0 -0
  69. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/commands/digest.rs +0 -0
  70. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/commands/facts.rs +0 -0
  71. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/commands/grep.rs +0 -0
  72. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/commands/list.rs +0 -0
  73. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/commands/mod.rs +0 -0
  74. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/commands/scratchpad.rs +0 -0
  75. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/commands/show.rs +0 -0
  76. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/commands/slice.rs +0 -0
  77. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/commands/stats.rs +0 -0
  78. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/commands/watch.rs +0 -0
  79. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/lib.rs +0 -0
  80. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/main.rs +0 -0
  81. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/output.rs +0 -0
  82. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/target.rs +0 -0
  83. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/cli/src/timearg.rs +0 -0
  84. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/Cargo.toml +0 -0
  85. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/benches/parse.rs +0 -0
  86. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/benches/render.rs +0 -0
  87. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/benches/toolcall.rs +0 -0
  88. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/activity.rs +0 -0
  89. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/actor.rs +0 -0
  90. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/blame.rs +0 -0
  91. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/buckets.rs +0 -0
  92. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/codex/discovery.rs +0 -0
  93. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/codex/lower.rs +0 -0
  94. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/codex/mod.rs +0 -0
  95. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/codex/parse.rs +0 -0
  96. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/codex/probe.rs +0 -0
  97. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/codex/protocol.rs +0 -0
  98. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/codex/types.rs +0 -0
  99. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/command.rs +0 -0
  100. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/corrections.rs +0 -0
  101. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/cost.rs +0 -0
  102. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/discovery.rs +0 -0
  103. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/facts.rs +0 -0
  104. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/feedback.rs +0 -0
  105. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/filter.rs +0 -0
  106. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/gateway.rs +0 -0
  107. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/ids.rs +0 -0
  108. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/judge.rs +0 -0
  109. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/lib.rs +0 -0
  110. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/literals/command.rs +0 -0
  111. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/literals/corrections.rs +0 -0
  112. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/literals/feedback.rs +0 -0
  113. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/literals/mining.rs +0 -0
  114. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/literals/mod.rs +0 -0
  115. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/literals/protocol.rs +0 -0
  116. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/notifications.rs +0 -0
  117. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/parse.rs +0 -0
  118. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/protocol.rs +0 -0
  119. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/pystr.rs +0 -0
  120. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/query.rs +0 -0
  121. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/rng.rs +0 -0
  122. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/schema.rs +0 -0
  123. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/sqlite.rs +0 -0
  124. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/toolcall.rs +0 -0
  125. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/types.rs +0 -0
  126. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/value.rs +0 -0
  127. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/core/src/watch.rs +0 -0
  128. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/Cargo.toml +0 -0
  129. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/build.rs +0 -0
  130. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/data/command_prefix_pins.tsv +0 -0
  131. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/actor_bridge.rs +0 -0
  132. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/bin/stub_gen.rs +0 -0
  133. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/codex.rs +0 -0
  134. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/command.rs +0 -0
  135. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/context.rs +0 -0
  136. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/corrections.rs +0 -0
  137. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/discovery.rs +0 -0
  138. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/feedback.rs +0 -0
  139. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/judge.rs +0 -0
  140. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/lexicon.rs +0 -0
  141. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/lib.rs +0 -0
  142. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/mining.rs +0 -0
  143. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/nlp.rs +0 -0
  144. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/python.rs +0 -0
  145. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/score.rs +0 -0
  146. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/sqlite.rs +0 -0
  147. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/toolcall.rs +0 -0
  148. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/attachment.rs +0 -0
  149. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/blocks.rs +0 -0
  150. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/command.rs +0 -0
  151. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/convert.rs +0 -0
  152. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/dunder.rs +0 -0
  153. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/events.rs +0 -0
  154. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/meta.rs +0 -0
  155. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/mod.rs +0 -0
  156. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/print.rs +0 -0
  157. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/store.rs +0 -0
  158. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/system.rs +0 -0
  159. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/toolcall.rs +0 -0
  160. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/toolresult.rs +0 -0
  161. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/views/transcript.rs +0 -0
  162. {cc_transcript-14.20.1 → cc_transcript-14.22.0}/rust/crates/py/src/watch.rs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cc-transcript
3
- Version: 14.20.1
3
+ Version: 14.22.0
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -2500,7 +2500,7 @@ def render_tool_call(name: builtins.str, input_json: builtins.str, turn_chars: b
2500
2500
 
2501
2501
  def render_tool_call_view(call: tools.ToolCall, turn_chars: builtins.int, tool_chars: builtins.int) -> builtins.str: ...
2502
2502
 
2503
- def render_turn_from_events(prompt: builtins.str, events: list[models.TranscriptEvent], turn_chars: builtins.int, tool_chars: builtins.int) -> builtins.str: ...
2503
+ def render_turn_from_events(prompt: builtins.str, events: list[models.TranscriptEvent], turn_chars: builtins.int, tool_chars: builtins.int, tool_results: builtins.bool) -> builtins.str: ...
2504
2504
 
2505
2505
  def score_post_process(spec_json: builtins.str, buckets: typing.Sequence[typing.Sequence[builtins.str]], raw: typing.Sequence[builtins.int]) -> builtins.list[builtins.int]: ...
2506
2506
 
@@ -61,20 +61,39 @@ def prefixed(prefix: str, text: str) -> tuple[str, ...]:
61
61
  return tuple(f"{prefix}{line}" for line in text.splitlines()) or (prefix.rstrip(),)
62
62
 
63
63
 
64
- def render_turn(turn: Turn, *, budget: Budget) -> str:
65
- """Render one turn: the prompt, assistant prose, and every tool call, in order.
64
+ def render_turn(turn: Turn, *, budget: Budget, tool_results: bool = False) -> str:
65
+ """Render one turn: the prompt, the user's mid-turn messages, assistant prose, and every tool call, in order.
66
66
 
67
67
  Prose chunks clip to ``budget.turn_chars``; each tool call renders via
68
- :func:`render_tool_call` under ``budget.tool_chars``.
68
+ :func:`render_tool_call` under ``budget.tool_chars``. An AskUserQuestion answer
69
+ renders as ``user answered:`` with the chosen option's description, the
70
+ selected preview and any notes.
71
+
72
+ Args:
73
+ turn: The turn to render.
74
+ budget: Character budgets for prose and tool calls.
75
+ tool_results: Render each other tool result after its call, as ``result:``,
76
+ or ``failed:`` when the call errored, clipped to ``budget.turn_chars``.
69
77
  """
70
78
  return _native.render_turn_from_events(
71
79
  turn.prompt,
72
80
  list(turn.events),
73
81
  budget.turn_chars,
74
82
  budget.tool_chars,
83
+ tool_results,
75
84
  )
76
85
 
77
86
 
78
- def render_session(activity: SessionActivity, *, budget: Budget) -> str:
79
- """Render every turn of a session under ``budget``, separated by blank lines."""
80
- return "\n\n".join(rendered for turn in activity.turns if (rendered := render_turn(turn, budget=budget)))
87
+ def render_session(activity: SessionActivity, *, budget: Budget, tool_results: bool = False) -> str:
88
+ """Render every turn of a session under ``budget``, separated by blank lines.
89
+
90
+ Args:
91
+ activity: The session to render.
92
+ budget: Character budgets for prose and tool calls.
93
+ tool_results: Render each tool result after its call; see :func:`render_turn`.
94
+ """
95
+ return "\n\n".join(
96
+ rendered
97
+ for turn in activity.turns
98
+ if (rendered := render_turn(turn, budget=budget, tool_results=tool_results))
99
+ )
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cc-transcript"
3
- version = "14.20.1" # informational — releases stamp the version from the git tag
3
+ version = "14.22.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"
@@ -514,7 +514,7 @@ fn turn_ref(turn: &Turn, budget: &Budget) -> TurnRef {
514
514
  tool_use_id: None,
515
515
  })
516
516
  .collect(),
517
- preview: render_turn(turn, budget),
517
+ preview: render_turn(turn, budget, false),
518
518
  tool_digests: turn_tool_uses(turn)
519
519
  .map(|tu| tool_digest(&tu.name, &tu.input).expect("tool input digests"))
520
520
  .collect(),
@@ -1,7 +1,7 @@
1
1
  //! The one renderer, ported from `cc_transcript/render.py` — every cut happens here,
2
2
  //! under a [`Budget`]. Parity notes on the individual helpers.
3
3
 
4
- use std::collections::{HashMap, HashSet};
4
+ use std::collections::HashMap;
5
5
 
6
6
  use chrono::{DateTime, FixedOffset};
7
7
  use sonic_rs::{JsonContainerTrait, JsonType, JsonValueTrait, Value};
@@ -14,13 +14,16 @@ use crate::facts::{McpServerSummary, ToolFact};
14
14
  use crate::filter::{entry_text, event_kind};
15
15
  use crate::ids::encode_string;
16
16
  use crate::pystr;
17
- use crate::toolcall::{parse_tool_call, ToolCall};
17
+ use crate::toolcall::{
18
+ parse_tool_call, parse_tool_result, AskUserQuestionResult, ToolCall, ToolResult,
19
+ };
18
20
  use crate::types::{
19
21
  joined_text, ApiError, AssistantEntry, AttachmentDetail, Attribution, CacheCreation,
20
22
  CompactBoundary, ContentBlock, Entry, EntryMeta, HookInfo, ModelRefusalFallback,
21
23
  PreservedMessages, PreservedSegment, ServerToolUse, StopHookSummary, SystemDetail,
22
24
  ToolResultBlock, TurnDuration, Usage, UserEntry,
23
25
  };
26
+ use crate::value::{field, field_str};
24
27
 
25
28
  const SIZE_UNITS: [&str; 5] = ["B", "KB", "MB", "GB", "TB"];
26
29
  const BLANK_TIME: &str = " ";
@@ -435,14 +438,15 @@ pub fn render_tool_call(call: &ToolCall, budget: &Budget) -> String {
435
438
 
436
439
  /// Render one turn — the prompt, the user's mid-turn messages, assistant prose,
437
440
  /// every tool call, and the user's AskUserQuestion answers, in order (render.py
438
- /// render_turn). Prose clips to `budget.turn_chars`; each tool call and answer
441
+ /// render_turn). With `tool_results`, each other result follows its call. Prose and
442
+ /// tool results clip to `budget.turn_chars`; each tool call and answer preview
439
443
  /// renders under `budget.tool_chars`.
440
- pub fn render_turn(turn: &Turn, budget: &Budget) -> String {
444
+ pub fn render_turn(turn: &Turn, budget: &Budget, tool_results: bool) -> String {
441
445
  let mut parts: Vec<String> = Vec::new();
442
446
  if !turn.prompt.is_empty() {
443
447
  parts.push(format!("user: {}", clip(&turn.prompt, budget.turn_chars)));
444
448
  }
445
- let mut questions: HashSet<&str> = HashSet::new();
449
+ let mut calls: HashMap<&str, &str> = HashMap::new();
446
450
  for &event in &turn.events {
447
451
  match event {
448
452
  Entry::Assistant(assistant) => {
@@ -452,9 +456,7 @@ pub fn render_turn(turn: &Turn, budget: &Budget) -> String {
452
456
  parts.push(format!("assistant: {}", clip(text, budget.turn_chars)));
453
457
  }
454
458
  ContentBlock::ToolUse(tool_use) => {
455
- if tool_use.name == ASK_USER_QUESTION {
456
- questions.insert(&tool_use.id);
457
- }
459
+ calls.insert(&tool_use.id, &tool_use.name);
458
460
  parts.push(render_tool_call(
459
461
  &parse_tool_call(&tool_use.name, &tool_use.input),
460
462
  budget,
@@ -465,17 +467,13 @@ pub fn render_turn(turn: &Turn, budget: &Budget) -> String {
465
467
  }
466
468
  }
467
469
  Entry::User(user) => {
468
- parts.extend(user.blocks().iter().filter_map(|block| match block {
469
- ContentBlock::ToolResult(result)
470
- if !result.is_error && questions.contains(result.tool_use_id.as_str()) =>
471
- {
472
- Some(format!(
473
- "user answered: {}",
474
- clip(&result.content, budget.tool_chars)
475
- ))
470
+ for block in user.blocks() {
471
+ if let ContentBlock::ToolResult(result) = block {
472
+ if let Some(name) = calls.get(result.tool_use_id.as_str()) {
473
+ parts.extend(result_lines(name, result, budget, tool_results));
474
+ }
476
475
  }
477
- _ => None,
478
- }));
476
+ }
479
477
  }
480
478
  Entry::Attachment(attachment) => {
481
479
  if let Some(prompt) = human_queued_prompt(&attachment.detail) {
@@ -488,6 +486,86 @@ pub fn render_turn(turn: &Turn, budget: &Budget) -> String {
488
486
  parts.join("\n")
489
487
  }
490
488
 
489
+ fn result_lines(
490
+ name: &str,
491
+ result: &ToolResultBlock,
492
+ budget: &Budget,
493
+ tool_results: bool,
494
+ ) -> Vec<String> {
495
+ if result.is_error {
496
+ if !tool_results {
497
+ return Vec::new();
498
+ }
499
+ return vec![format!(
500
+ "failed: {}",
501
+ clip(&result.content, budget.turn_chars)
502
+ )];
503
+ }
504
+ if name == ASK_USER_QUESTION {
505
+ if let Some(ToolResult::AskUserQuestion(answer)) = result
506
+ .tool_use_result
507
+ .as_ref()
508
+ .map(|payload| parse_tool_result(name, payload))
509
+ {
510
+ return answer_lines(&answer, budget);
511
+ }
512
+ return vec![format!(
513
+ "user answered: {}",
514
+ clip(&result.content, budget.tool_chars)
515
+ )];
516
+ }
517
+ if !tool_results || pystr::strip(&result.content).is_empty() {
518
+ return Vec::new();
519
+ }
520
+ vec![format!(
521
+ "result: {}",
522
+ clip(&result.content, budget.turn_chars)
523
+ )]
524
+ }
525
+
526
+ fn answer_lines(answer: &AskUserQuestionResult, budget: &Budget) -> Vec<String> {
527
+ let mut lines = Vec::new();
528
+ for (question, label) in &answer.answers {
529
+ let option = chosen_option(&answer.raw, question, label);
530
+ let annotation = answer
531
+ .annotations
532
+ .iter()
533
+ .find_map(|(asked, annotation)| (asked == question).then_some(annotation));
534
+ lines.push(format!(
535
+ "user answered: {} -> {}",
536
+ clip(question, budget.turn_chars),
537
+ clip(label, budget.turn_chars)
538
+ ));
539
+ if let Some(description) = option.and_then(|option| field_str(option, "description")) {
540
+ lines.push(format!(
541
+ " option: {}",
542
+ clip(description, budget.turn_chars)
543
+ ));
544
+ }
545
+ let preview = annotation
546
+ .and_then(|annotation| annotation.preview.as_deref())
547
+ .or_else(|| option.and_then(|option| field_str(option, "preview")));
548
+ if let Some(preview) = preview {
549
+ lines.push(format!(" preview: {}", clip(preview, budget.tool_chars)));
550
+ }
551
+ if let Some(notes) = annotation.and_then(|annotation| annotation.notes.as_deref()) {
552
+ lines.push(format!(" notes: {}", clip(notes, budget.turn_chars)));
553
+ }
554
+ }
555
+ lines
556
+ }
557
+
558
+ fn chosen_option<'a>(payload: &'a Value, question: &str, label: &str) -> Option<&'a Value> {
559
+ field(payload, "questions")?
560
+ .as_array()?
561
+ .iter()
562
+ .find(|asked| field_str(asked, "question") == Some(question))
563
+ .and_then(|asked| field(asked, "options"))
564
+ .and_then(JsonContainerTrait::as_array)?
565
+ .iter()
566
+ .find(|option| field_str(option, "label") == Some(label))
567
+ }
568
+
491
569
  pub(crate) fn human_queued_prompt(detail: &AttachmentDetail) -> Option<&str> {
492
570
  match detail {
493
571
  AttachmentDetail::QueuedCommand(queued)
@@ -72,6 +72,7 @@ pub(crate) fn render_turn_from_events(
72
72
  events: Vec<Bound<'_, PyAny>>,
73
73
  turn_chars: usize,
74
74
  tool_chars: usize,
75
+ tool_results: bool,
75
76
  ) -> PyResult<String> {
76
77
  let entries = events
77
78
  .iter()
@@ -91,6 +92,7 @@ pub(crate) fn render_turn_from_events(
91
92
  turn_chars,
92
93
  tool_chars,
93
94
  },
95
+ tool_results,
94
96
  ))
95
97
  }
96
98
 
File without changes