by-framework-langgraph 0.2.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.
@@ -0,0 +1,68 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ share/python-wheels/
20
+ *.egg-info/
21
+ .installed.cfg
22
+ *.egg
23
+ MANIFEST
24
+
25
+ # Environment
26
+ .env
27
+ .venv
28
+ env/
29
+ venv/
30
+ ENV/
31
+ env.bak/
32
+ venv.bak/
33
+
34
+ # Node.js
35
+ node_modules/
36
+ npm-debug.log*
37
+ yarn-debug.log*
38
+ yarn-error.log*
39
+ .pnpm-debug.log*
40
+ dist/
41
+ .cache/
42
+ .next/
43
+ out/
44
+ .next-env.d.ts
45
+
46
+ # IDEs / Editors
47
+ .idea/
48
+ .vscode/
49
+ *.swp
50
+ *.swo
51
+ .DS_Store
52
+ .DS_Store?
53
+ ._*
54
+ .Spotlight-V100
55
+ .Trashes
56
+ ehthumbs.db
57
+ Thumbs.db
58
+
59
+ # Project Specific
60
+ .worktrees/
61
+ *.log
62
+ .gemini/
63
+ /brain/
64
+ .agents/
65
+ .agent/
66
+ *gateway-sdk.log*
67
+ .claude/settings.local.json
68
+ .claude/settings.json
@@ -0,0 +1,69 @@
1
+ Metadata-Version: 2.4
2
+ Name: by-framework-langgraph
3
+ Version: 0.2.0
4
+ Summary: LangGraph integration for by-framework
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: by-framework>=1.0.0
7
+ Requires-Dist: langchain-core>=1.2.28
8
+ Requires-Dist: langgraph>=1.1.6
9
+ Provides-Extra: dev
10
+ Requires-Dist: isort>=5.13.0; extra == 'dev'
11
+ Requires-Dist: pyink>=24.0.0; extra == 'dev'
12
+ Requires-Dist: pylint>=3.0.0; extra == 'dev'
13
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
14
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
15
+ Requires-Dist: ruff>=0.3.0; extra == 'dev'
16
+ Provides-Extra: langfuse
17
+ Requires-Dist: by-framework-trace-langfuse>=0.2.0; extra == 'langfuse'
18
+ Provides-Extra: phoenix
19
+ Requires-Dist: by-framework-trace-phoenix>=0.2.0; extra == 'phoenix'
20
+ Requires-Dist: openinference-instrumentation-langchain>=0.1.0; extra == 'phoenix'
21
+ Requires-Dist: openinference-instrumentation-openai>=0.1.0; extra == 'phoenix'
22
+ Description-Content-Type: text/markdown
23
+
24
+ # by-framework-langgraph
25
+
26
+ LangGraph integration for by-framework. Provides two integration modes:
27
+
28
+ 1. **Adapter Mode** — Plug existing LangGraph graphs into by-framework with one line
29
+ 2. **Native Mode** — Build LangGraph workers with native `call_agent` / `ask_user` / `resume` support
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ uv add by-framework-langgraph
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ### Adapter Mode — Plug in existing graphs
40
+
41
+ ```python
42
+ from by_framework.worker import ByaiWorker
43
+ from by_framework_langgraph import LangGraphAdapter
44
+
45
+ class MyWorker(ByaiWorker):
46
+ def get_agent_types(self):
47
+ return ["my-agent"]
48
+
49
+ async def process_command(self, command, context):
50
+ graph = build_my_existing_graph() # your existing LangGraph
51
+ adapter = LangGraphAdapter(graph, context)
52
+ return await adapter.run(command)
53
+ ```
54
+
55
+ ### Native Mode — Framework-native LangGraph workers
56
+
57
+ ```python
58
+ from by_framework_langgraph import LangGraphWorker, make_remote_agent_tool, make_ask_user_tool
59
+
60
+ class OrchestratorWorker(LangGraphWorker):
61
+ def get_agent_types(self):
62
+ return ["orchestrator"]
63
+
64
+ def build_graph(self, context, command):
65
+ poet = make_remote_agent_tool(context, "invoke_poet", "poet-agent", "调度诗人创作")
66
+ ask = make_ask_user_tool(context)
67
+ llm = ChatOpenAI(model="gpt-4o").bind_tools([poet, ask])
68
+ # ... build and return compiled graph
69
+ ```
@@ -0,0 +1,46 @@
1
+ # by-framework-langgraph
2
+
3
+ LangGraph integration for by-framework. Provides two integration modes:
4
+
5
+ 1. **Adapter Mode** — Plug existing LangGraph graphs into by-framework with one line
6
+ 2. **Native Mode** — Build LangGraph workers with native `call_agent` / `ask_user` / `resume` support
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ uv add by-framework-langgraph
12
+ ```
13
+
14
+ ## Quick Start
15
+
16
+ ### Adapter Mode — Plug in existing graphs
17
+
18
+ ```python
19
+ from by_framework.worker import ByaiWorker
20
+ from by_framework_langgraph import LangGraphAdapter
21
+
22
+ class MyWorker(ByaiWorker):
23
+ def get_agent_types(self):
24
+ return ["my-agent"]
25
+
26
+ async def process_command(self, command, context):
27
+ graph = build_my_existing_graph() # your existing LangGraph
28
+ adapter = LangGraphAdapter(graph, context)
29
+ return await adapter.run(command)
30
+ ```
31
+
32
+ ### Native Mode — Framework-native LangGraph workers
33
+
34
+ ```python
35
+ from by_framework_langgraph import LangGraphWorker, make_remote_agent_tool, make_ask_user_tool
36
+
37
+ class OrchestratorWorker(LangGraphWorker):
38
+ def get_agent_types(self):
39
+ return ["orchestrator"]
40
+
41
+ def build_graph(self, context, command):
42
+ poet = make_remote_agent_tool(context, "invoke_poet", "poet-agent", "调度诗人创作")
43
+ ask = make_ask_user_tool(context)
44
+ llm = ChatOpenAI(model="gpt-4o").bind_tools([poet, ask])
45
+ # ... build and return compiled graph
46
+ ```
@@ -0,0 +1,45 @@
1
+ [project]
2
+ name = "by-framework-langgraph"
3
+ version = "0.2.0"
4
+ description = "LangGraph integration for by-framework"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "by-framework>=1.0.0",
9
+ "langgraph>=1.1.6",
10
+ "langchain-core>=1.2.28",
11
+ ]
12
+
13
+ [project.optional-dependencies]
14
+ dev = [
15
+ "pytest>=8.0.0",
16
+ "pytest-asyncio>=0.23.0",
17
+ "isort>=5.13.0",
18
+ "pyink>=24.0.0",
19
+ "pylint>=3.0.0",
20
+ "ruff>=0.3.0",
21
+ ]
22
+ langfuse = [
23
+ "by-framework-trace-langfuse>=0.2.0",
24
+ ]
25
+ phoenix = [
26
+ "by-framework-trace-phoenix>=0.2.0",
27
+ "openinference-instrumentation-langchain>=0.1.0",
28
+ "openinference-instrumentation-openai>=0.1.0",
29
+ ]
30
+
31
+ [tool.uv.sources]
32
+ by-framework = { workspace = true }
33
+ by-framework-trace-langfuse = { workspace = true }
34
+ by-framework-trace-phoenix = { workspace = true }
35
+
36
+ [build-system]
37
+ requires = ["hatchling"]
38
+ build-backend = "hatchling.build"
39
+
40
+ [tool.hatch.build.targets.wheel]
41
+ packages = ["src/by_framework_langgraph"]
42
+
43
+ [tool.pytest.ini_options]
44
+ pythonpath = ["src", "../../src"]
45
+ testpaths = ["tests"]
@@ -0,0 +1,36 @@
1
+ """LangGraph integration for by-framework.
2
+
3
+ Provides two integration modes:
4
+
5
+ 1. **Adapter Mode** — Plug existing LangGraph graphs into by-framework::
6
+
7
+ from by_framework_langgraph import LangGraphAdapter
8
+
9
+ adapter = LangGraphAdapter(my_graph, context)
10
+ return await adapter.run(command)
11
+
12
+ 2. **Native Mode** — Build LangGraph workers with framework-native tools::
13
+
14
+ from by_framework_langgraph import (
15
+ LangGraphWorker,
16
+ make_remote_agent_tool,
17
+ make_ask_user_tool,
18
+ )
19
+
20
+ class MyWorker(LangGraphWorker):
21
+ def build_graph(self, context, command):
22
+ poet = make_remote_agent_tool(context, ...)
23
+ ask = make_ask_user_tool(context)
24
+ # ... build and return compiled graph
25
+ """
26
+
27
+ from .adapter import LangGraphAdapter
28
+ from .tools import make_ask_user_tool, make_remote_agent_tool
29
+ from .worker import LangGraphWorker
30
+
31
+ __all__ = [
32
+ "LangGraphAdapter",
33
+ "LangGraphWorker",
34
+ "make_ask_user_tool",
35
+ "make_remote_agent_tool",
36
+ ]
@@ -0,0 +1,64 @@
1
+ """Internal utilities for LangGraph integration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ from typing import Any
7
+
8
+ from by_framework.core.protocol.commands import ResumeCommand
9
+
10
+
11
+ def extract_content_text(content: Any) -> str:
12
+ """Extract plain text from various command content formats.
13
+
14
+ Handles:
15
+ - str → return directly
16
+ - list[dict] (BaiYing message format) → extract text fields
17
+ - other → str() conversion
18
+ """
19
+ if isinstance(content, str):
20
+ return content
21
+
22
+ if isinstance(content, list):
23
+ texts: list[str] = []
24
+ for item in content:
25
+ if isinstance(item, dict):
26
+ # BaiYing message format: {"type": "text", "text": "..."}
27
+ text = item.get("text", "")
28
+ if text:
29
+ texts.append(str(text))
30
+ # Fallback: {"content": "..."}
31
+ elif "content" in item:
32
+ texts.append(str(item["content"]))
33
+ elif isinstance(item, str):
34
+ texts.append(item)
35
+ return "\n".join(texts) if texts else str(content)
36
+
37
+ return str(content)
38
+
39
+
40
+ def extract_resume_data(command: ResumeCommand) -> str:
41
+ """Extract resume data from a ResumeCommand.
42
+
43
+ Prioritizes reply_data (from call_agent callback) over content
44
+ (from ask_user reply), converting to string.
45
+ """
46
+ if command.reply_data is not None:
47
+ if isinstance(command.reply_data, str):
48
+ return command.reply_data
49
+ return str(command.reply_data)
50
+
51
+ if command.content:
52
+ return extract_content_text(command.content)
53
+
54
+ return ""
55
+
56
+
57
+ def str_to_uint128(s: str) -> int:
58
+ """Convert a string to a 128-bit integer (for OTEL TraceId)."""
59
+ return int(hashlib.md5(s.encode()).hexdigest(), 16)
60
+
61
+
62
+ def str_to_uint64(s: str) -> int:
63
+ """Convert a string to a 64-bit integer (for OTEL SpanId)."""
64
+ return int(hashlib.md5(s.encode()).hexdigest()[:16], 16)