agentseek-api 0.2.2__tar.gz → 0.2.3__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 (247) hide show
  1. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/.github/workflows/ci.yml +2 -0
  2. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/CHANGELOG.md +15 -0
  3. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/PKG-INFO +8 -3
  4. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/README.md +7 -2
  5. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/README.zh-CN.md +7 -2
  6. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/pyproject.toml +1 -1
  7. agentseek_api-0.2.3/src/agentseek_api/__init__.py +1 -0
  8. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/database.py +27 -8
  9. agentseek_api-0.2.3/src/agentseek_api/core/sqlite_checkpointer.py +82 -0
  10. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_metadata_db_config.py +53 -0
  11. agentseek_api-0.2.3/tests/unit/test_ci_workflow.py +25 -0
  12. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_database_manager.py +27 -13
  13. agentseek_api-0.2.3/tests/unit/test_sqlite_checkpointer.py +51 -0
  14. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/uv.lock +1 -1
  15. agentseek_api-0.2.2/src/agentseek_api/__init__.py +0 -1
  16. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/.dockerignore +0 -0
  17. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/.env.example +0 -0
  18. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  19. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/.github/workflows/live-provider-streaming.yml +0 -0
  20. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/.github/workflows/release.yml +0 -0
  21. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/.gitignore +0 -0
  22. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/AGENTS.md +0 -0
  23. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/CONTRIBUTING.md +0 -0
  24. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/LICENSE +0 -0
  25. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/Makefile +0 -0
  26. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/README.md +0 -0
  27. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/__init__.py +0 -0
  28. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/assistant_config/agentseek.json +0 -0
  29. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/assistant_config/graph.py +0 -0
  30. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/auth/api_key_auth.py +0 -0
  31. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/auth/bearer_token_auth.py +0 -0
  32. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/auth/custom_backend.py +0 -0
  33. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/auth/jwt.md +0 -0
  34. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/auth/jwt_auth.py +0 -0
  35. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/custom_routes/app.py +0 -0
  36. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/docker_ci_auth/auth_backend.py +0 -0
  37. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/docker_ci_auth/manifest.json +0 -0
  38. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/external_graph/__init__.py +0 -0
  39. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/external_graph/graph.py +0 -0
  40. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/external_graph/manifest.json +0 -0
  41. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/external_graph/run.py +0 -0
  42. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/graphs/__init__.py +0 -0
  43. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/graphs/react_agent/__init__.py +0 -0
  44. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/graphs/react_agent/graph.py +0 -0
  45. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/graphs/store_memory/graph.py +0 -0
  46. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/graphs/stress_test/__init__.py +0 -0
  47. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/graphs/stress_test/graph.py +0 -0
  48. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/graphs/stress_tool_agent/__init__.py +0 -0
  49. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/graphs/stress_tool_agent/graph.py +0 -0
  50. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/graphs/subgraph_agent/__init__.py +0 -0
  51. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/graphs/subgraph_agent/graph.py +0 -0
  52. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/graphs/subgraph_hitl_agent/__init__.py +0 -0
  53. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/graphs/subgraph_hitl_agent/graph.py +0 -0
  54. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/live_provider_graphs/__init__.py +0 -0
  55. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/live_provider_graphs/graph.py +0 -0
  56. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/live_provider_graphs/manifest.json +0 -0
  57. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/minimal_agentseek/agentseek.json +0 -0
  58. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/minimal_agentseek/graph.py +0 -0
  59. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/run_sample_graphs.py +0 -0
  60. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/examples/sample_graphs_manifest.json +0 -0
  61. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/build_live_provider_matrix.py +0 -0
  62. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/seekdb_checkpoint_smoke.py +0 -0
  63. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/seekdb_embed_launcher.py +0 -0
  64. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/test-checkpoints.sh +0 -0
  65. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/test-cli-dev-samples.sh +0 -0
  66. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/test-cli-docker.sh +0 -0
  67. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/test-live-provider.sh +0 -0
  68. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/test-redis-runtime.sh +0 -0
  69. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/test-seekdb.sh +0 -0
  70. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/test_cli_config_autodiscovery.py +0 -0
  71. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/test_cli_dev_studio_smoke.py +0 -0
  72. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/test_cli_embed_serve_smoke.py +0 -0
  73. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/test_cli_serve_smoke.py +0 -0
  74. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/test_minimum_cli_dependencies.py +0 -0
  75. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/verify_docker_api.py +0 -0
  76. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/scripts/verify_worker_concurrency.py +0 -0
  77. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/a2a_server.py +0 -0
  78. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/api/__init__.py +0 -0
  79. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/api/assistants.py +0 -0
  80. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/api/crons.py +0 -0
  81. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/api/runs.py +0 -0
  82. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/api/stateless_runs.py +0 -0
  83. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/api/store.py +0 -0
  84. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/api/streaming.py +0 -0
  85. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/api/threads.py +0 -0
  86. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/cli.py +0 -0
  87. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/constants.py +0 -0
  88. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/__init__.py +0 -0
  89. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/a2a_config.py +0 -0
  90. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/app_loader.py +0 -0
  91. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/auth_deps.py +0 -0
  92. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/auth_middleware.py +0 -0
  93. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/config_file.py +0 -0
  94. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/content_type_fix.py +0 -0
  95. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/cors_config.py +0 -0
  96. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/http_config.py +0 -0
  97. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/mcp_config.py +0 -0
  98. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/oceanbase_checkpointer.py +0 -0
  99. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/orm.py +0 -0
  100. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/runtime_store.py +0 -0
  101. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/core/store_config.py +0 -0
  102. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/dotenv_adapter.py +0 -0
  103. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/main.py +0 -0
  104. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/mcp_server.py +0 -0
  105. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/models/__init__.py +0 -0
  106. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/models/api.py +0 -0
  107. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/models/auth.py +0 -0
  108. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/models/protocol.py +0 -0
  109. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/process_supervisor.py +0 -0
  110. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/runtime_entrypoint.py +0 -0
  111. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/scheduler.py +0 -0
  112. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/__init__.py +0 -0
  113. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/cron_models.py +0 -0
  114. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/cron_rrule.py +0 -0
  115. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/cron_scheduler.py +0 -0
  116. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/cron_service.py +0 -0
  117. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/cron_webhooks.py +0 -0
  118. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/default_assistants.py +0 -0
  119. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/executor.py +0 -0
  120. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/langgraph_service.py +0 -0
  121. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/redis_queue.py +0 -0
  122. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/run_executor.py +0 -0
  123. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/run_jobs.py +0 -0
  124. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/run_preparation.py +0 -0
  125. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/run_state.py +0 -0
  126. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/sample_graphs.py +0 -0
  127. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/sse.py +0 -0
  128. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/stream_modes.py +0 -0
  129. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/stream_persistence.py +0 -0
  130. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/thread_checkpoint_store.py +0 -0
  131. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/thread_protocol.py +0 -0
  132. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/services/thread_service.py +0 -0
  133. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/settings.py +0 -0
  134. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/src/agentseek_api/worker.py +0 -0
  135. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/__init__.py +0 -0
  136. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/conftest.py +0 -0
  137. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/__init__.py +0 -0
  138. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/conftest.py +0 -0
  139. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/e2e_inprocess_flow.py +0 -0
  140. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/e2e_live_http_flow.py +0 -0
  141. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/e2e_live_http_multi_graph.py +0 -0
  142. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/e2e_live_http_resume_flow.py +0 -0
  143. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/fixtures/langgraph.store-e2e.json +0 -0
  144. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/live_provider_helpers.py +0 -0
  145. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/test_a2a_live.py +0 -0
  146. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/test_cron_api_live.py +0 -0
  147. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/test_cron_scheduler_live.py +0 -0
  148. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/test_langsmith_compat_live.py +0 -0
  149. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/test_live_provider_api.py +0 -0
  150. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/test_live_provider_mcp.py +0 -0
  151. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/test_mcp_live.py +0 -0
  152. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/e2e/test_real_api_flow.py +0 -0
  153. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/fixtures/runtime_settings_probe/sitecustomize.py +0 -0
  154. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/fixtures/termination_tree.py +0 -0
  155. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_a2a_endpoint.py +0 -0
  156. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_agent_card.py +0 -0
  157. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_agents_aliases.py +0 -0
  158. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_assistants_compat.py +0 -0
  159. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_assistants_config_context_sync.py +0 -0
  160. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_assistants_crud.py +0 -0
  161. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_assistants_ordering.py +0 -0
  162. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_auth_coverage_gaps.py +0 -0
  163. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_auth_handlers.py +0 -0
  164. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_auth_route_enforcement.py +0 -0
  165. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_auth_scope_matrix.py +0 -0
  166. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_cli_runtime_processes.py +0 -0
  167. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_core_api_flow.py +0 -0
  168. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_cron_api.py +0 -0
  169. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_langsmith_compat_coverage.py +0 -0
  170. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_langsmith_compat_extra.py +0 -0
  171. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_live_provider_streaming.py +0 -0
  172. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_live_redis_queue.py +0 -0
  173. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_live_redis_stream_persistence.py +0 -0
  174. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_mcp_endpoint.py +0 -0
  175. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_protocol_v2_streaming.py +0 -0
  176. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_run_cancellation_async.py +0 -0
  177. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_runs_compat.py +0 -0
  178. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_runs_crud.py +0 -0
  179. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_runs_ordering.py +0 -0
  180. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_runs_resume.py +0 -0
  181. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_runs_streaming.py +0 -0
  182. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_runs_streaming_errors.py +0 -0
  183. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_runs_validation.py +0 -0
  184. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_runs_wait_and_get.py +0 -0
  185. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_runs_wait_timeout.py +0 -0
  186. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_scheduler_runtime.py +0 -0
  187. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_stateless_runs_crud.py +0 -0
  188. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_store_api.py +0 -0
  189. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_stream_persistence.py +0 -0
  190. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_system_endpoints.py +0 -0
  191. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_threads_compat.py +0 -0
  192. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_threads_crud.py +0 -0
  193. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/integration/test_threads_ordering.py +0 -0
  194. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_a2a_config.py +0 -0
  195. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_a2a_server.py +0 -0
  196. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_app_loader.py +0 -0
  197. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_assistant_routes_unit.py +0 -0
  198. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_auth.py +0 -0
  199. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_auth_deps.py +0 -0
  200. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_auth_internals.py +0 -0
  201. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_checkpoint_guards.py +0 -0
  202. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_cli.py +0 -0
  203. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_content_type_fix.py +0 -0
  204. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_cron_rrule.py +0 -0
  205. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_cron_service.py +0 -0
  206. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_cron_webhooks.py +0 -0
  207. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_custom_routers.py +0 -0
  208. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_default_assistants.py +0 -0
  209. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_dotenv_adapter.py +0 -0
  210. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_examples.py +0 -0
  211. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_executor.py +0 -0
  212. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_graph_manifest.py +0 -0
  213. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_http_config.py +0 -0
  214. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_langgraph_service.py +0 -0
  215. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_live_provider_e2e_config.py +0 -0
  216. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_live_provider_graphs.py +0 -0
  217. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_live_provider_matrix.py +0 -0
  218. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_mcp_config.py +0 -0
  219. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_mcp_server.py +0 -0
  220. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_oceanbase_checkpointer.py +0 -0
  221. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_openapi_auth_config.py +0 -0
  222. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_process_supervisor.py +0 -0
  223. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_redis_queue.py +0 -0
  224. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_redis_runtime_script.py +0 -0
  225. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_run_controls_validation.py +0 -0
  226. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_run_executor.py +0 -0
  227. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_run_jobs.py +0 -0
  228. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_run_preparation.py +0 -0
  229. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_run_state.py +0 -0
  230. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_runtime_entrypoint.py +0 -0
  231. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_runtime_environment.py +0 -0
  232. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_runtime_store.py +0 -0
  233. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_sample_graphs.py +0 -0
  234. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_scheduler.py +0 -0
  235. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_scheduler_process.py +0 -0
  236. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_seekdb_checkpoint_smoke.py +0 -0
  237. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_seekdb_embed_launcher.py +0 -0
  238. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_sse_keepalive.py +0 -0
  239. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_store_config.py +0 -0
  240. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_stream_modes.py +0 -0
  241. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_stream_persistence_helpers.py +0 -0
  242. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_thread_checkpoint_store.py +0 -0
  243. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_thread_protocol.py +0 -0
  244. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_thread_routes_unit.py +0 -0
  245. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_thread_service.py +0 -0
  246. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_worker.py +0 -0
  247. {agentseek_api-0.2.2 → agentseek_api-0.2.3}/tests/unit/test_worker_concurrency_probe.py +0 -0
