-
Notifications
You must be signed in to change notification settings - Fork 87
add sdk for agentruntime #221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a3801dc
79dc475
6f1a60a
1860d47
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,93 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Copyright The Volcano Authors. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # you may not use this file except in compliance with the License. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # You may obtain a copy of the License at | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Unless required by applicable law or agreed to in writing, software | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # See the License for the specific language governing permissions and | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # limitations under the License. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import logging | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Any, Dict, Optional | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from requests.exceptions import JSONDecodeError | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from agentcube.clients.agent_runtime_data_plane import AgentRuntimeDataPlaneClient | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from agentcube.utils.log import get_logger | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class AgentRuntimeClient: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class AgentRuntimeClient: | |
| class AgentRuntimeClient: | |
| """ | |
| Client for managing Agent Runtime sessions via the AgentCube Router. | |
| This class provides a high-level interface for invoking long-lived agent | |
| runtimes exposed through the Router's data plane API. It is responsible for: | |
| * Bootstrapping a new agent runtime session when no ``session_id`` is provided. | |
| * Reusing an existing session when a ``session_id`` is supplied. | |
| * Sending invocation payloads to the agent runtime and returning the response. | |
| * Managing the underlying HTTP client lifecycle, including optional context | |
| manager support. | |
| Session management | |
| ------------------ | |
| When instantiated without a ``session_id``, the client will automatically | |
| bootstrap a new Agent Runtime session by calling | |
| :meth:`AgentRuntimeDataPlaneClient.bootstrap_session_id`. The newly created | |
| ``session_id`` is stored on ``self.session_id`` and logged for reference: | |
| * If ``session_id`` is ``None``: | |
| - A new session is created against the configured Router / namespace / agent. | |
| - ``self.session_id`` is set to the newly allocated ID. | |
| - Subsequent :meth:`invoke` calls use this session. | |
| * If ``session_id`` is provided: | |
| - The client will reuse the existing session identified by that ID. | |
| - No new session is created; this is useful for resuming work or sharing | |
| sessions across processes. | |
| Usage | |
| ----- | |
| The client can be used directly, or as a context manager to ensure the | |
| underlying HTTP resources are cleaned up automatically: | |
| .. code-block:: python | |
| from agentcube.agent_runtime import AgentRuntimeClient | |
| # Create a new Agent Runtime session and invoke the agent | |
| with AgentRuntimeClient( | |
| agent_name="my-agent", | |
| namespace="default", | |
| router_url="https://router.example.com", | |
| verbose=True, | |
| ) as client: | |
| result = client.invoke({"input": "hello agent"}) | |
| print(result) | |
| You can also reuse an existing session by passing a known ``session_id``: | |
| .. code-block:: python | |
| # Assume you have a previously created session_id | |
| existing_session_id = "session-1234" | |
| client = AgentRuntimeClient( | |
| agent_name="my-agent", | |
| namespace="default", | |
| router_url="https://router.example.com", | |
| session_id=existing_session_id, | |
| ) | |
| try: | |
| result = client.invoke({"input": "continue conversation"}) | |
| print(result) | |
| finally: | |
| client.close() | |
| Parameters | |
| ---------- | |
| agent_name: | |
| Name of the Agent Runtime to invoke, as configured in the Router. | |
| namespace: | |
| Kubernetes namespace (or logical namespace) where the agent is deployed. | |
| Defaults to ``"default"``. | |
| router_url: | |
| Base URL of the AgentCube Router. If not provided, the client will look | |
| up the ``ROUTER_URL`` environment variable. One of these must be set. | |
| verbose: | |
| If ``True``, enables debug-level logging for both this client and the | |
| underlying data plane client. | |
| session_id: | |
| Optional existing session identifier. If provided, the client will reuse | |
| this session instead of creating a new one. | |
| timeout: | |
| Request timeout (in seconds) applied to invocations sent to the Router. | |
| connect_timeout: | |
| Connection timeout (in seconds) for establishing HTTP connections to | |
| the Router. | |
| """ |
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The invoke method is missing a docstring that describes its parameters and return value. Following the pattern from CodeInterpreterClient methods (e.g., sdk-python/agentcube/code_interpreter.py:166-177), add a docstring that explains what the method does, the payload parameter, the optional timeout parameter, and what it returns.
| def invoke(self, payload: Dict[str, Any], timeout: Optional[float] = None) -> Any: | |
| def invoke(self, payload: Dict[str, Any], timeout: Optional[float] = None) -> Any: | |
| """Invoke the agent runtime for this session with the given payload. | |
| Parameters | |
| ---------- | |
| payload : Dict[str, Any] | |
| JSON-serializable request body to send to the agent runtime. | |
| timeout : Optional[float], optional | |
| Per-request timeout in seconds. If provided, this overrides the | |
| default timeout configured on the client. | |
| Returns | |
| ------- | |
| Any | |
| The decoded JSON response body if the response contains valid | |
| JSON; otherwise, the raw response text. | |
| """ |
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The except clause catches JSONDecodeError, but the test at sdk-python/tests/test_agent_runtime.py:81 mocks the response to raise ValueError. Since requests.exceptions.JSONDecodeError is a subclass of ValueError, the test should either raise JSONDecodeError instead, or this code should catch ValueError (which is more general and would catch both). Consider catching ValueError for broader compatibility, or update the test to raise JSONDecodeError for consistency.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,9 +13,12 @@ | |
| # limitations under the License. | ||
|
|
||
| from .control_plane import ControlPlaneClient | ||
| from .data_plane import DataPlaneClient | ||
| from .code_interpreter_data_plane import CodeInterpreterDataPlaneClient | ||
| from .agent_runtime_data_plane import AgentRuntimeDataPlaneClient | ||
|
|
||
| __all__ = [ | ||
| "ControlPlaneClient", | ||
| "DataPlaneClient" | ||
| "CodeInterpreterDataPlaneClient", | ||
| "AgentRuntimeDataPlaneClient", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now with the new class, the previous names are a little general
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, so I renamed |
||
| ] | ||
|
|
||
|
warjiang marked this conversation as resolved.
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,89 @@ | ||||||||||||||||||||||||||||||||||
| # Copyright The Volcano Authors. | ||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||||||||||||||||||||||||||||||||
| # you may not use this file except in compliance with the License. | ||||||||||||||||||||||||||||||||||
| # You may obtain a copy of the License at | ||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||
| # Unless required by applicable law or agreed to in writing, software | ||||||||||||||||||||||||||||||||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||||||||||||||||||||||||||||||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||||||||||||||||||||||||||||||
| # See the License for the specific language governing permissions and | ||||||||||||||||||||||||||||||||||
| # limitations under the License. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| from typing import Any, Dict, Optional | ||||||||||||||||||||||||||||||||||
| from urllib.parse import urljoin | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| import requests | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| from agentcube.utils.http import create_session | ||||||||||||||||||||||||||||||||||
| from agentcube.utils.log import get_logger | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| class AgentRuntimeDataPlaneClient: | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
| class AgentRuntimeDataPlaneClient: | |
| class AgentRuntimeDataPlaneClient: | |
| """Client for communicating with the Router for AgentRuntime invocations. | |
| This client is responsible for interacting with the Router's | |
| `/v1/namespaces/{namespace}/agent-runtimes/{name}/invocations/` endpoint | |
| for a specific AgentRuntime. It bootstraps a new session by issuing a | |
| GET request to obtain a session ID from the Router, and then uses that | |
| session ID in subsequent POST requests to send invocation payloads. | |
| """ |
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The invoke method is missing a docstring. Following the pattern from DataPlaneClient.execute_command (sdk-python/agentcube/clients/data_plane.py:126-132), add a docstring that explains the parameters (session_id, payload, timeout) and return value (requests.Response object).
| ) -> requests.Response: | |
| ) -> requests.Response: | |
| """ | |
| Invoke the agent runtime using an existing session. | |
| Args: | |
| session_id: The AgentCube session identifier used to route the | |
| invocation to the correct agent runtime instance. | |
| payload: The JSON-serializable request body to send to the agent | |
| runtime. | |
| timeout: Optional per-request read timeout in seconds. If not | |
| provided, the client's default timeout is used. | |
| Returns: | |
| requests.Response: The HTTP response returned by the router. | |
| """ |
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The close method is missing a docstring. Following the pattern from DataPlaneClient and ControlPlaneClient, add a docstring that explains this method closes the underlying HTTP session and releases connection pool resources.
| def close(self) -> None: | |
| def close(self) -> None: | |
| """Close the underlying HTTP session and release connection pool resources.""" |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,47 @@ | ||||||||||
| # Copyright The Volcano Authors. | ||||||||||
| # | ||||||||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||||||||
| # you may not use this file except in compliance with the License. | ||||||||||
| # You may obtain a copy of the License at | ||||||||||
| # | ||||||||||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||||||||||
| # | ||||||||||
| # Unless required by applicable law or agreed to in writing, software | ||||||||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||||||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||||||
| # See the License for the specific language governing permissions and | ||||||||||
| # limitations under the License. | ||||||||||
|
|
||||||||||
| from agentcube import AgentRuntimeClient | ||||||||||
|
|
||||||||||
| # first time: it will create a new pod | ||||||||||
| agent_client_v1 = AgentRuntimeClient( | ||||||||||
| agent_name="my-agent", | ||||||||||
| router_url="http://localhost:18081", | ||||||||||
| namespace="default", | ||||||||||
| verbose=True, | ||||||||||
| ) | ||||||||||
| print(agent_client_v1.session_id) | ||||||||||
|
|
||||||||||
| result_v1 = agent_client_v1.invoke( | ||||||||||
| payload={"prompt": "Hello World!"}, | ||||||||||
| ) | ||||||||||
| print(result_v1) | ||||||||||
|
|
||||||||||
| # second time: it will try to reuse the pod created before | ||||||||||
| agent_client_v2 = AgentRuntimeClient( | ||||||||||
| agent_name="my-agent", | ||||||||||
| router_url="http://localhost:18081", | ||||||||||
| namespace="default", | ||||||||||
| session_id=agent_client_v1.session_id, | ||||||||||
| verbose=True, | ||||||||||
| ) | ||||||||||
| # same with the first time | ||||||||||
| print(agent_client_v2.session_id) | ||||||||||
|
|
||||||||||
| result_v2 = agent_client_v2.invoke( | ||||||||||
| payload={"prompt": "Hello World!"}, | ||||||||||
| ) | ||||||||||
| print(result_v2) | ||||||||||
|
|
||||||||||
|
|
||||||||||
|
warjiang marked this conversation as resolved.
warjiang marked this conversation as resolved.
|
||||||||||
| # close clients to release HTTP connection pool resources | |
| agent_client_v2.close() | |
| agent_client_v1.close() |
Uh oh!
There was an error while loading. Please reload this page.