yamlgraph 0.1.1__py3-none-any.whl
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 yamlgraph might be problematic. Click here for more details.
- examples/__init__.py +1 -0
- examples/storyboard/__init__.py +1 -0
- examples/storyboard/generate_videos.py +335 -0
- examples/storyboard/nodes/__init__.py +10 -0
- examples/storyboard/nodes/animated_character_node.py +248 -0
- examples/storyboard/nodes/animated_image_node.py +138 -0
- examples/storyboard/nodes/character_node.py +162 -0
- examples/storyboard/nodes/image_node.py +118 -0
- examples/storyboard/nodes/replicate_tool.py +238 -0
- examples/storyboard/retry_images.py +118 -0
- tests/__init__.py +1 -0
- tests/conftest.py +178 -0
- tests/integration/__init__.py +1 -0
- tests/integration/test_animated_storyboard.py +63 -0
- tests/integration/test_cli_commands.py +242 -0
- tests/integration/test_map_demo.py +50 -0
- tests/integration/test_memory_demo.py +281 -0
- tests/integration/test_pipeline_flow.py +105 -0
- tests/integration/test_providers.py +163 -0
- tests/integration/test_resume.py +75 -0
- tests/unit/__init__.py +1 -0
- tests/unit/test_agent_nodes.py +200 -0
- tests/unit/test_checkpointer.py +212 -0
- tests/unit/test_cli.py +121 -0
- tests/unit/test_cli_package.py +81 -0
- tests/unit/test_compile_graph_map.py +132 -0
- tests/unit/test_conditions_routing.py +253 -0
- tests/unit/test_config.py +93 -0
- tests/unit/test_conversation_memory.py +270 -0
- tests/unit/test_database.py +145 -0
- tests/unit/test_deprecation.py +104 -0
- tests/unit/test_executor.py +60 -0
- tests/unit/test_executor_async.py +179 -0
- tests/unit/test_export.py +150 -0
- tests/unit/test_expressions.py +178 -0
- tests/unit/test_format_prompt.py +145 -0
- tests/unit/test_generic_report.py +200 -0
- tests/unit/test_graph_commands.py +327 -0
- tests/unit/test_graph_loader.py +299 -0
- tests/unit/test_graph_schema.py +193 -0
- tests/unit/test_inline_schema.py +151 -0
- tests/unit/test_issues.py +164 -0
- tests/unit/test_jinja2_prompts.py +85 -0
- tests/unit/test_langsmith.py +319 -0
- tests/unit/test_llm_factory.py +109 -0
- tests/unit/test_llm_factory_async.py +118 -0
- tests/unit/test_loops.py +403 -0
- tests/unit/test_map_node.py +144 -0
- tests/unit/test_no_backward_compat.py +56 -0
- tests/unit/test_node_factory.py +225 -0
- tests/unit/test_prompts.py +166 -0
- tests/unit/test_python_nodes.py +198 -0
- tests/unit/test_reliability.py +298 -0
- tests/unit/test_result_export.py +234 -0
- tests/unit/test_router.py +296 -0
- tests/unit/test_sanitize.py +99 -0
- tests/unit/test_schema_loader.py +295 -0
- tests/unit/test_shell_tools.py +229 -0
- tests/unit/test_state_builder.py +331 -0
- tests/unit/test_state_builder_map.py +104 -0
- tests/unit/test_state_config.py +197 -0
- tests/unit/test_template.py +190 -0
- tests/unit/test_tool_nodes.py +129 -0
- yamlgraph/__init__.py +35 -0
- yamlgraph/builder.py +110 -0
- yamlgraph/cli/__init__.py +139 -0
- yamlgraph/cli/__main__.py +6 -0
- yamlgraph/cli/commands.py +232 -0
- yamlgraph/cli/deprecation.py +92 -0
- yamlgraph/cli/graph_commands.py +382 -0
- yamlgraph/cli/validators.py +37 -0
- yamlgraph/config.py +67 -0
- yamlgraph/constants.py +66 -0
- yamlgraph/error_handlers.py +226 -0
- yamlgraph/executor.py +275 -0
- yamlgraph/executor_async.py +122 -0
- yamlgraph/graph_loader.py +337 -0
- yamlgraph/map_compiler.py +138 -0
- yamlgraph/models/__init__.py +36 -0
- yamlgraph/models/graph_schema.py +141 -0
- yamlgraph/models/schemas.py +124 -0
- yamlgraph/models/state_builder.py +236 -0
- yamlgraph/node_factory.py +240 -0
- yamlgraph/routing.py +87 -0
- yamlgraph/schema_loader.py +160 -0
- yamlgraph/storage/__init__.py +17 -0
- yamlgraph/storage/checkpointer.py +72 -0
- yamlgraph/storage/database.py +320 -0
- yamlgraph/storage/export.py +269 -0
- yamlgraph/tools/__init__.py +1 -0
- yamlgraph/tools/agent.py +235 -0
- yamlgraph/tools/nodes.py +124 -0
- yamlgraph/tools/python_tool.py +178 -0
- yamlgraph/tools/shell.py +205 -0
- yamlgraph/utils/__init__.py +47 -0
- yamlgraph/utils/conditions.py +157 -0
- yamlgraph/utils/expressions.py +111 -0
- yamlgraph/utils/langsmith.py +308 -0
- yamlgraph/utils/llm_factory.py +118 -0
- yamlgraph/utils/llm_factory_async.py +105 -0
- yamlgraph/utils/logging.py +127 -0
- yamlgraph/utils/prompts.py +116 -0
- yamlgraph/utils/sanitize.py +98 -0
- yamlgraph/utils/template.py +102 -0
- yamlgraph/utils/validators.py +181 -0
- yamlgraph-0.1.1.dist-info/METADATA +854 -0
- yamlgraph-0.1.1.dist-info/RECORD +111 -0
- yamlgraph-0.1.1.dist-info/WHEEL +5 -0
- yamlgraph-0.1.1.dist-info/entry_points.txt +2 -0
- yamlgraph-0.1.1.dist-info/licenses/LICENSE +21 -0
- yamlgraph-0.1.1.dist-info/top_level.txt +3 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""YamlGraph CLI - Command-line interface for yamlgraph.
|
|
2
|
+
|
|
3
|
+
This package provides the CLI entry point and command implementations.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
yamlgraph graph run graphs/yamlgraph.yaml --var topic="AI" --var style=casual
|
|
7
|
+
yamlgraph graph run graphs/router-demo.yaml --var message="hello"
|
|
8
|
+
yamlgraph graph list
|
|
9
|
+
yamlgraph list-runs
|
|
10
|
+
yamlgraph resume --thread-id abc123
|
|
11
|
+
yamlgraph trace --run-id <run-id>
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
|
|
16
|
+
# Import submodules for package access
|
|
17
|
+
from yamlgraph.cli import commands, validators
|
|
18
|
+
from yamlgraph.cli.commands import (
|
|
19
|
+
cmd_export,
|
|
20
|
+
cmd_list_runs,
|
|
21
|
+
cmd_resume,
|
|
22
|
+
cmd_trace,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
# Submodules
|
|
27
|
+
"commands",
|
|
28
|
+
"validators",
|
|
29
|
+
# Entry points
|
|
30
|
+
"main",
|
|
31
|
+
"create_parser",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def create_parser() -> argparse.ArgumentParser:
|
|
36
|
+
"""Create and configure the CLI argument parser.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Configured ArgumentParser for testing and main().
|
|
40
|
+
"""
|
|
41
|
+
parser = argparse.ArgumentParser(
|
|
42
|
+
description="YAMLGraph - YAML-first LLM Pipeline Framework",
|
|
43
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
47
|
+
|
|
48
|
+
# List runs command
|
|
49
|
+
list_parser = subparsers.add_parser("list-runs", help="List recent runs")
|
|
50
|
+
list_parser.add_argument(
|
|
51
|
+
"--limit", "-l", type=int, default=10, help="Maximum runs to show"
|
|
52
|
+
)
|
|
53
|
+
list_parser.set_defaults(func=cmd_list_runs)
|
|
54
|
+
|
|
55
|
+
# Resume command
|
|
56
|
+
resume_parser = subparsers.add_parser("resume", help="Resume a pipeline")
|
|
57
|
+
resume_parser.add_argument(
|
|
58
|
+
"--thread-id", "-i", required=True, help="Thread ID to resume"
|
|
59
|
+
)
|
|
60
|
+
resume_parser.set_defaults(func=cmd_resume)
|
|
61
|
+
|
|
62
|
+
# Trace command
|
|
63
|
+
trace_parser = subparsers.add_parser("trace", help="Show execution trace")
|
|
64
|
+
trace_parser.add_argument(
|
|
65
|
+
"--run-id", "-r", help="Run ID (uses latest if not provided)"
|
|
66
|
+
)
|
|
67
|
+
trace_parser.add_argument(
|
|
68
|
+
"--verbose", "-v", action="store_true", help="Include timing details"
|
|
69
|
+
)
|
|
70
|
+
trace_parser.set_defaults(func=cmd_trace)
|
|
71
|
+
|
|
72
|
+
# Export command
|
|
73
|
+
export_parser = subparsers.add_parser("export", help="Export a run to JSON")
|
|
74
|
+
export_parser.add_argument(
|
|
75
|
+
"--thread-id", "-i", required=True, help="Thread ID to export"
|
|
76
|
+
)
|
|
77
|
+
export_parser.set_defaults(func=cmd_export)
|
|
78
|
+
|
|
79
|
+
# Graph command group (universal runner)
|
|
80
|
+
from yamlgraph.cli.graph_commands import cmd_graph_dispatch
|
|
81
|
+
|
|
82
|
+
graph_parser = subparsers.add_parser(
|
|
83
|
+
"graph", help="Universal graph runner and utilities"
|
|
84
|
+
)
|
|
85
|
+
graph_subparsers = graph_parser.add_subparsers(
|
|
86
|
+
dest="graph_command", help="Graph commands"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# graph run
|
|
90
|
+
graph_run_parser = graph_subparsers.add_parser("run", help="Run any graph")
|
|
91
|
+
graph_run_parser.add_argument("graph_path", help="Path to graph YAML file")
|
|
92
|
+
graph_run_parser.add_argument(
|
|
93
|
+
"--var",
|
|
94
|
+
"-v",
|
|
95
|
+
action="append",
|
|
96
|
+
default=[],
|
|
97
|
+
help="Set state variable (key=value), can repeat",
|
|
98
|
+
)
|
|
99
|
+
graph_run_parser.add_argument(
|
|
100
|
+
"--thread", "-t", type=str, default=None, help="Thread ID for persistence"
|
|
101
|
+
)
|
|
102
|
+
graph_run_parser.add_argument(
|
|
103
|
+
"--export", "-e", action="store_true", help="Export results to files"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# graph list
|
|
107
|
+
graph_subparsers.add_parser("list", help="List available graphs")
|
|
108
|
+
|
|
109
|
+
# graph info
|
|
110
|
+
graph_info_parser = graph_subparsers.add_parser(
|
|
111
|
+
"info", help="Show graph information"
|
|
112
|
+
)
|
|
113
|
+
graph_info_parser.add_argument("graph_path", help="Path to graph YAML file")
|
|
114
|
+
|
|
115
|
+
# graph validate
|
|
116
|
+
graph_validate_parser = graph_subparsers.add_parser(
|
|
117
|
+
"validate", help="Validate graph YAML schema"
|
|
118
|
+
)
|
|
119
|
+
graph_validate_parser.add_argument("graph_path", help="Path to graph YAML file")
|
|
120
|
+
|
|
121
|
+
graph_parser.set_defaults(func=cmd_graph_dispatch)
|
|
122
|
+
|
|
123
|
+
return parser
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def main():
|
|
127
|
+
"""Main CLI entry point."""
|
|
128
|
+
parser = create_parser()
|
|
129
|
+
args = parser.parse_args()
|
|
130
|
+
|
|
131
|
+
if not args.command:
|
|
132
|
+
parser.print_help()
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
args.func(args)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if __name__ == "__main__":
|
|
139
|
+
main()
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""CLI command implementations.
|
|
2
|
+
|
|
3
|
+
Contains all cmd_* functions for CLI subcommands.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
from argparse import Namespace
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
12
|
+
from yamlgraph.cli.validators import validate_run_args
|
|
13
|
+
|
|
14
|
+
# Internal keys to skip when formatting results
|
|
15
|
+
_INTERNAL_KEYS = frozenset(
|
|
16
|
+
{
|
|
17
|
+
"_route",
|
|
18
|
+
"_loop_counts",
|
|
19
|
+
"thread_id",
|
|
20
|
+
"current_step",
|
|
21
|
+
"errors",
|
|
22
|
+
"topic",
|
|
23
|
+
"style",
|
|
24
|
+
"word_count",
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _format_value(value: Any, max_length: int = 200) -> str:
|
|
30
|
+
"""Format a single value for display.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
value: The value to format (str, list, Pydantic model, etc.)
|
|
34
|
+
max_length: Maximum length before truncation
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Formatted string representation
|
|
38
|
+
"""
|
|
39
|
+
if isinstance(value, BaseModel):
|
|
40
|
+
# Format Pydantic model as key: value pairs
|
|
41
|
+
lines = []
|
|
42
|
+
for field_name, field_value in value.model_dump().items():
|
|
43
|
+
formatted = _format_value(field_value, max_length)
|
|
44
|
+
lines.append(f" {field_name}: {formatted}")
|
|
45
|
+
return "\n" + "\n".join(lines)
|
|
46
|
+
|
|
47
|
+
if isinstance(value, list):
|
|
48
|
+
# Format list items
|
|
49
|
+
if not value:
|
|
50
|
+
return "[]"
|
|
51
|
+
if len(value) <= 3:
|
|
52
|
+
return str(value)
|
|
53
|
+
return f"[{len(value)} items]"
|
|
54
|
+
|
|
55
|
+
if isinstance(value, str):
|
|
56
|
+
if len(value) > max_length:
|
|
57
|
+
return value[:max_length] + "..."
|
|
58
|
+
return value
|
|
59
|
+
|
|
60
|
+
return str(value)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _format_result(result: dict[str, Any]) -> None:
|
|
64
|
+
"""Format and print pipeline result generically.
|
|
65
|
+
|
|
66
|
+
Iterates over all non-internal keys in the result dict
|
|
67
|
+
and prints their values. Works with any Pydantic model.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
result: Pipeline result dict with arbitrary Pydantic models
|
|
71
|
+
"""
|
|
72
|
+
for key, value in result.items():
|
|
73
|
+
if key in _INTERNAL_KEYS or value is None:
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
print(f"\nš {key}:")
|
|
77
|
+
formatted = _format_value(value)
|
|
78
|
+
if formatted.startswith("\n"):
|
|
79
|
+
print(formatted)
|
|
80
|
+
else:
|
|
81
|
+
print(f" {formatted}")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def cmd_run(args: Namespace) -> None:
|
|
85
|
+
"""Run the yamlgraph pipeline."""
|
|
86
|
+
if not validate_run_args(args):
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
|
|
89
|
+
from yamlgraph.builder import run_pipeline
|
|
90
|
+
from yamlgraph.storage import YamlGraphDB, export_state
|
|
91
|
+
from yamlgraph.utils import get_run_url, is_tracing_enabled
|
|
92
|
+
|
|
93
|
+
print("\nš Running yamlgraph pipeline")
|
|
94
|
+
print(f" Topic: {args.topic}")
|
|
95
|
+
print(f" Style: {args.style}")
|
|
96
|
+
print(f" Words: {args.word_count}")
|
|
97
|
+
print()
|
|
98
|
+
|
|
99
|
+
# Run pipeline
|
|
100
|
+
result = run_pipeline(
|
|
101
|
+
topic=args.topic,
|
|
102
|
+
style=args.style,
|
|
103
|
+
word_count=args.word_count,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Save to database
|
|
107
|
+
db = YamlGraphDB()
|
|
108
|
+
db.save_state(result["thread_id"], result, status="completed")
|
|
109
|
+
print(f"\nš¾ Saved to database: thread_id={result['thread_id']}")
|
|
110
|
+
|
|
111
|
+
# Export to JSON
|
|
112
|
+
if args.export:
|
|
113
|
+
filepath = export_state(result)
|
|
114
|
+
print(f"š Exported to: {filepath}")
|
|
115
|
+
|
|
116
|
+
# Show results
|
|
117
|
+
print("\n" + "=" * 60)
|
|
118
|
+
print("RESULTS")
|
|
119
|
+
print("=" * 60)
|
|
120
|
+
|
|
121
|
+
_format_result(result)
|
|
122
|
+
|
|
123
|
+
# Show LangSmith link
|
|
124
|
+
if is_tracing_enabled():
|
|
125
|
+
if url := get_run_url():
|
|
126
|
+
print(f"\nš LangSmith: {url}")
|
|
127
|
+
|
|
128
|
+
print()
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def cmd_list_runs(args: Namespace) -> None:
|
|
132
|
+
"""List recent pipeline runs."""
|
|
133
|
+
from yamlgraph.storage import YamlGraphDB
|
|
134
|
+
|
|
135
|
+
db = YamlGraphDB()
|
|
136
|
+
runs = db.list_runs(limit=args.limit)
|
|
137
|
+
|
|
138
|
+
if not runs:
|
|
139
|
+
print("No runs found.")
|
|
140
|
+
return
|
|
141
|
+
|
|
142
|
+
print(f"\nš Recent runs ({len(runs)}):\n")
|
|
143
|
+
print(f"{'Thread ID':<12} {'Status':<12} {'Updated':<20}")
|
|
144
|
+
print("-" * 50)
|
|
145
|
+
|
|
146
|
+
for run in runs:
|
|
147
|
+
print(f"{run['thread_id']:<12} {run['status']:<12} {run['updated_at'][:19]}")
|
|
148
|
+
|
|
149
|
+
print()
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def cmd_resume(args: Namespace) -> None:
|
|
153
|
+
"""Resume a pipeline from saved state."""
|
|
154
|
+
from yamlgraph.builder import build_resume_graph
|
|
155
|
+
from yamlgraph.storage import YamlGraphDB
|
|
156
|
+
|
|
157
|
+
db = YamlGraphDB()
|
|
158
|
+
state = db.load_state(args.thread_id)
|
|
159
|
+
|
|
160
|
+
if not state:
|
|
161
|
+
print(f"ā No run found with thread_id: {args.thread_id}")
|
|
162
|
+
return
|
|
163
|
+
|
|
164
|
+
print(f"\nš Resuming from: {state.get('current_step', 'unknown')}")
|
|
165
|
+
|
|
166
|
+
# Check what's already completed
|
|
167
|
+
if state.get("final_summary"):
|
|
168
|
+
print("ā
Pipeline already complete!")
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
# Show what will be skipped vs run
|
|
172
|
+
skipping = []
|
|
173
|
+
running = []
|
|
174
|
+
if state.get("generated"):
|
|
175
|
+
skipping.append("generate")
|
|
176
|
+
else:
|
|
177
|
+
running.append("generate")
|
|
178
|
+
if state.get("analysis"):
|
|
179
|
+
skipping.append("analyze")
|
|
180
|
+
else:
|
|
181
|
+
running.append("analyze")
|
|
182
|
+
running.append("summarize") # Always runs if we get here
|
|
183
|
+
|
|
184
|
+
if skipping:
|
|
185
|
+
print(f" Skipping: {', '.join(skipping)} (already in state)")
|
|
186
|
+
print(f" Running: {', '.join(running)}")
|
|
187
|
+
|
|
188
|
+
graph = build_resume_graph().compile()
|
|
189
|
+
result = graph.invoke(state)
|
|
190
|
+
|
|
191
|
+
# Save updated state
|
|
192
|
+
db.save_state(args.thread_id, result, status="completed")
|
|
193
|
+
print("\nā
Pipeline completed!")
|
|
194
|
+
|
|
195
|
+
if summary := result.get("final_summary"):
|
|
196
|
+
print(f"\nš Summary: {summary[:200]}...")
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def cmd_trace(args: Namespace) -> None:
|
|
200
|
+
"""Show execution trace for a run."""
|
|
201
|
+
from yamlgraph.utils import get_latest_run_id, get_run_url, print_run_tree
|
|
202
|
+
|
|
203
|
+
run_id = args.run_id or get_latest_run_id()
|
|
204
|
+
|
|
205
|
+
if not run_id:
|
|
206
|
+
print("ā No run ID provided and could not find latest run.")
|
|
207
|
+
return
|
|
208
|
+
|
|
209
|
+
print(f"\nš Execution trace for: {run_id}")
|
|
210
|
+
print("ā" * 50)
|
|
211
|
+
print()
|
|
212
|
+
print_run_tree(run_id, verbose=args.verbose)
|
|
213
|
+
|
|
214
|
+
if url := get_run_url(run_id):
|
|
215
|
+
print(f"\nš View in LangSmith: {url}")
|
|
216
|
+
|
|
217
|
+
print()
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def cmd_export(args: Namespace) -> None:
|
|
221
|
+
"""Export a run to JSON."""
|
|
222
|
+
from yamlgraph.storage import YamlGraphDB, export_state
|
|
223
|
+
|
|
224
|
+
db = YamlGraphDB()
|
|
225
|
+
state = db.load_state(args.thread_id)
|
|
226
|
+
|
|
227
|
+
if not state:
|
|
228
|
+
print(f"ā No run found with thread_id: {args.thread_id}")
|
|
229
|
+
return
|
|
230
|
+
|
|
231
|
+
filepath = export_state(state)
|
|
232
|
+
print(f"ā
Exported to: {filepath}")
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Deprecation utilities for CLI commands.
|
|
2
|
+
|
|
3
|
+
Provides DeprecationError exception and helpers for migrating
|
|
4
|
+
old commands to the universal graph runner.
|
|
5
|
+
|
|
6
|
+
Term 'backward compatibility' signals refactoring need per project guidelines.
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
>>> from yamlgraph.cli.deprecation import DeprecationError, deprecated_command
|
|
10
|
+
>>>
|
|
11
|
+
>>> def cmd_old_command(args):
|
|
12
|
+
... # Signal this command needs refactoring
|
|
13
|
+
... deprecated_command("old", "graph run graphs/new.yaml --var x=y")
|
|
14
|
+
...
|
|
15
|
+
>>> # Running raises:
|
|
16
|
+
>>> # DeprecationError: DEPRECATED: 'old' is deprecated.
|
|
17
|
+
>>> # Use 'graph run graphs/new.yaml --var x=y' instead.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DeprecationError(Exception):
|
|
22
|
+
"""Raised when a deprecated command is used.
|
|
23
|
+
|
|
24
|
+
Signals "Refactor me" - deprecated commands should be removed.
|
|
25
|
+
|
|
26
|
+
Attributes:
|
|
27
|
+
old_command: The deprecated command being used
|
|
28
|
+
new_command: The replacement command to use instead
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, old_command: str, new_command: str):
|
|
32
|
+
self.old_command = old_command
|
|
33
|
+
self.new_command = new_command
|
|
34
|
+
message = (
|
|
35
|
+
f"DEPRECATED: '{old_command}' is deprecated. Use '{new_command}' instead."
|
|
36
|
+
)
|
|
37
|
+
super().__init__(message)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# Command mappings: old command -> graph path
|
|
41
|
+
COMMAND_MAPPINGS = {
|
|
42
|
+
"route": "graphs/router-demo.yaml",
|
|
43
|
+
"refine": "graphs/reflexion-demo.yaml",
|
|
44
|
+
"git-report": "graphs/git-report.yaml",
|
|
45
|
+
"memory-demo": "graphs/memory-demo.yaml",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# Variable mappings: old command -> arg name -> var name
|
|
49
|
+
ARG_MAPPINGS = {
|
|
50
|
+
"route": {"message": "message"},
|
|
51
|
+
"refine": {"topic": "topic"},
|
|
52
|
+
"git-report": {"query": "input"},
|
|
53
|
+
"memory-demo": {"input": "input"},
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_replacement_command(old_command: str, args: dict[str, str]) -> str | None:
|
|
58
|
+
"""Get the replacement graph run command.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
old_command: The deprecated command name
|
|
62
|
+
args: Dict of argument values
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Replacement command string, or None if unknown command
|
|
66
|
+
"""
|
|
67
|
+
graph_path = COMMAND_MAPPINGS.get(old_command)
|
|
68
|
+
if not graph_path:
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
# Build --var arguments
|
|
72
|
+
var_args = []
|
|
73
|
+
arg_mapping = ARG_MAPPINGS.get(old_command, {})
|
|
74
|
+
for arg_name, var_name in arg_mapping.items():
|
|
75
|
+
if arg_name in args:
|
|
76
|
+
var_args.append(f"--var {var_name}={args[arg_name]}")
|
|
77
|
+
|
|
78
|
+
var_str = " ".join(var_args)
|
|
79
|
+
return f"graph run {graph_path} {var_str}".strip()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def deprecated_command(old_command: str, new_command: str) -> None:
|
|
83
|
+
"""Raise DeprecationError for a deprecated command.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
old_command: The deprecated command being used
|
|
87
|
+
new_command: The replacement command suggestion
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
DeprecationError: Always raised to signal deprecation
|
|
91
|
+
"""
|
|
92
|
+
raise DeprecationError(old_command, new_command)
|