stackone-ai 2.9.1__tar.gz → 2.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. stackone_ai-2.10.0/.release-please-manifest.json +3 -0
  2. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/CHANGELOG.md +7 -0
  3. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/PKG-INFO +1 -1
  4. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/pyproject.toml +1 -1
  5. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/__init__.py +1 -1
  6. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/toolset.py +39 -19
  7. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/test_fetch_tools.py +18 -0
  8. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/test_tool_calling.py +27 -10
  9. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/uv.lock +1 -1
  10. stackone_ai-2.9.1/.release-please-manifest.json +0 -3
  11. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.claude/rules/development-workflow.md +0 -0
  12. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.claude/rules/examples-standards.md +0 -0
  13. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.claude/rules/git-workflow.md +0 -0
  14. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.claude/rules/nix-workflow.md +0 -0
  15. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.claude/rules/no-relative-imports.md +0 -0
  16. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.claude/rules/package-installation.md +0 -0
  17. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.claude/rules/release-please-standards.md +0 -0
  18. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.claude/rules/uv-scripts.md +0 -0
  19. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.cursor/rules/development-workflow.mdc +0 -0
  20. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.cursor/rules/examples-standards.mdc +0 -0
  21. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.cursor/rules/git-workflow.mdc +0 -0
  22. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.cursor/rules/no-relative-imports.mdc +0 -0
  23. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.cursor/rules/package-installation.mdc +0 -0
  24. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.cursor/rules/release-please-standards.mdc +0 -0
  25. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.cursor/rules/uv-scripts.mdc +0 -0
  26. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.env.example +0 -0
  27. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.envrc +0 -0
  28. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.github/actions/setup-nix/action.yaml +0 -0
  29. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.github/dependabot.yaml +0 -0
  30. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.github/workflows/ci.yaml +0 -0
  31. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.github/workflows/nix-flake-update.yaml +0 -0
  32. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.github/workflows/nix-flake.yaml +0 -0
  33. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.github/workflows/release.yaml +0 -0
  34. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.gitignore +0 -0
  35. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.gitleaks.toml +0 -0
  36. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.gitmodules +0 -0
  37. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.mcp.json +0 -0
  38. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/.release-please-config.json +0 -0
  39. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/CLAUDE.md +0 -0
  40. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/LICENSE +0 -0
  41. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/README.md +0 -0
  42. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/examples/auth_management.py +0 -0
  43. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/examples/crewai_integration.py +0 -0
  44. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/examples/langchain_integration.py +0 -0
  45. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/examples/langgraph_integration.py +0 -0
  46. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/examples/openai_integration.py +0 -0
  47. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/examples/pydantic_ai_integration.py +0 -0
  48. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/examples/search_tools.py +0 -0
  49. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/examples/test_examples.py +0 -0
  50. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/flake.lock +0 -0
  51. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/flake.nix +0 -0
  52. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/justfile +0 -0
  53. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/scripts/benchmark_search.py +0 -0
  54. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/constants.py +0 -0
  55. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/feedback/__init__.py +0 -0
  56. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/feedback/tool.py +0 -0
  57. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/integrations/__init__.py +0 -0
  58. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/integrations/langgraph.py +0 -0
  59. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/local_search.py +0 -0
  60. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/models.py +0 -0
  61. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/py.typed +0 -0
  62. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/semantic_search.py +0 -0
  63. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/utils/__init__.py +0 -0
  64. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/utils/normalize.py +0 -0
  65. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/stackone_ai/utils/tfidf_index.py +0 -0
  66. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/conftest.py +0 -0
  67. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/mocks/serve.ts +0 -0
  68. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/test_agent_tools.py +0 -0
  69. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/test_feedback.py +0 -0
  70. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/test_integrations_langgraph.py +0 -0
  71. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/test_integrations_pydantic_ai.py +0 -0
  72. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/test_local_search.py +0 -0
  73. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/test_models.py +0 -0
  74. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/test_semantic_search.py +0 -0
  75. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/test_tfidf_index.py +0 -0
  76. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/tests/test_toolset.py +0 -0
  77. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.claude/rules/development-workflow.md +0 -0
  78. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.claude/rules/file-operations.md +0 -0
  79. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.claude/rules/git-workflow.md +0 -0
  80. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.claude/rules/pnpm-usage.md +0 -0
  81. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.claude/rules/typescript-patterns.md +0 -0
  82. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.claude/rules/typescript-testing.md +0 -0
  83. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.claude/skills/orama-integration/SKILL.md +0 -0
  84. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.cursor/rules/development-workflow.mdc +0 -0
  85. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.cursor/rules/file-operations.mdc +0 -0
  86. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.cursor/rules/git-workflow.mdc +0 -0
  87. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.cursor/rules/orama-integration.mdc +0 -0
  88. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.cursor/rules/pnpm-usage.mdc +0 -0
  89. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.cursor/rules/typescript-patterns.mdc +0 -0
  90. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.cursor/rules/typescript-testing.mdc +0 -0
  91. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.envrc +0 -0
  92. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.github/CODEOWNERS +0 -0
  93. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.github/actions/setup-nix/action.yaml +0 -0
  94. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.github/workflows/check-title.yaml +0 -0
  95. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.github/workflows/ci.yaml +0 -0
  96. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.github/workflows/claude.yaml +0 -0
  97. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.github/workflows/dry-publish.yaml +0 -0
  98. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.github/workflows/nix-flake.yaml +0 -0
  99. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.github/workflows/release.yaml +0 -0
  100. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.gitignore +0 -0
  101. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.gitleaks.toml +0 -0
  102. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.mcp.json +0 -0
  103. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.oxfmtrc.jsonc +0 -0
  104. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/.oxlintrc.jsonc +0 -0
  105. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/AGENTS.md +0 -0
  106. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/CHANGELOG.md +0 -0
  107. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/CLAUDE.md +0 -0
  108. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/LICENSE +0 -0
  109. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/README.md +0 -0
  110. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/README.md +0 -0
  111. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/ai-sdk-integration.test.ts +0 -0
  112. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/ai-sdk-integration.ts +0 -0
  113. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/anthropic-integration.ts +0 -0
  114. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/claude-agent-sdk-integration.test.ts +0 -0
  115. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/claude-agent-sdk-integration.ts +0 -0
  116. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/fetch-tools-debug.ts +0 -0
  117. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/fetch-tools.test.ts +0 -0
  118. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/fetch-tools.ts +0 -0
  119. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/meta-tools.ts +0 -0
  120. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/openai-integration.test.ts +0 -0
  121. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/openai-integration.ts +0 -0
  122. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/openai-responses-integration.test.ts +0 -0
  123. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/openai-responses-integration.ts +0 -0
  124. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/package.json +0 -0
  125. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/tanstack-ai-integration.test.ts +0 -0
  126. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/tanstack-ai-integration.ts +0 -0
  127. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/examples/tsconfig.json +0 -0
  128. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/flake.lock +0 -0
  129. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/flake.nix +0 -0
  130. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/knip.config.ts +0 -0
  131. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/lefthook.yaml +0 -0
  132. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/mocks/handlers.example-api.ts +0 -0
  133. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/mocks/handlers.mcp.ts +0 -0
  134. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/mocks/handlers.openai.ts +0 -0
  135. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/mocks/handlers.stackone-ai.ts +0 -0
  136. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/mocks/handlers.stackone-rpc.ts +0 -0
  137. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/mocks/handlers.ts +0 -0
  138. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/mocks/handlers.utils.ts +0 -0
  139. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/mocks/mcp-server.ts +0 -0
  140. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/mocks/node.ts +0 -0
  141. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/package.json +0 -0
  142. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/pnpm-lock.yaml +0 -0
  143. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/pnpm-workspace.yaml +0 -0
  144. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/consts.ts +0 -0
  145. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/feedback.test.ts +0 -0
  146. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/feedback.ts +0 -0
  147. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/headers.test.ts +0 -0
  148. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/headers.ts +0 -0
  149. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/index.ts +0 -0
  150. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/mcp-client.test.ts +0 -0
  151. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/mcp-client.ts +0 -0
  152. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/requestBuilder.test.ts +0 -0
  153. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/requestBuilder.ts +0 -0
  154. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/rpc-client.test.ts +0 -0
  155. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/rpc-client.ts +0 -0
  156. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/schema.ts +0 -0
  157. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/tool.test-d.ts +0 -0
  158. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/tool.test.ts +0 -0
  159. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/tool.ts +0 -0
  160. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/toolsets.test-d.ts +0 -0
  161. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/toolsets.test.ts +0 -0
  162. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/toolsets.ts +0 -0
  163. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/types.ts +0 -0
  164. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/utils/array.test.ts +0 -0
  165. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/utils/array.ts +0 -0
  166. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/utils/error-stackone-api.test.ts +0 -0
  167. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/utils/error-stackone-api.ts +0 -0
  168. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/utils/error-stackone.test.ts +0 -0
  169. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/utils/error-stackone.ts +0 -0
  170. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/utils/tfidf-index.test.ts +0 -0
  171. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/utils/tfidf-index.ts +0 -0
  172. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/utils/try-import.test.ts +0 -0
  173. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/utils/try-import.ts +0 -0
  174. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/src/utils/type.ts +0 -0
  175. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/tsconfig.json +0 -0
  176. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/tsdown.config.ts +0 -0
  177. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/vitest.config.ts +0 -0
  178. {stackone_ai-2.9.1 → stackone_ai-2.10.0}/vendor/stackone-ai-node/vitest.setup.ts +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "2.10.0"