@@ -91,7 +91,9 @@ jobs:
91
91
  tests/unit/test_runtime_environment.py
92
92
  tests/unit/test_runtime_entrypoint.py
93
93
  tests/unit/test_process_supervisor.py
94
+ tests/unit/test_sqlite_checkpointer.py
94
95
  tests/integration/test_cli_runtime_processes.py
96
+ tests/integration/test_metadata_db_config.py
95
97
  -q
96
98
 
97
99
  - name: Sync embedded SeekDB extra for serve smoke
@@ -4,6 +4,21 @@ Notable changes to AgentSeek API are documented in this file.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.2.3 - 2026-08-17
8
+
9
+ ### Fixed
10
+
11
+ - When `METADATA_DB_BACKEND=sqlite`, store completed-run snapshots in the
12
+ configured SQLite metadata database instead of constructing an OceanBase
13
+ saver and attempting a MySQL-family connection.
14
+
15
+ ### Upgrade notes
16
+
17
+ - No manual schema or configuration migration is required. The
18
+ `agentseek_checkpoints` table is created idempotently at startup.
19
+ - This fix covers completed-run snapshots only. LangGraph checkpoint state
20
+ remains in memory when the metadata backend is SQLite.
21
+
7
22
  ## 0.2.2 - 2026-08-16
