ni.agentkit 0.7.3__tar.gz → 0.8.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.
Files changed (147) hide show
  1. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/PKG-INFO +3 -3
  2. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/README.md +2 -2
  3. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/__init__.py +1 -1
  4. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/agents/agent.py +7 -4
  5. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/agents/base_agent.py +116 -0
  6. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/docs/Architecture.md +19 -9
  7. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/docs/QuickStart.md +142 -57
  8. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/docs/README.md +3 -3
  9. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/docs/Reference.md +15 -1
  10. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/docs/TestReport.md +31 -31
  11. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/01_basic_chat.py +2 -2
  12. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/02_tool_calling.py +2 -2
  13. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/03_skill_usage.py +2 -2
  14. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/03b_skill_tools_entry.py +2 -2
  15. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/04_multi_agent.py +3 -3
  16. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/05_guardrail.py +4 -4
  17. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/06_orchestration.py +4 -4
  18. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/07_sync_async_stream.py +17 -17
  19. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/08_memory.py +7 -7
  20. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/08a_memory_simple_provider.py +3 -3
  21. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/08b_memory_mem0_provider.py +3 -3
  22. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/08c_memory_file_provider.py +3 -3
  23. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/09a_structured_data_sql.py +2 -2
  24. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/09b_structured_data_graph.py +2 -2
  25. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/10_skill_lifecycle.py +2 -2
  26. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/11_orchestration_enhancement.py +3 -3
  27. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/14_event_standardization.py +2 -2
  28. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/15_multi_tenant_isolation.py +4 -5
  29. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/16_lifecycle_hooks.py +3 -4
  30. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/18_model_cosplay.py +3 -3
  31. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/20_simple_rag_agent.py +2 -2
  32. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/quickstart.py +8 -8
  33. ni_agentkit-0.8.0/examples/rag/app.py +99 -0
  34. ni_agentkit-0.8.0/examples/rag/cli.py +72 -0
  35. ni_agentkit-0.8.0/examples/rag/core.py +95 -0
  36. ni_agentkit-0.8.0/examples/rag/web.py +14 -0
  37. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/01_basic_chat.py +2 -2
  38. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/02_tool_calling.py +2 -2
  39. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/03_skill_usage.py +2 -2
  40. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/03b_skill_tools_entry.py +2 -2
  41. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/04_multi_agent.py +3 -3
  42. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/05_guardrail.py +4 -4
  43. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/06_orchestration.py +4 -4
  44. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/07_sync_async_stream.py +17 -17
  45. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/08_memory.py +7 -7
  46. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/08a_memory_simple_provider.py +3 -3
  47. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/08b_memory_mem0_provider.py +3 -3
  48. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/08c_memory_file_provider.py +3 -3
  49. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/09a_structured_data_sql.py +2 -2
  50. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/09b_structured_data_graph.py +2 -2
  51. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/10_skill_lifecycle.py +2 -2
  52. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/11_orchestration_enhancement.py +3 -3
  53. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/14_event_standardization.py +2 -2
  54. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/15_multi_tenant_isolation.py +3 -4
  55. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/16_lifecycle_hooks.py +2 -3
  56. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/18_model_cosplay.py +3 -3
  57. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/20_simple_rag_agent.py +2 -2
  58. ni_agentkit-0.8.0/examples/test_standard.py +120 -0
  59. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/llm/cache.py +19 -3
  60. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/llm/registry.py +16 -0
  61. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/ni.agentkit.egg-info/PKG-INFO +3 -3
  62. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/ni.agentkit.egg-info/SOURCES.txt +13 -0
  63. ni_agentkit-0.8.0/ni.agentkit.egg-info/dependency_links.txt +1 -0
  64. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/pyproject.toml +1 -1
  65. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/rag/file_memory_provider.py +32 -6
  66. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/rag/sqlite_store.py +11 -2
  67. ni_agentkit-0.8.0/tests/test_default_model_env.py +15 -0
  68. ni_agentkit-0.8.0/utils/env.py +86 -0
  69. ni_agentkit-0.7.3/examples/test_standard.py +0 -60
  70. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/LICENSE +0 -0
  71. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/_cli.py +0 -0
  72. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/agents/__init__.py +0 -0
  73. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/agents/orchestrators.py +0 -0
  74. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/Skill.md +0 -0
  75. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/__init__.py +0 -0
  76. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/05_human_in_the_loop.py +0 -0
  77. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/09c_nebula_graph_tool.py +0 -0
  78. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/12_run_context_serialization.py +0 -0
  79. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/13_human_in_the_loop.py +0 -0
  80. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/17_checkpoint_handoff_resume.py +0 -0
  81. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/19_hitl_deterministic.py +0 -0
  82. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/README.md +0 -0
  83. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/__init__.py +0 -0
  84. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/ollama/model_config.py +0 -0
  85. /ni_agentkit-0.7.3/ni.agentkit.egg-info/dependency_links.txt → /ni_agentkit-0.8.0/examples/rag/__init__.py +0 -0
  86. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/skills/weather-tools-entry/SKILL.md +0 -0
  87. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/skills/weather-tools-entry/tools/weather_tools.py +0 -0
  88. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/05_human_in_the_loop.py +0 -0
  89. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/09c_nebula_graph_tool.py +0 -0
  90. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/12_run_context_serialization.py +0 -0
  91. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/13_human_in_the_loop.py +0 -0
  92. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/17_checkpoint_handoff_resume.py +0 -0
  93. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/19_hitl_deterministic.py +0 -0
  94. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/README.md +0 -0
  95. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/__init__.py +0 -0
  96. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/standard/model_config.py +0 -0
  97. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/examples/test_ollama.py +0 -0
  98. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/llm/__init__.py +0 -0
  99. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/llm/adapters/__init__.py +0 -0
  100. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/llm/adapters/anthropic_adapter.py +0 -0
  101. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/llm/adapters/google_adapter.py +0 -0
  102. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/llm/adapters/ollama_adapter.py +0 -0
  103. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/llm/adapters/openai_adapter.py +0 -0
  104. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/llm/adapters/openai_compatible.py +0 -0
  105. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/llm/base.py +0 -0
  106. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/llm/middleware.py +0 -0
  107. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/llm/types.py +0 -0
  108. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/memory/__init__.py +0 -0
  109. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/memory/base.py +0 -0
  110. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/memory/mem0_provider.py +0 -0
  111. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/ni.agentkit.egg-info/entry_points.txt +0 -0
  112. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/ni.agentkit.egg-info/requires.txt +0 -0
  113. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/ni.agentkit.egg-info/top_level.txt +0 -0
  114. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/rag/__init__.py +0 -0
  115. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/rag/document_store.py +0 -0
  116. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/rag/loaders.py +0 -0
  117. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/rag/retrievers.py +0 -0
  118. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/rag/simple_rag_agent.py +0 -0
  119. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/rag/types.py +0 -0
  120. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/runner/__init__.py +0 -0
  121. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/runner/context.py +0 -0
  122. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/runner/context_store.py +0 -0
  123. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/runner/events.py +0 -0
  124. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/runner/runner.py +0 -0
  125. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/safety/__init__.py +0 -0
  126. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/safety/guardrails.py +0 -0
  127. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/safety/permissions.py +0 -0
  128. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/setup.cfg +0 -0
  129. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/skills/__init__.py +0 -0
  130. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/skills/loader.py +0 -0
  131. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/skills/models.py +0 -0
  132. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/skills/registry.py +0 -0
  133. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tests/test_after_callback.py +0 -0
  134. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tests/test_graph_repository.py +0 -0
  135. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tests/test_quickstart_core.py +0 -0
  136. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tests/test_runner_checkpoint_resume.py +0 -0
  137. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tests/test_simple_rag.py +0 -0
  138. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tests/test_skill_frontmatter.py +0 -0
  139. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tools/__init__.py +0 -0
  140. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tools/base_tool.py +0 -0
  141. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tools/function_tool.py +0 -0
  142. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tools/nebula_tool.py +0 -0
  143. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tools/skill_toolset.py +0 -0
  144. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tools/sqlite_tool.py +0 -0
  145. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/tools/structured_data.py +0 -0
  146. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/utils/__init__.py +0 -0
  147. {ni_agentkit-0.7.3 → ni_agentkit-0.8.0}/utils/schema.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ni.agentkit
