wuwei 3.2.1__tar.gz → 3.2.2__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 (226) hide show
  1. {wuwei-3.2.1 → wuwei-3.2.2}/CHANGELOG.md +7 -0
  2. {wuwei-3.2.1 → wuwei-3.2.2}/PKG-INFO +2 -2
  3. {wuwei-3.2.1 → wuwei-3.2.2}/USAGE.md +29 -0
  4. {wuwei-3.2.1 → wuwei-3.2.2}/docs/RELEASING.md +4 -4
  5. {wuwei-3.2.1 → wuwei-3.2.2}/docs/changelog.md +7 -0
  6. {wuwei-3.2.1 → wuwei-3.2.2}/pyproject.toml +2 -2
  7. wuwei-3.2.2/tests/test_openai_sdk_capabilities.py +127 -0
  8. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/agent/agent.py +3 -4
  9. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/llm/adapters/openai.py +4 -13
  10. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/llm/adapters/responses.py +12 -14
  11. wuwei-3.2.2/wuwei/llm/adapters/usage.py +27 -0
  12. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/llm/gateway.py +1 -1
  13. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/planning/executor.py +2 -2
  14. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/runtime/agent_runner.py +4 -6
  15. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei.egg-info/PKG-INFO +2 -2
  16. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei.egg-info/SOURCES.txt +2 -0
  17. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei.egg-info/requires.txt +1 -1
  18. {wuwei-3.2.1 → wuwei-3.2.2}/LICENSE +0 -0
  19. {wuwei-3.2.1 → wuwei-3.2.2}/MANIFEST.in +0 -0
  20. {wuwei-3.2.1 → wuwei-3.2.2}/MIGRATION.md +0 -0
  21. {wuwei-3.2.1 → wuwei-3.2.2}/README.md +0 -0
  22. {wuwei-3.2.1 → wuwei-3.2.2}/docs/api/reference.md +0 -0
  23. {wuwei-3.2.1 → wuwei-3.2.2}/docs/core/agent.md +0 -0
  24. {wuwei-3.2.1 → wuwei-3.2.2}/docs/core/architecture.md +0 -0
  25. {wuwei-3.2.1 → wuwei-3.2.2}/docs/core/session.md +0 -0
  26. {wuwei-3.2.1 → wuwei-3.2.2}/docs/examples/minimal.md +0 -0
  27. {wuwei-3.2.1 → wuwei-3.2.2}/docs/examples/offline.md +0 -0
  28. {wuwei-3.2.1 → wuwei-3.2.2}/docs/examples/session.md +0 -0
  29. {wuwei-3.2.1 → wuwei-3.2.2}/docs/getting-started/configuration.md +0 -0
  30. {wuwei-3.2.1 → wuwei-3.2.2}/docs/getting-started/installation.md +0 -0
  31. {wuwei-3.2.1 → wuwei-3.2.2}/docs/getting-started/quickstart.md +0 -0
  32. {wuwei-3.2.1 → wuwei-3.2.2}/docs/governance.md +0 -0
  33. {wuwei-3.2.1 → wuwei-3.2.2}/docs/hitl/overview.md +0 -0
  34. {wuwei-3.2.1 → wuwei-3.2.2}/docs/index.md +0 -0
  35. {wuwei-3.2.1 → wuwei-3.2.2}/docs/memory/compression.md +0 -0
  36. {wuwei-3.2.1 → wuwei-3.2.2}/docs/memory/context-window.md +0 -0
  37. {wuwei-3.2.1 → wuwei-3.2.2}/docs/memory/context.md +0 -0
  38. {wuwei-3.2.1 → wuwei-3.2.2}/docs/memory/storage.md +0 -0
  39. {wuwei-3.2.1 → wuwei-3.2.2}/docs/operations.md +0 -0
  40. {wuwei-3.2.1 → wuwei-3.2.2}/docs/planning/overview.md +0 -0
  41. {wuwei-3.2.1 → wuwei-3.2.2}/docs/planning/task-dag.md +0 -0
  42. {wuwei-3.2.1 → wuwei-3.2.2}/docs/plugin.md +0 -0
  43. {wuwei-3.2.1 → wuwei-3.2.2}/docs/protocols.md +0 -0
  44. {wuwei-3.2.1 → wuwei-3.2.2}/docs/skill/authoring.md +0 -0
  45. {wuwei-3.2.1 → wuwei-3.2.2}/docs/skill/overview.md +0 -0
  46. {wuwei-3.2.1 → wuwei-3.2.2}/docs/stylesheets/extra.css +0 -0
  47. {wuwei-3.2.1 → wuwei-3.2.2}/docs/tools/custom.md +0 -0
  48. {wuwei-3.2.1 → wuwei-3.2.2}/docs/tools/overview.md +0 -0
  49. {wuwei-3.2.1 → wuwei-3.2.2}/examples/advanced_features.py +0 -0
  50. {wuwei-3.2.1 → wuwei-3.2.2}/examples/decision_client_demo.py +0 -0
  51. {wuwei-3.2.1 → wuwei-3.2.2}/examples/full_flow.py +0 -0
  52. {wuwei-3.2.1 → wuwei-3.2.2}/examples/repl_agent.py +0 -0
  53. {wuwei-3.2.1 → wuwei-3.2.2}/examples/skills/code-review/SKILL.md +0 -0
  54. {wuwei-3.2.1 → wuwei-3.2.2}/examples/skills/code-review/scripts/count_lines.py +0 -0
  55. {wuwei-3.2.1 → wuwei-3.2.2}/mkdocs.yml +0 -0
  56. {wuwei-3.2.1 → wuwei-3.2.2}/setup.cfg +0 -0
  57. {wuwei-3.2.1 → wuwei-3.2.2}/tests/conftest.py +0 -0
  58. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_boundary_hardening.py +0 -0
  59. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_builtin_tools.py +0 -0
  60. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_core.py +0 -0
  61. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_coverage_gaps.py +0 -0
  62. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_delegation_hardening.py +0 -0
  63. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_documentation_hardening.py +0 -0
  64. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_e2e_all.py +0 -0
  65. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_evals.py +0 -0
  66. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_framework.py +0 -0
  67. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_fs.py +0 -0
  68. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_graph.py +0 -0
  69. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_integration.py +0 -0
  70. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_mcp.py +0 -0
  71. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_middleware.py +0 -0
  72. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_middleware_lifecycle.py +0 -0
  73. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_model_hardening.py +0 -0
  74. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_multi_agent_integration.py +0 -0
  75. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_runtime_hardening.py +0 -0
  76. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_sandbox.py +0 -0
  77. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_serve.py +0 -0
  78. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_skill_execution.py +0 -0
  79. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_skill_integration.py +0 -0
  80. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_v31_core.py +0 -0
  81. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_v32_features.py +0 -0
  82. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_v32_kernel.py +0 -0
  83. {wuwei-3.2.1 → wuwei-3.2.2}/tests/test_vectorstore.py +0 -0
  84. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/__init__.py +0 -0
  85. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/agent/__init__.py +0 -0
  86. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/agent/async_sub_agent.py +0 -0
  87. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/agent/base.py +0 -0
  88. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/agent/multi_agent.py +0 -0
  89. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/agent/session.py +0 -0
  90. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/agent/sub_agent.py +0 -0
  91. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/codemode.py +0 -0
  92. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/config/__init__.py +0 -0
  93. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/config/yaml_loader.py +0 -0
  94. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/core/__init__.py +0 -0
  95. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/core/errors.py +0 -0
  96. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/core/message.py +0 -0
  97. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/core/runnable.py +0 -0
  98. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/core/types.py +0 -0
  99. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/debug.py +0 -0
  100. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/decision/__init__.py +0 -0
  101. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/decision/client.py +0 -0
  102. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/evals/__init__.py +0 -0
  103. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/evals/__main__.py +0 -0
  104. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/evals/case.py +0 -0
  105. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/evals/cli.py +0 -0
  106. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/evals/dataset.py +0 -0
  107. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/evals/report.py +0 -0
  108. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/evals/runner.py +0 -0
  109. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/fs/__init__.py +0 -0
  110. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/fs/base.py +0 -0
  111. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/fs/local.py +0 -0
  112. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/fs/memory.py +0 -0
  113. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/fs/tools.py +0 -0
  114. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/gateway/__init__.py +0 -0
  115. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/gateway/adapters/__init__.py +0 -0
  116. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/gateway/adapters/dingtalk.py +0 -0
  117. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/gateway/adapters/feishu.py +0 -0
  118. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/gateway/adapters/telegram.py +0 -0
  119. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/gateway/adapters/wechat.py +0 -0
  120. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/gateway/base.py +0 -0
  121. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/gateway/webhook.py +0 -0
  122. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/graph/__init__.py +0 -0
  123. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/graph/checkpoint.py +0 -0
  124. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/graph/graph.py +0 -0
  125. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/graph/reducers.py +0 -0
  126. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/graph/state.py +0 -0
  127. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/llm/__init__.py +0 -0
  128. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/llm/adapters/__init__.py +0 -0
  129. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/llm/adapters/anthropic.py +0 -0
  130. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/llm/adapters/base.py +0 -0
  131. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/llm/types.py +0 -0
  132. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/mcp/__init__.py +0 -0
  133. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/mcp/client.py +0 -0
  134. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/mcp/config.py +0 -0
  135. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/mcp/session.py +0 -0
  136. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/mcp/tool_search.py +0 -0
  137. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/mcp/tools.py +0 -0
  138. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/memory/__init__.py +0 -0
  139. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/memory/context.py +0 -0
  140. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/memory/context_compressor.py +0 -0
  141. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/memory/context_window.py +0 -0
  142. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/memory/curator.py +0 -0
  143. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/memory/embedder.py +0 -0
  144. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/memory/knowledge_store.py +0 -0
  145. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/memory/memory_store.py +0 -0
  146. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/memory/memory_types.py +0 -0
  147. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/memory/storage.py +0 -0
  148. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/middleware/__init__.py +0 -0
  149. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/middleware/base.py +0 -0
  150. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/middleware/budget.py +0 -0
  151. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/middleware/context_compression.py +0 -0
  152. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/middleware/hitl.py +0 -0
  153. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/middleware/ledger.py +0 -0
  154. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/middleware/logging.py +0 -0
  155. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/middleware/memory.py +0 -0
  156. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/middleware/rag.py +0 -0
  157. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/middleware/stack.py +0 -0
  158. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/middleware/storage.py +0 -0
  159. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/observability/__init__.py +0 -0
  160. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/observability/tracing.py +0 -0
  161. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/parsers/__init__.py +0 -0
  162. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/parsers/base.py +0 -0
  163. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/parsers/json.py +0 -0
  164. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/parsers/list.py +0 -0
  165. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/parsers/pydantic.py +0 -0
  166. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/planning/__init__.py +0 -0
  167. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/planning/planner.py +0 -0
  168. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/planning/task.py +0 -0
  169. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/__init__.py +0 -0
  170. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/__init__.py +0 -0
  171. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/calc.py +0 -0
  172. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/decision.py +0 -0
  173. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/file.py +0 -0
  174. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/git.py +0 -0
  175. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/http.py +0 -0
  176. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/json_tools.py +0 -0
  177. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/mcp.py +0 -0
  178. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/npm.py +0 -0
  179. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/python.py +0 -0
  180. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/rag.py +0 -0
  181. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/skill.py +0 -0
  182. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/text.py +0 -0
  183. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/time_plugin.py +0 -0
  184. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/builtin/vfs.py +0 -0
  185. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/manager.py +0 -0
  186. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/plugin/plugin.py +0 -0
  187. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/runtime/__init__.py +0 -0
  188. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/runtime/action_log.py +0 -0
  189. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/runtime/context.py +0 -0
  190. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/runtime/event_bus.py +0 -0
  191. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/runtime/interrupt.py +0 -0
  192. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/sandbox/__init__.py +0 -0
  193. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/sandbox/base.py +0 -0
  194. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/sandbox/docker.py +0 -0
  195. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/sandbox/e2b.py +0 -0
  196. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/sandbox/factory.py +0 -0
  197. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/sandbox/local.py +0 -0
  198. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/security/__init__.py +0 -0
  199. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/security/permissions.py +0 -0
  200. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/serve/__init__.py +0 -0
  201. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/serve/_http.py +0 -0
  202. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/serve/a2a.py +0 -0
  203. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/serve/ag_ui.py +0 -0
  204. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/serve/mcp_server.py +0 -0
  205. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/skill/__init__.py +0 -0
  206. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/skill/fs_provider.py +0 -0
  207. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/skill/skill.py +0 -0
  208. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/streaming/__init__.py +0 -0
  209. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/streaming/types.py +0 -0
  210. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/tools/__init__.py +0 -0
  211. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/tools/executor.py +0 -0
  212. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/tools/registry.py +0 -0
  213. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/tools/tool.py +0 -0
  214. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/vectorstore/__init__.py +0 -0
  215. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/vectorstore/_util.py +0 -0
  216. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/vectorstore/adapter.py +0 -0
  217. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/vectorstore/base.py +0 -0
  218. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/vectorstore/chroma.py +0 -0
  219. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/vectorstore/factory.py +0 -0
  220. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/vectorstore/inmemory.py +0 -0
  221. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/vectorstore/milvus.py +0 -0
  222. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/vectorstore/pgvector.py +0 -0
  223. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei/vectorstore/qdrant.py +0 -0
  224. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei.egg-info/dependency_links.txt +0 -0
  225. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei.egg-info/entry_points.txt +0 -0
  226. {wuwei-3.2.1 → wuwei-3.2.2}/wuwei.egg-info/top_level.txt +0 -0
