agent-api-server 2.2.1a2__tar.gz → 2.2.1a3__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.
Files changed (52) hide show
  1. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/PKG-INFO +2 -2
  2. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/adapters/openclaw_adapter/openclaw_adapter.py +220 -21
  3. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/pyproject.toml +1 -1
  4. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/README.md +0 -0
  5. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/adapters/__init__.py +0 -0
  6. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/adapters/langgraph_adapter/__init__.py +0 -0
  7. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/adapters/langgraph_adapter/formatter.py +0 -0
  8. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/adapters/langgraph_adapter/langgraph_adapter.py +0 -0
  9. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/adapters/openclaw_adapter/__init__.py +0 -0
  10. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/agent_api_server.py +0 -0
  11. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/api/__init__.py +0 -0
  12. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/api/config.py +0 -0
  13. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/api/graph.py +0 -0
  14. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/api/router.py +0 -0
  15. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/api/schema.py +0 -0
  16. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/api/thread.py +0 -0
  17. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/client/css/styles.css +0 -0
  18. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/client/favicon.ico +0 -0
  19. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/client/index.html +0 -0
  20. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/client/js/app.js +0 -0
  21. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/client/js/index.umd.js +0 -0
  22. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/common/__init__.py +0 -0
  23. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/common/config.py +0 -0
  24. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/common/crypto.py +0 -0
  25. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/common/formatting.py +0 -0
  26. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/common/logging.py +0 -0
  27. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/common/nats.py +0 -0
  28. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/common/postgres.py +0 -0
  29. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/common/redis.py +0 -0
  30. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/__init__.py +0 -0
  31. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/loader.py +0 -0
  32. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/model/__init__.py +0 -0
  33. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/model/agent_models.py +0 -0
  34. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/model/base_model.py +0 -0
  35. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/model/detect_message.py +0 -0
  36. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/model/dynamic_llm.py +0 -0
  37. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/model/input_normalization.py +0 -0
  38. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/model/middleware.py +0 -0
  39. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/model/model_info.py +0 -0
  40. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/model/schema_utils.py +0 -0
  41. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/model/streaming.py +0 -0
  42. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/runtime/__init__.py +0 -0
  43. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/runtime/base.py +0 -0
  44. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/core/runtime/manager.py +0 -0
  45. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/demo.py +0 -0
  46. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/integration/__init__.py +0 -0
  47. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/integration/listener.py +0 -0
  48. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/integration/registry.py +0 -0
  49. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/logging.json +0 -0
  50. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/sdk/__init__.py +0 -0
  51. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/sdk/client.py +0 -0
  52. {agent_api_server-2.2.1a2 → agent_api_server-2.2.1a3}/service.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: agent-api-server
3
- Version: 2.2.1a2
3
+ Version: 2.2.1a3
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
@@ -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
- result = await agent.execute(
385
- self._resolve_query(inputs),
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,216 @@ 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_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_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_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_semantic_tool_message(tool_message):
754
+ last_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_tool_message=last_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_tool_message=last_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_tool_message: ChatMessage | None,
821
+ extra_metadata: dict[str, Any] | None = None,
822
+ ) -> ChatMessage:
823
+ if last_tool_message is not None:
824
+ return last_tool_message.model_copy(
825
+ update={"response_metadata": {**last_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 _resolve_run_completion_idle_timeout_seconds(
859
+ settings: dict[str, Any],
860
+ execution_settings: dict[str, Any],
861
+ ) -> float | None:
862
+ for source in (settings, execution_settings):
863
+ raw_value = source.get("run_completion_idle_timeout_seconds")
864
+ if raw_value is None:
865
+ continue
866
+ timeout = float(raw_value)
867
+ return timeout if timeout > 0 else None
868
+ return 5.0
869
+
870
+ def _build_tool_message(
871
+ self,
872
+ *,
873
+ output: str,
874
+ tool: str,
875
+ duration_ms: Any,
876
+ context: AgentExecutionContext,
877
+ session_name: str,
878
+ extra_metadata: dict[str, Any] | None = None,
879
+ ) -> ChatMessage:
880
+ return ChatMessage(
881
+ type="tool",
882
+ content_type=detect_content_type(output),
883
+ content=output,
884
+ tool_calls=[],
885
+ response_metadata={
886
+ "duration_ms": duration_ms,
887
+ "tool": tool,
888
+ "conversation_id": self._resolve_conversation_id(context),
889
+ "session_name": session_name,
890
+ **(extra_metadata or {}),
891
+ },
892
+ references=[],
893
+ )
894
+
696
895
  @staticmethod
697
896
  def _build_attachments(items: list[dict[str, Any]]):
698
897
  attachments = []
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agent-api-server"
3
- version = "2.2.1-alpha2"
3
+ version = "2.2.1-alpha3"
4
4
  description = "A Langgraph agent API server that implements Langgraph agent's web capabilities and can interact with chatbot"
5
5
  authors = []
6
6
  readme = "README.md"