synapsekit 0.6.3__tar.gz → 0.6.4__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 (204) hide show
  1. {synapsekit-0.6.3 → synapsekit-0.6.4}/PKG-INFO +10 -7
  2. {synapsekit-0.6.3 → synapsekit-0.6.4}/README.md +7 -6
  3. {synapsekit-0.6.3 → synapsekit-0.6.4}/pyproject.toml +3 -1
  4. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/__init__.py +15 -1
  5. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/__init__.py +6 -0
  6. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/__init__.py +6 -0
  7. synapsekit-0.6.4/src/synapsekit/agents/tools/shell.py +70 -0
  8. synapsekit-0.6.4/src/synapsekit/agents/tools/sql_schema.py +132 -0
  9. synapsekit-0.6.4/src/synapsekit/agents/tools/web_scraper.py +80 -0
  10. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/__init__.py +7 -1
  11. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/checkpointers/__init__.py +2 -0
  12. synapsekit-0.6.4/src/synapsekit/graph/checkpointers/json_file.py +40 -0
  13. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/compiled.py +26 -16
  14. synapsekit-0.6.4/src/synapsekit/llm/_filesystem_cache.py +56 -0
  15. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/base.py +5 -1
  16. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/loaders/__init__.py +4 -0
  17. synapsekit-0.6.4/src/synapsekit/loaders/docx.py +30 -0
  18. synapsekit-0.6.4/src/synapsekit/loaders/markdown.py +30 -0
  19. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/observability/tracer.py +19 -0
  20. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/__init__.py +2 -0
  21. synapsekit-0.6.4/src/synapsekit/retrieval/hyde.py +45 -0
  22. synapsekit-0.6.4/tests/agents/test_shell_tool.py +55 -0
  23. synapsekit-0.6.4/tests/agents/test_sql_schema.py +64 -0
  24. synapsekit-0.6.4/tests/agents/test_web_scraper.py +142 -0
  25. synapsekit-0.6.4/tests/graph/test_json_checkpointer.py +36 -0
  26. synapsekit-0.6.4/tests/llm/test_filesystem_cache.py +49 -0
  27. synapsekit-0.6.4/tests/loaders/test_docx_loader.py +47 -0
  28. synapsekit-0.6.4/tests/loaders/test_markdown_loader.py +52 -0
  29. synapsekit-0.6.4/tests/retrieval/test_hyde.py +61 -0
  30. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/test_v060_features.py +1 -1
  31. {synapsekit-0.6.3 → synapsekit-0.6.4}/uv.lock +19 -2
  32. {synapsekit-0.6.3 → synapsekit-0.6.4}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
  33. {synapsekit-0.6.3 → synapsekit-0.6.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  34. {synapsekit-0.6.3 → synapsekit-0.6.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  35. {synapsekit-0.6.3 → synapsekit-0.6.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  36. {synapsekit-0.6.3 → synapsekit-0.6.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  37. {synapsekit-0.6.3 → synapsekit-0.6.4}/.github/profile/README.md +0 -0
  38. {synapsekit-0.6.3 → synapsekit-0.6.4}/.github/workflows/ci.yml +0 -0
  39. {synapsekit-0.6.3 → synapsekit-0.6.4}/.gitignore +0 -0
  40. {synapsekit-0.6.3 → synapsekit-0.6.4}/.pre-commit-config.yaml +0 -0
  41. {synapsekit-0.6.3 → synapsekit-0.6.4}/CHANGELOG.md +0 -0
  42. {synapsekit-0.6.3 → synapsekit-0.6.4}/CODE_OF_CONDUCT.md +0 -0
  43. {synapsekit-0.6.3 → synapsekit-0.6.4}/CONTRIBUTING.md +0 -0
  44. {synapsekit-0.6.3 → synapsekit-0.6.4}/LICENSE +0 -0
  45. {synapsekit-0.6.3 → synapsekit-0.6.4}/Makefile +0 -0
  46. {synapsekit-0.6.3 → synapsekit-0.6.4}/SECURITY.md +0 -0
  47. {synapsekit-0.6.3 → synapsekit-0.6.4}/assets/banner.svg +0 -0
  48. {synapsekit-0.6.3 → synapsekit-0.6.4}/assets/favicon.svg +0 -0
  49. {synapsekit-0.6.3 → synapsekit-0.6.4}/assets/logo.svg +0 -0
  50. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/_compat.py +0 -0
  51. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/base.py +0 -0
  52. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/executor.py +0 -0
  53. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/function_calling.py +0 -0
  54. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/memory.py +0 -0
  55. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/react.py +0 -0
  56. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/registry.py +0 -0
  57. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tool_decorator.py +0 -0
  58. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/calculator.py +0 -0
  59. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/datetime_tool.py +0 -0
  60. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/file_list.py +0 -0
  61. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/file_read.py +0 -0
  62. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/file_write.py +0 -0
  63. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/http_request.py +0 -0
  64. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/human_input.py +0 -0
  65. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/json_query.py +0 -0
  66. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/python_repl.py +0 -0
  67. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/regex_tool.py +0 -0
  68. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/sentiment.py +0 -0
  69. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/sql_query.py +0 -0
  70. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/summarization.py +0 -0
  71. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/translation.py +0 -0
  72. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/web_search.py +0 -0
  73. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/agents/tools/wikipedia.py +0 -0
  74. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/embeddings/__init__.py +0 -0
  75. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/embeddings/backend.py +0 -0
  76. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/checkpointers/base.py +0 -0
  77. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/checkpointers/memory.py +0 -0
  78. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/checkpointers/sqlite.py +0 -0
  79. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/edge.py +0 -0
  80. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/errors.py +0 -0
  81. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/fan_out.py +0 -0
  82. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/graph.py +0 -0
  83. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/interrupt.py +0 -0
  84. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/mermaid.py +0 -0
  85. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/node.py +0 -0
  86. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/state.py +0 -0
  87. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/streaming.py +0 -0
  88. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/graph/subgraph.py +0 -0
  89. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/__init__.py +0 -0
  90. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/_cache.py +0 -0
  91. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/_rate_limit.py +0 -0
  92. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/_retry.py +0 -0
  93. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/_semantic_cache.py +0 -0
  94. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/_sqlite_cache.py +0 -0
  95. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/anthropic.py +0 -0
  96. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/azure_openai.py +0 -0
  97. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/bedrock.py +0 -0
  98. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/cohere.py +0 -0
  99. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/deepseek.py +0 -0
  100. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/fireworks.py +0 -0
  101. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/gemini.py +0 -0
  102. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/groq.py +0 -0
  103. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/mistral.py +0 -0
  104. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/ollama.py +0 -0
  105. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/openai.py +0 -0
  106. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/openrouter.py +0 -0
  107. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/structured.py +0 -0
  108. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/llm/together.py +0 -0
  109. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/loaders/base.py +0 -0
  110. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/loaders/csv.py +0 -0
  111. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/loaders/directory.py +0 -0
  112. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/loaders/excel.py +0 -0
  113. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/loaders/html.py +0 -0
  114. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/loaders/json_loader.py +0 -0
  115. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/loaders/pdf.py +0 -0
  116. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/loaders/pptx.py +0 -0
  117. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/loaders/text.py +0 -0
  118. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/loaders/web.py +0 -0
  119. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/memory/__init__.py +0 -0
  120. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/memory/conversation.py +0 -0
  121. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/memory/hybrid.py +0 -0
  122. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/memory/sqlite.py +0 -0
  123. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/memory/summary_buffer.py +0 -0
  124. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/observability/__init__.py +0 -0
  125. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/parsers/__init__.py +0 -0
  126. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/parsers/json_parser.py +0 -0
  127. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/parsers/list_parser.py +0 -0
  128. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/parsers/pydantic_parser.py +0 -0
  129. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/prompts/__init__.py +0 -0
  130. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/prompts/template.py +0 -0
  131. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/py.typed +0 -0
  132. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/rag/__init__.py +0 -0
  133. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/rag/facade.py +0 -0
  134. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/rag/pipeline.py +0 -0
  135. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/base.py +0 -0
  136. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/chroma.py +0 -0
  137. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/contextual.py +0 -0
  138. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/contextual_compression.py +0 -0
  139. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/crag.py +0 -0
  140. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/cross_encoder.py +0 -0
  141. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/ensemble.py +0 -0
  142. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/faiss.py +0 -0
  143. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/parent_document.py +0 -0
  144. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/pinecone.py +0 -0
  145. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/qdrant.py +0 -0
  146. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/query_decomposition.py +0 -0
  147. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/rag_fusion.py +0 -0
  148. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/retriever.py +0 -0
  149. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/self_query.py +0 -0
  150. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/sentence_window.py +0 -0
  151. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/retrieval/vectorstore.py +0 -0
  152. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/text_splitters/__init__.py +0 -0
  153. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/text_splitters/base.py +0 -0
  154. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/text_splitters/character.py +0 -0
  155. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/text_splitters/recursive.py +0 -0
  156. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/text_splitters/semantic.py +0 -0
  157. {synapsekit-0.6.3 → synapsekit-0.6.4}/src/synapsekit/text_splitters/token.py +0 -0
  158. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/__init__.py +0 -0
  159. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/agents/__init__.py +0 -0
  160. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/agents/test_executor.py +0 -0
  161. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/agents/test_function_calling.py +0 -0
  162. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/agents/test_memory.py +0 -0
  163. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/agents/test_react.py +0 -0
  164. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/agents/test_tool_decorator.py +0 -0
  165. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/agents/test_tools.py +0 -0
  166. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/conftest.py +0 -0
  167. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/graph/__init__.py +0 -0
  168. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/graph/test_build.py +0 -0
  169. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/graph/test_checkpointing.py +0 -0
  170. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/graph/test_cycles.py +0 -0
  171. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/graph/test_mermaid.py +0 -0
  172. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/graph/test_run.py +0 -0
  173. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/graph/test_state.py +0 -0
  174. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/graph/test_stream.py +0 -0
  175. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/llm/__init__.py +0 -0
  176. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/llm/test_cache_retry.py +0 -0
  177. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/llm/test_function_calling_providers.py +0 -0
  178. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/llm/test_llm.py +0 -0
  179. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/llm/test_providers.py +0 -0
  180. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/loaders/__init__.py +0 -0
  181. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/loaders/test_loaders.py +0 -0
  182. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/memory/__init__.py +0 -0
  183. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/memory/test_memory.py +0 -0
  184. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/observability/__init__.py +0 -0
  185. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/observability/test_tracer.py +0 -0
  186. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/parsers/__init__.py +0 -0
  187. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/parsers/test_parsers.py +0 -0
  188. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/prompts/__init__.py +0 -0
  189. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/prompts/test_prompts.py +0 -0
  190. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/rag/__init__.py +0 -0
  191. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/rag/test_facade.py +0 -0
  192. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/rag/test_pipeline.py +0 -0
  193. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/retrieval/__init__.py +0 -0
  194. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/retrieval/test_backends.py +0 -0
  195. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/retrieval/test_retriever.py +0 -0
  196. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/retrieval/test_vectorstore.py +0 -0
  197. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/test_v051_features.py +0 -0
  198. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/test_v052_features.py +0 -0
  199. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/test_v053_features.py +0 -0
  200. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/test_v061_features.py +0 -0
  201. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/test_v062_features.py +0 -0
  202. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/test_v063_features.py +0 -0
  203. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/text_splitters/__init__.py +0 -0
  204. {synapsekit-0.6.3 → synapsekit-0.6.4}/tests/text_splitters/test_splitters.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: synapsekit
3
- Version: 0.6.3
3
+ Version: 0.6.4
4
4
  Summary: Async-native Python framework for building production-grade LLM applications. Streaming-first, 2 dependencies, fully transparent.
5
5
  Project-URL: Homepage, https://github.com/SynapseKit/SynapseKit
6
6
  Project-URL: Repository, https://github.com/SynapseKit/SynapseKit
@@ -43,6 +43,8 @@ Provides-Extra: chroma
43
43
  Requires-Dist: chromadb>=0.5; extra == 'chroma'
44
44
  Provides-Extra: cohere
45
45
  Requires-Dist: cohere>=5.0; extra == 'cohere'
46
+ Provides-Extra: docx
47
+ Requires-Dist: python-docx>=1.0; extra == 'docx'
46
48
  Provides-Extra: excel
47
49
  Requires-Dist: openpyxl>=3.1; extra == 'excel'
48
50
  Provides-Extra: faiss
@@ -88,7 +90,8 @@ Description-Content-Type: text/markdown
88
90
  [![PyPI version](https://img.shields.io/pypi/v/synapsekit?color=0a7bbd&label=pypi&logo=pypi&logoColor=white)](https://pypi.org/project/synapsekit/)
89
91
  [![Python](https://img.shields.io/badge/python-3.14%2B-blue?logo=python&logoColor=white)](https://www.python.org/)
90
92
  [![License: MIT](https://img.shields.io/badge/license-MIT-22c55e)](LICENSE)
91
- [![Tests](https://img.shields.io/badge/tests-332%20passing-22c55e?logo=pytest&logoColor=white)]()
93
+ [![Tests](https://img.shields.io/badge/tests-540%20passing-22c55e?logo=pytest&logoColor=white)]()
94
+ [![Downloads](https://img.shields.io/pypi/dm/synapsekit?color=0a7bbd&logo=pypi&logoColor=white)](https://pypistats.org/packages/synapsekit)
92
95
  [![Docs](https://img.shields.io/badge/docs-online-0a7bbd?logo=readthedocs&logoColor=white)](https://synapsekit.github.io/synapsekit-docs/)
93
96
 
94
97
  **[Documentation](https://synapsekit.github.io/synapsekit-docs/) · [Quickstart](https://synapsekit.github.io/synapsekit-docs/docs/getting-started/quickstart) · [API Reference](https://synapsekit.github.io/synapsekit-docs/docs/api/llm) · [Changelog](CHANGELOG.md) · [Report a Bug](https://github.com/SynapseKit/SynapseKit/issues/new?template=bug_report.yml)**
@@ -121,7 +124,7 @@ Token-level streaming is the default,<br/>not an afterthought.<br/>Works across
121
124
  <tr>
122
125
  <td align="center" width="33%">
123
126
  <h3>🔌 One interface</h3>
124
- 9 LLM providers and 4 vector stores<br/>behind the same API.<br/>Swap without rewriting.
127
+ 13 LLM providers and 5 vector stores<br/>behind the same API.<br/>Swap without rewriting.
125
128
  </td>
126
129
  <td align="center" width="33%">
127
130
  <h3>🧩 Composable</h3>
@@ -164,7 +167,7 @@ Retrieval-augmented generation with streaming, BM25 reranking, conversation memo
164
167
  <td width="50%">
165
168
 
166
169
  **🤖 Agents**<br/>
167
- ReAct loop (any LLM) and native function calling (OpenAI / Anthropic). Built-in tools for calculator, Python REPL, file read, web search, and SQL. Fully extensible.
170
+ ReAct loop (any LLM) and native function calling (OpenAI / Anthropic / Gemini / Mistral). 16 built-in tools including calculator, Python REPL, web search, SQL, HTTP, summarization, sentiment analysis, and translation. Fully extensible.
168
171
 
169
172
  </td>
170
173
  </tr>
@@ -172,13 +175,13 @@ ReAct loop (any LLM) and native function calling (OpenAI / Anthropic). Built-in
172
175
  <td width="50%">
173
176
 
174
177
  **🔀 Graph Workflows**<br/>
175
- DAG-based async pipelines. Nodes run in waves — parallel nodes execute concurrently. Conditional routing, compile-time validation, cycle detection, and Mermaid export.
178
+ DAG-based async pipelines. Nodes run in waves — parallel nodes execute concurrently. Conditional routing, typed state with reducers, fan-out/fan-in, SSE streaming, event callbacks, human-in-the-loop, checkpointing, and Mermaid export.
176
179
 
177
180
  </td>
178
181
  <td width="50%">
179
182
 
180
183
  **🧠 LLM Providers**<br/>
181
- OpenAI, Anthropic, Ollama, Gemini, Cohere, Mistral, Bedrock — all behind one interface. Auto-detected from the model name. Swap without rewriting.
184
+ OpenAI, Anthropic, Ollama, Gemini, Cohere, Mistral, Bedrock, Azure OpenAI, Groq, DeepSeek, OpenRouter, Together, Fireworks — all behind one interface. Auto-detected from the model name. Swap without rewriting.
182
185
 
183
186
  </td>
184
187
  </tr>
@@ -238,7 +241,7 @@ Everything you need to get started and go deep is in the docs.
238
241
  | 🗂 [RAG](https://synapsekit.github.io/synapsekit-docs/docs/rag/pipeline) | Pipelines, loaders, retrieval, vector stores |
239
242
  | 🤖 [Agents](https://synapsekit.github.io/synapsekit-docs/docs/agents/overview) | ReAct, function calling, tools, executor |
240
243
  | 🔀 [Graph Workflows](https://synapsekit.github.io/synapsekit-docs/docs/graph/overview) | DAG pipelines, conditional routing, parallel execution |
241
- | 🧠 [LLM Providers](https://synapsekit.github.io/synapsekit-docs/docs/llms/overview) | All 9 providers with examples |
244
+ | 🧠 [LLM Providers](https://synapsekit.github.io/synapsekit-docs/docs/llms/overview) | All 13 providers with examples |
242
245
  | 📖 [API Reference](https://synapsekit.github.io/synapsekit-docs/docs/api/llm) | Full class and method reference |
243
246
 
244
247
  ---
@@ -7,7 +7,8 @@
7
7
  [![PyPI version](https://img.shields.io/pypi/v/synapsekit?color=0a7bbd&label=pypi&logo=pypi&logoColor=white)](https://pypi.org/project/synapsekit/)
8
8
  [![Python](https://img.shields.io/badge/python-3.14%2B-blue?logo=python&logoColor=white)](https://www.python.org/)
9
9
  [![License: MIT](https://img.shields.io/badge/license-MIT-22c55e)](LICENSE)
10
- [![Tests](https://img.shields.io/badge/tests-332%20passing-22c55e?logo=pytest&logoColor=white)]()
10
+ [![Tests](https://img.shields.io/badge/tests-540%20passing-22c55e?logo=pytest&logoColor=white)]()
11
+ [![Downloads](https://img.shields.io/pypi/dm/synapsekit?color=0a7bbd&logo=pypi&logoColor=white)](https://pypistats.org/packages/synapsekit)
11
12
  [![Docs](https://img.shields.io/badge/docs-online-0a7bbd?logo=readthedocs&logoColor=white)](https://synapsekit.github.io/synapsekit-docs/)
12
13
 
13
14
  **[Documentation](https://synapsekit.github.io/synapsekit-docs/) · [Quickstart](https://synapsekit.github.io/synapsekit-docs/docs/getting-started/quickstart) · [API Reference](https://synapsekit.github.io/synapsekit-docs/docs/api/llm) · [Changelog](CHANGELOG.md) · [Report a Bug](https://github.com/SynapseKit/SynapseKit/issues/new?template=bug_report.yml)**
@@ -40,7 +41,7 @@ Token-level streaming is the default,<br/>not an afterthought.<br/>Works across
40
41
  <tr>
41
42
  <td align="center" width="33%">
42
43
  <h3>🔌 One interface</h3>
43
- 9 LLM providers and 4 vector stores<br/>behind the same API.<br/>Swap without rewriting.
44
+ 13 LLM providers and 5 vector stores<br/>behind the same API.<br/>Swap without rewriting.
44
45
  </td>
45
46
  <td align="center" width="33%">
46
47
  <h3>🧩 Composable</h3>
@@ -83,7 +84,7 @@ Retrieval-augmented generation with streaming, BM25 reranking, conversation memo
83
84
  <td width="50%">
84
85
 
85
86
  **🤖 Agents**<br/>
86
- ReAct loop (any LLM) and native function calling (OpenAI / Anthropic). Built-in tools for calculator, Python REPL, file read, web search, and SQL. Fully extensible.
87
+ ReAct loop (any LLM) and native function calling (OpenAI / Anthropic / Gemini / Mistral). 16 built-in tools including calculator, Python REPL, web search, SQL, HTTP, summarization, sentiment analysis, and translation. Fully extensible.
87
88
 
88
89
  </td>
89
90
  </tr>
@@ -91,13 +92,13 @@ ReAct loop (any LLM) and native function calling (OpenAI / Anthropic). Built-in
91
92
  <td width="50%">
92
93
 
93
94
  **🔀 Graph Workflows**<br/>
94
- DAG-based async pipelines. Nodes run in waves — parallel nodes execute concurrently. Conditional routing, compile-time validation, cycle detection, and Mermaid export.
95
+ DAG-based async pipelines. Nodes run in waves — parallel nodes execute concurrently. Conditional routing, typed state with reducers, fan-out/fan-in, SSE streaming, event callbacks, human-in-the-loop, checkpointing, and Mermaid export.
95
96
 
96
97
  </td>
97
98
  <td width="50%">
98
99
 
99
100
  **🧠 LLM Providers**<br/>
100
- OpenAI, Anthropic, Ollama, Gemini, Cohere, Mistral, Bedrock — all behind one interface. Auto-detected from the model name. Swap without rewriting.
101
+ OpenAI, Anthropic, Ollama, Gemini, Cohere, Mistral, Bedrock, Azure OpenAI, Groq, DeepSeek, OpenRouter, Together, Fireworks — all behind one interface. Auto-detected from the model name. Swap without rewriting.
101
102
 
102
103
  </td>
103
104
  </tr>
@@ -157,7 +158,7 @@ Everything you need to get started and go deep is in the docs.
157
158
  | 🗂 [RAG](https://synapsekit.github.io/synapsekit-docs/docs/rag/pipeline) | Pipelines, loaders, retrieval, vector stores |
158
159
  | 🤖 [Agents](https://synapsekit.github.io/synapsekit-docs/docs/agents/overview) | ReAct, function calling, tools, executor |
159
160
  | 🔀 [Graph Workflows](https://synapsekit.github.io/synapsekit-docs/docs/graph/overview) | DAG pipelines, conditional routing, parallel execution |
160
- | 🧠 [LLM Providers](https://synapsekit.github.io/synapsekit-docs/docs/llms/overview) | All 9 providers with examples |
161
+ | 🧠 [LLM Providers](https://synapsekit.github.io/synapsekit-docs/docs/llms/overview) | All 13 providers with examples |
161
162
  | 📖 [API Reference](https://synapsekit.github.io/synapsekit-docs/docs/api/llm) | Full class and method reference |
162
163
 
163
164
  ---
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "synapsekit"
7
- version = "0.6.3"
7
+ version = "0.6.4"
8
8
  description = "Async-native Python framework for building production-grade LLM applications. Streaming-first, 2 dependencies, fully transparent."
9
9
  authors = [{ name = "Amit", email = "de.amit.nautiyal@gmail.com" }]
10
10
  license = { text = "MIT" }
@@ -48,6 +48,7 @@ bedrock = ["boto3>=1.34"]
48
48
  groq = ["groq>=0.9"]
49
49
  excel = ["openpyxl>=3.1"]
50
50
  pptx = ["python-pptx>=0.6"]
51
+ docx = ["python-docx>=1.0"]
51
52
  http = ["aiohttp>=3.9"]
52
53
  search = ["duckduckgo-search>=6.0"]
53
54
  all = [
@@ -157,6 +158,7 @@ google-generativeai = "google"
157
158
  beautifulsoup4 = "bs4"
158
159
  faiss-cpu = "faiss"
159
160
  python-pptx = "pptx"
161
+ python-docx = "docx"
160
162
 
161
163
  [tool.deptry.per_rule_ignores]
162
164
  DEP001 = ["sqlalchemy", "pydantic", "aiohttp"]
@@ -33,11 +33,14 @@ from .agents import (
33
33
  ReActAgent,
34
34
  RegexTool,
35
35
  SentimentAnalysisTool,
36
+ ShellTool,
36
37
  SQLQueryTool,
38
+ SQLSchemaInspectionTool,
37
39
  SummarizationTool,
38
40
  ToolRegistry,
39
41
  ToolResult,
40
42
  TranslationTool,
43
+ WebScraperTool,
41
44
  WebSearchTool,
42
45
  WikipediaTool,
43
46
  tool,
@@ -58,6 +61,7 @@ from .graph import (
58
61
  GraphState,
59
62
  InMemoryCheckpointer,
60
63
  InterruptState,
64
+ JSONFileCheckpointer,
61
65
  Node,
62
66
  NodeFn,
63
67
  SQLiteCheckpointer,
@@ -78,6 +82,7 @@ from .loaders.csv import CSVLoader
78
82
  from .loaders.directory import DirectoryLoader
79
83
  from .loaders.html import HTMLLoader
80
84
  from .loaders.json_loader import JSONLoader
85
+ from .loaders.markdown import MarkdownLoader
81
86
  from .loaders.pdf import PDFLoader
82
87
  from .loaders.text import StringLoader, TextLoader
83
88
  from .loaders.web import WebLoader
@@ -98,6 +103,7 @@ from .retrieval.contextual_compression import ContextualCompressionRetriever
98
103
  from .retrieval.crag import CRAGRetriever
99
104
  from .retrieval.cross_encoder import CrossEncoderReranker
100
105
  from .retrieval.ensemble import EnsembleRetriever
106
+ from .retrieval.hyde import HyDERetriever
101
107
  from .retrieval.parent_document import ParentDocumentRetriever
102
108
  from .retrieval.query_decomposition import QueryDecompositionRetriever
103
109
  from .retrieval.rag_fusion import RAGFusionRetriever
@@ -113,7 +119,7 @@ from .text_splitters import (
113
119
  TokenAwareSplitter,
114
120
  )
115
121
 
116
- __version__ = "0.6.3"
122
+ __version__ = "0.6.4"
117
123
  __all__ = [
118
124
  # Facade
119
125
  "RAG",
@@ -146,6 +152,7 @@ __all__ = [
146
152
  "CRAGRetriever",
147
153
  "CrossEncoderReranker",
148
154
  "EnsembleRetriever",
155
+ "HyDERetriever",
149
156
  "ParentDocumentRetriever",
150
157
  "QueryDecompositionRetriever",
151
158
  "SelfQueryRetriever",
@@ -165,6 +172,8 @@ __all__ = [
165
172
  "CSVLoader",
166
173
  "JSONLoader",
167
174
  "DirectoryLoader",
175
+ "DocxLoader",
176
+ "MarkdownLoader",
168
177
  "WebLoader",
169
178
  "ExcelLoader",
170
179
  "PowerPointLoader",
@@ -200,9 +209,12 @@ __all__ = [
200
209
  "PythonREPLTool",
201
210
  "RegexTool",
202
211
  "SentimentAnalysisTool",
212
+ "ShellTool",
203
213
  "SQLQueryTool",
214
+ "SQLSchemaInspectionTool",
204
215
  "SummarizationTool",
205
216
  "TranslationTool",
217
+ "WebScraperTool",
206
218
  "WebSearchTool",
207
219
  "WikipediaTool",
208
220
  # Text splitters
@@ -238,6 +250,7 @@ __all__ = [
238
250
  # Checkpointers
239
251
  "BaseCheckpointer",
240
252
  "InMemoryCheckpointer",
253
+ "JSONFileCheckpointer",
241
254
  "SQLiteCheckpointer",
242
255
  # Structured output
243
256
  "generate_structured",
@@ -258,6 +271,7 @@ _LAZY_IMPORTS = {
258
271
  "OpenRouterLLM": "llm.openrouter",
259
272
  "TogetherLLM": "llm.together",
260
273
  # Loaders
274
+ "DocxLoader": "loaders.docx",
261
275
  "ExcelLoader": "loaders.excel",
262
276
  "PowerPointLoader": "loaders.pptx",
263
277
  }
@@ -17,9 +17,12 @@ from .tools import (
17
17
  PythonREPLTool,
18
18
  RegexTool,
19
19
  SentimentAnalysisTool,
20
+ ShellTool,
20
21
  SQLQueryTool,
22
+ SQLSchemaInspectionTool,
21
23
  SummarizationTool,
22
24
  TranslationTool,
25
+ WebScraperTool,
23
26
  WebSearchTool,
24
27
  WikipediaTool,
25
28
  )
@@ -50,9 +53,12 @@ __all__ = [
50
53
  "PythonREPLTool",
51
54
  "RegexTool",
52
55
  "SentimentAnalysisTool",
56
+ "ShellTool",
53
57
  "SQLQueryTool",
58
+ "SQLSchemaInspectionTool",
54
59
  "SummarizationTool",
55
60
  "TranslationTool",
61
+ "WebScraperTool",
56
62
  "WebSearchTool",
57
63
  "WikipediaTool",
58
64
  ]
@@ -9,9 +9,12 @@ from .json_query import JSONQueryTool
9
9
  from .python_repl import PythonREPLTool
10
10
  from .regex_tool import RegexTool
11
11
  from .sentiment import SentimentAnalysisTool
12
+ from .shell import ShellTool
12
13
  from .sql_query import SQLQueryTool
14
+ from .sql_schema import SQLSchemaInspectionTool
13
15
  from .summarization import SummarizationTool
14
16
  from .translation import TranslationTool
17
+ from .web_scraper import WebScraperTool
15
18
  from .web_search import WebSearchTool
16
19
  from .wikipedia import WikipediaTool
17
20
 
@@ -27,9 +30,12 @@ __all__ = [
27
30
  "PythonREPLTool",
28
31
  "RegexTool",
29
32
  "SentimentAnalysisTool",
33
+ "ShellTool",
30
34
  "SQLQueryTool",
35
+ "SQLSchemaInspectionTool",
31
36
  "SummarizationTool",
32
37
  "TranslationTool",
38
+ "WebScraperTool",
33
39
  "WebSearchTool",
34
40
  "WikipediaTool",
35
41
  ]
@@ -0,0 +1,70 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from typing import Any
5
+
6
+ from ..base import BaseTool, ToolResult
7
+
8
+
9
+ class ShellTool(BaseTool):
10
+ """Execute shell commands and return their output."""
11
+
12
+ name = "shell"
13
+ description = (
14
+ "Execute a shell command and return stdout/stderr. "
15
+ "Input: a command string. "
16
+ "Optional: allowed_commands to restrict which commands can be run."
17
+ )
18
+ parameters = {
19
+ "type": "object",
20
+ "properties": {
21
+ "command": {
22
+ "type": "string",
23
+ "description": "The shell command to execute",
24
+ },
25
+ },
26
+ "required": ["command"],
27
+ }
28
+
29
+ def __init__(
30
+ self,
31
+ timeout: int = 30,
32
+ allowed_commands: list[str] | None = None,
33
+ ) -> None:
34
+ self.timeout = timeout
35
+ self.allowed_commands = allowed_commands
36
+
37
+ async def run(self, command: str = "", **kwargs: Any) -> ToolResult:
38
+ """Execute the shell command."""
39
+ target = command or kwargs.get("input", "")
40
+ if not target:
41
+ return ToolResult(output="", error="No command provided.")
42
+
43
+ if self.allowed_commands is not None:
44
+ base_cmd = target.split()[0]
45
+ if base_cmd not in self.allowed_commands:
46
+ return ToolResult(
47
+ output="",
48
+ error=f"Command {base_cmd!r} is not in the allowed list.",
49
+ )
50
+
51
+ try:
52
+ proc = await asyncio.create_subprocess_shell(
53
+ target,
54
+ stdout=asyncio.subprocess.PIPE,
55
+ stderr=asyncio.subprocess.PIPE,
56
+ )
57
+ stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=self.timeout)
58
+ output = stdout.decode() if stdout else ""
59
+ err = stderr.decode() if stderr else ""
60
+
61
+ if proc.returncode != 0:
62
+ return ToolResult(
63
+ output=output,
64
+ error=f"Exit code {proc.returncode}: {err}".strip(),
65
+ )
66
+ return ToolResult(output=output + err)
67
+ except TimeoutError:
68
+ return ToolResult(output="", error=f"Command timed out after {self.timeout}s.")
69
+ except Exception as e:
70
+ return ToolResult(output="", error=f"Shell error: {e}")
@@ -0,0 +1,132 @@
1
+ from __future__ import annotations
2
+
3
+ import sqlite3
4
+ from typing import Any
5
+
6
+ from ..base import BaseTool, ToolResult
7
+
8
+
9
+ class SQLSchemaInspectionTool(BaseTool):
10
+ """Inspect database schema: list tables and describe columns."""
11
+
12
+ name = "sql_schema"
13
+ description = (
14
+ "Inspect the schema of a SQL database. "
15
+ "Actions: 'list_tables' returns all table names, "
16
+ "'describe_table' returns column details for a given table. "
17
+ "Input: action (required), table_name (optional, for describe_table)."
18
+ )
19
+ parameters = {
20
+ "type": "object",
21
+ "properties": {
22
+ "action": {
23
+ "type": "string",
24
+ "description": "The action to perform: 'list_tables' or 'describe_table'",
25
+ "enum": ["list_tables", "describe_table"],
26
+ },
27
+ "table_name": {
28
+ "type": "string",
29
+ "description": "Table name (required for describe_table)",
30
+ },
31
+ },
32
+ "required": ["action"],
33
+ }
34
+
35
+ def __init__(self, connection_string: str) -> None:
36
+ self._connection_string = connection_string
37
+
38
+ def _is_sqlite(self) -> bool:
39
+ return self._connection_string.endswith(".db") or self._connection_string == ":memory:"
40
+
41
+ def _list_tables_sqlite(self) -> list[str]:
42
+ conn = sqlite3.connect(self._connection_string)
43
+ try:
44
+ rows = conn.execute(
45
+ "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
46
+ ).fetchall()
47
+ return [r[0] for r in rows]
48
+ finally:
49
+ conn.close()
50
+
51
+ def _describe_table_sqlite(self, table_name: str) -> list[dict[str, Any]]:
52
+ conn = sqlite3.connect(self._connection_string)
53
+ try:
54
+ rows = conn.execute(f"PRAGMA table_info({table_name})").fetchall()
55
+ return [
56
+ {
57
+ "name": r[1],
58
+ "type": r[2],
59
+ "nullable": not r[3],
60
+ "pk": bool(r[5]),
61
+ }
62
+ for r in rows
63
+ ]
64
+ finally:
65
+ conn.close()
66
+
67
+ def _list_tables_sqlalchemy(self) -> list[str]:
68
+ try:
69
+ from sqlalchemy import create_engine, inspect
70
+ except ImportError:
71
+ raise ImportError(
72
+ "sqlalchemy required for non-SQLite databases: pip install sqlalchemy"
73
+ ) from None
74
+ engine = create_engine(self._connection_string)
75
+ inspector = inspect(engine)
76
+ return sorted(inspector.get_table_names())
77
+
78
+ def _describe_table_sqlalchemy(self, table_name: str) -> list[dict[str, Any]]:
79
+ try:
80
+ from sqlalchemy import create_engine, inspect
81
+ except ImportError:
82
+ raise ImportError(
83
+ "sqlalchemy required for non-SQLite databases: pip install sqlalchemy"
84
+ ) from None
85
+ engine = create_engine(self._connection_string)
86
+ inspector = inspect(engine)
87
+ columns = inspector.get_columns(table_name)
88
+ pk_cols = {
89
+ c for c in (inspector.get_pk_constraint(table_name).get("constrained_columns") or [])
90
+ }
91
+ return [
92
+ {
93
+ "name": col["name"],
94
+ "type": str(col["type"]),
95
+ "nullable": col.get("nullable", True),
96
+ "pk": col["name"] in pk_cols,
97
+ }
98
+ for col in columns
99
+ ]
100
+
101
+ async def run(self, action: str = "", table_name: str = "", **kwargs: Any) -> ToolResult:
102
+ if not action:
103
+ return ToolResult(output="", error="action is required.")
104
+
105
+ try:
106
+ if action == "list_tables":
107
+ if self._is_sqlite():
108
+ tables = self._list_tables_sqlite()
109
+ else:
110
+ tables = self._list_tables_sqlalchemy()
111
+ return ToolResult(output=", ".join(tables) if tables else "(no tables)")
112
+
113
+ if action == "describe_table":
114
+ if not table_name:
115
+ return ToolResult(output="", error="table_name is required for describe_table.")
116
+ if self._is_sqlite():
117
+ cols = self._describe_table_sqlite(table_name)
118
+ else:
119
+ cols = self._describe_table_sqlalchemy(table_name)
120
+ if not cols:
121
+ return ToolResult(
122
+ output="", error=f"Table {table_name!r} not found or has no columns."
123
+ )
124
+ lines = [
125
+ f"{c['name']} ({c['type']}, nullable={c['nullable']}, pk={c['pk']})"
126
+ for c in cols
127
+ ]
128
+ return ToolResult(output="\n".join(lines))
129
+
130
+ return ToolResult(output="", error=f"Unknown action: {action!r}")
131
+ except Exception as e:
132
+ return ToolResult(output="", error=f"SQL schema error: {e}")
@@ -0,0 +1,80 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from ..base import BaseTool, ToolResult
6
+
7
+
8
+ class WebScraperTool(BaseTool):
9
+ """Fetch a URL and extract clean text content from the webpage."""
10
+
11
+ name = "web_scraper"
12
+ description = (
13
+ "Fetch a webpage URL and return clean text content. "
14
+ "Input: a URL string, e.g. 'https://example.com/article'. "
15
+ "Optional: css_selector to extract specific content. "
16
+ "Removes scripts, styles, nav, header, footer elements."
17
+ )
18
+ parameters = {
19
+ "type": "object",
20
+ "properties": {
21
+ "url": {
22
+ "type": "string",
23
+ "description": "The URL of the webpage to scrape",
24
+ },
25
+ "css_selector": {
26
+ "type": "string",
27
+ "description": "Optional CSS selector to extract specific content (e.g. 'article', '.content')",
28
+ },
29
+ },
30
+ "required": ["url"],
31
+ }
32
+
33
+ def __init__(self, timeout: int = 30):
34
+ self.timeout = timeout
35
+
36
+ def _clean_html(self, html: str, css_selector: str | None = None) -> str:
37
+ """Parse HTML and extract clean text."""
38
+ try:
39
+ from bs4 import BeautifulSoup
40
+ except ImportError:
41
+ raise ImportError("beautifulsoup4 required: pip install synapsekit[web]") from None
42
+
43
+ soup = BeautifulSoup(html, "html.parser")
44
+
45
+ for element in soup(["script", "style", "nav", "header", "footer", "aside"]):
46
+ element.decompose()
47
+
48
+ if css_selector:
49
+ elements = soup.select(css_selector)
50
+ if not elements:
51
+ return ""
52
+ content = "\n\n".join(elem.get_text(separator="\n", strip=True) for elem in elements)
53
+ else:
54
+ content = soup.get_text(separator="\n", strip=True)
55
+
56
+ return content
57
+
58
+ async def run(
59
+ self, url: str = "", css_selector: str | None = None, **kwargs: Any
60
+ ) -> ToolResult:
61
+ """Fetch URL and return clean text."""
62
+ try:
63
+ import httpx
64
+ except ImportError:
65
+ raise ImportError("httpx required: pip install synapsekit[web]") from None
66
+
67
+ target_url = url or kwargs.get("input", "")
68
+ if not target_url:
69
+ return ToolResult(output="", error="No URL provided.")
70
+
71
+ try:
72
+ async with httpx.AsyncClient() as client:
73
+ response = await client.get(target_url, timeout=self.timeout)
74
+ response.raise_for_status()
75
+ text = self._clean_html(response.text, css_selector)
76
+ return ToolResult(output=text)
77
+ except httpx.HTTPError as e:
78
+ return ToolResult(output="", error=f"HTTP error: {e}")
79
+ except Exception as e:
80
+ return ToolResult(output="", error=f"Scraping failed: {e}")
@@ -1,4 +1,9 @@
1
- from .checkpointers import BaseCheckpointer, InMemoryCheckpointer, SQLiteCheckpointer
1
+ from .checkpointers import (
2
+ BaseCheckpointer,
3
+ InMemoryCheckpointer,
4
+ JSONFileCheckpointer,
5
+ SQLiteCheckpointer,
6
+ )
2
7
  from .compiled import CompiledGraph
3
8
  from .edge import ConditionalEdge, ConditionFn, Edge
4
9
  from .errors import GraphConfigError, GraphRuntimeError
@@ -25,6 +30,7 @@ __all__ = [
25
30
  "GraphState",
26
31
  "InMemoryCheckpointer",
27
32
  "InterruptState",
33
+ "JSONFileCheckpointer",
28
34
  "Node",
29
35
  "NodeFn",
30
36
  "SQLiteCheckpointer",
@@ -1,9 +1,11 @@
1
1
  from .base import BaseCheckpointer
2
+ from .json_file import JSONFileCheckpointer
2
3
  from .memory import InMemoryCheckpointer
3
4
  from .sqlite import SQLiteCheckpointer
4
5
 
5
6
  __all__ = [
6
7
  "BaseCheckpointer",
7
8
  "InMemoryCheckpointer",
9
+ "JSONFileCheckpointer",
8
10
  "SQLiteCheckpointer",
9
11
  ]
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ from typing import Any
6
+
7
+ from .base import BaseCheckpointer
8
+
9
+
10
+ class JSONFileCheckpointer(BaseCheckpointer):
11
+ """File-based checkpointer using JSON files.
12
+
13
+ Each graph checkpoint is stored as a separate JSON file named
14
+ ``{graph_id}.json`` in the given directory.
15
+ """
16
+
17
+ def __init__(self, directory: str = ".") -> None:
18
+ self._directory = directory
19
+ os.makedirs(directory, exist_ok=True)
20
+
21
+ def _path_for(self, graph_id: str) -> str:
22
+ return os.path.join(self._directory, f"{graph_id}.json")
23
+
24
+ def save(self, graph_id: str, step: int, state: dict[str, Any]) -> None:
25
+ path = self._path_for(graph_id)
26
+ with open(path, "w", encoding="utf-8") as f:
27
+ json.dump({"step": step, "state": state}, f)
28
+
29
+ def load(self, graph_id: str) -> tuple[int, dict[str, Any]] | None:
30
+ path = self._path_for(graph_id)
31
+ if not os.path.exists(path):
32
+ return None
33
+ with open(path, encoding="utf-8") as f:
34
+ data = json.load(f)
35
+ return data["step"], data["state"]
36
+
37
+ def delete(self, graph_id: str) -> None:
38
+ path = self._path_for(graph_id)
39
+ if os.path.exists(path):
40
+ os.remove(path)