8
23
 
9
24
  ### Highlights
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentseek-api
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: AgentSeek API core runtime with OceanBase checkpoints.
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -217,7 +217,7 @@ When the server starts it prints the banner and local URLs:
217
217
  ╠═╣│ ┬├┤ │││ │ ╚═╗├┤ ├┤ ├┴┐
218
218
  ╩ ╩└─┘└─┘┘└┘ ┴ ╚═╝└─┘└─┘┴ ┴
219
219
 
220
- AgentSeek v0.2.2
220
+ AgentSeek v0.2.3
221
221
 
222
222
  - 🚀 API: http://localhost:2024
223
223
  - 📚 Docs: http://localhost:2024/docs
@@ -691,7 +691,12 @@ parent api build --config ./langgraph.json -t my-api:dev
691
691
  - `METADATA_DB_BACKEND=auto` normalizes drivers:
692
692
  - PostgreSQL: `postgresql+asyncpg://...`
693
693
  - OceanBase / MySQL: `mysql+aiomysql://...`
694
- - Checkpoint persistence defaults to OceanBase / seekdb settings
694
+ - SQLite: `sqlite+aiosqlite://...`
695
+ - Completed-run snapshots default to OceanBase / seekdb settings. With
696
+ `METADATA_DB_BACKEND=sqlite`, they are stored in the configured SQLite
697
+ metadata database without constructing an OceanBase saver.
698
+ - The SQLite metadata path still uses an in-memory LangGraph checkpointer; it
699
+ does not make LangGraph graph checkpoints durable.
695
700
  - Auth: configure via `agentseek.json` `"auth.path"` or `AUTH_MODULE_PATH` env var.
