agentex-sdk 0.7.0__py3-none-any.whl → 0.7.2__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.
- agentex/_version.py +1 -1
- agentex/lib/adk/providers/_modules/sync_provider.py +116 -15
- agentex/lib/cli/commands/init.py +16 -1
- agentex/lib/cli/templates/temporal-openai-agents/.dockerignore.j2 +43 -0
- agentex/lib/cli/templates/temporal-openai-agents/Dockerfile-uv.j2 +48 -0
- agentex/lib/cli/templates/temporal-openai-agents/Dockerfile.j2 +48 -0
- agentex/lib/cli/templates/temporal-openai-agents/README.md.j2 +224 -0
- agentex/lib/cli/templates/temporal-openai-agents/dev.ipynb.j2 +126 -0
- agentex/lib/cli/templates/temporal-openai-agents/environments.yaml.j2 +64 -0
- agentex/lib/cli/templates/temporal-openai-agents/manifest.yaml.j2 +140 -0
- agentex/lib/cli/templates/temporal-openai-agents/project/acp.py.j2 +80 -0
- agentex/lib/cli/templates/temporal-openai-agents/project/activities.py.j2 +116 -0
- agentex/lib/cli/templates/temporal-openai-agents/project/run_worker.py.j2 +56 -0
- agentex/lib/cli/templates/temporal-openai-agents/project/workflow.py.j2 +169 -0
- agentex/lib/cli/templates/temporal-openai-agents/pyproject.toml.j2 +35 -0
- agentex/lib/cli/templates/temporal-openai-agents/requirements.txt.j2 +4 -0
- agentex/lib/cli/templates/temporal-openai-agents/test_agent.py.j2 +147 -0
- agentex/resources/messages/messages.py +155 -3
- agentex/types/__init__.py +2 -0
- agentex/types/message_list_paginated_params.py +19 -0
- agentex/types/message_list_paginated_response.py +21 -0
- {agentex_sdk-0.7.0.dist-info → agentex_sdk-0.7.2.dist-info}/METADATA +1 -1
- {agentex_sdk-0.7.0.dist-info → agentex_sdk-0.7.2.dist-info}/RECORD +26 -10
- {agentex_sdk-0.7.0.dist-info → agentex_sdk-0.7.2.dist-info}/WHEEL +0 -0
- {agentex_sdk-0.7.0.dist-info → agentex_sdk-0.7.2.dist-info}/entry_points.txt +0 -0
- {agentex_sdk-0.7.0.dist-info → agentex_sdk-0.7.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from temporalio import workflow
|
|
5
|
+
|
|
6
|
+
from agentex.lib import adk
|
|
7
|
+
from agentex.lib.types.acp import CreateTaskParams, SendEventParams
|
|
8
|
+
from agentex.lib.core.temporal.workflows.workflow import BaseWorkflow
|
|
9
|
+
from agentex.lib.core.temporal.types.workflow import SignalName
|
|
10
|
+
from agentex.lib.utils.logging import make_logger
|
|
11
|
+
from agentex.types.text_content import TextContent
|
|
12
|
+
from agentex.lib.environment_variables import EnvironmentVariables
|
|
13
|
+
from agents import Agent, Runner
|
|
14
|
+
from agentex.lib.core.temporal.plugins.openai_agents.hooks.hooks import TemporalStreamingHooks
|
|
15
|
+
from pydantic import BaseModel
|
|
16
|
+
from typing import List, Dict, Any
|
|
17
|
+
from temporalio.contrib import openai_agents
|
|
18
|
+
from project.activities import get_weather
|
|
19
|
+
from agentex.lib.core.tracing.tracing_processor_manager import (
|
|
20
|
+
add_tracing_processor_config,
|
|
21
|
+
)
|
|
22
|
+
from agentex.lib.types.tracing import SGPTracingProcessorConfig
|
|
23
|
+
from datetime import timedelta
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
environment_variables = EnvironmentVariables.refresh()
|
|
27
|
+
|
|
28
|
+
if environment_variables.WORKFLOW_NAME is None:
|
|
29
|
+
raise ValueError("Environment variable WORKFLOW_NAME is not set")
|
|
30
|
+
|
|
31
|
+
if environment_variables.AGENT_NAME is None:
|
|
32
|
+
raise ValueError("Environment variable AGENT_NAME is not set")
|
|
33
|
+
|
|
34
|
+
logger = make_logger(__name__)
|
|
35
|
+
|
|
36
|
+
# Setup tracing for SGP (Scale GenAI Platform)
|
|
37
|
+
# This enables visibility into your agent's execution in the SGP dashboard
|
|
38
|
+
add_tracing_processor_config(
|
|
39
|
+
SGPTracingProcessorConfig(
|
|
40
|
+
sgp_api_key=os.environ.get("SGP_API_KEY", ""),
|
|
41
|
+
sgp_account_id=os.environ.get("SGP_ACCOUNT_ID", ""),
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class StateModel(BaseModel):
|
|
47
|
+
"""
|
|
48
|
+
State model for preserving conversation history across turns.
|
|
49
|
+
|
|
50
|
+
This allows the agent to maintain context throughout the conversation,
|
|
51
|
+
making it possible to reference previous messages and build on the discussion.
|
|
52
|
+
|
|
53
|
+
Attributes:
|
|
54
|
+
input_list: The conversation history in OpenAI message format.
|
|
55
|
+
turn_number: Counter for tracking conversation turns (useful for tracing).
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
input_list: List[Dict[str, Any]]
|
|
59
|
+
turn_number: int
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class TurnInput(BaseModel):
|
|
63
|
+
"""Input model for tracing spans."""
|
|
64
|
+
input_list: List[Dict[str, Any]]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class TurnOutput(BaseModel):
|
|
68
|
+
"""Output model for tracing spans."""
|
|
69
|
+
final_output: Any
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@workflow.defn(name=environment_variables.WORKFLOW_NAME)
|
|
73
|
+
class {{ workflow_class }}(BaseWorkflow):
|
|
74
|
+
"""
|
|
75
|
+
Workflow for {{ agent_name }} agent using OpenAI Agents SDK.
|
|
76
|
+
|
|
77
|
+
This workflow:
|
|
78
|
+
- Maintains conversation state across turns
|
|
79
|
+
- Creates tracing spans for each turn
|
|
80
|
+
- Runs an OpenAI agent with tools (activities)
|
|
81
|
+
- Streams responses back to the client
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
def __init__(self):
|
|
85
|
+
super().__init__(display_name=environment_variables.AGENT_NAME)
|
|
86
|
+
self._complete_task = False
|
|
87
|
+
self._state: StateModel = StateModel(input_list=[], turn_number=0)
|
|
88
|
+
self._task_id = None
|
|
89
|
+
self._trace_id = None
|
|
90
|
+
self._parent_span_id = None
|
|
91
|
+
|
|
92
|
+
@workflow.signal(name=SignalName.RECEIVE_EVENT)
|
|
93
|
+
async def on_task_event_send(self, params: SendEventParams) -> None:
|
|
94
|
+
logger.info(f"Received task message instruction: {params}")
|
|
95
|
+
|
|
96
|
+
# Increment turn number for tracing
|
|
97
|
+
self._state.turn_number += 1
|
|
98
|
+
|
|
99
|
+
self._task_id = params.task.id
|
|
100
|
+
self._trace_id = params.task.id
|
|
101
|
+
self._parent_span_id = params.task.id
|
|
102
|
+
|
|
103
|
+
# Add the user message to conversation history
|
|
104
|
+
self._state.input_list.append({"role": "user", "content": params.event.content.content})
|
|
105
|
+
|
|
106
|
+
# Echo back the client's message to show it in the UI
|
|
107
|
+
await adk.messages.create(task_id=params.task.id, content=params.event.content)
|
|
108
|
+
|
|
109
|
+
temporal_streaming_hooks = TemporalStreamingHooks(task_id=params.task.id)
|
|
110
|
+
|
|
111
|
+
# Create a span to track this turn of the conversation
|
|
112
|
+
turn_input = TurnInput(
|
|
113
|
+
input_list=self._state.input_list,
|
|
114
|
+
)
|
|
115
|
+
async with adk.tracing.span(
|
|
116
|
+
trace_id=params.task.id,
|
|
117
|
+
name=f"Turn {self._state.turn_number}",
|
|
118
|
+
input=turn_input.model_dump(),
|
|
119
|
+
) as span:
|
|
120
|
+
self._parent_span_id = span.id if span else None
|
|
121
|
+
|
|
122
|
+
# Create the OpenAI agent with tools
|
|
123
|
+
# Add your activities as tools using activity_as_tool()
|
|
124
|
+
agent = Agent(
|
|
125
|
+
name="{{ agent_name }}",
|
|
126
|
+
instructions="You are a helpful assistant. Use your tools to help the user.",
|
|
127
|
+
model="gpt-4o-mini",
|
|
128
|
+
tools=[
|
|
129
|
+
openai_agents.workflow.activity_as_tool(
|
|
130
|
+
get_weather,
|
|
131
|
+
start_to_close_timeout=timedelta(minutes=5),
|
|
132
|
+
),
|
|
133
|
+
# Add more tools here as you create new activities:
|
|
134
|
+
# openai_agents.workflow.activity_as_tool(
|
|
135
|
+
# your_new_activity,
|
|
136
|
+
# start_to_close_timeout=timedelta(minutes=5),
|
|
137
|
+
# ),
|
|
138
|
+
],
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Run the agent with hooks to enable streaming responses
|
|
142
|
+
result = await Runner.run(agent, self._state.input_list, hooks=temporal_streaming_hooks)
|
|
143
|
+
|
|
144
|
+
# Update the state with the assistant's response for the next turn
|
|
145
|
+
self._state.input_list = result.to_input_list() # type: ignore[assignment]
|
|
146
|
+
|
|
147
|
+
# Set span output for tracing - include full state
|
|
148
|
+
if span:
|
|
149
|
+
turn_output = TurnOutput(final_output=result.final_output)
|
|
150
|
+
span.output = turn_output.model_dump()
|
|
151
|
+
|
|
152
|
+
@workflow.run
|
|
153
|
+
async def on_task_create(self, params: CreateTaskParams) -> str:
|
|
154
|
+
logger.info(f"Received task create params: {params}")
|
|
155
|
+
|
|
156
|
+
# Acknowledge that the task has been created
|
|
157
|
+
await adk.messages.create(
|
|
158
|
+
task_id=params.task.id,
|
|
159
|
+
content=TextContent(
|
|
160
|
+
author="agent",
|
|
161
|
+
content=f"Hello! I'm {{ agent_name }}, your AI assistant. How can I help you today?\n\nParams received:\n{json.dumps(params.params, indent=2)}",
|
|
162
|
+
),
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
await workflow.wait_condition(
|
|
166
|
+
lambda: self._complete_task,
|
|
167
|
+
timeout=None,
|
|
168
|
+
)
|
|
169
|
+
return "Task completed"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "{{ project_name }}"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "{{ description }}"
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"agentex-sdk",
|
|
12
|
+
"scale-gp",
|
|
13
|
+
"temporalio",
|
|
14
|
+
"openai-agents>=0.4.2",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.optional-dependencies]
|
|
18
|
+
dev = [
|
|
19
|
+
"pytest",
|
|
20
|
+
"black",
|
|
21
|
+
"isort",
|
|
22
|
+
"flake8",
|
|
23
|
+
"debugpy>=1.8.15",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[tool.hatch.build.targets.wheel]
|
|
27
|
+
packages = ["project"]
|
|
28
|
+
|
|
29
|
+
[tool.black]
|
|
30
|
+
line-length = 88
|
|
31
|
+
target-version = ['py312']
|
|
32
|
+
|
|
33
|
+
[tool.isort]
|
|
34
|
+
profile = "black"
|
|
35
|
+
line_length = 88
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Sample tests for AgentEx ACP agent.
|
|
3
|
+
|
|
4
|
+
This test suite demonstrates how to test the main AgentEx API functions:
|
|
5
|
+
- Non-streaming event sending and polling
|
|
6
|
+
- Streaming event sending
|
|
7
|
+
|
|
8
|
+
To run these tests:
|
|
9
|
+
1. Make sure the agent is running (via docker-compose or `agentex agents run`)
|
|
10
|
+
2. Set the AGENTEX_API_BASE_URL environment variable if not using default
|
|
11
|
+
3. Run: pytest test_agent.py -v
|
|
12
|
+
|
|
13
|
+
Configuration:
|
|
14
|
+
- AGENTEX_API_BASE_URL: Base URL for the AgentEx server (default: http://localhost:5003)
|
|
15
|
+
- AGENT_NAME: Name of the agent to test (default: {{ agent_name }})
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import uuid
|
|
20
|
+
import asyncio
|
|
21
|
+
import pytest
|
|
22
|
+
import pytest_asyncio
|
|
23
|
+
from agentex import AsyncAgentex
|
|
24
|
+
from agentex.types import TaskMessage
|
|
25
|
+
from agentex.types.agent_rpc_params import ParamsCreateTaskRequest
|
|
26
|
+
from agentex.types.text_content_param import TextContentParam
|
|
27
|
+
from test_utils.async_utils import (
|
|
28
|
+
poll_for_agent_response,
|
|
29
|
+
send_event_and_poll_yielding,
|
|
30
|
+
stream_agent_response,
|
|
31
|
+
validate_text_in_response,
|
|
32
|
+
poll_messages,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Configuration from environment variables
|
|
37
|
+
AGENTEX_API_BASE_URL = os.environ.get("AGENTEX_API_BASE_URL", "http://localhost:5003")
|
|
38
|
+
AGENT_NAME = os.environ.get("AGENT_NAME", "{{ agent_name }}")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest_asyncio.fixture
|
|
42
|
+
async def client():
|
|
43
|
+
"""Create an AsyncAgentex client instance for testing."""
|
|
44
|
+
client = AsyncAgentex(base_url=AGENTEX_API_BASE_URL)
|
|
45
|
+
yield client
|
|
46
|
+
await client.close()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@pytest.fixture
|
|
50
|
+
def agent_name():
|
|
51
|
+
"""Return the agent name for testing."""
|
|
52
|
+
return AGENT_NAME
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest_asyncio.fixture
|
|
56
|
+
async def agent_id(client, agent_name):
|
|
57
|
+
"""Retrieve the agent ID based on the agent name."""
|
|
58
|
+
agents = await client.agents.list()
|
|
59
|
+
for agent in agents:
|
|
60
|
+
if agent.name == agent_name:
|
|
61
|
+
return agent.id
|
|
62
|
+
raise ValueError(f"Agent with name {agent_name} not found.")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class TestNonStreamingEvents:
|
|
66
|
+
"""Test non-streaming event sending and polling."""
|
|
67
|
+
|
|
68
|
+
@pytest.mark.asyncio
|
|
69
|
+
async def test_send_event_and_poll(self, client: AsyncAgentex, _agent_name: str, agent_id: str):
|
|
70
|
+
"""Test sending an event and polling for the response."""
|
|
71
|
+
# TODO: Create a task for this conversation
|
|
72
|
+
# task_response = await client.agents.create_task(agent_id, params=ParamsCreateTaskRequest(name=uuid.uuid1().hex))
|
|
73
|
+
# task = task_response.result
|
|
74
|
+
# assert task is not None
|
|
75
|
+
|
|
76
|
+
# TODO: Poll for the initial task creation message (if your agent sends one)
|
|
77
|
+
# async for message in poll_messages(
|
|
78
|
+
# client=client,
|
|
79
|
+
# task_id=task.id,
|
|
80
|
+
# timeout=30,
|
|
81
|
+
# sleep_interval=1.0,
|
|
82
|
+
# ):
|
|
83
|
+
# assert isinstance(message, TaskMessage)
|
|
84
|
+
# if message.content and message.content.type == "text" and message.content.author == "agent":
|
|
85
|
+
# # Check for your expected initial message
|
|
86
|
+
# assert "expected initial text" in message.content.content
|
|
87
|
+
# break
|
|
88
|
+
|
|
89
|
+
# TODO: Send an event and poll for response using the yielding helper function
|
|
90
|
+
# user_message = "Your test message here"
|
|
91
|
+
# async for message in send_event_and_poll_yielding(
|
|
92
|
+
# client=client,
|
|
93
|
+
# agent_id=agent_id,
|
|
94
|
+
# task_id=task.id,
|
|
95
|
+
# user_message=user_message,
|
|
96
|
+
# timeout=30,
|
|
97
|
+
# sleep_interval=1.0,
|
|
98
|
+
# ):
|
|
99
|
+
# assert isinstance(message, TaskMessage)
|
|
100
|
+
# if message.content and message.content.type == "text" and message.content.author == "agent":
|
|
101
|
+
# # Check for your expected response
|
|
102
|
+
# assert "expected response text" in message.content.content
|
|
103
|
+
# break
|
|
104
|
+
pass
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class TestStreamingEvents:
|
|
108
|
+
"""Test streaming event sending."""
|
|
109
|
+
|
|
110
|
+
@pytest.mark.asyncio
|
|
111
|
+
async def test_send_event_and_stream(self, client: AsyncAgentex, _agent_name: str, agent_id: str):
|
|
112
|
+
"""Test sending an event and streaming the response."""
|
|
113
|
+
# TODO: Create a task for this conversation
|
|
114
|
+
# task_response = await client.agents.create_task(agent_id, params=ParamsCreateTaskRequest(name=uuid.uuid1().hex))
|
|
115
|
+
# task = task_response.result
|
|
116
|
+
# assert task is not None
|
|
117
|
+
|
|
118
|
+
# user_message = "Your test message here"
|
|
119
|
+
|
|
120
|
+
# # Collect events from stream
|
|
121
|
+
# all_events = []
|
|
122
|
+
|
|
123
|
+
# async def collect_stream_events():
|
|
124
|
+
# async for event in stream_agent_response(
|
|
125
|
+
# client=client,
|
|
126
|
+
# task_id=task.id,
|
|
127
|
+
# timeout=30,
|
|
128
|
+
# ):
|
|
129
|
+
# all_events.append(event)
|
|
130
|
+
|
|
131
|
+
# # Start streaming task
|
|
132
|
+
# stream_task = asyncio.create_task(collect_stream_events())
|
|
133
|
+
|
|
134
|
+
# # Send the event
|
|
135
|
+
# event_content = TextContentParam(type="text", author="user", content=user_message)
|
|
136
|
+
# await client.agents.send_event(agent_id=agent_id, params={"task_id": task.id, "content": event_content})
|
|
137
|
+
|
|
138
|
+
# # Wait for streaming to complete
|
|
139
|
+
# await stream_task
|
|
140
|
+
|
|
141
|
+
# # TODO: Add your validation here
|
|
142
|
+
# assert len(all_events) > 0, "No events received in streaming response"
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
if __name__ == "__main__":
|
|
147
|
+
pytest.main([__file__, "-v"])
|
|
@@ -15,7 +15,12 @@ from .batch import (
|
|
|
15
15
|
BatchResourceWithStreamingResponse,
|
|
16
16
|
AsyncBatchResourceWithStreamingResponse,
|
|
17
17
|
)
|
|
18
|
-
from ...types import
|
|
18
|
+
from ...types import (
|
|
19
|
+
message_list_params,
|
|
20
|
+
message_create_params,
|
|
21
|
+
message_update_params,
|
|
22
|
+
message_list_paginated_params,
|
|
23
|
+
)
|
|
19
24
|
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
|
|
20
25
|
from ..._utils import maybe_transform, async_maybe_transform
|
|
21
26
|
from ..._compat import cached_property
|
|
@@ -30,6 +35,7 @@ from ..._base_client import make_request_options
|
|
|
30
35
|
from ...types.task_message import TaskMessage
|
|
31
36
|
from ...types.message_list_response import MessageListResponse
|
|
32
37
|
from ...types.task_message_content_param import TaskMessageContentParam
|
|
38
|
+
from ...types.message_list_paginated_response import MessageListPaginatedResponse
|
|
33
39
|
|
|
34
40
|
__all__ = ["MessagesResource", "AsyncMessagesResource"]
|
|
35
41
|
|
|
@@ -192,7 +198,10 @@ class MessagesResource(SyncAPIResource):
|
|
|
192
198
|
timeout: float | httpx.Timeout | None | NotGiven = not_given,
|
|
193
199
|
) -> MessageListResponse:
|
|
194
200
|
"""
|
|
195
|
-
List
|
|
201
|
+
List messages for a task with offset-based pagination.
|
|
202
|
+
|
|
203
|
+
For cursor-based pagination with infinite scroll support, use
|
|
204
|
+
/messages/paginated.
|
|
196
205
|
|
|
197
206
|
Args:
|
|
198
207
|
task_id: The task ID
|
|
@@ -226,6 +235,70 @@ class MessagesResource(SyncAPIResource):
|
|
|
226
235
|
cast_to=MessageListResponse,
|
|
227
236
|
)
|
|
228
237
|
|
|
238
|
+
def list_paginated(
|
|
239
|
+
self,
|
|
240
|
+
*,
|
|
241
|
+
task_id: str,
|
|
242
|
+
cursor: Optional[str] | Omit = omit,
|
|
243
|
+
direction: Literal["older", "newer"] | Omit = omit,
|
|
244
|
+
limit: int | Omit = omit,
|
|
245
|
+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
|
|
246
|
+
# The extra values given here take precedence over values defined on the client or passed to this method.
|
|
247
|
+
extra_headers: Headers | None = None,
|
|
248
|
+
extra_query: Query | None = None,
|
|
249
|
+
extra_body: Body | None = None,
|
|
250
|
+
timeout: float | httpx.Timeout | None | NotGiven = not_given,
|
|
251
|
+
) -> MessageListPaginatedResponse:
|
|
252
|
+
"""
|
|
253
|
+
List messages for a task with cursor-based pagination.
|
|
254
|
+
|
|
255
|
+
This endpoint is designed for infinite scroll UIs where new messages may arrive
|
|
256
|
+
while paginating through older ones.
|
|
257
|
+
|
|
258
|
+
Args: task_id: The task ID to filter messages by limit: Maximum number of
|
|
259
|
+
messages to return (default: 50) cursor: Opaque cursor string for pagination.
|
|
260
|
+
Pass the `next_cursor` from a previous response to get the next page. direction:
|
|
261
|
+
Pagination direction - "older" to get older messages (default), "newer" to get
|
|
262
|
+
newer messages.
|
|
263
|
+
|
|
264
|
+
Returns: PaginatedMessagesResponse with: - data: List of messages (newest first
|
|
265
|
+
when direction="older") - next_cursor: Cursor for fetching the next page (null
|
|
266
|
+
if no more pages) - has_more: Whether there are more messages to fetch
|
|
267
|
+
|
|
268
|
+
Example: First request: GET /messages/paginated?task_id=xxx&limit=50 Next page:
|
|
269
|
+
GET /messages/paginated?task_id=xxx&limit=50&cursor=<next_cursor>
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
task_id: The task ID
|
|
273
|
+
|
|
274
|
+
extra_headers: Send extra headers
|
|
275
|
+
|
|
276
|
+
extra_query: Add additional query parameters to the request
|
|
277
|
+
|
|
278
|
+
extra_body: Add additional JSON properties to the request
|
|
279
|
+
|
|
280
|
+
timeout: Override the client-level default timeout for this request, in seconds
|
|
281
|
+
"""
|
|
282
|
+
return self._get(
|
|
283
|
+
"/messages/paginated",
|
|
284
|
+
options=make_request_options(
|
|
285
|
+
extra_headers=extra_headers,
|
|
286
|
+
extra_query=extra_query,
|
|
287
|
+
extra_body=extra_body,
|
|
288
|
+
timeout=timeout,
|
|
289
|
+
query=maybe_transform(
|
|
290
|
+
{
|
|
291
|
+
"task_id": task_id,
|
|
292
|
+
"cursor": cursor,
|
|
293
|
+
"direction": direction,
|
|
294
|
+
"limit": limit,
|
|
295
|
+
},
|
|
296
|
+
message_list_paginated_params.MessageListPaginatedParams,
|
|
297
|
+
),
|
|
298
|
+
),
|
|
299
|
+
cast_to=MessageListPaginatedResponse,
|
|
300
|
+
)
|
|
301
|
+
|
|
229
302
|
|
|
230
303
|
class AsyncMessagesResource(AsyncAPIResource):
|
|
231
304
|
@cached_property
|
|
@@ -385,7 +458,10 @@ class AsyncMessagesResource(AsyncAPIResource):
|
|
|
385
458
|
timeout: float | httpx.Timeout | None | NotGiven = not_given,
|
|
386
459
|
) -> MessageListResponse:
|
|
387
460
|
"""
|
|
388
|
-
List
|
|
461
|
+
List messages for a task with offset-based pagination.
|
|
462
|
+
|
|
463
|
+
For cursor-based pagination with infinite scroll support, use
|
|
464
|
+
/messages/paginated.
|
|
389
465
|
|
|
390
466
|
Args:
|
|
391
467
|
task_id: The task ID
|
|
@@ -419,6 +495,70 @@ class AsyncMessagesResource(AsyncAPIResource):
|
|
|
419
495
|
cast_to=MessageListResponse,
|
|
420
496
|
)
|
|
421
497
|
|
|
498
|
+
async def list_paginated(
|
|
499
|
+
self,
|
|
500
|
+
*,
|
|
501
|
+
task_id: str,
|
|
502
|
+
cursor: Optional[str] | Omit = omit,
|
|
503
|
+
direction: Literal["older", "newer"] | Omit = omit,
|
|
504
|
+
limit: int | Omit = omit,
|
|
505
|
+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
|
|
506
|
+
# The extra values given here take precedence over values defined on the client or passed to this method.
|
|
507
|
+
extra_headers: Headers | None = None,
|
|
508
|
+
extra_query: Query | None = None,
|
|
509
|
+
extra_body: Body | None = None,
|
|
510
|
+
timeout: float | httpx.Timeout | None | NotGiven = not_given,
|
|
511
|
+
) -> MessageListPaginatedResponse:
|
|
512
|
+
"""
|
|
513
|
+
List messages for a task with cursor-based pagination.
|
|
514
|
+
|
|
515
|
+
This endpoint is designed for infinite scroll UIs where new messages may arrive
|
|
516
|
+
while paginating through older ones.
|
|
517
|
+
|
|
518
|
+
Args: task_id: The task ID to filter messages by limit: Maximum number of
|
|
519
|
+
messages to return (default: 50) cursor: Opaque cursor string for pagination.
|
|
520
|
+
Pass the `next_cursor` from a previous response to get the next page. direction:
|
|
521
|
+
Pagination direction - "older" to get older messages (default), "newer" to get
|
|
522
|
+
newer messages.
|
|
523
|
+
|
|
524
|
+
Returns: PaginatedMessagesResponse with: - data: List of messages (newest first
|
|
525
|
+
when direction="older") - next_cursor: Cursor for fetching the next page (null
|
|
526
|
+
if no more pages) - has_more: Whether there are more messages to fetch
|
|
527
|
+
|
|
528
|
+
Example: First request: GET /messages/paginated?task_id=xxx&limit=50 Next page:
|
|
529
|
+
GET /messages/paginated?task_id=xxx&limit=50&cursor=<next_cursor>
|
|
530
|
+
|
|
531
|
+
Args:
|
|
532
|
+
task_id: The task ID
|
|
533
|
+
|
|
534
|
+
extra_headers: Send extra headers
|
|
535
|
+
|
|
536
|
+
extra_query: Add additional query parameters to the request
|
|
537
|
+
|
|
538
|
+
extra_body: Add additional JSON properties to the request
|
|
539
|
+
|
|
540
|
+
timeout: Override the client-level default timeout for this request, in seconds
|
|
541
|
+
"""
|
|
542
|
+
return await self._get(
|
|
543
|
+
"/messages/paginated",
|
|
544
|
+
options=make_request_options(
|
|
545
|
+
extra_headers=extra_headers,
|
|
546
|
+
extra_query=extra_query,
|
|
547
|
+
extra_body=extra_body,
|
|
548
|
+
timeout=timeout,
|
|
549
|
+
query=await async_maybe_transform(
|
|
550
|
+
{
|
|
551
|
+
"task_id": task_id,
|
|
552
|
+
"cursor": cursor,
|
|
553
|
+
"direction": direction,
|
|
554
|
+
"limit": limit,
|
|
555
|
+
},
|
|
556
|
+
message_list_paginated_params.MessageListPaginatedParams,
|
|
557
|
+
),
|
|
558
|
+
),
|
|
559
|
+
cast_to=MessageListPaginatedResponse,
|
|
560
|
+
)
|
|
561
|
+
|
|
422
562
|
|
|
423
563
|
class MessagesResourceWithRawResponse:
|
|
424
564
|
def __init__(self, messages: MessagesResource) -> None:
|
|
@@ -436,6 +576,9 @@ class MessagesResourceWithRawResponse:
|
|
|
436
576
|
self.list = to_raw_response_wrapper(
|
|
437
577
|
messages.list,
|
|
438
578
|
)
|
|
579
|
+
self.list_paginated = to_raw_response_wrapper(
|
|
580
|
+
messages.list_paginated,
|
|
581
|
+
)
|
|
439
582
|
|
|
440
583
|
@cached_property
|
|
441
584
|
def batch(self) -> BatchResourceWithRawResponse:
|
|
@@ -458,6 +601,9 @@ class AsyncMessagesResourceWithRawResponse:
|
|
|
458
601
|
self.list = async_to_raw_response_wrapper(
|
|
459
602
|
messages.list,
|
|
460
603
|
)
|
|
604
|
+
self.list_paginated = async_to_raw_response_wrapper(
|
|
605
|
+
messages.list_paginated,
|
|
606
|
+
)
|
|
461
607
|
|
|
462
608
|
@cached_property
|
|
463
609
|
def batch(self) -> AsyncBatchResourceWithRawResponse:
|
|
@@ -480,6 +626,9 @@ class MessagesResourceWithStreamingResponse:
|
|
|
480
626
|
self.list = to_streamed_response_wrapper(
|
|
481
627
|
messages.list,
|
|
482
628
|
)
|
|
629
|
+
self.list_paginated = to_streamed_response_wrapper(
|
|
630
|
+
messages.list_paginated,
|
|
631
|
+
)
|
|
483
632
|
|
|
484
633
|
@cached_property
|
|
485
634
|
def batch(self) -> BatchResourceWithStreamingResponse:
|
|
@@ -502,6 +651,9 @@ class AsyncMessagesResourceWithStreamingResponse:
|
|
|
502
651
|
self.list = async_to_streamed_response_wrapper(
|
|
503
652
|
messages.list,
|
|
504
653
|
)
|
|
654
|
+
self.list_paginated = async_to_streamed_response_wrapper(
|
|
655
|
+
messages.list_paginated,
|
|
656
|
+
)
|
|
505
657
|
|
|
506
658
|
@cached_property
|
|
507
659
|
def batch(self) -> AsyncBatchResourceWithStreamingResponse:
|
agentex/types/__init__.py
CHANGED
|
@@ -63,6 +63,8 @@ from .task_message_content_param import TaskMessageContentParam as TaskMessageCo
|
|
|
63
63
|
from .tool_request_content_param import ToolRequestContentParam as ToolRequestContentParam
|
|
64
64
|
from .tool_response_content_param import ToolResponseContentParam as ToolResponseContentParam
|
|
65
65
|
from .task_retrieve_by_name_params import TaskRetrieveByNameParams as TaskRetrieveByNameParams
|
|
66
|
+
from .message_list_paginated_params import MessageListPaginatedParams as MessageListPaginatedParams
|
|
66
67
|
from .deployment_history_list_params import DeploymentHistoryListParams as DeploymentHistoryListParams
|
|
67
68
|
from .task_retrieve_by_name_response import TaskRetrieveByNameResponse as TaskRetrieveByNameResponse
|
|
69
|
+
from .message_list_paginated_response import MessageListPaginatedResponse as MessageListPaginatedResponse
|
|
68
70
|
from .deployment_history_list_response import DeploymentHistoryListResponse as DeploymentHistoryListResponse
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from typing_extensions import Literal, Required, TypedDict
|
|
7
|
+
|
|
8
|
+
__all__ = ["MessageListPaginatedParams"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MessageListPaginatedParams(TypedDict, total=False):
|
|
12
|
+
task_id: Required[str]
|
|
13
|
+
"""The task ID"""
|
|
14
|
+
|
|
15
|
+
cursor: Optional[str]
|
|
16
|
+
|
|
17
|
+
direction: Literal["older", "newer"]
|
|
18
|
+
|
|
19
|
+
limit: int
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
+
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
from .._models import BaseModel
|
|
6
|
+
from .task_message import TaskMessage
|
|
7
|
+
|
|
8
|
+
__all__ = ["MessageListPaginatedResponse"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MessageListPaginatedResponse(BaseModel):
|
|
12
|
+
"""Response with cursor pagination metadata."""
|
|
13
|
+
|
|
14
|
+
data: List[TaskMessage]
|
|
15
|
+
"""List of messages"""
|
|
16
|
+
|
|
17
|
+
has_more: Optional[bool] = None
|
|
18
|
+
"""Whether there are more messages to fetch"""
|
|
19
|
+
|
|
20
|
+
next_cursor: Optional[str] = None
|
|
21
|
+
"""Cursor for fetching the next page of older messages"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: agentex-sdk
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: The official Python library for the agentex API
|
|
5
5
|
Project-URL: Homepage, https://github.com/scaleapi/scale-agentex-python
|
|
6
6
|
Project-URL: Repository, https://github.com/scaleapi/scale-agentex-python
|