langgraph-init-cli 0.1.0__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.
- langgraph_cli/__init__.py +5 -0
- langgraph_cli/cli.py +42 -0
- langgraph_cli/generator.py +47 -0
- langgraph_cli/templates/advanced/README.md +3 -0
- langgraph_cli/templates/advanced/langgraph.json +6 -0
- langgraph_cli/templates/advanced/pyproject.toml +20 -0
- langgraph_cli/templates/advanced/src/__init__.py +1 -0
- langgraph_cli/templates/advanced/src/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/__init__.py +1 -0
- langgraph_cli/templates/advanced/src/app/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/__pycache__/main.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/graph/__init__.py +1 -0
- langgraph_cli/templates/advanced/src/app/graph/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/graph/__pycache__/builder.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/graph/__pycache__/constants.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/graph/__pycache__/edges.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/graph/__pycache__/registry.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/graph/__pycache__/state.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/graph/builder.py +18 -0
- langgraph_cli/templates/advanced/src/app/graph/constants.py +20 -0
- langgraph_cli/templates/advanced/src/app/graph/edges.py +14 -0
- langgraph_cli/templates/advanced/src/app/graph/registry.py +8 -0
- langgraph_cli/templates/advanced/src/app/graph/state.py +9 -0
- langgraph_cli/templates/advanced/src/app/main.py +12 -0
- langgraph_cli/templates/advanced/src/app/nodes/__init__.py +1 -0
- langgraph_cli/templates/advanced/src/app/nodes/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/nodes/__pycache__/intent.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/nodes/__pycache__/output.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/nodes/__pycache__/processing.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/nodes/intent.py +9 -0
- langgraph_cli/templates/advanced/src/app/nodes/output.py +10 -0
- langgraph_cli/templates/advanced/src/app/nodes/processing.py +14 -0
- langgraph_cli/templates/advanced/src/app/prompts/__init__.py +1 -0
- langgraph_cli/templates/advanced/src/app/prompts/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/prompts/__pycache__/registry.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/prompts/registry.py +12 -0
- langgraph_cli/templates/advanced/src/app/services/__init__.py +1 -0
- langgraph_cli/templates/advanced/src/app/services/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/services/__pycache__/prompt_service.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/services/prompt_service.py +6 -0
- langgraph_cli/templates/advanced/src/app/utils/__init__.py +1 -0
- langgraph_cli/templates/advanced/src/app/utils/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/utils/__pycache__/logger.cpython-313.pyc +0 -0
- langgraph_cli/templates/advanced/src/app/utils/logger.py +6 -0
- langgraph_cli/templates/base/README.md +3 -0
- langgraph_cli/templates/base/langgraph.json +6 -0
- langgraph_cli/templates/base/pyproject.toml +20 -0
- langgraph_cli/templates/base/src/__init__.py +1 -0
- langgraph_cli/templates/base/src/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/base/src/app/__init__.py +1 -0
- langgraph_cli/templates/base/src/app/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/base/src/app/__pycache__/main.cpython-313.pyc +0 -0
- langgraph_cli/templates/base/src/app/__pycache__/nodes.cpython-313.pyc +0 -0
- langgraph_cli/templates/base/src/app/__pycache__/state.cpython-313.pyc +0 -0
- langgraph_cli/templates/base/src/app/main.py +27 -0
- langgraph_cli/templates/base/src/app/nodes.py +22 -0
- langgraph_cli/templates/base/src/app/state.py +7 -0
- langgraph_cli/templates/production/README.md +121 -0
- langgraph_cli/templates/production/langgraph.json +6 -0
- langgraph_cli/templates/production/pyproject.toml +20 -0
- langgraph_cli/templates/production/src/__init__.py +1 -0
- langgraph_cli/templates/production/src/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/__init__.py +1 -0
- langgraph_cli/templates/production/src/app/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/__pycache__/config.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/__pycache__/main.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/api/__init__.py +1 -0
- langgraph_cli/templates/production/src/app/api/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/api/__pycache__/app.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/api/__pycache__/routes.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/api/app.py +11 -0
- langgraph_cli/templates/production/src/app/api/routes.py +16 -0
- langgraph_cli/templates/production/src/app/config.py +37 -0
- langgraph_cli/templates/production/src/app/evaluation/__init__.py +1 -0
- langgraph_cli/templates/production/src/app/evaluation/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/evaluation/__pycache__/evaluator.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/evaluation/__pycache__/scoring.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/evaluation/evaluator.py +12 -0
- langgraph_cli/templates/production/src/app/evaluation/scoring.py +2 -0
- langgraph_cli/templates/production/src/app/graph/__init__.py +1 -0
- langgraph_cli/templates/production/src/app/graph/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/graph/__pycache__/builder.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/graph/__pycache__/constants.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/graph/__pycache__/edges.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/graph/__pycache__/registry.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/graph/__pycache__/state.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/graph/builder.py +20 -0
- langgraph_cli/templates/production/src/app/graph/constants.py +28 -0
- langgraph_cli/templates/production/src/app/graph/edges.py +21 -0
- langgraph_cli/templates/production/src/app/graph/registry.py +10 -0
- langgraph_cli/templates/production/src/app/graph/state.py +15 -0
- langgraph_cli/templates/production/src/app/main.py +27 -0
- langgraph_cli/templates/production/src/app/models/__init__.py +1 -0
- langgraph_cli/templates/production/src/app/models/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/models/__pycache__/schema.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/models/__pycache__/workflow.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/models/schema.py +11 -0
- langgraph_cli/templates/production/src/app/models/workflow.py +30 -0
- langgraph_cli/templates/production/src/app/nodes/__init__.py +1 -0
- langgraph_cli/templates/production/src/app/nodes/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/nodes/__pycache__/error.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/nodes/__pycache__/intent.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/nodes/__pycache__/output.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/nodes/__pycache__/processing.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/nodes/__pycache__/validation.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/nodes/error.py +7 -0
- langgraph_cli/templates/production/src/app/nodes/intent.py +21 -0
- langgraph_cli/templates/production/src/app/nodes/output.py +13 -0
- langgraph_cli/templates/production/src/app/nodes/processing.py +32 -0
- langgraph_cli/templates/production/src/app/nodes/validation.py +22 -0
- langgraph_cli/templates/production/src/app/observability/__init__.py +1 -0
- langgraph_cli/templates/production/src/app/observability/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/observability/__pycache__/langsmith.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/observability/__pycache__/metrics.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/observability/langsmith.py +31 -0
- langgraph_cli/templates/production/src/app/observability/metrics.py +15 -0
- langgraph_cli/templates/production/src/app/prompts/__init__.py +1 -0
- langgraph_cli/templates/production/src/app/prompts/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/prompts/__pycache__/registry.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/prompts/registry.py +20 -0
- langgraph_cli/templates/production/src/app/prompts/versions/extraction/v1.txt +1 -0
- langgraph_cli/templates/production/src/app/prompts/versions/intent/v1.txt +1 -0
- langgraph_cli/templates/production/src/app/prompts/versions/intent/v2.txt +1 -0
- langgraph_cli/templates/production/src/app/prompts/versions/validation/v1.txt +1 -0
- langgraph_cli/templates/production/src/app/services/__init__.py +1 -0
- langgraph_cli/templates/production/src/app/services/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/services/__pycache__/evaluation_service.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/services/__pycache__/llm_service.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/services/__pycache__/prompt_service.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/services/__pycache__/tool_service.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/services/__pycache__/versioning_service.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/services/evaluation_service.py +19 -0
- langgraph_cli/templates/production/src/app/services/llm_service.py +56 -0
- langgraph_cli/templates/production/src/app/services/prompt_service.py +21 -0
- langgraph_cli/templates/production/src/app/services/tool_service.py +22 -0
- langgraph_cli/templates/production/src/app/services/versioning_service.py +12 -0
- langgraph_cli/templates/production/src/app/storage/__init__.py +1 -0
- langgraph_cli/templates/production/src/app/storage/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/storage/__pycache__/cache.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/storage/__pycache__/prompt_store.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/storage/__pycache__/workflow_store.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/storage/cache.py +12 -0
- langgraph_cli/templates/production/src/app/storage/prompt_store.py +11 -0
- langgraph_cli/templates/production/src/app/storage/workflow_store.py +13 -0
- langgraph_cli/templates/production/src/app/tools/__init__.py +1 -0
- langgraph_cli/templates/production/src/app/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/tools/__pycache__/base.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/tools/__pycache__/registry.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/tools/api/__pycache__/http_tool.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/tools/api/http_tool.py +12 -0
- langgraph_cli/templates/production/src/app/tools/base.py +15 -0
- langgraph_cli/templates/production/src/app/tools/db/__pycache__/query_tool.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/tools/db/query_tool.py +12 -0
- langgraph_cli/templates/production/src/app/tools/rag/__pycache__/retriever_tool.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/tools/rag/retriever_tool.py +18 -0
- langgraph_cli/templates/production/src/app/tools/registry.py +26 -0
- langgraph_cli/templates/production/src/app/tools/utils/__pycache__/calculator_tool.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/tools/utils/calculator_tool.py +21 -0
- langgraph_cli/templates/production/src/app/utils/__init__.py +1 -0
- langgraph_cli/templates/production/src/app/utils/__pycache__/__init__.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/utils/__pycache__/logger.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/utils/__pycache__/parallel.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/utils/__pycache__/tracing.cpython-313.pyc +0 -0
- langgraph_cli/templates/production/src/app/utils/logger.py +33 -0
- langgraph_cli/templates/production/src/app/utils/parallel.py +9 -0
- langgraph_cli/templates/production/src/app/utils/tracing.py +16 -0
- langgraph_init_cli-0.1.0.dist-info/METADATA +383 -0
- langgraph_init_cli-0.1.0.dist-info/RECORD +172 -0
- langgraph_init_cli-0.1.0.dist-info/WHEEL +5 -0
- langgraph_init_cli-0.1.0.dist-info/entry_points.txt +2 -0
- langgraph_init_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- langgraph_init_cli-0.1.0.dist-info/top_level.txt +1 -0
langgraph_cli/cli.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from langgraph_cli.generator import TEMPLATE_NAMES, scaffold_project
|
|
6
|
+
|
|
7
|
+
app = typer.Typer(
|
|
8
|
+
add_completion=False,
|
|
9
|
+
help="Scaffold LangGraph projects with modular templates.",
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@app.command()
|
|
14
|
+
def main(
|
|
15
|
+
project_name: str = typer.Argument(..., help="Directory name for the new project."),
|
|
16
|
+
template: str = typer.Option(
|
|
17
|
+
"base",
|
|
18
|
+
"--template",
|
|
19
|
+
"-t",
|
|
20
|
+
help="Project template to use.",
|
|
21
|
+
case_sensitive=False,
|
|
22
|
+
),
|
|
23
|
+
) -> None:
|
|
24
|
+
normalized = template.lower()
|
|
25
|
+
if normalized not in TEMPLATE_NAMES:
|
|
26
|
+
typer.secho(
|
|
27
|
+
f"Unsupported template '{template}'. Choose from: {', '.join(TEMPLATE_NAMES)}.",
|
|
28
|
+
fg=typer.colors.RED,
|
|
29
|
+
err=True,
|
|
30
|
+
)
|
|
31
|
+
raise typer.Exit(code=1)
|
|
32
|
+
|
|
33
|
+
target_path = Path(project_name).resolve()
|
|
34
|
+
scaffold_project(project_name=project_name, template_name=normalized, target_dir=target_path)
|
|
35
|
+
typer.secho(
|
|
36
|
+
f"Created {normalized} LangGraph project at {target_path}",
|
|
37
|
+
fg=typer.colors.GREEN,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
if __name__ == "__main__":
|
|
42
|
+
app()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
from importlib import resources
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
TEMPLATE_NAMES = ("base", "advanced", "production")
|
|
8
|
+
TOKEN_MAP_KEY = "{{PROJECT_NAME}}"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _template_root() -> Path:
|
|
12
|
+
return Path(str(resources.files("langgraph_cli").joinpath("templates")))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _replace_tokens(content: str, project_name: str) -> str:
|
|
16
|
+
return content.replace(TOKEN_MAP_KEY, project_name)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def scaffold_project(project_name: str, template_name: str, target_dir: Path) -> Path:
|
|
20
|
+
source_dir = _template_root() / template_name
|
|
21
|
+
if not source_dir.exists():
|
|
22
|
+
raise FileNotFoundError(f"Template '{template_name}' does not exist.")
|
|
23
|
+
|
|
24
|
+
if target_dir.exists() and any(target_dir.iterdir()):
|
|
25
|
+
raise FileExistsError(f"Target directory '{target_dir}' already exists and is not empty.")
|
|
26
|
+
|
|
27
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
28
|
+
|
|
29
|
+
for source_path in source_dir.rglob("*"):
|
|
30
|
+
if "__pycache__" in source_path.parts or source_path.suffix == ".pyc":
|
|
31
|
+
continue
|
|
32
|
+
relative_path = source_path.relative_to(source_dir)
|
|
33
|
+
destination = target_dir / relative_path
|
|
34
|
+
|
|
35
|
+
if source_path.is_dir():
|
|
36
|
+
destination.mkdir(parents=True, exist_ok=True)
|
|
37
|
+
continue
|
|
38
|
+
|
|
39
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
40
|
+
if source_path.suffix in {".png", ".jpg", ".jpeg", ".gif", ".ico"}:
|
|
41
|
+
shutil.copy2(source_path, destination)
|
|
42
|
+
continue
|
|
43
|
+
|
|
44
|
+
rendered = _replace_tokens(source_path.read_text(encoding="utf-8"), project_name=project_name)
|
|
45
|
+
destination.write_text(rendered, encoding="utf-8")
|
|
46
|
+
|
|
47
|
+
return target_dir
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "{{PROJECT_NAME}}"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Advanced LangGraph scaffold for {{PROJECT_NAME}}"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"langgraph>=0.2.0",
|
|
13
|
+
"langchain>=0.3.0",
|
|
14
|
+
"langsmith>=0.1.0",
|
|
15
|
+
"python-dotenv>=1.0.0",
|
|
16
|
+
"typer>=0.12.0",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[tool.setuptools.packages.find]
|
|
20
|
+
include = ["src*"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Project source package."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Advanced app package."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Graph package."""
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from langgraph.graph import END, START, StateGraph
|
|
2
|
+
|
|
3
|
+
from src.app.graph.constants import Names
|
|
4
|
+
from src.app.graph.edges import EDGE_MAP, route_after_process
|
|
5
|
+
from src.app.graph.registry import NODE_REGISTRY
|
|
6
|
+
from src.app.graph.state import WorkflowState
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def build_graph():
|
|
10
|
+
graph = StateGraph(WorkflowState)
|
|
11
|
+
for name, node in NODE_REGISTRY.items():
|
|
12
|
+
graph.add_node(name, node)
|
|
13
|
+
|
|
14
|
+
graph.add_edge(START, Names.INTENT)
|
|
15
|
+
graph.add_edge(Names.INTENT, Names.PROCESS)
|
|
16
|
+
graph.add_conditional_edges(Names.PROCESS, route_after_process, EDGE_MAP)
|
|
17
|
+
graph.add_edge(Names.OUTPUT, END)
|
|
18
|
+
return graph.compile()
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from src.app.nodes.intent import intent_node
|
|
2
|
+
from src.app.nodes.output import output_node
|
|
3
|
+
from src.app.nodes.processing import processing_node
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Names:
|
|
7
|
+
INTENT = "intent"
|
|
8
|
+
PROCESS = "process"
|
|
9
|
+
OUTPUT = "output"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Tags:
|
|
13
|
+
CONTINUE = "continue"
|
|
14
|
+
COMPLETE = "complete"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Nodes:
|
|
18
|
+
INTENT = intent_node
|
|
19
|
+
PROCESS = processing_node
|
|
20
|
+
OUTPUT = output_node
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from src.app.graph.constants import Names, Tags
|
|
2
|
+
from src.app.graph.state import WorkflowState
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def route_after_process(state: WorkflowState) -> str:
|
|
6
|
+
if state.get("validation_passed"):
|
|
7
|
+
return Tags.COMPLETE
|
|
8
|
+
return Tags.CONTINUE
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
EDGE_MAP = {
|
|
12
|
+
Tags.COMPLETE: Names.OUTPUT,
|
|
13
|
+
Tags.CONTINUE: Names.PROCESS,
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Nodes package."""
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from src.app.graph.state import WorkflowState
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def intent_node(state: WorkflowState) -> WorkflowState:
|
|
5
|
+
text = state.get("input_text", "").lower()
|
|
6
|
+
intent = "answer"
|
|
7
|
+
if any(token in text for token in ("calculate", "+", "-", "*", "/")):
|
|
8
|
+
intent = "math"
|
|
9
|
+
return {"intent": intent}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from src.app.graph.state import WorkflowState
|
|
4
|
+
from src.app.prompts.registry import PromptRegistry
|
|
5
|
+
from src.app.services.prompt_service import PromptService
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def processing_node(state: WorkflowState) -> WorkflowState:
|
|
9
|
+
prompt = PromptService(PromptRegistry()).get_prompt("processing")
|
|
10
|
+
text = state.get("input_text", "")
|
|
11
|
+
numbers = re.findall(r"\d+", text)
|
|
12
|
+
extracted = ", ".join(numbers) if numbers else prompt
|
|
13
|
+
validation_passed = bool(extracted)
|
|
14
|
+
return {"extracted_value": extracted, "validation_passed": validation_passed}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Prompts package."""
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class PromptRegistry:
|
|
2
|
+
def __init__(self) -> None:
|
|
3
|
+
self._prompts = {
|
|
4
|
+
"processing": {
|
|
5
|
+
"v1": "Extract relevant entities from the request.",
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
self._defaults = {"processing": "v1"}
|
|
9
|
+
|
|
10
|
+
def get(self, task: str, version: str | None = None) -> str:
|
|
11
|
+
selected_version = version or self._defaults[task]
|
|
12
|
+
return self._prompts[task][selected_version]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Services package."""
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Utility package."""
|
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "{{PROJECT_NAME}}"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Base LangGraph scaffold for {{PROJECT_NAME}}"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"langgraph>=0.2.0",
|
|
13
|
+
"langchain>=0.3.0",
|
|
14
|
+
"langsmith>=0.1.0",
|
|
15
|
+
"python-dotenv>=1.0.0",
|
|
16
|
+
"typer>=0.12.0",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[tool.setuptools.packages.find]
|
|
20
|
+
include = ["src*"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Project source package."""
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Base app package."""
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from langgraph.graph import END, START, StateGraph
|
|
2
|
+
|
|
3
|
+
from src.app.nodes import draft_node, intake_node, output_node
|
|
4
|
+
from src.app.state import AppState
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def build_graph():
|
|
8
|
+
graph = StateGraph(AppState)
|
|
9
|
+
graph.add_node("intake", intake_node)
|
|
10
|
+
graph.add_node("draft", draft_node)
|
|
11
|
+
graph.add_node("output", output_node)
|
|
12
|
+
graph.add_edge(START, "intake")
|
|
13
|
+
graph.add_edge("intake", "draft")
|
|
14
|
+
graph.add_edge("draft", "output")
|
|
15
|
+
graph.add_edge("output", END)
|
|
16
|
+
return graph.compile()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def run() -> AppState:
|
|
20
|
+
app = build_graph()
|
|
21
|
+
result = app.invoke({"user_input": "Support request for order status"})
|
|
22
|
+
print(result["response"])
|
|
23
|
+
return result
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
if __name__ == "__main__":
|
|
27
|
+
run()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from src.app.state import AppState
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def intake_node(state: AppState) -> AppState:
|
|
5
|
+
text = state.get("user_input", "").strip()
|
|
6
|
+
topic = "general"
|
|
7
|
+
lowered = text.lower()
|
|
8
|
+
if "billing" in lowered:
|
|
9
|
+
topic = "billing"
|
|
10
|
+
elif "support" in lowered:
|
|
11
|
+
topic = "support"
|
|
12
|
+
return {"topic": topic}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def draft_node(state: AppState) -> AppState:
|
|
16
|
+
topic = state.get("topic", "general")
|
|
17
|
+
text = state.get("user_input", "")
|
|
18
|
+
return {"response": f"[{topic}] {text}"}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def output_node(state: AppState) -> AppState:
|
|
22
|
+
return {"response": state.get("response", "No response generated.")}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
Production-grade LangGraph scaffold generated by `langgraph-init`.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This project is a modular LangGraph application designed to serve as a strong starting point for agentic workflows in production-style environments. It includes graph orchestration, node isolation, service boundaries, prompt versioning, evaluation, structured logging, LangSmith integration hooks, and an extensible tool system.
|
|
8
|
+
|
|
9
|
+
## Project Layout
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
src/app/
|
|
13
|
+
├── main.py
|
|
14
|
+
├── config.py
|
|
15
|
+
├── graph/
|
|
16
|
+
├── nodes/
|
|
17
|
+
├── services/
|
|
18
|
+
├── tools/
|
|
19
|
+
├── prompts/
|
|
20
|
+
├── models/
|
|
21
|
+
├── storage/
|
|
22
|
+
├── utils/
|
|
23
|
+
├── observability/
|
|
24
|
+
├── evaluation/
|
|
25
|
+
└── api/
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
Install dependencies:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install -e .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Run the sample workflow:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
python -m src.app.main
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## How It Works
|
|
43
|
+
|
|
44
|
+
The application compiles a `StateGraph` in `src/app/graph/builder.py`.
|
|
45
|
+
|
|
46
|
+
Execution flow:
|
|
47
|
+
|
|
48
|
+
1. `intent` classifies the request
|
|
49
|
+
2. `processing` extracts structured data and calls tools
|
|
50
|
+
3. `validation` scores the extraction
|
|
51
|
+
4. `output` returns the final response when validation passes
|
|
52
|
+
5. `error` returns a failure response when retries are exhausted
|
|
53
|
+
|
|
54
|
+
Validation uses conditional routing, so unsuccessful validation can retry processing before terminating.
|
|
55
|
+
|
|
56
|
+
## Graph Conventions
|
|
57
|
+
|
|
58
|
+
The graph layer uses three abstractions:
|
|
59
|
+
|
|
60
|
+
- `Names`: stable node names used when building the graph
|
|
61
|
+
- `Nodes`: callable implementations
|
|
62
|
+
- `Tags`: conditional routing labels
|
|
63
|
+
|
|
64
|
+
This keeps graph orchestration readable and easy to extend.
|
|
65
|
+
|
|
66
|
+
## Prompts
|
|
67
|
+
|
|
68
|
+
Prompt files live in `src/app/prompts/versions/` and are loaded by task/version.
|
|
69
|
+
|
|
70
|
+
Features:
|
|
71
|
+
|
|
72
|
+
- Default version selection from config
|
|
73
|
+
- Version-specific lookup
|
|
74
|
+
- Fallback to `v1`
|
|
75
|
+
- Prompt access tracking
|
|
76
|
+
|
|
77
|
+
## Tools
|
|
78
|
+
|
|
79
|
+
The scaffold includes a built-in registry and several deterministic tools:
|
|
80
|
+
|
|
81
|
+
- `calculator`
|
|
82
|
+
- `query`
|
|
83
|
+
- `http`
|
|
84
|
+
- `retriever`
|
|
85
|
+
|
|
86
|
+
Add new tools by implementing `BaseTool` and registering them in `src/app/tools/registry.py`.
|
|
87
|
+
|
|
88
|
+
## Evaluation
|
|
89
|
+
|
|
90
|
+
The evaluation layer currently measures:
|
|
91
|
+
|
|
92
|
+
- Field coverage
|
|
93
|
+
- Confidence score
|
|
94
|
+
- Validation pass/fail
|
|
95
|
+
|
|
96
|
+
This makes it easy to swap in richer metrics later.
|
|
97
|
+
|
|
98
|
+
## Observability
|
|
99
|
+
|
|
100
|
+
Observability support includes:
|
|
101
|
+
|
|
102
|
+
- Structured JSON logging
|
|
103
|
+
- Basic metrics counters
|
|
104
|
+
- LangSmith environment wiring
|
|
105
|
+
- Trace decorators for service methods
|
|
106
|
+
|
|
107
|
+
To enable LangSmith tracing, copy `.env.example` to `.env` and set the required values.
|
|
108
|
+
|
|
109
|
+
## API Surface
|
|
110
|
+
|
|
111
|
+
A lightweight API-facing wrapper is included under `src/app/api/` so the graph can be invoked through another interface later without changing the core graph design.
|
|
112
|
+
|
|
113
|
+
## Next Steps
|
|
114
|
+
|
|
115
|
+
Recommended follow-up work:
|
|
116
|
+
|
|
117
|
+
- Connect a real LLM provider
|
|
118
|
+
- Add persistent storage backends
|
|
119
|
+
- Add domain-specific tools
|
|
120
|
+
- Add tests for graph transitions and service behavior
|
|
121
|
+
- Expand prompt sets and versions
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "{{PROJECT_NAME}}"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Production LangGraph scaffold for {{PROJECT_NAME}}"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"langgraph>=0.2.0",
|
|
13
|
+
"langchain>=0.3.0",
|
|
14
|
+
"langsmith>=0.1.0",
|
|
15
|
+
"python-dotenv>=1.0.0",
|
|
16
|
+
"typer>=0.12.0",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[tool.setuptools.packages.find]
|
|
20
|
+
include = ["src*"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Project source package."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Production app package."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""API package."""
|
|
Binary file
|