696
701
  Uses `langgraph_sdk.Auth` with `@auth.authenticate` and `@auth.on` handlers.
697
702
  If not set, all requests pass through as default_user (noop).
@@ -185,7 +185,7 @@ When the server starts it prints the banner and local URLs:
185
185
  ╠═╣│ ┬├┤ │││ │ ╚═╗├┤ ├┤ ├┴┐
186
186
  ╩ ╩└─┘└─┘┘└┘ ┴ ╚═╝└─┘└─┘┴ ┴
187
187
 
188
- AgentSeek v0.2.2
188
+ AgentSeek v0.2.3
189
189
 
190
190
  - 🚀 API: http://localhost:2024
191
191
  - 📚 Docs: http://localhost:2024/docs
@@ -659,7 +659,12 @@ parent api build --config ./langgraph.json -t my-api:dev
659
659
  - `METADATA_DB_BACKEND=auto` normalizes drivers:
660
660
  - PostgreSQL: `postgresql+asyncpg://...`
661
661
  - OceanBase / MySQL: `mysql+aiomysql://...`
662
- - Checkpoint persistence defaults to OceanBase / seekdb settings
662
+ - SQLite: `sqlite+aiosqlite://...`
663
+ - Completed-run snapshots default to OceanBase / seekdb settings. With
664
+ `METADATA_DB_BACKEND=sqlite`, they are stored in the configured SQLite
665
+ metadata database without constructing an OceanBase saver.
666
+ - The SQLite metadata path still uses an in-memory LangGraph checkpointer; it
667
+ does not make LangGraph graph checkpoints durable.
663
668
  - Auth: configure via `agentseek.json` `"auth.path"` or `AUTH_MODULE_PATH` env var.
664
669
  Uses `langgraph_sdk.Auth` with `@auth.authenticate` and `@auth.on` handlers.
665
670
  If not set, all requests pass through as default_user (noop).
@@ -181,7 +181,7 @@ uv run agentseek-api dev --config ./langgraph.json
181
181
  ╠═╣│ ┬├┤ │││ │ ╚═╗├┤ ├┤ ├┴┐
182
182
  ╩ ╩└─┘└─┘┘└┘ ┴ ╚═╝└─┘└─┘┴ ┴
183
183
 
184
- AgentSeek v0.2.2
184
+ AgentSeek v0.2.3
185
185
 
186
186
  - 🚀 API: http://localhost:2024
187
187
  - 📚 Docs: http://localhost:2024/docs
@@ -623,7 +623,12 @@ parent api build --config ./langgraph.json -t my-api:dev
623
623
  - `METADATA_DB_BACKEND=auto` 会对驱动进行归一化:
624
624
  - PostgreSQL:`postgresql+asyncpg://...`
625
625
  - OceanBase / MySQL:`mysql+aiomysql://...`
