agent-api-server 2.2.1a2__tar.gz → 2.2.1a4__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.
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/PKG-INFO +2 -2
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/adapters/openclaw_adapter/openclaw_adapter.py +235 -21
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/api/thread.py +29 -7
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/pyproject.toml +1 -1
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/sdk/client.py +12 -6
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/README.md +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/adapters/__init__.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/adapters/langgraph_adapter/__init__.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/adapters/langgraph_adapter/formatter.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/adapters/langgraph_adapter/langgraph_adapter.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/adapters/openclaw_adapter/__init__.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/agent_api_server.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/api/__init__.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/api/config.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/api/graph.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/api/router.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/api/schema.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/client/css/styles.css +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/client/favicon.ico +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/client/index.html +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/client/js/app.js +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/client/js/index.umd.js +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/common/__init__.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/common/config.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/common/crypto.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/common/formatting.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/common/logging.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/common/nats.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/common/postgres.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/common/redis.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/__init__.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/loader.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/model/__init__.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/model/agent_models.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/model/base_model.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/model/detect_message.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/model/dynamic_llm.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/model/input_normalization.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/model/middleware.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/model/model_info.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/model/schema_utils.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/model/streaming.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/runtime/__init__.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/runtime/base.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/core/runtime/manager.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/demo.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/integration/__init__.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/integration/listener.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/integration/registry.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/logging.json +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/sdk/__init__.py +0 -0
- {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/service.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-api-server
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.1a4
|
|
4
4
|
Summary: A Langgraph agent API server that implements Langgraph agent's web capabilities and can interact with chatbot
|
|
5
5
|
Keywords: fastapi,langgraph,agent,api-server
|
|
6
6
|
Requires-Python: >=3.11,<3.14
|
{agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/adapters/openclaw_adapter/openclaw_adapter.py
RENAMED
|
@@ -3,6 +3,7 @@ import hashlib
|
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
5
|
import platform
|
|
6
|
+
import re
|
|
6
7
|
import shlex
|
|
7
8
|
import time
|
|
8
9
|
from pathlib import Path
|
|
@@ -317,6 +318,10 @@ class OpenClawAgentAdapter(BaseAgentAdapter):
|
|
|
317
318
|
self.session_name = self.settings.get("session_name", "main")
|
|
318
319
|
self.query_field = self.settings.get("query_field")
|
|
319
320
|
self.execution_settings = dict(self.settings.get("execution_options") or {})
|
|
321
|
+
self.run_completion_idle_timeout_seconds = self._resolve_run_completion_idle_timeout_seconds(
|
|
322
|
+
self.settings,
|
|
323
|
+
self.execution_settings,
|
|
324
|
+
)
|
|
320
325
|
self.workspace = self._resolve_workspace(self.settings.get("workspace"))
|
|
321
326
|
self.agent_config = dict(self.settings.get("agent_config") or {})
|
|
322
327
|
|
|
@@ -381,8 +386,11 @@ class OpenClawAgentAdapter(BaseAgentAdapter):
|
|
|
381
386
|
session_name = self._resolve_session_name(context=context)
|
|
382
387
|
try:
|
|
383
388
|
agent = await self._load_agent(client, context=context)
|
|
384
|
-
|
|
385
|
-
|
|
389
|
+
return await self._collect_run_result(
|
|
390
|
+
agent=agent,
|
|
391
|
+
query=self._resolve_query(inputs),
|
|
392
|
+
context=context,
|
|
393
|
+
session_name=session_name,
|
|
386
394
|
options=self._build_execution_options(context),
|
|
387
395
|
)
|
|
388
396
|
except Exception as exc:
|
|
@@ -390,25 +398,6 @@ class OpenClawAgentAdapter(BaseAgentAdapter):
|
|
|
390
398
|
finally:
|
|
391
399
|
await client.close()
|
|
392
400
|
|
|
393
|
-
if not result.success and result.error_message:
|
|
394
|
-
raise RuntimeError(result.error_message)
|
|
395
|
-
|
|
396
|
-
return ChatMessage(
|
|
397
|
-
type="ai",
|
|
398
|
-
content_type=detect_content_type(result.content),
|
|
399
|
-
content=result.content,
|
|
400
|
-
tool_calls=[self._normalize_tool_call(tool_call) for tool_call in result.tool_calls],
|
|
401
|
-
response_metadata={
|
|
402
|
-
"latency_ms": result.latency_ms,
|
|
403
|
-
"stop_reason": result.stop_reason,
|
|
404
|
-
"token_usage": serialize_data(result.token_usage),
|
|
405
|
-
"completed_at": serialize_data(result.completed_at),
|
|
406
|
-
"conversation_id": self._resolve_conversation_id(context),
|
|
407
|
-
"session_name": session_name,
|
|
408
|
-
},
|
|
409
|
-
references=[],
|
|
410
|
-
)
|
|
411
|
-
|
|
412
401
|
async def stream(self, inputs: dict[str, Any], context: AgentExecutionContext) -> AsyncIterator[str]:
|
|
413
402
|
client = await self._connect_client()
|
|
414
403
|
content_parts: list[str] = []
|
|
@@ -693,6 +682,231 @@ class OpenClawAgentAdapter(BaseAgentAdapter):
|
|
|
693
682
|
options["attachments"] = attachments
|
|
694
683
|
return ExecutionOptions(**options)
|
|
695
684
|
|
|
685
|
+
async def _collect_run_result(
|
|
686
|
+
self,
|
|
687
|
+
*,
|
|
688
|
+
agent,
|
|
689
|
+
query: str,
|
|
690
|
+
context: AgentExecutionContext,
|
|
691
|
+
session_name: str,
|
|
692
|
+
options,
|
|
693
|
+
) -> ChatMessage:
|
|
694
|
+
content_parts: list[str] = []
|
|
695
|
+
tool_calls: list[dict[str, Any]] = []
|
|
696
|
+
last_message: ChatMessage | None = None
|
|
697
|
+
last_real_tool_message: ChatMessage | None = None
|
|
698
|
+
event_iterator = agent.execute_stream_typed(query, options=options).__aiter__()
|
|
699
|
+
|
|
700
|
+
while True:
|
|
701
|
+
timeout = self.run_completion_idle_timeout_seconds if last_message is not None else None
|
|
702
|
+
try:
|
|
703
|
+
if timeout is None:
|
|
704
|
+
event = await anext(event_iterator)
|
|
705
|
+
else:
|
|
706
|
+
event = await asyncio.wait_for(anext(event_iterator), timeout=timeout)
|
|
707
|
+
except StopAsyncIteration:
|
|
708
|
+
break
|
|
709
|
+
except asyncio.TimeoutError:
|
|
710
|
+
logger.warning(
|
|
711
|
+
"OpenClaw run stream idle timeout without DoneEvent; agent=%s session=%s timeout_s=%s last_message_type=%s last_real_tool_message=%s",
|
|
712
|
+
self.agent_id,
|
|
713
|
+
session_name,
|
|
714
|
+
timeout,
|
|
715
|
+
last_message.type if last_message is not None else None,
|
|
716
|
+
last_real_tool_message is not None,
|
|
717
|
+
)
|
|
718
|
+
break
|
|
719
|
+
|
|
720
|
+
if isinstance(event, ContentEvent):
|
|
721
|
+
if event.text:
|
|
722
|
+
content_parts.append(event.text)
|
|
723
|
+
last_message = self._build_ai_message(
|
|
724
|
+
content="".join(content_parts),
|
|
725
|
+
tool_calls=tool_calls,
|
|
726
|
+
context=context,
|
|
727
|
+
session_name=session_name,
|
|
728
|
+
)
|
|
729
|
+
continue
|
|
730
|
+
|
|
731
|
+
if ThinkingEvent is not None and isinstance(event, ThinkingEvent):
|
|
732
|
+
continue
|
|
733
|
+
|
|
734
|
+
if isinstance(event, ToolCallEvent):
|
|
735
|
+
tool_calls = [*tool_calls, self._normalize_tool_call({"tool": event.tool, "input": event.input})]
|
|
736
|
+
last_message = self._build_ai_message(
|
|
737
|
+
content="".join(content_parts),
|
|
738
|
+
tool_calls=tool_calls,
|
|
739
|
+
context=context,
|
|
740
|
+
session_name=session_name,
|
|
741
|
+
)
|
|
742
|
+
continue
|
|
743
|
+
|
|
744
|
+
if isinstance(event, ToolResultEvent):
|
|
745
|
+
tool_message = self._build_tool_message(
|
|
746
|
+
output=event.output,
|
|
747
|
+
tool=event.tool,
|
|
748
|
+
duration_ms=event.duration_ms,
|
|
749
|
+
context=context,
|
|
750
|
+
session_name=session_name,
|
|
751
|
+
)
|
|
752
|
+
last_message = tool_message
|
|
753
|
+
if self._is_real_tool_message(tool_message):
|
|
754
|
+
last_real_tool_message = tool_message
|
|
755
|
+
continue
|
|
756
|
+
|
|
757
|
+
if isinstance(event, DoneEvent):
|
|
758
|
+
final_content = event.content or "".join(content_parts)
|
|
759
|
+
if final_content:
|
|
760
|
+
return self._build_ai_message(
|
|
761
|
+
content=final_content,
|
|
762
|
+
tool_calls=[],
|
|
763
|
+
context=context,
|
|
764
|
+
session_name=session_name,
|
|
765
|
+
extra_metadata={
|
|
766
|
+
"token_usage": serialize_data(event.token_usage),
|
|
767
|
+
"stop_reason": event.stop_reason,
|
|
768
|
+
},
|
|
769
|
+
)
|
|
770
|
+
|
|
771
|
+
return self._build_terminal_fallback_message(
|
|
772
|
+
context=context,
|
|
773
|
+
session_name=session_name,
|
|
774
|
+
tool_calls=tool_calls,
|
|
775
|
+
last_message=last_message,
|
|
776
|
+
last_real_tool_message=last_real_tool_message,
|
|
777
|
+
extra_metadata={"token_usage": serialize_data(event.token_usage), "stop_reason": event.stop_reason},
|
|
778
|
+
)
|
|
779
|
+
|
|
780
|
+
if isinstance(event, ErrorEvent):
|
|
781
|
+
raise RuntimeError(event.message)
|
|
782
|
+
|
|
783
|
+
return self._build_terminal_fallback_message(
|
|
784
|
+
context=context,
|
|
785
|
+
session_name=session_name,
|
|
786
|
+
tool_calls=tool_calls,
|
|
787
|
+
last_message=last_message,
|
|
788
|
+
last_real_tool_message=last_real_tool_message,
|
|
789
|
+
)
|
|
790
|
+
|
|
791
|
+
def _build_ai_message(
|
|
792
|
+
self,
|
|
793
|
+
*,
|
|
794
|
+
content: str,
|
|
795
|
+
tool_calls: list[dict[str, Any]],
|
|
796
|
+
context: AgentExecutionContext,
|
|
797
|
+
session_name: str,
|
|
798
|
+
extra_metadata: dict[str, Any] | None = None,
|
|
799
|
+
) -> ChatMessage:
|
|
800
|
+
return ChatMessage(
|
|
801
|
+
type="ai",
|
|
802
|
+
content_type=detect_content_type(content),
|
|
803
|
+
content=content,
|
|
804
|
+
tool_calls=list(tool_calls),
|
|
805
|
+
response_metadata={
|
|
806
|
+
"conversation_id": self._resolve_conversation_id(context),
|
|
807
|
+
"session_name": session_name,
|
|
808
|
+
**(extra_metadata or {}),
|
|
809
|
+
},
|
|
810
|
+
references=[],
|
|
811
|
+
)
|
|
812
|
+
|
|
813
|
+
def _build_terminal_fallback_message(
|
|
814
|
+
self,
|
|
815
|
+
*,
|
|
816
|
+
context: AgentExecutionContext,
|
|
817
|
+
session_name: str,
|
|
818
|
+
tool_calls: list[dict[str, Any]],
|
|
819
|
+
last_message: ChatMessage | None,
|
|
820
|
+
last_real_tool_message: ChatMessage | None,
|
|
821
|
+
extra_metadata: dict[str, Any] | None = None,
|
|
822
|
+
) -> ChatMessage:
|
|
823
|
+
if last_real_tool_message is not None:
|
|
824
|
+
return last_real_tool_message.model_copy(
|
|
825
|
+
update={"response_metadata": {**last_real_tool_message.response_metadata, **(extra_metadata or {})}}
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
if last_message is not None and last_message.type == "ai":
|
|
829
|
+
return last_message.model_copy(
|
|
830
|
+
update={"response_metadata": {**last_message.response_metadata, **(extra_metadata or {})}}
|
|
831
|
+
)
|
|
832
|
+
|
|
833
|
+
return self._build_ai_message(
|
|
834
|
+
content="",
|
|
835
|
+
tool_calls=tool_calls,
|
|
836
|
+
context=context,
|
|
837
|
+
session_name=session_name,
|
|
838
|
+
extra_metadata=extra_metadata,
|
|
839
|
+
)
|
|
840
|
+
|
|
841
|
+
@staticmethod
|
|
842
|
+
def _is_semantic_tool_message(message: ChatMessage) -> bool:
|
|
843
|
+
content = message.content.strip()
|
|
844
|
+
if not content:
|
|
845
|
+
return False
|
|
846
|
+
if message.content_type != "text":
|
|
847
|
+
return True
|
|
848
|
+
|
|
849
|
+
low_signal_patterns = (
|
|
850
|
+
r"^Successfully wrote \d+ bytes to .+",
|
|
851
|
+
r"^Wrote \d+ bytes to .+",
|
|
852
|
+
r"^File written to .+",
|
|
853
|
+
r"^Saved to .+",
|
|
854
|
+
)
|
|
855
|
+
return not any(re.match(pattern, content) for pattern in low_signal_patterns)
|
|
856
|
+
|
|
857
|
+
@staticmethod
|
|
858
|
+
def _is_real_tool_message(message: ChatMessage) -> bool:
|
|
859
|
+
content = message.content.strip()
|
|
860
|
+
if not OpenClawAgentAdapter._is_semantic_tool_message(message):
|
|
861
|
+
return False
|
|
862
|
+
if message.content_type != "text":
|
|
863
|
+
return True
|
|
864
|
+
|
|
865
|
+
low_value_status_patterns = (
|
|
866
|
+
r"^(done|ok|success|completed)\.?$",
|
|
867
|
+
r"^(analysis|task|job) (done|completed|finished)\.?$",
|
|
868
|
+
r"^(saved|written) successfully\.?$",
|
|
869
|
+
)
|
|
870
|
+
return not any(re.match(pattern, content, re.IGNORECASE) for pattern in low_value_status_patterns)
|
|
871
|
+
|
|
872
|
+
@staticmethod
|
|
873
|
+
def _resolve_run_completion_idle_timeout_seconds(
|
|
874
|
+
settings: dict[str, Any],
|
|
875
|
+
execution_settings: dict[str, Any],
|
|
876
|
+
) -> float | None:
|
|
877
|
+
for source in (settings, execution_settings):
|
|
878
|
+
raw_value = source.get("run_completion_idle_timeout_seconds")
|
|
879
|
+
if raw_value is None:
|
|
880
|
+
continue
|
|
881
|
+
timeout = float(raw_value)
|
|
882
|
+
return timeout if timeout > 0 else None
|
|
883
|
+
return 5.0
|
|
884
|
+
|
|
885
|
+
def _build_tool_message(
|
|
886
|
+
self,
|
|
887
|
+
*,
|
|
888
|
+
output: str,
|
|
889
|
+
tool: str,
|
|
890
|
+
duration_ms: Any,
|
|
891
|
+
context: AgentExecutionContext,
|
|
892
|
+
session_name: str,
|
|
893
|
+
extra_metadata: dict[str, Any] | None = None,
|
|
894
|
+
) -> ChatMessage:
|
|
895
|
+
return ChatMessage(
|
|
896
|
+
type="tool",
|
|
897
|
+
content_type=detect_content_type(output),
|
|
898
|
+
content=output,
|
|
899
|
+
tool_calls=[],
|
|
900
|
+
response_metadata={
|
|
901
|
+
"duration_ms": duration_ms,
|
|
902
|
+
"tool": tool,
|
|
903
|
+
"conversation_id": self._resolve_conversation_id(context),
|
|
904
|
+
"session_name": session_name,
|
|
905
|
+
**(extra_metadata or {}),
|
|
906
|
+
},
|
|
907
|
+
references=[],
|
|
908
|
+
)
|
|
909
|
+
|
|
696
910
|
@staticmethod
|
|
697
911
|
def _build_attachments(items: list[dict[str, Any]]):
|
|
698
912
|
attachments = []
|
|
@@ -57,15 +57,34 @@ def _ensure_thread_ready(state: ThreadState, thread_id: str) -> None:
|
|
|
57
57
|
)
|
|
58
58
|
|
|
59
59
|
|
|
60
|
+
def _thread_agent_conflict(thread_id: str, existing_graph_name: str, requested_graph_name: str) -> HTTPException:
|
|
61
|
+
return HTTPException(
|
|
62
|
+
status_code=status.HTTP_409_CONFLICT,
|
|
63
|
+
detail={
|
|
64
|
+
"error": "thread_agent_conflict",
|
|
65
|
+
"message": "Thread is already bound to a different agent",
|
|
66
|
+
"thread_id": thread_id,
|
|
67
|
+
"existing_graph_name": existing_graph_name,
|
|
68
|
+
"requested_graph_name": requested_graph_name,
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _ensure_thread_matches_graph(
|
|
74
|
+
state: ThreadState,
|
|
75
|
+
*,
|
|
76
|
+
thread_id: str,
|
|
77
|
+
requested_graph_name: str | None = None,
|
|
78
|
+
) -> None:
|
|
79
|
+
if requested_graph_name and state.graph_name != requested_graph_name:
|
|
80
|
+
raise _thread_agent_conflict(thread_id, state.graph_name, requested_graph_name)
|
|
81
|
+
|
|
82
|
+
|
|
60
83
|
async def _resolve_thread_for_execution(thread_id: str, request: Request) -> ThreadState:
|
|
61
84
|
graph_name = request.headers.get("X-Agent-Name", "")
|
|
62
85
|
state = await _get_or_create_thread(thread_id, graph_name)
|
|
63
86
|
_ensure_thread_ready(state, thread_id)
|
|
64
|
-
|
|
65
|
-
if graph_name:
|
|
66
|
-
logger.info("Graph name overridden by header: %s", graph_name)
|
|
67
|
-
state.graph_name = graph_name
|
|
68
|
-
|
|
87
|
+
_ensure_thread_matches_graph(state, thread_id=thread_id, requested_graph_name=graph_name or None)
|
|
69
88
|
return state
|
|
70
89
|
|
|
71
90
|
|
|
@@ -114,6 +133,7 @@ async def _get_or_create_thread(thread_id: str, graph_name: Optional[str] = "")
|
|
|
114
133
|
storage = AsyncRedisThreadStorage.get_worker_instance()
|
|
115
134
|
thread_data = await storage.get_thread(thread_id)
|
|
116
135
|
if thread_data:
|
|
136
|
+
_ensure_thread_matches_graph(thread_data, thread_id=thread_id, requested_graph_name=graph_name or None)
|
|
117
137
|
return thread_data
|
|
118
138
|
|
|
119
139
|
if not graph_name:
|
|
@@ -248,10 +268,12 @@ async def create_thread(graph_name: str, thread_id: Optional[str] = None) -> Thr
|
|
|
248
268
|
if thread_id:
|
|
249
269
|
try:
|
|
250
270
|
state = await _get_existing_thread_or_404(thread_id)
|
|
271
|
+
_ensure_thread_matches_graph(state, thread_id=thread_id, requested_graph_name=graph_name)
|
|
251
272
|
logger.info("%s already exists, returning existing thread", thread_id)
|
|
252
273
|
return _thread_info(state)
|
|
253
|
-
except HTTPException:
|
|
254
|
-
|
|
274
|
+
except HTTPException as exc:
|
|
275
|
+
if exc.status_code != status.HTTP_404_NOT_FOUND:
|
|
276
|
+
raise
|
|
255
277
|
|
|
256
278
|
storage = None
|
|
257
279
|
thread_state = None
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from typing import Any, AsyncIterator, Iterator
|
|
2
|
+
from uuid import uuid4
|
|
2
3
|
|
|
3
4
|
from core import AgentDefinition, AgentExecutionContext, AgentFramework, AgentManager, get_agent_manager
|
|
4
5
|
from core import BaseAgentAdapter
|
|
@@ -177,6 +178,10 @@ class AgentSDK:
|
|
|
177
178
|
await self.manager.get_definition(resolved_agent_name)
|
|
178
179
|
return {}
|
|
179
180
|
|
|
181
|
+
@staticmethod
|
|
182
|
+
def _resolve_thread_id(thread_id: str | None) -> str:
|
|
183
|
+
return thread_id or f"sdk-{uuid4().hex}"
|
|
184
|
+
|
|
180
185
|
@staticmethod
|
|
181
186
|
def _build_context(
|
|
182
187
|
agent_name: str,
|
|
@@ -201,7 +206,7 @@ class AgentSDK:
|
|
|
201
206
|
self,
|
|
202
207
|
agent_name: str,
|
|
203
208
|
query: str | dict[str, Any],
|
|
204
|
-
thread_id: str,
|
|
209
|
+
thread_id: str | None,
|
|
205
210
|
ts_tenant: str | None,
|
|
206
211
|
ei_token: str | None,
|
|
207
212
|
attachments: list[dict[str, Any]] | None,
|
|
@@ -209,9 +214,10 @@ class AgentSDK:
|
|
|
209
214
|
use_system_llm: bool | str | None,
|
|
210
215
|
) -> tuple[dict[str, Any], AgentExecutionContext]:
|
|
211
216
|
inputs, normalized_attachments = normalize_agent_query(query, attachments)
|
|
217
|
+
resolved_thread_id = self._resolve_thread_id(thread_id)
|
|
212
218
|
context = self._build_context(
|
|
213
219
|
agent_name=agent_name,
|
|
214
|
-
thread_id=
|
|
220
|
+
thread_id=resolved_thread_id,
|
|
215
221
|
ts_tenant=ts_tenant,
|
|
216
222
|
ei_token=ei_token,
|
|
217
223
|
attachments=normalized_attachments,
|
|
@@ -225,7 +231,7 @@ class AgentSDK:
|
|
|
225
231
|
agent_name: str | dict[str, Any] | None = None,
|
|
226
232
|
query: str | dict[str, Any] | None = None,
|
|
227
233
|
*,
|
|
228
|
-
thread_id: str =
|
|
234
|
+
thread_id: str | None = None,
|
|
229
235
|
ts_tenant: str | None = None,
|
|
230
236
|
ei_token: str | None = None,
|
|
231
237
|
attachments: list[dict[str, Any]] | None = None,
|
|
@@ -251,7 +257,7 @@ class AgentSDK:
|
|
|
251
257
|
agent_name: str | dict[str, Any] | None = None,
|
|
252
258
|
query: str | dict[str, Any] | None = None,
|
|
253
259
|
*,
|
|
254
|
-
thread_id: str =
|
|
260
|
+
thread_id: str | None = None,
|
|
255
261
|
ts_tenant: str | None = None,
|
|
256
262
|
ei_token: str | None = None,
|
|
257
263
|
attachments: list[dict[str, Any]] | None = None,
|
|
@@ -277,7 +283,7 @@ class AgentSDK:
|
|
|
277
283
|
agent_name: str | dict[str, Any] | None = None,
|
|
278
284
|
query: str | dict[str, Any] | None = None,
|
|
279
285
|
*,
|
|
280
|
-
thread_id: str =
|
|
286
|
+
thread_id: str | None = None,
|
|
281
287
|
ts_tenant: str | None = None,
|
|
282
288
|
ei_token: str | None = None,
|
|
283
289
|
attachments: list[dict[str, Any]] | None = None,
|
|
@@ -304,7 +310,7 @@ class AgentSDK:
|
|
|
304
310
|
agent_name: str | dict[str, Any] | None = None,
|
|
305
311
|
query: str | dict[str, Any] | None = None,
|
|
306
312
|
*,
|
|
307
|
-
thread_id: str =
|
|
313
|
+
thread_id: str | None = None,
|
|
308
314
|
ts_tenant: str | None = None,
|
|
309
315
|
ei_token: str | None = None,
|
|
310
316
|
attachments: list[dict[str, Any]] | None = None,
|
|
File without changes
|
|
File without changes
|
{agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/adapters/langgraph_adapter/__init__.py
RENAMED
|
File without changes
|
{agent_api_server-2.2.1a2 → agent_api_server-2.2.1a4}/adapters/langgraph_adapter/formatter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|