workgraph 0.3.3__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.
- workgraph-0.3.3/LICENSE +21 -0
- workgraph-0.3.3/PKG-INFO +139 -0
- workgraph-0.3.3/README.md +126 -0
- workgraph-0.3.3/pyproject.toml +58 -0
- workgraph-0.3.3/src/workgraph/__init__.py +1 -0
- workgraph-0.3.3/src/workgraph/claude.py +106 -0
- workgraph-0.3.3/src/workgraph/cli.py +379 -0
- workgraph-0.3.3/src/workgraph/codex.py +232 -0
- workgraph-0.3.3/src/workgraph/definitions/agents/wg_code-review.md +14 -0
- workgraph-0.3.3/src/workgraph/definitions/agents/wg_design.md +57 -0
- workgraph-0.3.3/src/workgraph/definitions/agents/wg_implement.md +39 -0
- workgraph-0.3.3/src/workgraph/definitions/agents/wg_overengineering-review.md +13 -0
- workgraph-0.3.3/src/workgraph/definitions/agents/wg_plan.md +79 -0
- workgraph-0.3.3/src/workgraph/definitions/agents/wg_pr.md +33 -0
- workgraph-0.3.3/src/workgraph/definitions/agents/wg_summarize-review.md +10 -0
- workgraph-0.3.3/src/workgraph/definitions/workflows/wg.toml +101 -0
- workgraph-0.3.3/src/workgraph/definitions/workflows/wg_codex.toml +106 -0
- workgraph-0.3.3/src/workgraph/graph.py +360 -0
- workgraph-0.3.3/src/workgraph/harness.py +112 -0
- workgraph-0.3.3/src/workgraph/run.py +942 -0
- workgraph-0.3.3/src/workgraph/show.py +676 -0
- workgraph-0.3.3/src/workgraph/workflow.py +263 -0
workgraph-0.3.3/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Maxime Schmitt
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
workgraph-0.3.3/PKG-INFO
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: workgraph
|
|
3
|
+
Version: 0.3.3
|
|
4
|
+
Summary: Graph workflow orchestrator.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Dist: termaid[rich]>=0.8.0
|
|
8
|
+
Requires-Dist: tomlkit>=0.15.1
|
|
9
|
+
Requires-Python: >=3.12
|
|
10
|
+
Project-URL: Changelog, https://github.com/sylmarien/workgraph/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Repository, https://github.com/sylmarien/workgraph
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# workgraph
|
|
15
|
+
|
|
16
|
+
workgraph orchestrates development workflows declared as graphs. Nodes run
|
|
17
|
+
agents or commands; a node's outcome selects the transition to follow. The
|
|
18
|
+
developer writes the workflow once and starts a run from a harness session
|
|
19
|
+
with `/workgraph`. The run prints one progress line per node. One command
|
|
20
|
+
resumes a stopped run.
|
|
21
|
+
|
|
22
|
+
The CLI bundles workflow and agent definitions; [Workflow
|
|
23
|
+
files](docs/workflow-files.md) lists them. This repository runs the bundled
|
|
24
|
+
`wg` workflow on itself:
|
|
25
|
+
|
|
26
|
+
```mermaid
|
|
27
|
+
flowchart TD
|
|
28
|
+
design([design])
|
|
29
|
+
design -->|done| approve-design
|
|
30
|
+
approve-design -->|accept| plan
|
|
31
|
+
approve-design -->|reject| design
|
|
32
|
+
plan -->|done| approve-plan
|
|
33
|
+
approve-plan -->|accept| implement
|
|
34
|
+
approve-plan -->|reject| plan
|
|
35
|
+
implement -->|done| test
|
|
36
|
+
test -->|pass| review
|
|
37
|
+
test -->|fail| implement
|
|
38
|
+
review --> code-review
|
|
39
|
+
review --> overengineering-review
|
|
40
|
+
review -->|pass| pr
|
|
41
|
+
review -->|fail| review-loop
|
|
42
|
+
review-loop -->|pass| implement
|
|
43
|
+
review-loop -->|fail| implement
|
|
44
|
+
review-loop -->|LIMIT| summary
|
|
45
|
+
summary -->|done| pr
|
|
46
|
+
pr -->|done| END
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
As a Claude Code plugin:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
/plugin marketplace add sylmarien/workgraph
|
|
55
|
+
/plugin install workgraph@workgraph
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Installing the plugin adds the `/workgraph` skill. The plugin's `install`
|
|
59
|
+
skill installs the CLI with `uv`, and its `update` skill upgrades it. Both
|
|
60
|
+
check that `uv` is on `PATH` and install nothing else.
|
|
61
|
+
|
|
62
|
+
The CLI bundles workflow and agent definitions. A user's own definitions
|
|
63
|
+
shadow them; see [Workflow files](docs/workflow-files.md) for the bundled
|
|
64
|
+
definitions and the resolution order.
|
|
65
|
+
|
|
66
|
+
As a Codex plugin:
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
codex plugin marketplace add sylmarien/workgraph
|
|
70
|
+
codex plugin add workgraph@workgraph
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Start a new Codex session and invoke `$workgraph <workflow> "#<issue>"`.
|
|
74
|
+
The plugin shares the install, update, and run skills with the Claude Code
|
|
75
|
+
plugin. The bundled workflows run nodes on the Claude harness, so they
|
|
76
|
+
require `claude` and `uv` on `PATH` in Codex too.
|
|
77
|
+
|
|
78
|
+
Codex reads the repository's existing marketplace at
|
|
79
|
+
`.claude-plugin/marketplace.json` and its manifest at
|
|
80
|
+
`.codex-plugin/plugin.json`. Both plugins ship in the same Git release.
|
|
81
|
+
The patch, minor, and major release workflows update both manifests and
|
|
82
|
+
the CLI to the same version. See the
|
|
83
|
+
[Codex packaging documentation](https://developers.openai.com/plugins/build/plugins).
|
|
84
|
+
|
|
85
|
+
Without the plugin:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
uv tool install workgraph
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`pip install workgraph` installs the same package from PyPI.
|
|
92
|
+
`uv tool upgrade workgraph` upgrades it. Requires Python 3.12+. An agent
|
|
93
|
+
node additionally requires the CLI of its harness on `PATH`: `claude` for
|
|
94
|
+
`harness = "claude"`, `codex` for `harness = "codex"`.
|
|
95
|
+
|
|
96
|
+
## Example
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
workgraph run wg "#12"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
design: done
|
|
104
|
+
approve-design: parked
|
|
105
|
+
parked at approve-design: Plan from this design? · spent 1m20s · $0.15
|
|
106
|
+
Review material from design:
|
|
107
|
+
https://github.com/sylmarien/workgraph/issues/12#issuecomment-5550441682
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
workgraph resume --decision accept
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
approve-design: accept
|
|
116
|
+
plan: done
|
|
117
|
+
approve-plan: parked
|
|
118
|
+
parked at approve-plan: Implement this plan? · spent 4m05s · $0.42
|
|
119
|
+
Review material from plan:
|
|
120
|
+
<the plan>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`workgraph resume --decision accept` delivers the decision and resumes the
|
|
124
|
+
run.
|
|
125
|
+
|
|
126
|
+
## Reference
|
|
127
|
+
|
|
128
|
+
- [Commands](docs/commands.md)
|
|
129
|
+
- [Workflow files](docs/workflow-files.md)
|
|
130
|
+
- [Agent definitions](docs/agent-definitions.md)
|
|
131
|
+
|
|
132
|
+
## Development
|
|
133
|
+
|
|
134
|
+
```sh
|
|
135
|
+
uv sync
|
|
136
|
+
uv run ruff check && uv run ruff format --check && uv run mypy && uv run pytest
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The dogfood workflow runs the same gate: `workgraph run wg "#<issue>"`.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# workgraph
|
|
2
|
+
|
|
3
|
+
workgraph orchestrates development workflows declared as graphs. Nodes run
|
|
4
|
+
agents or commands; a node's outcome selects the transition to follow. The
|
|
5
|
+
developer writes the workflow once and starts a run from a harness session
|
|
6
|
+
with `/workgraph`. The run prints one progress line per node. One command
|
|
7
|
+
resumes a stopped run.
|
|
8
|
+
|
|
9
|
+
The CLI bundles workflow and agent definitions; [Workflow
|
|
10
|
+
files](docs/workflow-files.md) lists them. This repository runs the bundled
|
|
11
|
+
`wg` workflow on itself:
|
|
12
|
+
|
|
13
|
+
```mermaid
|
|
14
|
+
flowchart TD
|
|
15
|
+
design([design])
|
|
16
|
+
design -->|done| approve-design
|
|
17
|
+
approve-design -->|accept| plan
|
|
18
|
+
approve-design -->|reject| design
|
|
19
|
+
plan -->|done| approve-plan
|
|
20
|
+
approve-plan -->|accept| implement
|
|
21
|
+
approve-plan -->|reject| plan
|
|
22
|
+
implement -->|done| test
|
|
23
|
+
test -->|pass| review
|
|
24
|
+
test -->|fail| implement
|
|
25
|
+
review --> code-review
|
|
26
|
+
review --> overengineering-review
|
|
27
|
+
review -->|pass| pr
|
|
28
|
+
review -->|fail| review-loop
|
|
29
|
+
review-loop -->|pass| implement
|
|
30
|
+
review-loop -->|fail| implement
|
|
31
|
+
review-loop -->|LIMIT| summary
|
|
32
|
+
summary -->|done| pr
|
|
33
|
+
pr -->|done| END
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
As a Claude Code plugin:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
/plugin marketplace add sylmarien/workgraph
|
|
42
|
+
/plugin install workgraph@workgraph
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Installing the plugin adds the `/workgraph` skill. The plugin's `install`
|
|
46
|
+
skill installs the CLI with `uv`, and its `update` skill upgrades it. Both
|
|
47
|
+
check that `uv` is on `PATH` and install nothing else.
|
|
48
|
+
|
|
49
|
+
The CLI bundles workflow and agent definitions. A user's own definitions
|
|
50
|
+
shadow them; see [Workflow files](docs/workflow-files.md) for the bundled
|
|
51
|
+
definitions and the resolution order.
|
|
52
|
+
|
|
53
|
+
As a Codex plugin:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
codex plugin marketplace add sylmarien/workgraph
|
|
57
|
+
codex plugin add workgraph@workgraph
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Start a new Codex session and invoke `$workgraph <workflow> "#<issue>"`.
|
|
61
|
+
The plugin shares the install, update, and run skills with the Claude Code
|
|
62
|
+
plugin. The bundled workflows run nodes on the Claude harness, so they
|
|
63
|
+
require `claude` and `uv` on `PATH` in Codex too.
|
|
64
|
+
|
|
65
|
+
Codex reads the repository's existing marketplace at
|
|
66
|
+
`.claude-plugin/marketplace.json` and its manifest at
|
|
67
|
+
`.codex-plugin/plugin.json`. Both plugins ship in the same Git release.
|
|
68
|
+
The patch, minor, and major release workflows update both manifests and
|
|
69
|
+
the CLI to the same version. See the
|
|
70
|
+
[Codex packaging documentation](https://developers.openai.com/plugins/build/plugins).
|
|
71
|
+
|
|
72
|
+
Without the plugin:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
uv tool install workgraph
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`pip install workgraph` installs the same package from PyPI.
|
|
79
|
+
`uv tool upgrade workgraph` upgrades it. Requires Python 3.12+. An agent
|
|
80
|
+
node additionally requires the CLI of its harness on `PATH`: `claude` for
|
|
81
|
+
`harness = "claude"`, `codex` for `harness = "codex"`.
|
|
82
|
+
|
|
83
|
+
## Example
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
workgraph run wg "#12"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
design: done
|
|
91
|
+
approve-design: parked
|
|
92
|
+
parked at approve-design: Plan from this design? · spent 1m20s · $0.15
|
|
93
|
+
Review material from design:
|
|
94
|
+
https://github.com/sylmarien/workgraph/issues/12#issuecomment-5550441682
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
workgraph resume --decision accept
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
approve-design: accept
|
|
103
|
+
plan: done
|
|
104
|
+
approve-plan: parked
|
|
105
|
+
parked at approve-plan: Implement this plan? · spent 4m05s · $0.42
|
|
106
|
+
Review material from plan:
|
|
107
|
+
<the plan>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`workgraph resume --decision accept` delivers the decision and resumes the
|
|
111
|
+
run.
|
|
112
|
+
|
|
113
|
+
## Reference
|
|
114
|
+
|
|
115
|
+
- [Commands](docs/commands.md)
|
|
116
|
+
- [Workflow files](docs/workflow-files.md)
|
|
117
|
+
- [Agent definitions](docs/agent-definitions.md)
|
|
118
|
+
|
|
119
|
+
## Development
|
|
120
|
+
|
|
121
|
+
```sh
|
|
122
|
+
uv sync
|
|
123
|
+
uv run ruff check && uv run ruff format --check && uv run mypy && uv run pytest
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The dogfood workflow runs the same gate: `workgraph run wg "#<issue>"`.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "workgraph"
|
|
3
|
+
version = "0.3.3"
|
|
4
|
+
description = "Graph workflow orchestrator."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
dependencies = [
|
|
10
|
+
"termaid[rich]>=0.8.0",
|
|
11
|
+
"tomlkit>=0.15.1",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.urls]
|
|
15
|
+
Repository = "https://github.com/sylmarien/workgraph"
|
|
16
|
+
Changelog = "https://github.com/sylmarien/workgraph/blob/main/CHANGELOG.md"
|
|
17
|
+
|
|
18
|
+
[project.scripts]
|
|
19
|
+
workgraph = "workgraph.cli:main"
|
|
20
|
+
|
|
21
|
+
[build-system]
|
|
22
|
+
requires = ["uv_build>=0.8.17,<0.9.0"]
|
|
23
|
+
build-backend = "uv_build"
|
|
24
|
+
|
|
25
|
+
[dependency-groups]
|
|
26
|
+
dev = [
|
|
27
|
+
"mypy>=1.17",
|
|
28
|
+
"pytest>=8.4",
|
|
29
|
+
"pytest-cov>=6.2",
|
|
30
|
+
"python-semantic-release>=10.6.2",
|
|
31
|
+
"ruff>=0.12",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[tool.ruff]
|
|
35
|
+
line-length = 100
|
|
36
|
+
|
|
37
|
+
[tool.ruff.lint]
|
|
38
|
+
select = ["E", "F", "W", "I", "UP", "B", "SIM"]
|
|
39
|
+
|
|
40
|
+
[tool.ruff.lint.pycodestyle]
|
|
41
|
+
max-line-length = 120
|
|
42
|
+
|
|
43
|
+
[tool.mypy]
|
|
44
|
+
strict = true
|
|
45
|
+
files = ["src", "tests"]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
testpaths = ["tests"]
|
|
49
|
+
addopts = "--cov=workgraph --cov-report=term-missing"
|
|
50
|
+
|
|
51
|
+
[tool.coverage.report]
|
|
52
|
+
fail_under = 100
|
|
53
|
+
|
|
54
|
+
[tool.semantic_release]
|
|
55
|
+
commit_parser = "release_parser:AlwaysPatchCommitParser"
|
|
56
|
+
version_toml = ["pyproject.toml:project.version"]
|
|
57
|
+
version_variables = [".claude-plugin/plugin.json:version", ".codex-plugin/plugin.json:version"]
|
|
58
|
+
allow_zero_version = true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Graph workflow orchestrator."""
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""The Claude Code harness: argv, result reading, and transcript rendering."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import textwrap
|
|
5
|
+
from collections.abc import Iterator, Sequence
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from rich.text import Text
|
|
10
|
+
|
|
11
|
+
from workgraph.harness import (
|
|
12
|
+
AgentInvocation,
|
|
13
|
+
NodeFailure,
|
|
14
|
+
iter_jsonl_events,
|
|
15
|
+
read_last_value,
|
|
16
|
+
split_lines,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@contextmanager
|
|
21
|
+
def build_argv(invocation: AgentInvocation) -> Iterator[list[str]]:
|
|
22
|
+
"""Yield the argv that runs the agent through the Claude Code CLI."""
|
|
23
|
+
agent_definition = invocation.agent_definition
|
|
24
|
+
agents = {
|
|
25
|
+
invocation.agent_name: {
|
|
26
|
+
"description": agent_definition.get("description", ""),
|
|
27
|
+
"prompt": agent_definition["prompt"],
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
# No --bare: bare mode reads no OAuth credentials, so agent nodes cannot
|
|
31
|
+
# authenticate for subscription users. Accepted cost: hooks and plugins
|
|
32
|
+
# load on every spawn.
|
|
33
|
+
argv = [
|
|
34
|
+
"claude",
|
|
35
|
+
"-p",
|
|
36
|
+
invocation.prompt,
|
|
37
|
+
"--output-format",
|
|
38
|
+
"stream-json",
|
|
39
|
+
"--verbose",
|
|
40
|
+
"--json-schema",
|
|
41
|
+
json.dumps(invocation.outcome_schema),
|
|
42
|
+
"--agents",
|
|
43
|
+
json.dumps(agents),
|
|
44
|
+
"--agent",
|
|
45
|
+
invocation.agent_name,
|
|
46
|
+
"--permission-mode",
|
|
47
|
+
"dontAsk",
|
|
48
|
+
"--model",
|
|
49
|
+
invocation.model,
|
|
50
|
+
"--effort",
|
|
51
|
+
invocation.effort,
|
|
52
|
+
]
|
|
53
|
+
allowed_tools = agent_definition.get("tools", invocation.allowed_tools)
|
|
54
|
+
if allowed_tools is not None:
|
|
55
|
+
argv += ["--allowedTools", allowed_tools]
|
|
56
|
+
if invocation.session is not None:
|
|
57
|
+
# The node run continues the session in place.
|
|
58
|
+
argv += ["--resume", invocation.session]
|
|
59
|
+
yield argv
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def read_result(invocation: AgentInvocation, stdout_lines: Sequence[str]) -> tuple[Any, float]:
|
|
63
|
+
"""Return the structured output of the last result event and the cost it reports."""
|
|
64
|
+
agent_node_name = invocation.agent_node_name
|
|
65
|
+
result_events = [
|
|
66
|
+
event for event in iter_jsonl_events(stdout_lines) if event.get("type") == "result"
|
|
67
|
+
]
|
|
68
|
+
if not result_events:
|
|
69
|
+
raise NodeFailure(f"node '{agent_node_name}': agent output holds no result event")
|
|
70
|
+
result_event = result_events[-1]
|
|
71
|
+
try:
|
|
72
|
+
cost = float(result_event.get("total_cost_usd") or 0)
|
|
73
|
+
except (TypeError, ValueError):
|
|
74
|
+
# A malformed cost counts as zero; the run continues.
|
|
75
|
+
cost = 0.0
|
|
76
|
+
if result_event.get("is_error"):
|
|
77
|
+
raise NodeFailure(f"node '{agent_node_name}': agent reported an error", cost)
|
|
78
|
+
return result_event.get("structured_output"), cost
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def read_session(stdout_lines: Sequence[str]) -> str | None:
|
|
82
|
+
"""Return the session id of the last stream event that carries one."""
|
|
83
|
+
return read_last_value(iter_jsonl_events(stdout_lines), "session_id")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def render_transcript(stdout_lines: Sequence[str]) -> list[Text]:
|
|
87
|
+
"""Render the text blocks and tool calls of stream-json lines. Drop every other line."""
|
|
88
|
+
transcript_rows: list[Text] = []
|
|
89
|
+
for stream_event in iter_jsonl_events(stdout_lines):
|
|
90
|
+
if stream_event.get("type") != "assistant":
|
|
91
|
+
continue
|
|
92
|
+
for block in stream_event["message"]["content"]:
|
|
93
|
+
if block["type"] == "text":
|
|
94
|
+
transcript_rows += split_lines(block["text"])
|
|
95
|
+
elif block["type"] == "tool_use" and block["name"] != "StructuredOutput":
|
|
96
|
+
transcript_rows.append(
|
|
97
|
+
Text(f"▸ {block['name']}: {_summarize_tool_input(block['input'])}", "bold")
|
|
98
|
+
)
|
|
99
|
+
return transcript_rows
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _summarize_tool_input(tool_input: dict[str, Any]) -> str:
|
|
103
|
+
for key in ("command", "file_path", "pattern", "url"):
|
|
104
|
+
if key in tool_input:
|
|
105
|
+
return str(tool_input[key])
|
|
106
|
+
return textwrap.shorten(json.dumps(tool_input), 100, placeholder="...")
|