kagent-claude 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,218 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # pytype static type analyzer
179
+ .pytype/
180
+
181
+ # Cython debug symbols
182
+ cython_debug/
183
+
184
+ # PyCharm
185
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
186
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
188
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
189
+ # .idea/
190
+
191
+ # Abstra
192
+ # Abstra is an AI-powered process automation framework.
193
+ # Ignore directories containing user credentials, local state, and settings.
194
+ # Learn more at https://abstra.io/docs
195
+ .abstra/
196
+
197
+ # Visual Studio Code
198
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
199
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
201
+ # you could uncomment the following to ignore the entire vscode folder
202
+ # .vscode/
203
+ # Temporary file for partial code execution
204
+ tempCodeRunnerFile.py
205
+
206
+ # Ruff stuff:
207
+ .ruff_cache/
208
+
209
+ # PyPI configuration file
210
+ .pypirc
211
+
212
+ # Marimo
213
+ marimo/_static/
214
+ marimo/_lsp/
215
+ __marimo__/
216
+
217
+ # Streamlit
218
+ .streamlit/secrets.toml
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.4
2
+ Name: kagent-claude
3
+ Version: 0.2.0
4
+ Summary: Claude Agent SDK integration for KAgent with A2A server support
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: a2a-sdk[http-server]<1.0.0,>=0.3.23
7
+ Requires-Dist: claude-agent-sdk>=0.2.0
8
+ Requires-Dist: fastapi>=0.100.0
9
+ Requires-Dist: httpx>=0.25.0
10
+ Requires-Dist: kagent-core>=0.1.0
11
+ Requires-Dist: openai>=1.0.0
12
+ Requires-Dist: opentelemetry-api>=1.38.0
13
+ Requires-Dist: opentelemetry-sdk>=1.38.0
14
+ Requires-Dist: pydantic>=2.0.0
15
+ Requires-Dist: typing-extensions>=4.0.0
16
+ Requires-Dist: uvicorn>=0.20.0
17
+ Provides-Extra: dev
18
+ Requires-Dist: black>=23.0.0; extra == 'dev'
19
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
20
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
21
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
22
+ Description-Content-Type: text/markdown
23
+
24
+ # kagent-claude
25
+
26
+ Claude Agent SDK integration for [kagent](https://kagent.dev) with A2A server support.
27
+
28
+ ## Overview
29
+
30
+ `kagent-claude` enables the Claude Agent SDK to run as a BYO (Bring Your Own) agent inside the kagent platform. It follows the same architectural pattern as `kagent-crewai` and `kagent-langgraph`.
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install kagent-claude
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ```python
41
+ from claude_agent_sdk import ClaudeAgentOptions
42
+ from kagent.claude import KAgentApp
43
+ from kagent.core import KAgentConfig
44
+ from a2a.types import AgentCard, AgentCapabilities, AgentSkill
45
+
46
+ app = KAgentApp(
47
+ options=ClaudeAgentOptions(
48
+ allowed_tools=["Bash", "Read", "WebSearch"],
49
+ ),
50
+ agent_card=AgentCard(
51
+ name="my-claude-agent",
52
+ description="A Claude-powered kagent agent",
53
+ url="http://my-claude-agent:8080/",
54
+ version="1.0.0",
55
+ capabilities=AgentCapabilities(streaming=True),
56
+ default_input_modes=["text"],
57
+ default_output_modes=["text"],
58
+ skills=[
59
+ AgentSkill(
60
+ id="code",
61
+ name="Code generation",
62
+ description="Generates and modifies code",
63
+ tags=["coding"],
64
+ )
65
+ ],
66
+ ),
67
+ config=KAgentConfig(
68
+ url="http://kagent-controller:8083",
69
+ name="my-claude-agent",
70
+ namespace="kagent",
71
+ ),
72
+ )
73
+
74
+ if __name__ == "__main__":
75
+ app.run(port=8080)
76
+ ```
77
+
78
+ ## Session Continuity
79
+
80
+ The package maps A2A `contextId` to Claude Agent SDK `session_id`, enabling multi-turn conversations that preserve Claude's context window across requests within the same context.
81
+
82
+ ## Environment Variables
83
+
84
+ - `ANTHROPIC_API_KEY` — Required for Claude Agent SDK authentication
85
+ - `KAGENT_URL` — kagent controller URL (alternative to passing in config)
86
+ - `KAGENT_NAME` — Agent name (alternative to passing in config)
87
+ - `KAGENT_NAMESPACE` — Agent namespace (alternative to passing in config)
@@ -0,0 +1,64 @@
1
+ # kagent-claude
2
+
3
+ Claude Agent SDK integration for [kagent](https://kagent.dev) with A2A server support.
4
+
5
+ ## Overview
6
+
7
+ `kagent-claude` enables the Claude Agent SDK to run as a BYO (Bring Your Own) agent inside the kagent platform. It follows the same architectural pattern as `kagent-crewai` and `kagent-langgraph`.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install kagent-claude
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```python
18
+ from claude_agent_sdk import ClaudeAgentOptions
19
+ from kagent.claude import KAgentApp
20
+ from kagent.core import KAgentConfig
21
+ from a2a.types import AgentCard, AgentCapabilities, AgentSkill
22
+
23
+ app = KAgentApp(
24
+ options=ClaudeAgentOptions(
25
+ allowed_tools=["Bash", "Read", "WebSearch"],
26
+ ),
27
+ agent_card=AgentCard(
28
+ name="my-claude-agent",
29
+ description="A Claude-powered kagent agent",
30
+ url="http://my-claude-agent:8080/",
31
+ version="1.0.0",
32
+ capabilities=AgentCapabilities(streaming=True),
33
+ default_input_modes=["text"],
34
+ default_output_modes=["text"],
35
+ skills=[
36
+ AgentSkill(
37
+ id="code",
38
+ name="Code generation",
39
+ description="Generates and modifies code",
40
+ tags=["coding"],
41
+ )
42
+ ],
43
+ ),
44
+ config=KAgentConfig(
45
+ url="http://kagent-controller:8083",
46
+ name="my-claude-agent",
47
+ namespace="kagent",
48
+ ),
49
+ )
50
+
51
+ if __name__ == "__main__":
52
+ app.run(port=8080)
53
+ ```
54
+
55
+ ## Session Continuity
56
+
57
+ The package maps A2A `contextId` to Claude Agent SDK `session_id`, enabling multi-turn conversations that preserve Claude's context window across requests within the same context.
58
+
59
+ ## Environment Variables
60
+
61
+ - `ANTHROPIC_API_KEY` — Required for Claude Agent SDK authentication
62
+ - `KAGENT_URL` — kagent controller URL (alternative to passing in config)
63
+ - `KAGENT_NAME` — Agent name (alternative to passing in config)
64
+ - `KAGENT_NAMESPACE` — Agent namespace (alternative to passing in config)
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "kagent-claude"
7
+ version = "0.2.0"
8
+ description = "Claude Agent SDK integration for KAgent with A2A server support"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "claude-agent-sdk>=0.2.0",
13
+ "httpx>=0.25.0",
14
+ "fastapi>=0.100.0",
15
+ "pydantic>=2.0.0",
16
+ "typing-extensions>=4.0.0",
17
+ "uvicorn>=0.20.0",
18
+ "a2a-sdk[http-server]>=0.3.23,<1.0.0",
19
+ "kagent-core>=0.1.0",
20
+ "opentelemetry-api>=1.38.0",
21
+ "opentelemetry-sdk>=1.38.0",
22
+ "openai>=1.0.0",
23
+ ]
24
+
25
+ [project.optional-dependencies]
26
+ dev = [
27
+ "pytest>=7.0.0",
28
+ "pytest-asyncio>=0.21.0",
29
+ "black>=23.0.0",
30
+ "ruff>=0.1.0",
31
+ ]
32
+
33
+ [project.scripts]
34
+ kagent-claude-server = "kagent.claude.server:main"
35
+
36
+ [tool.hatch.build.targets.wheel]
37
+ packages = ["src/kagent"]
38
+
39
+ [tool.ruff]
40
+ extend = "../../pyproject.toml"
@@ -0,0 +1,23 @@
1
+ from importlib.metadata import PackageNotFoundError, version
2
+
3
+ from ._a2a import KAgentApp
4
+ from ._executor import ClaudeAgentExecutor, ClaudeAgentExecutorConfig
5
+ from ._hitl import ApprovalDecision, HitlBridge
6
+ from ._session_store import ClaudeSessionStore, SessionStore
7
+ from ._tracing import trace_query
8
+
9
+ __all__ = [
10
+ "KAgentApp",
11
+ "ClaudeAgentExecutor",
12
+ "ClaudeAgentExecutorConfig",
13
+ "ClaudeSessionStore",
14
+ "SessionStore",
15
+ "HitlBridge",
16
+ "ApprovalDecision",
17
+ "trace_query",
18
+ ]
19
+
20
+ try:
21
+ __version__ = version("kagent-claude")
22
+ except PackageNotFoundError:
23
+ __version__ = "0.0.0-dev"
@@ -0,0 +1,132 @@
1
+ """KAgent Claude Agent SDK A2A Server Integration."""
2
+
3
+ import faulthandler
4
+ import logging
5
+ from contextlib import asynccontextmanager
6
+
7
+ import httpx
8
+ from a2a.server.apps import A2AStarletteApplication
9
+ from a2a.server.request_handlers import DefaultRequestHandler
10
+ from a2a.types import AgentCard
11
+ from claude_agent_sdk import ClaudeAgentOptions
12
+ from fastapi import FastAPI, Request
13
+ from fastapi.responses import PlainTextResponse
14
+
15
+ from kagent.core import KAgentConfig, configure_logging, configure_tracing
16
+ from kagent.core.a2a import (
17
+ KAgentRequestContextBuilder,
18
+ KAgentTaskStore,
19
+ get_a2a_max_content_length,
20
+ )
21
+
22
+ from ._executor import ClaudeAgentExecutor, ClaudeAgentExecutorConfig
23
+ from ._session_store import ClaudeSessionStore
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ def _health_check(request: Request) -> PlainTextResponse:
29
+ return PlainTextResponse("OK")
30
+
31
+
32
+ def _thread_dump(request: Request) -> PlainTextResponse:
33
+ import tempfile
34
+
35
+ with tempfile.TemporaryFile(mode="w+") as tmp:
36
+ faulthandler.dump_traceback(file=tmp, all_threads=True)
37
+ tmp.seek(0)
38
+ return PlainTextResponse(tmp.read())
39
+
40
+
41
+ class KAgentApp:
42
+ """
43
+ Builds an A2A-compliant HTTP server wrapping the Claude Agent SDK.
44
+
45
+ Usage:
46
+ app = KAgentApp(
47
+ options=ClaudeAgentOptions(allowed_tools=["Bash", "Read"]),
48
+ agent_card=AgentCard(...),
49
+ config=KAgentConfig(), # reads from KAGENT_URL, KAGENT_NAME, KAGENT_NAMESPACE env vars
50
+ )
51
+ app.run()
52
+ """
53
+
54
+ def __init__(
55
+ self,
56
+ *,
57
+ options: ClaudeAgentOptions,
58
+ agent_card: AgentCard,
59
+ config: KAgentConfig = None,
60
+ executor_config: ClaudeAgentExecutorConfig | None = None,
61
+ tracing: bool = True,
62
+ ):
63
+ self._options = options
64
+ self.agent_card = AgentCard.model_validate(agent_card)
65
+ self.config = config or KAgentConfig()
66
+ self._enable_tracing = tracing
67
+ self._session_store = ClaudeSessionStore()
68
+ self._executor_config = executor_config or ClaudeAgentExecutorConfig()
69
+
70
+ def build(self) -> FastAPI:
71
+ """Construct and return the FastAPI ASGI application."""
72
+ http_client = httpx.AsyncClient(base_url=self.config.url)
73
+
74
+ agent_executor = ClaudeAgentExecutor(
75
+ options=self._options,
76
+ session_store=self._session_store,
77
+ app_name=self.config.app_name,
78
+ config=self._executor_config,
79
+ )
80
+
81
+ task_store = KAgentTaskStore(http_client)
82
+ request_context_builder = KAgentRequestContextBuilder(task_store=task_store)
83
+ request_handler = DefaultRequestHandler(
84
+ agent_executor=agent_executor,
85
+ task_store=task_store,
86
+ request_context_builder=request_context_builder,
87
+ )
88
+
89
+ max_content_length = get_a2a_max_content_length()
90
+ a2a_app = A2AStarletteApplication(
91
+ agent_card=self.agent_card,
92
+ http_handler=request_handler,
93
+ max_content_length=max_content_length,
94
+ )
95
+
96
+ # Lifespan for graceful shutdown
97
+ @asynccontextmanager
98
+ async def lifespan(app: FastAPI):
99
+ logger.info(f"KAgent Claude starting: {self.config.app_name}")
100
+ yield
101
+ # Shutdown: cancel running queries
102
+ await agent_executor.shutdown()
103
+ await http_client.aclose()
104
+ logger.info(f"KAgent Claude stopped: {self.config.app_name}")
105
+
106
+ faulthandler.enable()
107
+ app = FastAPI(
108
+ title=f"KAgent Claude: {self.config.app_name}",
109
+ description=f"Claude Agent SDK with KAgent integration: {self.agent_card.description}",
110
+ version=self.agent_card.version,
111
+ lifespan=lifespan,
112
+ )
113
+
114
+ configure_logging()
115
+
116
+ if self._enable_tracing:
117
+ try:
118
+ configure_tracing(self.config.name, self.config.namespace, app)
119
+ except Exception:
120
+ logger.exception("Failed to configure tracing")
121
+
122
+ app.add_route("/health", methods=["GET"], route=_health_check)
123
+ app.add_route("/thread_dump", methods=["GET"], route=_thread_dump)
124
+ a2a_app.add_routes_to_app(app)
125
+
126
+ return app
127
+
128
+ def run(self, host: str = "0.0.0.0", port: int = 8080) -> None:
129
+ """Start the uvicorn server. Blocks until shutdown."""
130
+ import uvicorn
131
+
132
+ uvicorn.run(self.build(), host=host, port=port)