@@ -1,5 +1,12 @@
1
1
  # 更新日志
2
2
 
3
+ ## 3.2.2 — 2026-10-28
4
+
5
+ - OpenAI SDK 最低版本更新至 3.40.0,Responses 支持显式配置 prompt_cache_options / prompt_cache_key。
6
+ - 缓存读取、缓存写入和推理 token 细分统计贯通普通/流式运行、委派与规划汇总,不重复计入总 token。
7
+ - Responses 默认省略 temperature;保留显式配置、Chat Completions 默认值和适配器原有位置参数兼容性。
8
+ - 补充缓存配置、预算估算边界及离线 SDK 契约测试。
9
+
3
10
  ## 3.2.1 — 2026-10-28
4
11
 
5
12
  - 更新补丁版本号,承接执行契约、模型接入及协议兼容性加固。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wuwei
3
- Version: 3.2.1
3
+ Version: 3.2.2
4
4
  Summary: Wuwei - 无为而治的 AI 智能体框架
5
5
  Author-email: xiaojiaenen <xiaojiaenen@163.com>
6
6
  License-Expression: Apache-2.0
@@ -10,7 +10,7 @@ Project-URL: Documentation, https://github.com/xiaojiaenen/wuwei
10
10
  Requires-Python: >=3.11
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
- Requires-Dist: openai>=3.23.0
13
+ Requires-Dist: openai>=3.40.0
14
14
  Requires-Dist: pydantic>=2.0.0