3
+ }
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.10.0](https://github.com/StackOneHQ/stackone-ai-python/compare/stackone-ai-v2.9.1...stackone-ai-v2.10.0) (2026-07-27)
4
+
5
+
6
+ ### Features
7
+
8
+ * **ENG-733:** support flat_prefixed MCP param style ([#192](https://github.com/StackOneHQ/stackone-ai-python/issues/192)) ([ff8fb9a](https://github.com/StackOneHQ/stackone-ai-python/commit/ff8fb9a41add55e9c31bd84e04447bb3685ab024))
9
+
3
10
  ## [2.9.1](https://github.com/StackOneHQ/stackone-ai-python/compare/stackone-ai-v2.9.0...stackone-ai-v2.9.1) (2026-06-03)
4
11
 
5
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stackone-ai
3
- Version: 2.9.1
3
+ Version: 2.10.0
4
4
  Summary: agents performing actions on your SaaS
5
5
  Author-email: StackOne <support@stackone.com>
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "stackone-ai"
3
- version = "2.9.1"
3
+ version = "2.10.0"
4
4
  description = "agents performing actions on your SaaS"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -23,4 +23,4 @@ __all__ = [
23
23
  "SemanticSearchResponse",
24
24
  "SemanticSearchError",
25
25
  ]
26
- __version__ = "2.9.1"
26
+ __version__ = "2.10.0"
@@ -7,6 +7,7 @@ import fnmatch
7
7
  import json
8
8
  import logging
9
9
  import os
10
+ import re
10
11
  import threading
11
12
  from collections.abc import Coroutine, Sequence
12
13
  from dataclasses import dataclass
@@ -92,6 +93,14 @@ _RPC_PARAMETER_LOCATIONS = {
92
93
  }
93
94
  _USER_AGENT = f"stackone-ai-python/{_SDK_VERSION}"
94
95
 
96
+ # Param-style pinned on the /mcp tool-listing URL. The MCP schema and the RPC-execution unwrap
97
+ # (_split_envelope_params) must agree on this, so it is pinned rather than following the server
98
+ # default — the server default is free to change without breaking the SDK.
99
+ _MCP_PARAM_STYLE = "flat_prefixed"
100
+
101
+ # Matches a flat_prefixed envelope key: `<location>_<field>` (e.g. `path_id`, `query_limit`).
102
+ _FLAT_ENVELOPE_KEY_PATTERN = re.compile(r"^(path|query|body|headers)_(.+)$")
103
+
95
104
 
96
105
  # --- Internal tool_search + tool_execute ---
97
106
 
@@ -444,24 +453,17 @@ class _StackOneRpcTool(StackOneTool):
444
453
  ) -> dict[str, Any]:
445
454
  parsed_arguments = self._parse_arguments(arguments)
446
455
 
447
- body_payload = self._extract_record(parsed_arguments.pop("body", None))
448
- headers_payload = self._extract_record(parsed_arguments.pop("headers", None))
449
- path_payload = self._extract_record(parsed_arguments.pop("path", None))
450
- query_payload = self._extract_record(parsed_arguments.pop("query", None))
451
-
452
- rpc_body: dict[str, Any] = dict(body_payload or {})
453
- for key, value in parsed_arguments.items():
454
- rpc_body[key] = value
456
+ envelope = self._split_envelope_params(parsed_arguments)
455
457
 
456
458
  payload: dict[str, Any] = {
457
459
  "action": self.name,
458
- "body": rpc_body,
459
- "headers": self._build_action_headers(headers_payload),
460
+ "body": envelope["body"],
461
+ "headers": self._build_action_headers(envelope["headers"] or None),
460
462
  }
461
- if path_payload:
462
- payload["path"] = path_payload
463
- if query_payload:
464
- payload["query"] = query_payload
463
+ if envelope["path"]:
464
+ payload["path"] = envelope["path"]
465
+ if envelope["query"]:
466
+ payload["query"] = envelope["query"]
465
467
 
466
468
  return super().execute(payload, options=options)
467
469
 
@@ -477,10 +479,28 @@ class _StackOneRpcTool(StackOneTool):
477
479
  return dict(parsed)
478
480
 
479
481
  @staticmethod
480
- def _extract_record(value: Any) -> dict[str, Any] | None:
481
- if isinstance(value, dict):
482
- return dict(value)
483
- return None
482
+ def _split_envelope_params(params: dict[str, Any]) -> dict[str, dict[str, Any]]:
483
+ """Split LLM-supplied tool arguments into the RPC envelope (path/query/headers/body).
484
+
485
+ Tools are listed with ``?param-style=flat_prefixed``, so keys arrive as
486
+ ``<location>_<field>`` (for example ``path_id``, ``query_limit``). The prefix carries
487
+ the parameter location, so the split needs no per-action schema. A bare dict-valued
488
+ ``path``/``query``/``headers``/``body`` key is still bucketed for clients holding a
489
+ cached nested schema, and any other key falls through to the body.
490
+ """
491
+ buckets: dict[str, dict[str, Any]] = {"path": {}, "query": {}, "headers": {}, "body": {}}
492
+ for key, value in params.items():
493
+ match = _FLAT_ENVELOPE_KEY_PATTERN.match(key)
494
+ if match:
495
+ location, field = match.group(1), match.group(2)
496
+ buckets[location].setdefault(field, value)
497
+ continue
498
+ if key in ("path", "query", "headers", "body") and isinstance(value, dict):
499
+ for field, field_value in value.items():
500
+ buckets[key].setdefault(field, field_value)
501
+ continue
502
+ buckets["body"][key] = value
503
+ return buckets
484
504
 
485
505
  def _build_action_headers(self, additional_headers: dict[str, Any] | None) -> dict[str, str]:
486
506
  headers: dict[str, str] = {}
@@ -1240,7 +1260,7 @@ class StackOneToolSet:
1240
1260
  if cached is not None:
1241
1261
  return cached
1242
1262
 
1243
- endpoint = f"{self.base_url.rstrip('/')}/mcp"
1263
+ endpoint = f"{self.base_url.rstrip('/')}/mcp?param-style={_MCP_PARAM_STYLE}"
1244
1264
 
1245
1265
  def _fetch_for_account(account: str | None) -> list[StackOneTool]:
1246
1266
  headers = self._build_mcp_headers(account)
@@ -662,3 +662,21 @@ class TestToolIndexCache:
662
662
  toolset.search_tools("bar")
663
663
 
664
664
  assert build_count["count"] == 2
665
+
666
+
667
+ class TestMcpParamStylePinning:
668
+ """The /mcp listing URL must pin param-style so the schema matches the RPC unwrap."""
669
+
670
+ def test_fetch_tools_pins_flat_prefixed_param_style(self, monkeypatch):
671
+ captured: dict[str, str] = {}
672
+
673
+ def fake_fetch(endpoint: str, headers: dict[str, str]) -> list[_McpToolDefinition]:
674
+ captured["endpoint"] = endpoint
675
+ return []
676
+
677
+ monkeypatch.setattr("stackone_ai.toolset._fetch_mcp_tools", fake_fetch)
678
+
679
+ toolset = StackOneToolSet(api_key="test-key", base_url="https://api.example.com")
680
+ toolset.fetch_tools(account_ids=["acc1"])
681
+
682
+ assert captured["endpoint"] == "https://api.example.com/mcp?param-style=flat_prefixed"
@@ -327,16 +327,33 @@ class TestStackOneRpcTool:
327
327
  with pytest.raises(ValueError, match="Tool arguments must be a JSON object"):
328
328
  rpc_tool._parse_arguments("[1, 2, 3]")
329
329
 
330
- def test_extract_record_with_dict(self, rpc_tool):
331
- """Test _extract_record with dict input"""
332
- result = rpc_tool._extract_record({"key": "value"})
333
- assert result == {"key": "value"}
334
-
335
- def test_extract_record_with_non_dict(self, rpc_tool):
336
- """Test _extract_record with non-dict input"""
337
- assert rpc_tool._extract_record("string") is None
338
- assert rpc_tool._extract_record(123) is None
339
- assert rpc_tool._extract_record(None) is None
330
+ def test_split_envelope_params_routes_flat_prefixed_keys(self, rpc_tool):
331
+ """flat_prefixed keys are bucketed into the RPC envelope by their location prefix"""
332
+ actual = rpc_tool._split_envelope_params(
333
+ {
334
+ "path_id": "123",
335
+ "query_limit": 10,
336
+ "headers_x-custom": "value",
337
+ "body_name": "test",
338
+ }
339
+ )
340
+ assert actual["path"] == {"id": "123"}
341
+ assert actual["query"] == {"limit": 10}
342
+ assert actual["headers"] == {"x-custom": "value"}
343
+ assert actual["body"] == {"name": "test"}
344
+
345
+ def test_split_envelope_params_buckets_nested_and_unprefixed_keys(self, rpc_tool):
346
+ """Bare nested envelopes are accepted and unprefixed keys fall through to the body"""
347
+ actual = rpc_tool._split_envelope_params(
348
+ {
349
+ "body": {"nested": "value"},
350
+ "path": {"id": "1"},
351
+ "extra": "x",
352
+ }
353
+ )
354
+ assert actual["path"] == {"id": "1"}
355
+ assert actual["query"] == {}
356
+ assert actual["body"] == {"nested": "value", "extra": "x"}
340
357
 
341
358
 
342
359
  class TestBinaryDownloadResponse:
@@ -4762,7 +4762,7 @@ wheels = [
4762
4762
 
4763
4763
  [[package]]
4764
4764
  name = "stackone-ai"
4765
- version = "2.9.1"
4765
+ version = "2.10.0"
4766
4766
  source = { editable = "." }
4767
4767
  dependencies = [
4768
4768
  { name = "bm25s" },
@@ -1,3 +0,0 @@
1
- {
2
- ".": "2.9.1"
3
- }
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