626
- - Checkpoint 持久化默认使用 OceanBase / seekdb 配置
626
+ - SQLite:`sqlite+aiosqlite://...`
627
+ - 完成态 run 快照默认使用 OceanBase / seekdb 配置。当
628
+ `METADATA_DB_BACKEND=sqlite` 时,快照会写入已配置的 SQLite 元数据
629
+ 数据库,且不会构造 OceanBase saver。
630
+ - SQLite 元数据路径仍使用内存中的 LangGraph checkpointer,不提供持久化的
631
+ LangGraph 图 checkpoint。
627
632
  - 鉴权:通过 `agentseek.json` 的 `"auth.path"` 或 `AUTH_MODULE_PATH` 环境变量配置。
628
633
  使用 `langgraph_sdk.Auth` 的 `@auth.authenticate` 与 `@auth.on` 处理器风格。
629
634
  未配置时所有请求以 default_user 放行(noop)。
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentseek-api"
3
- version = "0.2.2"
3
+ version = "0.2.3"
4
4
  description = "AgentSeek API core runtime with OceanBase checkpoints."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -0,0 +1 @@
1
+ __version__ = "0.2.3"
@@ -3,7 +3,7 @@ import logging
3
3
  import os
4
4
  from collections.abc import Callable
5
5
  from pathlib import Path
6
- from typing import Any
6
+ from typing import Any, Protocol
7
7
 
8
8
  from langgraph.checkpoint.memory import InMemorySaver
9
9
  from langchain_oceanbase.checkpointer import OceanBaseCheckpointSaver as LangGraphOceanBaseCheckpointSaver
@@ -14,6 +14,7 @@ from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
14
14
  from agentseek_api.core.oceanbase_checkpointer import OceanBaseCheckpointSaver
15
15
  from agentseek_api.core.orm import Base
16
16
  from agentseek_api.core.runtime_store import SqliteStore
17
+ from agentseek_api.core.sqlite_checkpointer import SqliteCheckpointSaver
17
18
  from agentseek_api.core.store_config import load_store_config
18
19
  from agentseek_api.settings import settings
19
20
 
@@ -58,6 +59,18 @@ class NullStore:
58
59
  return None
59
60
 
60
61
 
62
+ class RunCheckpointSaver(Protocol):
63
+ def setup(self) -> None: ...
64
+
65
+ def save_checkpoint(
66
+ self,
67
+ *,
68
+ thread_id: str,
69
+ run_id: str,
70
+ payload: dict[str, Any],
71
+ ) -> None: ...
72
+
73
+
61
74
  def _is_already_exists_error(exc: Exception) -> bool:
62
75
  message = str(exc).lower()
63
76
  return "already exists" in message
@@ -156,7 +169,7 @@ class DatabaseManager:
156
169
  def __init__(self) -> None:
157
170
  self.engine: AsyncEngine | None = None
158
171
  self.session_factory: async_sessionmaker[AsyncSession] | None = None
159
- self._checkpointer: OceanBaseCheckpointSaver | None = None
172
+ self._checkpointer: RunCheckpointSaver | None = None
160
173
  self._langgraph_checkpointer: Any | None = None
161
174
  self._store: Any | None = None
162
175
  self._setup_lock: asyncio.Lock = asyncio.Lock()
@@ -208,11 +221,8 @@ class DatabaseManager:
208
221
  async with self.engine.begin() as conn:
209
222
  await conn.run_sync(Base.metadata.create_all)
210
223
  await conn.run_sync(self._apply_additive_migrations)
211
- conn_args = _resolve_connection_args()
212
- self._checkpointer = OceanBaseCheckpointSaver(
213
- connection_args=conn_args
214
- )
215
224
  if metadata_backend == "sqlite":
225
+ self._checkpointer = SqliteCheckpointSaver(url=metadata_db_url)
216
226
  self._langgraph_checkpointer = InMemorySaver()
217
227
  self._store = SqliteStore(
218
228
  url=metadata_db_url,
@@ -220,6 +230,8 @@ class DatabaseManager:
220
230
  ttl_config=runtime_ttl,
221
231
  )
222
232
  else:
233
+ conn_args = _resolve_connection_args()
234
+ self._checkpointer = OceanBaseCheckpointSaver(connection_args=conn_args)
223
235
  self._langgraph_checkpointer = LangGraphOceanBaseCheckpointSaver(
224
236
  connection_args=conn_args
225
237
  )
@@ -320,6 +332,14 @@ class DatabaseManager:
320
332
  self._store_setup_done = True
321
333
 
322
334
  async def close(self) -> None:
335
+ run_checkpointer = self._checkpointer
336
+ self._checkpointer = None
337
+ close_run_checkpointer = getattr(run_checkpointer, "close", None)
338
+ if callable(close_run_checkpointer):
339
+ try:
340
+ await asyncio.to_thread(close_run_checkpointer)
341
+ except Exception: # noqa: BLE001
342
+ logger.warning("Failed to close run checkpointer", exc_info=True)
323
343
  langgraph_checkpointer = self._langgraph_checkpointer