3
- Version: 0.7.3
3
+ Version: 0.8.0
4
4
  Summary: A Python-native Agent framework with first-class Skill support and multi-LLM adapter
5
5
  Author-email: Krix Tam <krix.tam@qq.com>
6
6
  License: MIT
@@ -155,8 +155,8 @@ python "$(python -c "import agentkit, os; print(os.path.join(agentkit.get_exampl
155
155
 
156
156
  ```bash
157
157
  dist/
158
- ├── ni_agentkit-0.7.3-py3-none-any.whl # pip install 用这个
159
- └── ni_agentkit-0.7.3.tar.gz # 源码分发
158
+ ├── ni_agentkit-0.7.4-py3-none-any.whl # pip install 用这个
159
+ └── ni_agentkit-0.7.4.tar.gz # 源码分发
160
160
  ```
161
161
 
162
162
  ## 📄 License
@@ -112,8 +112,8 @@ python "$(python -c "import agentkit, os; print(os.path.join(agentkit.get_exampl
112
112
 
113
113
  ```bash
114
114
  dist/
115
- ├── ni_agentkit-0.7.3-py3-none-any.whl # pip install 用这个
116
- └── ni_agentkit-0.7.3.tar.gz # 源码分发
115
+ ├── ni_agentkit-0.7.4-py3-none-any.whl # pip install 用这个
116
+ └── ni_agentkit-0.7.4.tar.gz # 源码分发
117
117
  ```
118
118
 
119
119
  ## 📄 License
@@ -33,7 +33,7 @@ from .tools.function_tool import FunctionTool, function_tool
33
33
  from .tools.structured_data import ResultFormatter, StructuredDataTool
34
34
  from .tools.sqlite_tool import SQLiteTool, SQLiteResultFormatter
35
35
 
36
- __version__ = "0.7.2"
36
+ __version__ = "0.8.0"
37
37
 
38
38
 
39
39
  def get_docs_dir() -> str:
@@ -153,8 +153,7 @@ class Agent(BaseAgent):
153
153
 
154
154
  async def _invoke(**kwargs: Any) -> Any:
155
155
  input_text = kwargs.get("input", "")
156
- from ..runner.runner import Runner
157
- result = await Runner.run(agent_ref, input=str(input_text))
156
+ result = await agent_ref.ainvoke(input=str(input_text))
158
157
  return result.final_output
159
158
 
160
159
  return FunctionTool(
@@ -293,11 +292,12 @@ class Agent(BaseAgent):
293
292
 
294
293
  # 5. 调用 LLM(支持缓存)
295
294
  cached = False
295
+ cache_key: str | None = None
296
296
 
297
297
  # 检查缓存
298
298
  if self.enable_cache:
299
299
  cache = self._get_cache()
300
- cached_response = cache.get(messages, tool_defs if tool_defs else None)
300
+ cache_key, cached_response = cache.get_with_key(messages, tool_defs if tool_defs else None)
301
301
  if cached_response is not None:
302
302
  response = cached_response
303
303
  cached = True
@@ -318,7 +318,10 @@ class Agent(BaseAgent):
318
318
 
319
319
  # 写入缓存
320
320
  if self.enable_cache:
321
- cache.put(messages, tool_defs if tool_defs else None, response)
321
+ if cache_key is not None:
322
+ cache.put_with_key(cache_key, response)
323
+ else:
324
+ cache.put(messages, tool_defs if tool_defs else None, response)
322
325
 
323
326
  cache_key_ms = 0.0
324
327
  if self.enable_cache:
@@ -96,6 +96,122 @@ class BaseAgent(BaseModel):
96
96
  elif result is not None:
97
97
  yield Event(agent=self.name, type="callback", data={"result": result, "duration": duration})
98
98
 
99
+ async def stream(
100
+ self,
101
+ input: str,
102
+ context: Any = None,
103
+ user_id: str | None = None,
104
+ session_id: str | None = None,
105
+ max_turns: int = 10,
106
+ ) -> AsyncGenerator[Event, None]:
107
+ import uuid
108
+
109
+ from ..runner.context import RunContext
110
+ from ..runner.events import EventType
111
+ from ..runner.runner import Runner
112
+
113
+ ctx = RunContext(
114
+ input=input,
115
+ shared_context=context,
116
+ user_id=user_id,
117
+ session_id=session_id or str(uuid.uuid4()),
118
+ )
119
+ current_agent: BaseAgent = self
120
+ handoff_agent_cache: dict[str, BaseAgent | None] = {}
121
+
122
+ for _ in range(max_turns):
123
+ input_guardrails = getattr(current_agent, "input_guardrails", None)
124
+ if input_guardrails:
125
+ for guardrail in input_guardrails:
126
+ result = await guardrail.check(ctx)
127
+ if result.triggered:
128
+ yield Event(agent=current_agent.name, type=EventType.ERROR, data=f"输入被安全护栏拦截: {result.reason}")
129
+ return
130
+
131
+ async for event in current_agent.run(ctx):
132
+ yield event
133
+
134
+ if event.type == EventType.FINAL_OUTPUT:
135
+ output_guardrails = getattr(current_agent, "output_guardrails", None)
136
+ if output_guardrails:
137
+ for guardrail in output_guardrails:
138
+ result = await guardrail.check(ctx, event.data)
139
+ if result.triggered:
140
+ yield Event(agent=current_agent.name, type=EventType.ERROR, data=f"输出被安全护栏拦截: {result.reason}")
141
+ return
142
+ return
143
+
144
+ if event.type == EventType.HANDOFF:
145
+ target_name = event.data.get("target", "") if isinstance(event.data, dict) else ""
146
+ if target_name in handoff_agent_cache:
147
+ new_agent = handoff_agent_cache[target_name]
148
+ else:
149
+ new_agent = Runner._find_agent(self, target_name)
150
+ handoff_agent_cache[target_name] = new_agent
151
+
152
+ if new_agent:
153
+ current_agent = new_agent
154
+ break
155
+
156
+ yield Event(agent=current_agent.name, type=EventType.ERROR, data=f"Handoff 目标 '{target_name}' 未找到")
157
+ return
158
+
159
+ if event.type == EventType.ERROR:
160
+ return
161
+
162
+ yield Event(agent=current_agent.name, type=EventType.ERROR, data=f"超过最大轮次 {max_turns}")
163
+
164
+ async def ainvoke(
165
+ self,
166
+ input: str,
167
+ context: Any = None,
168
+ user_id: str | None = None,
169
+ session_id: str | None = None,
170
+ max_turns: int = 10,
171
+ ) -> Any:
172
+ from ..runner.events import EventType, RunResult
173
+
174
+ events: list[Event] = []
175
+ final_output = None
176
+ error = None
177
+ last_agent = self.name
178
+
179
+ async for event in self.stream(
180
+ input=input,
181
+ context=context,
182
+ user_id=user_id,
183
+ session_id=session_id,
184
+ max_turns=max_turns,
185
+ ):
186
+ events.append(event)
187
+ last_agent = event.agent
188
+ if event.type == EventType.FINAL_OUTPUT:
189
+ final_output = event.data
190
+ elif event.type == EventType.ERROR:
191
+ error = str(event.data)
192
+
193
+ return RunResult(final_output=final_output, error=error, events=events, last_agent=last_agent)
194
+
195
+ def invoke(
196
+ self,
197
+ input: str,
198
+ context: Any = None,
199
+ user_id: str | None = None,
200
+ session_id: str | None = None,
201
+ max_turns: int = 10,
202
+ ) -> Any:
203
+ import asyncio
204
+
205
+ return asyncio.run(
206
+ self.ainvoke(
207
+ input=input,
208
+ context=context,
209
+ user_id=user_id,
210
+ session_id=session_id,
211
+ max_turns=max_turns,
212
+ )
213
+ )
214
+
99
215
  @abstractmethod
100
216
  async def _run_impl(self, ctx: "RunContext") -> AsyncGenerator[Event, None]:
101
217
  raise NotImplementedError
@@ -91,7 +91,14 @@ Application → Agent → Skill → Tool → Foundation
91
91
 
92
92
  ## 核心执行流程
93
93
 
94
- 当你调用 `Runner.run(agent, input="...")` 时,框架内部的完整流程如下:
94
+ 虽然 Agent 现在具备了独立执行的能力(`agent.invoke` / `agent.stream` 等),但 `Runner` 依然作为底层编排引擎存在,提供复杂场景下的能力:
95
+
96
+ - 统一的事件与 Hooks 调度
97
+ - 多 Agent `Handoff` 接力
98
+ - 异常兜底与错误报告
99
+ - Human-in-the-loop 挂起(Checkpoint)与恢复(Resume)
100
+
101
+ 当你调用 `agent.invoke(input="...")` 时,它内部实际上也是通过委托 `Runner` 来完成的完整流程:
95
102
 
96
103
  ```
97
104
  用户输入
@@ -99,7 +106,7 @@ Application → Agent → Skill → Tool → Foundation
99
106
 
100
107
  Runner.run()
101
108
 
102
- ├─ 创建 RunContext
109
+ ├─ 初始化 RunContext
103
110
 
104
111
  ├─ 检查输入护栏(InputGuardrail)
105
112
  │ └─ 如果触发 → 返回错误
@@ -225,18 +232,20 @@ Agent.run() ← 异步生成器(async generator,yield Event
225
232
 
226
233
  ### 三种运行方式
227
234
 
235
+ AgentKit 提供了三种执行方式,你可以直接在 Agent 对象上调用:
236
+
228
237
  | 方式 | API | 适用场景 |
229
238
  |------|-----|---------|
230
- | **同步** | `Runner.run_sync(agent, input=...)` | 脚本、快速测试、简单场景 |
231
- | **异步** | `await Runner.run(agent, input=...)` | Web 服务、并发任务、生产环境 |
232
- | **流式** | `async for event in Runner.run_streamed(agent, input=...)` | 实时展示进度、逐 token 输出 |
239
+ | **同步** | `agent.invoke(input=...)` | 脚本、快速测试、简单场景 |
240
+ | **异步** | `await agent.ainvoke(input=...)` | Web 服务、并发任务、生产环境 |
241
+ | **流式** | `async for event in agent.stream(input=...)` | 实时展示进度、逐 token 输出 |
233
242
 
234
243
  ### 为什么选择异步优先?
235
244
 
236
245
  1. **LLM 调用是 I/O 密集型**:一次 LLM 调用可能耗时几秒到几十秒,异步可以在等待期间处理其他请求
237
246
  2. **并行 Agent 需要并发**:`ParallelAgent` 并行执行多个子 Agent,必须用 `asyncio.gather`
238
247
  3. **工具可能涉及网络**:调用外部 API、数据库查询等都是异步操作
239
- 4. **`run_sync()` 兜底**:不熟悉异步的用户可以直接用同步入口,零学习成本
248
+ 4. **`invoke()` 兜底**:不熟悉异步的用户可以直接用同步入口,零学习成本
240
249
 
241
250
  ### 流式运行示例
242
251
 
@@ -244,7 +253,7 @@ Agent.run() ← 异步生成器(async generator,yield Event
244
253
  from agentkit.runner.events import EventType
245
254
 
246
255
  async def main():
247
- async for event in Runner.run_streamed(agent, input="你好"):
256
+ async for event in agent.stream(input="你好"):
248
257
  # 推荐使用 EventType 枚举匹配标准事件类型
249
258
  if event.type == EventType.LLM_RESPONSE:
250
259
  print("LLM 思考中...")
@@ -417,8 +426,8 @@ AgentKit 的记忆系统遵循**可选、可插拔、自动化**三个原则:
417
426
 
418
427
  ```python
419
428
  # 不同用户的记忆互不干扰
420
- await Runner.run(agent, input="我喜欢咖啡", user_id="user_A")
421
- await Runner.run(agent, input="我喜欢茶", user_id="user_B")
429
+ await agent.ainvoke(input="我喜欢咖啡", user_id="user_A")
430
+ await agent.ainvoke(input="我喜欢茶", user_id="user_B")
422
431
  ```
423
432
 
424
433
  ---
@@ -471,6 +480,7 @@ agent.clear_cache()
471
480
  > - 缓存仅在单 Agent 实例内有效,重新创建 Agent 会清空缓存
472
481
  > - 默认最大 128 条缓存,LRU 淘汰最久未使用的条目
473
482
  > - 缓存实现内置 key 生成统计:`key_gen_calls / key_gen_total_ms / key_gen_last_ms / key_gen_avg_ms`
483
+ > - 缓存实现对同一轮的缓存 key 计算做了复用(避免 miss 场景下重复算 key)
474
484
 
475
485
  ### 3. 记忆异步写入
476
486