15
15
  Requires-Dist: pyyaml>=6.0.3
16
16
  Requires-Dist: httpx>=0.25.0
@@ -27,6 +27,35 @@ llm = LLMGateway({"provider": "openai", "client": client,
27
27
 
28
28
  框架自建 SDK client 默认关闭 SDK 重试,让网关负责分类重试。借入客户端也应明确 retry 所有权;否则 SDK 与框架尝试次数可能相乘。`set_fallback(other_gateway)` 借用完整 fallback 策略,调用方管理 other_gateway 生命周期。已发布流式内容、工具或 usage 元数据后不重放请求。确定性参数错误不做传输重试。
29
29
 
30
+ ## OpenAI Responses:缓存与新模型参数
31
+
32
+ Responses 默认不发送 `temperature`,避免向不支持采样参数的模型强加旧默认值。显式配置数字仍会发送;`None` 表示省略,由服务端决定。Chat Completions 保留 `temperature=0.2` 兼容默认值;使用不支持该参数的模型时显式设为 `None`。
33
+
34
+ ```python
35
+ import os
36
+ from wuwei import LLMGateway
37
+
38
+ llm = LLMGateway({
39
+ "provider": "responses",
40
+ "api_key": os.environ["OPENAI_API_KEY"],
41
+ "model": os.environ["OPENAI_MODEL"],
42
+ "max_output_tokens": 4096,
43
+ "prompt_cache_key": "wuwei:assistant:v1",
44
+ "prompt_cache_options": {"mode": "implicit", "ttl": "30m"},
45
+ })
46
+ # 使用完 await llm.aclose()。
47
+ ```
48
+
49
+ 缓存参数要求支持该能力的 OpenAI 模型和服务端;自定义兼容端点未必接受。模型名称不设硬编码白名单,`reasoning` 等提供商参数可透传,但具体参数组合仍须符合模型契约。缓存 key 仅为稳定路由提示,不保证命中,也不要放入密钥或敏感身份信息。
50
+
51
+ 上例采用隐式断点。`mode="explicit"` 需要额外的内容块断点;当前字符串消息入口不提供断点构建能力,不应只切换 mode 而期待缓存生效。请求级 TTL 与旧 `prompt_cache_retention` 含义不同,框架不会自动互相转换。
52
+
53
+ Chat Completions 推理模型可配置 `temperature=None`、`max_completion_tokens=4096`;此时不会同时发送旧 `max_tokens`。`reasoning_effort` 等参数由模型决定是否支持,不通过模型名称猜测或静默删除显式配置。
54
+
55
+ 响应 `usage` 在服务端提供时包含 `cached_tokens`(缓存读取)、`cache_write_tokens`(缓存写入)、`reasoning_tokens`(推理输出);普通运行、流式运行、子任务和规划汇总保留这些字段。缺失字段不伪造为已测量值。这些是输入/输出 token 的细分,不额外加到 `total_tokens`。
56
+
57
+ 预算仍按配置的输入/输出价格估算,不根据这些细分字段自动套用缓存折扣或写入附加费;需要精确账单时,以服务端账单为准。新模型应显式配置预算价格,避免使用通用估算价。
58
+
30
59
  ## 注册有参数契约的工具
31
60
 
32
61
  ```python
@@ -25,9 +25,9 @@
25
25
  ```bash
26
26
  git switch master
27
27
  git pull --ff-only origin master
28
- # 当前项目版本为 3.2.1;后续按实际版本修改标签。
29
- git tag -a v3.2.1 -m 'Release 3.2.1'
30
- git push origin v3.2.1
28
+ # 当前项目版本为 3.2.2;后续按实际版本修改标签。
29
+ git tag -a v3.2.2 -m 'Release 3.2.2'
30
+ git push origin v3.2.2
31
31
  ```
32
32
 
33
33
  在 Actions 查看 Publish to PyPI,必要时批准 `pypi` 环境部署。推送标签会触发正式上传;不要在绑定完成前推送。标签必须严格等于 `v` + `project.version`,否则发布会被阻止。
@@ -35,7 +35,7 @@ git push origin v3.2.1
35
35
  上传后在 https://pypi.org/project/wuwei/ 确认版本,并在独立环境安装验证:
36
36
 
37
37
  ```bash
38
- uv run --isolated --no-project --with 'wuwei==3.2.1' \
38
+ uv run --isolated --no-project --with 'wuwei==3.2.2' \
39
39
  python -c "from importlib.metadata import version; print(version('wuwei'))"
40
40
  ```
41
41
 
@@ -1,5 +1,12 @@
1
1
  # 更新日志
2
2
 
3
+ ## 3.2.2 — 2026-10-28
4
+
5
+ - OpenAI SDK 最低版本更新至 3.40.0,Responses 支持显式配置 prompt_cache_options / prompt_cache_key。
6
+ - 缓存读取、缓存写入和推理 token 细分统计贯通普通/流式运行、委派与规划汇总,不重复计入总 token。
7
+ - Responses 默认省略 temperature;保留显式配置、Chat Completions 默认值和适配器原有位置参数兼容性。
8
+ - 补充缓存配置、预算估算边界及离线 SDK 契约测试。
9
+
3
10
  ## 3.2.1 — 2026-10-28
4
11
 
5
12
  - 更新补丁版本号,承接执行契约、模型接入及协议兼容性加固。
@@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wuwei"
7
- version = "3.2.1"
7
+ version = "3.2.2"
8
8
  description = "Wuwei - 无为而治的 AI 智能体框架"
9
9
  authors = [{name = "xiaojiaenen", email = "xiaojiaenen@163.com"}]
10
10
  license = "Apache-2.0"
11
11
  readme = "README.md"
12
12
  requires-python = ">=3.11"
13
13
  dependencies = [
14
- "openai>=3.23.0",
14
+ "openai>=3.40.0",
15
15
  "pydantic>=2.0.0",
16
16
  "pyyaml>=6.0.3",
17
17
  "httpx>=0.25.0",
@@ -0,0 +1,127 @@
1
+ from types import SimpleNamespace as Ns
2
+
3
+ import pytest
4
+
5
+ from wuwei.llm.adapters.openai import OpenAIAdapter
6
+ from wuwei.llm.adapters.responses import ResponsesAdapter
7
+ from wuwei.llm.gateway import LLMGateway
8
+ from wuwei.runtime.agent_runner import _merge_usage
9
+
10
+
11
+ def test_modern_responses_omits_sampling_unless_explicit():
12
+ adapter = LLMGateway({'provider': 'responses', 'api_key': 'unused', 'client': Ns()}).adapter
13
+ assert 'temperature' not in adapter.build_request([])
14
+ assert adapter.build_request([], temperature=0.7)['temperature'] == 0.7
15
+ assert 'temperature' not in adapter.build_request([], temperature=None)
16
+
17
+
18
+ def test_legacy_chat_defaults_and_explicit_modern_parameters():
19
+ old = OpenAIAdapter('unused', client=Ns())
20
+ assert old.build_request([])['temperature'] == 0.2
21
+ modern = LLMGateway({'api_key': 'unused', 'client': Ns(), 'temperature': None,
22
+ 'max_completion_tokens': 100, 'reasoning_effort': 'high'})
23
+ request = modern.adapter.build_request([])
24
+ assert 'temperature' not in request and 'max_tokens' not in request
25
+ assert request['max_completion_tokens'] == 100
26
+ assert request['reasoning_effort'] == 'high'
27
+
28
+
29
+ @pytest.mark.parametrize('stream', [False, True])
30
+ def test_cache_parameters_reach_sdk(stream):
31
+ adapter = ResponsesAdapter('unused', client=Ns(),
32
+ prompt_cache_options={'mode': 'explicit', 'ttl': '30m'},
33
+ prompt_cache_key='stable-prefix')
34
+ request = adapter.build_request([], stream=stream)
35
+ assert request['prompt_cache_options'] == {'mode': 'explicit', 'ttl': '30m'}
36
+ assert request['prompt_cache_key'] == 'stable-prefix'
37
+ assert request['stream'] == stream
38
+
39
+
40
+ def response_usage():
41
+ from openai.types.responses.response_usage import ResponseUsage
42
+ return ResponseUsage(input_tokens=100, output_tokens=30, total_tokens=130,
43
+ input_tokens_details={'cached_tokens': 60, 'cache_write_tokens': 20},
44
+ output_tokens_details={'reasoning_tokens': 10})
45
+
46
+
47
+ def test_responses_usage_details_nonstream_and_stream():
48
+ adapter = ResponsesAdapter('unused', client=Ns())
49
+ raw = Ns(output=[], usage=response_usage(), status='completed', model='test')
50
+ usage = adapter.parse_response(raw).usage
51
+ assert usage == {'prompt_tokens': 100, 'completion_tokens': 30, 'total_tokens': 130,
52
+ 'cached_tokens': 60, 'cache_write_tokens': 20, 'reasoning_tokens': 10}
53
+ event = adapter.parse_stream_chunk(Ns(type='response.completed', response=raw))
54
+ assert event['usage'] == usage
55
+ total = {'prompt_tokens': 0, 'completion_tokens': 0, 'total_tokens': 0}
56
+ _merge_usage(total, usage)
57
+ _merge_usage(total, usage)
58
+ assert total['cached_tokens'] == 120 and total['total_tokens'] == 260
59
+
60
+
61
+ def test_chat_usage_details_and_missing_fields():
62
+ usage = Ns(prompt_tokens=100, completion_tokens=30, total_tokens=130,
63
+ prompt_tokens_details=Ns(cached_tokens=60),
64
+ completion_tokens_details=Ns(reasoning_tokens=10))
65
+ parsed = OpenAIAdapter._parse_usage(usage)
66
+ assert parsed['cached_tokens'] == 60 and parsed['reasoning_tokens'] == 10
67
+ minimal = OpenAIAdapter._parse_usage(Ns(prompt_tokens=1, completion_tokens=2))
68
+ assert minimal == {'prompt_tokens': 1, 'completion_tokens': 2, 'total_tokens': 3}
69
+
70
+
71
+ @pytest.mark.asyncio
72
+ @pytest.mark.parametrize('stream', [False, True])
73
+ async def test_details_survive_agent_and_session(stream):
74
+ from tests.test_runtime_hardening import make_agent, response
75
+ answer = response('done')
76
+ answer.usage = ResponsesAdapter._parse_usage(response_usage())
77
+ agent = make_agent([answer])
78
+ session = agent.create_session()
79
+ if stream:
80
+ events = [event async for event in agent.stream_events('hello', session=session)]
81
+ usage = events[-1].data['usage']
82
+ else:
83
+ usage = (await agent.run('hello', session=session)).usage
84
+ assert usage['cached_tokens'] == 60 and usage['reasoning_tokens'] == 10
85
+ assert usage['total_tokens'] == 130
86
+ assert session.last_usage == usage
87
+
88
+
89
+ def test_plan_aggregation_preserves_details():
90
+ from wuwei.planning import PlanExecutor
91
+ executor = PlanExecutor(Ns())
92
+ detail = ResponsesAdapter._parse_usage(response_usage())
93
+ executor._tasks_usage = [(detail, 1), (detail, 1)]
94
+ usage, calls = executor._aggregate_usage()
95
+ assert calls == 2 and usage['cache_write_tokens'] == 40
96
+ assert usage['total_tokens'] == 260
97
+
98
+
99
+ @pytest.mark.asyncio
100
+ async def test_cache_request_serialized_by_actual_sdk():
101
+ import json
102
+ import httpx
103
+ from openai import AsyncOpenAI
104
+
105
+ seen = []
106
+ def handler(request):
107
+ seen.append(json.loads(request.content))
108
+ return httpx.Response(200, json={'id': 'resp_1', 'object': 'response',
109
+ 'created_at': 0, 'status': 'completed', 'model': 'test',
110
+ 'output': [], 'usage': response_usage().model_dump()})
111
+
112
+ async with AsyncOpenAI(api_key='unused', max_retries=0,
113
+ http_client=httpx.AsyncClient(transport=httpx.MockTransport(handler))) as client:
114
+ adapter = ResponsesAdapter('unused', client=client,
115
+ prompt_cache_options={'mode': 'implicit', 'ttl': '30m'})
116
+ raw = await adapter.call(adapter.build_request([]))
117
+ assert adapter.parse_response(raw).usage['cached_tokens'] == 60
118
+ assert seen[0]['prompt_cache_options']['ttl'] == '30m'
119
+ assert 'temperature' not in seen[0]
120
+
121
+
122
+ def test_responses_original_positional_constructor():
123
+ client = Ns()
124
+ adapter = ResponsesAdapter('unused', 'test', None, 0.4, 42, client)
125
+ request = adapter.build_request([])
126
+ assert request['max_output_tokens'] == 42 and request['temperature'] == 0.4
127
+ assert adapter.client is client
@@ -333,10 +333,9 @@ class Agent(BaseSessionAgent):
333
333
  before = metadata["llm_calls"]
334
334
  tasks = await p.plan_task(goal)
335
335
  if before == metadata["llm_calls"]:
336
- for key in metadata["usage_total"]:
337
- metadata["usage_total"][key] += (
338
- getattr(p, "last_usage", {}) or {}
339
- ).get(key, 0)
336
+ for key, value in (getattr(p, "last_usage", {}) or {}).items():
337
+ totals = metadata["usage_total"]
338
+ totals[key] = totals.get(key, 0) + (value or 0)
340
339
  metadata["llm_calls"] += getattr(p, "last_llm_calls", 0)
341
340
  for task in tasks:
342
341
  task.status = "pending"
@@ -19,6 +19,7 @@ from ..types import (
19
19
  normalize_finish_reason,
20
20
  )
21
21
  from .base import BaseAdapter, make_client
22
+ from .usage import parse_openai_usage
22
23
 
23
24
 
24
25
  class OpenAIAdapter(BaseAdapter):
@@ -31,7 +32,7 @@ class OpenAIAdapter(BaseAdapter):
31
32
  api_key: str,
32
33
  model: str = "gpt-4o",
33
34
  base_url: str | None = None,
34
- temperature: float = 0.2,
35
+ temperature: float | None = 0.2,
35
36
  max_tokens: int = 4096,
36
37
  client=None,
37
38
  client_factory=None,
@@ -82,7 +83,7 @@ class OpenAIAdapter(BaseAdapter):
82
83
  request["tools"] = [
83
84
  tool.to_schema() if hasattr(tool, "to_schema") else tool for tool in tools
84
85
  ]
85
- return request
86
+ return {k: v for k, v in request.items() if v is not None}
86
87
 
87
88
  async def call(self, request: dict[str, Any]) -> Any:
88
89
  return await self.client.chat.completions.create(**request)
@@ -166,17 +167,7 @@ class OpenAIAdapter(BaseAdapter):
166
167
  @staticmethod
167
168
  def _parse_usage(usage: Any) -> dict[str, int]:
168
169
  """统一解析 usage,避免不同端点返回 None 或缺字段时崩溃。"""
169
- if usage is None:
170
- return {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}
171
- prompt = getattr(usage, "prompt_tokens", 0) or 0
172
- completion = getattr(usage, "completion_tokens", 0) or 0
173
- total = getattr(usage, "total_tokens", None)
174
- total = total if total is not None else prompt + completion
175
- return {
176
- "prompt_tokens": prompt,
177
- "completion_tokens": completion,
178
- "total_tokens": total,
179
- }
170
+ return parse_openai_usage(usage)
180
171
 
181
172
  @staticmethod
182
173
  def _get_extra_field(obj: Any, field_name: str) -> Any:
@@ -18,6 +18,7 @@ from ..types import (
18
18
  ToolCall,
19
19
  )
20
20
  from .base import BaseAdapter, make_client
21
+ from .usage import parse_openai_usage
21
22
 
22
23
 
23
24
  class ResponsesAdapter(BaseAdapter):
@@ -30,11 +31,14 @@ class ResponsesAdapter(BaseAdapter):
30
31
  api_key: str,
31
32
  model: str = "gpt-4o",
32
33
  base_url: str | None = None,
33
- temperature: float = 0.2,
34
+ temperature: float | None = None,
34
35
  max_output_tokens: int = 4096,
35
36
  client=None,
36
37
  client_factory=None,
37
38
  owns_client=None,
39
+ *,
40
+ prompt_cache_options: dict[str, Any] | None = None,
41
+ prompt_cache_key: str | None = None,
38
42
  **kwargs,
39
43
  ):
40
44
  self.client, self.owns_client = make_client(
@@ -43,6 +47,10 @@ class ResponsesAdapter(BaseAdapter):
43
47
  max_output_tokens = kwargs.pop("max_tokens", max_output_tokens)
44
48
  self.model = model
45
49
  self.default_params: dict[str, Any] = {k: v for k, v in kwargs.items() if v is not None}
50
+ if prompt_cache_options is not None:
51
+ self.default_params["prompt_cache_options"] = dict(prompt_cache_options)
52
+ if prompt_cache_key is not None:
53
+ self.default_params["prompt_cache_key"] = prompt_cache_key
46
54
  self.max_output_tokens = max_output_tokens
47
55
  self.temperature = temperature
48
56
 
@@ -125,7 +133,7 @@ class ResponsesAdapter(BaseAdapter):
125
133
  request["instructions"] = instructions
126
134
  if tools:
127
135
  request["tools"] = self._convert_tools(tools)
128
- return request
136
+ return {k: v for k, v in request.items() if v is not None}
129
137
 
130
138
  async def call(self, request: dict[str, Any]) -> Any:
131
139
  return await self.client.responses.create(**request)
@@ -240,7 +248,7 @@ class ResponsesAdapter(BaseAdapter):
240
248
  ]
241
249
  }
242
250
  usage = self._parse_usage(getattr(response, "usage", None))
243
- if usage.get("total_tokens"):
251
+ if getattr(response, "usage", None) is not None:
244
252
  result["usage"] = usage
245
253
  return result
246
254
 
@@ -250,14 +258,4 @@ class ResponsesAdapter(BaseAdapter):
250
258
 
251
259
  @staticmethod
252
260
  def _parse_usage(usage: Any) -> dict[str, int]:
253
- if usage is None:
254
- return {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}
255
- prompt = getattr(usage, "input_tokens", 0) or 0
256
- completion = getattr(usage, "output_tokens", 0) or 0
257
- total = getattr(usage, "total_tokens", None)
258
- total = total if total is not None else prompt + completion
259
- return {
260
- "prompt_tokens": prompt,
261
- "completion_tokens": completion,
262
- "total_tokens": total,
263
- }
261
+ return parse_openai_usage(usage, responses=True)
@@ -0,0 +1,27 @@
1
+ """Normalize OpenAI usage without counting detail tokens a second time."""
2
+
3
+
4
+ def parse_openai_usage(usage, *, responses=False):
5
+ def field(obj, name, default=None):
6
+ return obj.get(name, default) if isinstance(obj, dict) else getattr(obj, name, default)
7
+
8
+ input_name, output_name = (
9
+ ("input_tokens", "output_tokens") if responses else ("prompt_tokens", "completion_tokens")
10
+ )
11
+ prompt = field(usage, input_name, 0) or 0
12
+ completion = field(usage, output_name, 0) or 0
13
+ total = field(usage, "total_tokens")
14
+ result = {
15
+ "prompt_tokens": prompt,
16
+ "completion_tokens": completion,
17
+ "total_tokens": total if total is not None else prompt + completion,
18
+ }
19
+ for detail, names in (
20
+ (field(usage, f"{input_name}_details"), ("cached_tokens", "cache_write_tokens")),
21
+ (field(usage, f"{output_name}_details"), ("reasoning_tokens",)),
22
+ ):
23
+ for name in names:
24
+ value = field(detail, name)
25
+ if value is not None:
26
+ result[name] = value
27
+ return result
@@ -110,7 +110,7 @@ class LLMGateway:
110
110
  adapter_kwargs: dict[str, Any] = {
111
111
  "api_key": config.get("api_key") or "missing",
112
112
  "model": config.get("model", spec["default_model"]),
113
- "temperature": config.get("temperature", 0.2),
113
+ "temperature": config.get("temperature", None if provider == "responses" else 0.2),
114
114
  }
115
115
  if provider == "responses":
116
116
  adapter_kwargs["max_output_tokens"] = config.get(
@@ -310,7 +310,7 @@ class PlanExecutor:
310
310
  usage = {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}
311
311
  llm_calls = 0
312
312
  for u, calls in self._tasks_usage:
313
- for k in usage:
314
- usage[k] += u.get(k, 0)
313
+ for k, value in u.items():
314
+ usage[k] = usage.get(k, 0) + (value or 0)
315
315
  llm_calls += calls
316
316
  return usage, llm_calls
@@ -28,8 +28,8 @@ def _empty_usage():
28
28
 
29
29
 
30
30
  def _merge_usage(total, usage):
31
- for key in total:
32
- total[key] += (usage or {}).get(key, 0) or 0
31
+ for key, value in (usage or {}).items():
32
+ total[key] = total.get(key, 0) + (value or 0)
33
33
 
34
34
 
35
35
  class AgentRunner:
@@ -373,10 +373,8 @@ class AgentRunner:
373
373
  pending = chunk.tool_calls_complete
374
374
  if chunk.finish_reason:
375
375
  finish = chunk.finish_reason
376
- for key in call_usage:
377
- call_usage[key] = max(
378
- call_usage[key], (chunk.usage or {}).get(key, 0) or 0
379
- )
376
+ for key, value in (chunk.usage or {}).items():
377
+ call_usage[key] = max(call_usage.get(key, 0), value or 0)
380
378
  finally:
381
379
  close = getattr(result, "aclose", None)
382
380
  if close:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wuwei
3
- Version: 3.2.1
3
+ Version: 3.2.2
4
4
  Summary: Wuwei - 无为而治的 AI 智能体框架
5
5
  Author-email: xiaojiaenen <xiaojiaenen@163.com>
6
6
  License-Expression: Apache-2.0
@@ -10,7 +10,7 @@ Project-URL: Documentation, https://github.com/xiaojiaenen/wuwei
10
10
  Requires-Python: >=3.11
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
- Requires-Dist: openai>=3.23.0
13
+ Requires-Dist: openai>=3.40.0
14
14
  Requires-Dist: pydantic>=2.0.0
15
15
  Requires-Dist: pyyaml>=6.0.3
16
16
  Requires-Dist: httpx>=0.25.0
@@ -59,6 +59,7 @@ tests/test_middleware.py
59
59
  tests/test_middleware_lifecycle.py
60
60
  tests/test_model_hardening.py
61
61
  tests/test_multi_agent_integration.py
62
+ tests/test_openai_sdk_capabilities.py
62
63
  tests/test_runtime_hardening.py
63
64
  tests/test_sandbox.py
64
65
  tests/test_serve.py
@@ -126,6 +127,7 @@ wuwei/llm/adapters/anthropic.py
126
127
  wuwei/llm/adapters/base.py
127
128
  wuwei/llm/adapters/openai.py
128
129
  wuwei/llm/adapters/responses.py
130
+ wuwei/llm/adapters/usage.py
129
131
  wuwei/mcp/__init__.py
130
132
  wuwei/mcp/client.py
131
133
  wuwei/mcp/config.py
@@ -1,4 +1,4 @@
1
- openai>=3.23.0
1
+ openai>=3.40.0
2
2
  pydantic>=2.0.0
3
3
  pyyaml>=6.0.3
4
4
  httpx>=0.25.0
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