324
344
  self._langgraph_checkpointer = None
325
345
  close_checkpointer = getattr(langgraph_checkpointer, "close", None)
@@ -336,7 +356,6 @@ class DatabaseManager:
336
356
  await asyncio.to_thread(dispose_store_engine)
337
357
  self.engine = None
338
358
  self.session_factory = None
339
- self._checkpointer = None
340
359
  self._store = None
341
360
  self._checkpointer_setup_done = False
342
361
  self._langgraph_checkpointer_setup_done = False
@@ -352,7 +371,7 @@ class DatabaseManager:
352
371
  raise RuntimeError("Database not initialized")
353
372
  return self.session_factory
354
373
 
355
- def get_checkpointer(self) -> OceanBaseCheckpointSaver:
374
+ def get_checkpointer(self) -> RunCheckpointSaver:
356
375
  if self._checkpointer is None:
357
376
  raise RuntimeError("Database not initialized")
358
377
  return self._checkpointer
@@ -0,0 +1,82 @@
1
+ from __future__ import annotations
2
+
3
+ import threading
4
+ from datetime import UTC, datetime
5
+ from typing import Any
6
+
7
+ from sqlalchemy import create_engine, text
8
+ from sqlalchemy.engine import Engine, make_url
9
+ from sqlalchemy.pool import StaticPool
10
+
11
+ from agentseek_api.services.sse import safe_json_dumps
12
+
13
+
14
+ class SqliteCheckpointSaver:
15
+ """Persist completed run snapshots in the configured SQLite database."""
16
+
17
+ def __init__(self, *, url: str) -> None:
18
+ parsed_url = make_url(url)
19
+ if parsed_url.get_backend_name() != "sqlite":
20
+ raise ValueError("SqliteCheckpointSaver requires a SQLite URL")
21
+
22
+ sqlite_url = parsed_url.set(drivername="sqlite").render_as_string(
23
+ hide_password=False
24
+ )
25
+ engine_options: dict[str, Any] = {"connect_args": {"check_same_thread": False}}
26
+ if parsed_url.database in {None, "", ":memory:"}:
27
+ engine_options["poolclass"] = StaticPool
28
+
29
+ self._engine: Engine = create_engine(sqlite_url, **engine_options)
30
+ self._lock = threading.Lock()
31
+
32
+ def setup(self) -> None:
33
+ with self._lock, self._engine.begin() as connection:
34
+ connection.execute(
35
+ text(
36
+ """
37
+ CREATE TABLE IF NOT EXISTS agentseek_checkpoints (
38
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
39
+ thread_id TEXT NOT NULL,
40
+ run_id TEXT NOT NULL,
41
+ checkpoint TEXT NOT NULL,
42
+ created_at DATETIME NOT NULL
43
+ )
44
+ """
45
+ )
46
+ )
47
+ connection.execute(
48
+ text(
49
+ """
50
+ CREATE INDEX IF NOT EXISTS idx_agentseek_checkpoints_thread_run
51
+ ON agentseek_checkpoints (thread_id, run_id)
52
+ """
53
+ )
54
+ )
55
+
56
+ def save_checkpoint(
57
+ self,
58
+ *,
59
+ thread_id: str,
60
+ run_id: str,
61
+ payload: dict[str, Any],
62
+ ) -> None:
63
+ with self._lock, self._engine.begin() as connection:
64
+ connection.execute(
65
+ text(
66
+ """
67
+ INSERT INTO agentseek_checkpoints
68
+ (thread_id, run_id, checkpoint, created_at)
69
+ VALUES (:thread_id, :run_id, :checkpoint, :created_at)
70
+ """
71
+ ),
72
+ {
73
+ "thread_id": thread_id,
74
+ "run_id": run_id,
75
+ "checkpoint": safe_json_dumps(payload),
76
+ "created_at": datetime.now(UTC).replace(tzinfo=None).isoformat(),
77
+ },
78
+ )
79
+
80
+ def close(self) -> None:
81
+ with self._lock:
82
+ self._engine.dispose()
@@ -1,4 +1,7 @@
1
+ import json
2
+ import sqlite3
1
3
  from collections.abc import Callable
4
+ from pathlib import Path
2
5
  from typing import Any
3
6
 
4
7
  import pytest
@@ -123,3 +126,53 @@ def test_health_uses_mysql_async_driver(monkeypatch: pytest.MonkeyPatch) -> None
123
126
 
124
127
  def test_sqlite_metadata_engine_options_keep_dialect_defaults() -> None:
125
128
  assert database_module._metadata_engine_options("sqlite") == {"pool_pre_ping": True}
129
+
130
+
131
+ def test_sqlite_runtime_starts_and_saves_checkpoints_without_oceanbase(
132
+ monkeypatch: pytest.MonkeyPatch,
133
+ tmp_path: Path,
134
+ ) -> None:
135
+ database_path = tmp_path / "agentseek.sqlite3"
136
+
137
+ class RejectOceanBaseCheckpointSaver:
138
+ def __init__(self, *_args: object, **_kwargs: object) -> None:
139
+ raise AssertionError(
140
+ "SQLite runtime constructed the OceanBase checkpoint saver"
141
+ )
142
+
143
+ monkeypatch.setattr(
144
+ "agentseek_api.core.database.OceanBaseCheckpointSaver",
145
+ RejectOceanBaseCheckpointSaver,
146
+ )
147
+ monkeypatch.setattr(
148
+ "agentseek_api.main.ensure_default_assistants", _noop_ensure_default_assistants
149
+ )
150
+ monkeypatch.setattr(settings, "SEEKDB_EMBED", False)
151
+ monkeypatch.setattr(settings, "METADATA_DB_BACKEND", "sqlite")
152
+ monkeypatch.setattr(
153
+ settings,
154
+ "METADATA_DB_URL",
155
+ f"sqlite+aiosqlite:///{database_path.as_posix()}",
156
+ )
157
+
158
+ manager = DatabaseManager()
159
+ monkeypatch.setattr("agentseek_api.main.db_manager", manager)
160
+
161
+ with TestClient(create_app()) as client:
162
+ response = client.get("/health")
163
+ assert response.status_code == 200
164
+
165
+ manager.get_checkpointer().save_checkpoint(
166
+ thread_id="thread-sqlite",
167
+ run_id="run-sqlite",
168
+ payload={"status": "complete"},
169
+ )
170
+
171
+ with sqlite3.connect(database_path) as connection:
172
+ row = connection.execute(
173
+ "SELECT thread_id, run_id, checkpoint FROM agentseek_checkpoints"
174
+ ).fetchone()
175
+
176
+ assert row is not None
177
+ assert row[:2] == ("thread-sqlite", "run-sqlite")
178
+ assert json.loads(row[2]) == {"status": "complete"}
@@ -0,0 +1,25 @@
1
+ import re
2
+ from pathlib import Path
3
+
4
+
5
+ def test_cli_compatibility_step_runs_sqlite_runtime_regressions_on_every_os() -> None:
6
+ workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8")
7
+ job = re.search(
8
+ r"(?ms)^ cli-compatibility:\n(?P<body>.*?)(?=^ \S|\Z)",
9
+ workflow,
10
+ )
11
+ assert job is not None
12
+
13
+ step = re.search(
14
+ r"(?ms)^ - name: CLI config, host environment, and process tests\n"
15
+ r"(?P<body>.*?)(?=^ - name:|\Z)",
16
+ job.group("body"),
17
+ )
18
+ assert step is not None
19
+
20
+ command_tokens = set(step.group("body").split())
21
+ required_tests = {
22
+ "tests/unit/test_sqlite_checkpointer.py",
23
+ "tests/integration/test_metadata_db_config.py",
24
+ }
25
+ assert required_tests <= command_tokens
@@ -12,30 +12,26 @@ from agentseek_api.settings import settings
12
12
  async def test_checkpointer_setup_called_once(monkeypatch: pytest.MonkeyPatch) -> None:
13
13
  class FakeCheckpointer:
14
14
  setup_calls = 0
15
- latest_connection_args: dict[str, str] | None = None
15
+ latest_url: str | None = None
16
16
 
17
- def __init__(self, connection_args: dict[str, str]) -> None:
18
- FakeCheckpointer.latest_connection_args = connection_args
17
+ def __init__(self, *, url: str) -> None:
18
+ FakeCheckpointer.latest_url = url
19
19
 
20
20
  def setup(self) -> None:
21
21
  FakeCheckpointer.setup_calls += 1
22
22
 
23
- monkeypatch.setattr("agentseek_api.core.database.OceanBaseCheckpointSaver", FakeCheckpointer)
24
- monkeypatch.setattr(settings, "SEEKDB_URL", "sqlite+aiosqlite:///:memory:")
25
- monkeypatch.setattr(settings, "OCEANBASE_HOST", "127.0.0.1")
26
- monkeypatch.setattr(settings, "OCEANBASE_PORT", "2881")
27
- monkeypatch.setattr(settings, "OCEANBASE_USER", "root@test")
28
- monkeypatch.setattr(settings, "OCEANBASE_PASSWORD", "")
29
- monkeypatch.setattr(settings, "OCEANBASE_DB_NAME", "test")
23
+ monkeypatch.setattr(
24
+ "agentseek_api.core.database.SqliteCheckpointSaver", FakeCheckpointer
25
+ )
26
+ monkeypatch.setattr(settings, "METADATA_DB_URL", "sqlite+aiosqlite:///:memory:")
27
+ monkeypatch.setattr(settings, "METADATA_DB_BACKEND", "sqlite")
30
28
 
31
29
  manager = DatabaseManager()
32
30
  await manager.initialize()
33
31
  await manager.initialize()
34
32
 
35
33
  assert FakeCheckpointer.setup_calls == 1
36
- assert FakeCheckpointer.latest_connection_args is not None
37
- assert FakeCheckpointer.latest_connection_args["host"] == "127.0.0.1"
38
- assert FakeCheckpointer.latest_connection_args["db_name"] == "test"
34
+ assert FakeCheckpointer.latest_url == "sqlite+aiosqlite:///:memory:"
39
35
  assert isinstance(manager.get_store(), SqliteStore)
40
36
 
41
37
  await manager.close()
@@ -60,6 +56,24 @@ async def test_close_cleans_up_langgraph_checkpointer() -> None:
60
56
  engine.dispose.assert_awaited_once()
61
57
 
62
58
 
59
+ @pytest.mark.asyncio
60
+ async def test_close_cleans_up_run_checkpointer() -> None:
61
+ manager = DatabaseManager()
62
+ checkpointer = Mock()
63
+ close_thread_ids: list[int] = []
64
+ checkpointer.close.side_effect = lambda: close_thread_ids.append(
65
+ threading.get_ident()
66
+ )
67
+ manager._checkpointer = checkpointer
68
+ event_loop_thread_id = threading.get_ident()
69
+
70
+ await manager.close()
71
+ await manager.close()
72
+
73
+ checkpointer.close.assert_called_once()
74
+ assert close_thread_ids[0] != event_loop_thread_id
75
+
76
+
63
77
  @pytest.mark.asyncio
64
78
  async def test_close_continues_after_checkpointer_cleanup_fails(
65
79
  caplog: pytest.LogCaptureFixture,
@@ -0,0 +1,51 @@
1
+ import json
2
+ import sqlite3
3
+ from pathlib import Path
4
+
5
+ import pytest
6
+
7
+ from agentseek_api.core.sqlite_checkpointer import SqliteCheckpointSaver
8
+
9
+
10
+ def test_setup_is_idempotent_and_save_checkpoint_persists_json(tmp_path: Path) -> None:
11
+ database_path = tmp_path / "checkpoints.sqlite3"
12
+ saver = SqliteCheckpointSaver(url=f"sqlite+aiosqlite:///{database_path.as_posix()}")
13
+
14
+ try:
15
+ saver.setup()
16
+ saver.setup()
17
+ saver.save_checkpoint(
18
+ thread_id="thread-unit",
19
+ run_id="run-unit",
20
+ payload={"messages": ["hello"], "complete": True},
21
+ )
22
+
23
+ with sqlite3.connect(database_path) as connection:
24
+ row = connection.execute(
25
+ "SELECT thread_id, run_id, checkpoint FROM agentseek_checkpoints"
26
+ ).fetchone()
27
+ indexes = connection.execute(
28
+ "PRAGMA index_list(agentseek_checkpoints)"
29
+ ).fetchall()
30
+ finally:
31
+ saver.close()
32
+
33
+ assert row is not None
34
+ assert row[:2] == ("thread-unit", "run-unit")
35
+ assert json.loads(row[2]) == {"messages": ["hello"], "complete": True}
36
+ assert "idx_agentseek_checkpoints_thread_run" in {index[1] for index in indexes}
37
+
38
+
39
+ def test_rejects_non_sqlite_url() -> None:
40
+ with pytest.raises(ValueError, match="requires a SQLite URL"):
41
+ SqliteCheckpointSaver(url="mysql+aiomysql://root@localhost/agentseek")
42
+
43
+
44
+ def test_normalizes_windows_drive_path_without_opening_database() -> None:
45
+ saver = SqliteCheckpointSaver(url="sqlite+aiosqlite:///C:/agentseek/runtime.db")
46
+
47
+ try:
48
+ assert saver._engine.url.drivername == "sqlite"
49
+ assert saver._engine.url.database == "C:/agentseek/runtime.db"
50
+ finally:
51
+ saver.close()
@@ -29,7 +29,7 @@ wheels = [
29
29
 
30
30
  [[package]]
31
31
  name = "agentseek-api"
32
- version = "0.2.2"
32
+ version = "0.2.3"
33
33
  source = { editable = "." }
34
34
  dependencies = [
35
35
  { name = "aiomysql" },
@@ -1 +0,0 @@
1
- __version__ = "0.2.2"
File without changes
File without changes
File without changes
File without changes