stackone-ai 0.3.2__tar.gz → 0.3.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 (88) hide show
  1. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.github/workflows/docs.yml +1 -1
  2. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.github/workflows/lint.yml +8 -3
  3. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.github/workflows/release.yml +1 -1
  4. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.github/workflows/test.yml +1 -1
  5. stackone_ai-0.3.4/.release-please-manifest.json +3 -0
  6. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/CHANGELOG.md +26 -0
  7. stackone_ai-0.3.4/PKG-INFO +439 -0
  8. stackone_ai-0.3.4/README.md +401 -0
  9. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/pyproject.toml +15 -2
  10. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/__init__.py +6 -2
  11. stackone_ai-0.3.4/stackone_ai/constants.py +11 -0
  12. stackone_ai-0.3.4/stackone_ai/feedback/__init__.py +5 -0
  13. stackone_ai-0.3.4/stackone_ai/feedback/tool.py +238 -0
  14. stackone_ai-0.3.4/stackone_ai/integrations/__init__.py +20 -0
  15. stackone_ai-0.3.4/stackone_ai/integrations/langgraph.py +94 -0
  16. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/meta_tools.py +95 -24
  17. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/models.py +107 -57
  18. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/server.py +3 -3
  19. stackone_ai-0.3.4/stackone_ai/toolset.py +547 -0
  20. stackone_ai-0.3.4/stackone_ai/utils/__init__.py +1 -0
  21. stackone_ai-0.3.4/stackone_ai/utils/tfidf_index.py +242 -0
  22. stackone_ai-0.3.4/tests/test_feedback.py +269 -0
  23. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/test_meta_tools.py +79 -0
  24. stackone_ai-0.3.4/tests/test_tfidf_index.py +299 -0
  25. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/test_tool_calling.py +0 -18
  26. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/test_toolset.py +44 -0
  27. stackone_ai-0.3.4/tests/test_toolset_mcp.py +272 -0
  28. stackone_ai-0.3.4/uv.lock +5984 -0
  29. stackone_ai-0.3.2/.release-please-manifest.json +0 -3
  30. stackone_ai-0.3.2/PKG-INFO +0 -213
  31. stackone_ai-0.3.2/README.md +0 -176
  32. stackone_ai-0.3.2/examples/langgraph_tool_node.py +0 -39
  33. stackone_ai-0.3.2/stackone_ai/constants.py +0 -5
  34. stackone_ai-0.3.2/stackone_ai/toolset.py +0 -178
  35. stackone_ai-0.3.2/uv.lock +0 -5156
  36. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.cursor/rules/cursor-rules-location.mdc +0 -0
  37. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.cursor/rules/examples-standards.mdc +0 -0
  38. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.cursor/rules/no-relative-imports.mdc +0 -0
  39. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.cursor/rules/package-installation.mdc +0 -0
  40. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.cursor/rules/release-please-standards.mdc +0 -0
  41. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.cursor/rules/uv-scripts.mdc +0 -0
  42. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.env_example +0 -0
  43. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.gitignore +0 -0
  44. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.mcp.json +0 -0
  45. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.pre-commit-config.yaml +0 -0
  46. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.release-please-config.json +0 -0
  47. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/.vscode/settings.json +0 -0
  48. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/CLAUDE.md +0 -0
  49. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/LICENSE +0 -0
  50. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/Makefile +0 -0
  51. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/examples/available_tools.py +0 -0
  52. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/examples/crewai_integration.py +0 -0
  53. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/examples/custom_base_url.py +0 -0
  54. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/examples/error_handling.py +0 -0
  55. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/examples/file_uploads.py +0 -0
  56. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/examples/index.py +0 -0
  57. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/examples/langchain_integration.py +0 -0
  58. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/examples/mcp_server.py +0 -0
  59. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/examples/meta_tools_example.py +0 -0
  60. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/examples/openai_integration.py +0 -0
  61. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/examples/stackone_account_ids.py +0 -0
  62. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/examples/test_examples.py +0 -0
  63. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/mkdocs.yml +0 -0
  64. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/py.typed +0 -0
  65. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/scripts/build_docs.py +0 -0
  66. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/scripts/pull_oas.py +0 -0
  67. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/scripts/update_version.py +0 -0
  68. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/oas/ats.json +0 -0
  69. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/oas/core.json +0 -0
  70. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/oas/crm.json +0 -0
  71. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/oas/documents.json +0 -0
  72. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/oas/hris.json +0 -0
  73. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/oas/iam.json +0 -0
  74. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/oas/lms.json +0 -0
  75. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/oas/marketing.json +0 -0
  76. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/py.typed +0 -0
  77. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/specs/loader.py +0 -0
  78. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/stackone_ai/specs/parser.py +0 -0
  79. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/snapshots/test_parser/test_parse_all_oas_specs/ats_tools.json +0 -0
  80. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/snapshots/test_parser/test_parse_all_oas_specs/core_tools.json +0 -0
  81. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/snapshots/test_parser/test_parse_all_oas_specs/crm_tools.json +0 -0
  82. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/snapshots/test_parser/test_parse_all_oas_specs/documents_tools.json +0 -0
  83. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/snapshots/test_parser/test_parse_all_oas_specs/hris_tools.json +0 -0
  84. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/snapshots/test_parser/test_parse_all_oas_specs/iam_tools.json +0 -0
  85. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/snapshots/test_parser/test_parse_all_oas_specs/lms_tools.json +0 -0
  86. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/snapshots/test_parser/test_parse_all_oas_specs/marketing_tools.json +0 -0
  87. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/test_models.py +0 -0
  88. {stackone_ai-0.3.2 → stackone_ai-0.3.4}/tests/test_parser.py +0 -0
@@ -15,7 +15,7 @@ jobs:
15
15
  - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
16
16
 
17
17
  - name: Install uv
18
- uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
18
+ uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1
19
19
  with:
20
20
  python-version: "3.11"
21
21
  enable-cache: true
@@ -20,7 +20,7 @@ jobs:
20
20
  - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
21
21
 
22
22
  - name: Install uv
23
- uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
23
+ uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1
24
24
  with:
25
25
  python-version: ${{ matrix.python-version }}
26
26
  enable-cache: true
@@ -29,9 +29,14 @@ jobs:
29
29
  run: uv sync ${{ matrix.sync-extras }}
30
30
 
31
31
  - name: Run Ruff
32
- uses: astral-sh/ruff-action@0c50076f12c38c3d0115b7b519b54a91cb9cf0ad # v3.5.0
32
+ uses: astral-sh/ruff-action@57714a7c8a2e59f32539362ba31877a1957dded1 # v3.5.1
33
33
  with:
34
34
  args: check .
35
35
 
36
36
  - name: Run Mypy
37
- run: uv run mypy stackone_ai --exclude stackone_ai/server.py
37
+ run: |
38
+ if [[ "${{ matrix.python-version }}" == "3.9" ]]; then
39
+ uv run mypy stackone_ai --exclude stackone_ai/server.py
40
+ else
41
+ uv run mypy stackone_ai
42
+ fi
@@ -25,7 +25,7 @@ jobs:
25
25
 
26
26
  - name: Install uv
27
27
  if: ${{ steps.release.outputs.release_created }}
28
- uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
28
+ uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1
29
29
  with:
30
30
  python-version: "3.11"
31
31
  enable-cache: true
@@ -25,7 +25,7 @@ jobs:
25
25
  - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
26
26
 
27
27
  - name: Install uv
28
- uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
28
+ uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1
29
29
  with:
30
30
  python-version: ${{ matrix.python-version }}
31
31
  enable-cache: true
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.3.4"
3
+ }
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.4](https://github.com/StackOneHQ/stackone-ai-python/compare/stackone-ai-v0.3.3...stackone-ai-v0.3.4) (2025-11-12)
4
+
5
+
6
+ ### Features
7
+
8
+ * Add MCP-backed dynamic tool fetching to Python SDK ([#39](https://github.com/StackOneHQ/stackone-ai-python/issues/39)) ([d72ca80](https://github.com/StackOneHQ/stackone-ai-python/commit/d72ca808233600bd32374c7e2028232eb54167de))
9
+ * add provider/action filtering and hybrid BM25 + TF-IDF search ([#37](https://github.com/StackOneHQ/stackone-ai-python/issues/37)) ([a1c688b](https://github.com/StackOneHQ/stackone-ai-python/commit/a1c688b4efaef9257ecec9827baa7ef90529b9f7))
10
+
11
+ ## [0.3.3](https://github.com/StackOneHQ/stackone-ai-python/compare/stackone-ai-v0.3.2...stackone-ai-v0.3.3) (2025-10-17)
12
+
13
+
14
+ ### Features
15
+
16
+ * feedback tool ([#36](https://github.com/StackOneHQ/stackone-ai-python/issues/36)) ([9179918](https://github.com/StackOneHQ/stackone-ai-python/commit/9179918104c0ec4cfe0488713ca325f0e8e7c6f1))
17
+ * LangGraph integration helpers and example ([#33](https://github.com/StackOneHQ/stackone-ai-python/issues/33)) ([983e2f7](https://github.com/StackOneHQ/stackone-ai-python/commit/983e2f7e6551e3722f235ea534ae61f24644350e))
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * remove async method ([#31](https://github.com/StackOneHQ/stackone-ai-python/issues/31)) ([370699e](https://github.com/StackOneHQ/stackone-ai-python/commit/370699e390e4a46d8b4ae664fed8f5de6395eb9d))
23
+
24
+
25
+ ### Documentation
26
+
27
+ * use uv for installing ([#30](https://github.com/StackOneHQ/stackone-ai-python/issues/30)) ([3c5d8fb](https://github.com/StackOneHQ/stackone-ai-python/commit/3c5d8fb54e61f8f730098e97f8bf2dfc78cf3bec))
28
+
3
29
  ## [0.3.2](https://github.com/StackOneHQ/stackone-ai-python/compare/stackone-ai-v0.3.1...stackone-ai-v0.3.2) (2025-08-26)
4
30
 
5
31
 
@@ -0,0 +1,439 @@
1
+ Metadata-Version: 2.4
2
+ Name: stackone-ai
3
+ Version: 0.3.4
4
+ Summary: agents performing actions on your SaaS
5
+ Author-email: StackOne <support@stackone.com>
6
+ License-File: LICENSE
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Requires-Python: >=3.9
18
+ Requires-Dist: bm25s>=0.2.2
19
+ Requires-Dist: eval-type-backport; python_version < '3.10'
20
+ Requires-Dist: langchain-core>=0.1.0
21
+ Requires-Dist: numpy>=1.24.0
22
+ Requires-Dist: pydantic>=2.10.6
23
+ Requires-Dist: requests>=2.32.3
24
+ Requires-Dist: typing-extensions>=4.0.0
25
+ Provides-Extra: docs
26
+ Requires-Dist: mkdocs-terminal>=4.7.0; extra == 'docs'
27
+ Requires-Dist: pygments>=2.12; extra == 'docs'
28
+ Requires-Dist: pymdown-extensions; extra == 'docs'
29
+ Provides-Extra: examples
30
+ Requires-Dist: crewai>=0.102.0; (python_version >= '3.10') and extra == 'examples'
31
+ Requires-Dist: langchain-openai>=0.3.6; extra == 'examples'
32
+ Requires-Dist: langgraph>=0.2.0; extra == 'examples'
33
+ Requires-Dist: openai>=1.63.2; extra == 'examples'
34
+ Requires-Dist: python-dotenv>=1.0.1; extra == 'examples'
35
+ Provides-Extra: mcp
36
+ Requires-Dist: mcp[cli]>=1.3.0; (python_version >= '3.10') and extra == 'mcp'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # StackOne AI SDK
40
+
41
+ [![PyPI version](https://badge.fury.io/py/stackone-ai.svg)](https://badge.fury.io/py/stackone-ai)
42
+ [![GitHub release (latest by date)](https://img.shields.io/github/v/release/StackOneHQ/stackone-ai-python)](https://github.com/StackOneHQ/stackone-ai-python/releases)
43
+
44
+ StackOne AI provides a unified interface for accessing various SaaS tools through AI-friendly APIs.
45
+
46
+ ## Features
47
+
48
+ - Unified interface for multiple SaaS tools
49
+ - AI-friendly tool descriptions and parameters
50
+ - **Tool Calling**: Direct method calling with `tool.call()` for intuitive usage
51
+ - **Advanced Tool Filtering**:
52
+ - Glob pattern filtering with patterns like `"hris_*"` and exclusions `"!hris_delete_*"`
53
+ - Provider and action filtering with `fetch_tools()`
54
+ - Multi-account support
55
+ - Dynamic MCP-backed discovery via `fetch_tools()` so you can pull the latest tools at runtime (accounts, providers, or globbed actions)
56
+ - **Meta Tools** (Beta): Dynamic tool discovery and execution based on natural language queries using hybrid BM25 + TF-IDF search
57
+ - Integration with popular AI frameworks:
58
+ - OpenAI Functions
59
+ - LangChain Tools
60
+ - CrewAI Tools
61
+ - LangGraph Tool Node
62
+
63
+ ## Requirements
64
+
65
+ - Python 3.9+ (core SDK functionality)
66
+ - Python 3.10+ (for MCP server and CrewAI examples)
67
+
68
+ ## Installation
69
+
70
+ ### Basic Installation
71
+
72
+ ```bash
73
+ pip install stackone-ai
74
+
75
+ # Or with uv
76
+ uv add stackone-ai
77
+ ```
78
+
79
+ ### Optional Features
80
+
81
+ ```bash
82
+ # Install with MCP server support (requires Python 3.10+)
83
+ uv add 'stackone-ai[mcp]'
84
+ # or
85
+ pip install 'stackone-ai[mcp]'
86
+
87
+ # Install with CrewAI examples (requires Python 3.10+)
88
+ uv add 'stackone-ai[examples]'
89
+ # or
90
+ pip install 'stackone-ai[examples]'
91
+
92
+ # Install everything
93
+ uv add 'stackone-ai[mcp,examples]'
94
+ # or
95
+ pip install 'stackone-ai[mcp,examples]'
96
+ ```
97
+
98
+ ## Quick Start
99
+
100
+ ```python
101
+ from stackone_ai import StackOneToolSet
102
+
103
+ # Initialize with API key
104
+ toolset = StackOneToolSet() # Uses STACKONE_API_KEY env var
105
+ # Or explicitly: toolset = StackOneToolSet(api_key="your-api-key")
106
+
107
+ # Get HRIS-related tools with glob patterns
108
+ tools = toolset.get_tools("hris_*", account_id="your-account-id")
109
+ # Exclude certain tools with negative patterns
110
+ tools = toolset.get_tools(["hris_*", "!hris_delete_*"])
111
+
112
+ # Use a specific tool with the new call method
113
+ employee_tool = tools.get_tool("hris_get_employee")
114
+ # Call with keyword arguments
115
+ employee = employee_tool.call(id="employee-id")
116
+ # Or with traditional execute method
117
+ employee = employee_tool.execute({"id": "employee-id"})
118
+ ```
119
+
120
+ ## Tool Filtering
121
+
122
+ StackOne AI SDK provides powerful filtering capabilities to help you select the exact tools you need.
123
+
124
+ ### Filtering with `get_tools()`
125
+
126
+ Use glob patterns to filter tools by name:
127
+
128
+ ```python
129
+ from stackone_ai import StackOneToolSet
130
+
131
+ toolset = StackOneToolSet()
132
+
133
+ # Get all HRIS tools
134
+ tools = toolset.get_tools("hris_*", account_id="your-account-id")
135
+
136
+ # Get multiple categories
137
+ tools = toolset.get_tools(["hris_*", "ats_*"])
138
+
139
+ # Exclude specific tools with negative patterns
140
+ tools = toolset.get_tools(["hris_*", "!hris_delete_*"])
141
+ ```
142
+
143
+ ### Advanced Filtering with `fetch_tools()`
144
+
145
+ The `fetch_tools()` method provides advanced filtering by providers, actions, and account IDs:
146
+
147
+ > `fetch_tools()` uses the StackOne MCP server under the hood. Install the optional extra (`pip install 'stackone-ai[mcp]'`) on Python 3.10+ to enable dynamic discovery.
148
+
149
+ ```python
150
+ from stackone_ai import StackOneToolSet
151
+
152
+ toolset = StackOneToolSet()
153
+
154
+ # Filter by account IDs
155
+ tools = toolset.fetch_tools(account_ids=["acc-123", "acc-456"])
156
+
157
+ # Filter by providers (case-insensitive)
158
+ tools = toolset.fetch_tools(providers=["hibob", "bamboohr"])
159
+
160
+ # Filter by action patterns with glob support
161
+ tools = toolset.fetch_tools(actions=["*_list_employees"])
162
+
163
+ # Combine multiple filters
164
+ tools = toolset.fetch_tools(
165
+ account_ids=["acc-123"],
166
+ providers=["hibob"],
167
+ actions=["*_list_*"]
168
+ )
169
+
170
+ # Use set_accounts() for chaining
171
+ toolset.set_accounts(["acc-123", "acc-456"])
172
+ tools = toolset.fetch_tools(providers=["hibob"])
173
+ ```
174
+
175
+ **Filtering Options:**
176
+
177
+ - **`account_ids`**: Filter tools by account IDs. Tools will be loaded for each specified account.
178
+ - **`providers`**: Filter by provider names (e.g., `["hibob", "bamboohr"]`). Case-insensitive matching.
179
+ - **`actions`**: Filter by action patterns with glob support:
180
+ - Exact match: `["hris_list_employees"]`
181
+ - Glob pattern: `["*_list_employees"]` matches all tools ending with `_list_employees`
182
+ - Provider prefix: `["hris_*"]` matches all HRIS tools
183
+
184
+ ## Implicit Feedback (Beta)
185
+
186
+ The Python SDK can emit implicit behavioural feedback to LangSmith so you can triage low-quality tool results without manually tagging runs.
187
+
188
+ ### Automatic configuration
189
+
190
+ Set `LANGSMITH_API_KEY` in your environment and the SDK will initialise the implicit feedback manager on first tool execution. You can optionally fine-tune behaviour with:
191
+
192
+ - `STACKONE_IMPLICIT_FEEDBACK_ENABLED` (`true`/`false`, defaults to `true` when an API key is present)
193
+ - `STACKONE_IMPLICIT_FEEDBACK_PROJECT` to pin a LangSmith project name
194
+ - `STACKONE_IMPLICIT_FEEDBACK_TAGS` with a comma-separated list of tags applied to every run
195
+
196
+ ### Manual configuration
197
+
198
+ If you want custom session or user resolvers, call `configure_implicit_feedback` during start-up:
199
+
200
+ ```python
201
+ from stackone_ai import configure_implicit_feedback
202
+
203
+ configure_implicit_feedback(
204
+ api_key="/path/to/langsmith.key",
205
+ project_name="stackone-agents",
206
+ default_tags=["python-sdk"],
207
+ )
208
+ ```
209
+
210
+ Providing your own `session_resolver`/`user_resolver` callbacks lets you derive identifiers from the request context before events are sent to LangSmith.
211
+
212
+ ### Attaching session context to tool calls
213
+
214
+ Both `tool.execute` and `tool.call` accept an `options` keyword that is excluded from the API request but forwarded to the feedback manager:
215
+
216
+ ```python
217
+ tool.execute(
218
+ {"id": "employee-id"},
219
+ options={
220
+ "feedback_session_id": "chat-42",
221
+ "feedback_user_id": "user-123",
222
+ "feedback_metadata": {"conversation_id": "abc"},
223
+ },
224
+ )
225
+ ```
226
+
227
+ When two calls for the same session happen within a few seconds, the SDK emits a `refinement_needed` event, and you can inspect suitability scores directly in LangSmith.
228
+
229
+ ## Integration Examples
230
+
231
+ <details>
232
+ <summary>LangChain Integration</summary>
233
+
234
+ StackOne tools work seamlessly with LangChain, enabling powerful AI agent workflows:
235
+
236
+ ```python
237
+ from langchain_openai import ChatOpenAI
238
+ from stackone_ai import StackOneToolSet
239
+
240
+ # Initialize StackOne tools
241
+ toolset = StackOneToolSet()
242
+ tools = toolset.get_tools("hris_*", account_id="your-account-id")
243
+
244
+ # Convert to LangChain format
245
+ langchain_tools = tools.to_langchain()
246
+
247
+ # Use with LangChain models
248
+ model = ChatOpenAI(model="gpt-4o-mini")
249
+ model_with_tools = model.bind_tools(langchain_tools)
250
+
251
+ # Execute AI-driven tool calls
252
+ response = model_with_tools.invoke("Get employee information for ID: emp123")
253
+
254
+ # Handle tool calls
255
+ for tool_call in response.tool_calls:
256
+ tool = tools.get_tool(tool_call["name"])
257
+ if tool:
258
+ result = tool.execute(tool_call["args"])
259
+ print(f"Result: {result}")
260
+ ```
261
+
262
+ </details>
263
+
264
+ <details>
265
+ <summary>LangGraph Integration</summary>
266
+
267
+ StackOne tools convert to LangChain tools, which LangGraph consumes via its prebuilt nodes:
268
+
269
+ Prerequisites:
270
+
271
+ ```bash
272
+ pip install langgraph langchain-openai
273
+ ```
274
+
275
+ ```python
276
+ from langchain_openai import ChatOpenAI
277
+ from typing import Annotated
278
+ from typing_extensions import TypedDict
279
+
280
+ from langgraph.graph import StateGraph, START, END
281
+ from langgraph.graph.message import add_messages
282
+ from langgraph.prebuilt import tools_condition
283
+
284
+ from stackone_ai import StackOneToolSet
285
+ from stackone_ai.integrations.langgraph import to_tool_node, bind_model_with_tools
286
+
287
+ # Prepare tools
288
+ toolset = StackOneToolSet()
289
+ tools = toolset.get_tools("hris_*", account_id="your-account-id")
290
+ langchain_tools = tools.to_langchain()
291
+
292
+ class State(TypedDict):
293
+ messages: Annotated[list, add_messages]
294
+
295
+ # Build a small agent loop: LLM -> maybe tools -> back to LLM
296
+ graph = StateGraph(State)
297
+ graph.add_node("tools", to_tool_node(langchain_tools))
298
+
299
+ def call_llm(state: dict):
300
+ llm = ChatOpenAI(model="gpt-4o-mini")
301
+ llm = bind_model_with_tools(llm, langchain_tools)
302
+ resp = llm.invoke(state["messages"]) # returns AIMessage with optional tool_calls
303
+ return {"messages": state["messages"] + [resp]}
304
+
305
+ graph.add_node("llm", call_llm)
306
+ graph.add_edge(START, "llm")
307
+ graph.add_conditional_edges("llm", tools_condition)
308
+ graph.add_edge("tools", "llm")
309
+ app = graph.compile()
310
+
311
+ _ = app.invoke({"messages": [("user", "Get employee with id emp123") ]})
312
+ ```
313
+
314
+ </details>
315
+
316
+ <details>
317
+ <summary>CrewAI Integration (Python 3.10+)</summary>
318
+
319
+ CrewAI uses LangChain tools natively, making integration seamless:
320
+
321
+ > **Note**: CrewAI requires Python 3.10+. Install with `pip install 'stackone-ai[examples]'`
322
+
323
+ ```python
324
+ from crewai import Agent, Crew, Task
325
+ from stackone_ai import StackOneToolSet
326
+
327
+ # Get tools and convert to LangChain format
328
+ toolset = StackOneToolSet()
329
+ tools = toolset.get_tools("hris_*", account_id="your-account-id")
330
+ langchain_tools = tools.to_langchain()
331
+
332
+ # Create CrewAI agent with StackOne tools
333
+ agent = Agent(
334
+ role="HR Manager",
335
+ goal="Analyze employee data and generate insights",
336
+ backstory="Expert in HR analytics and employee management",
337
+ tools=langchain_tools,
338
+ llm="gpt-4o-mini"
339
+ )
340
+
341
+ # Define task and execute
342
+ task = Task(
343
+ description="Find all employees in the engineering department",
344
+ agent=agent,
345
+ expected_output="List of engineering employees with their details"
346
+ )
347
+
348
+ crew = Crew(agents=[agent], tasks=[task])
349
+ result = crew.kickoff()
350
+ ```
351
+
352
+ </details>
353
+
354
+ ## Feedback Collection
355
+
356
+ The SDK includes a feedback collection tool (`meta_collect_tool_feedback`) that allows users to submit feedback about their experience with StackOne tools. This tool is automatically included in the toolset and is designed to be invoked by AI agents after user permission.
357
+
358
+ ```python
359
+ from stackone_ai import StackOneToolSet
360
+
361
+ toolset = StackOneToolSet()
362
+
363
+ # Get the feedback tool (included with "meta_*" pattern or all tools)
364
+ tools = toolset.get_tools("meta_*")
365
+ feedback_tool = tools.get_tool("meta_collect_tool_feedback")
366
+
367
+ # Submit feedback (typically invoked by AI after user consent)
368
+ result = feedback_tool.call(
369
+ feedback="The HRIS tools are working great! Very fast response times.",
370
+ account_id="acc_123456",
371
+ tool_names=["hris_list_employees", "hris_get_employee"]
372
+ )
373
+ ```
374
+
375
+ **Important**: The AI agent should always ask for user permission before submitting feedback:
376
+ - "Are you ok with sending feedback to StackOne? The LLM will take care of sending it."
377
+ - Only call the tool after the user explicitly agrees.
378
+
379
+ ## Meta Tools (Beta)
380
+
381
+ Meta tools enable dynamic tool discovery and execution without hardcoding tool names. The search functionality uses **hybrid BM25 + TF-IDF search** for improved accuracy (10.8% improvement over BM25 alone).
382
+
383
+ ### Basic Usage
384
+
385
+ ```python
386
+ # Get meta tools for dynamic discovery
387
+ tools = toolset.get_tools("hris_*")
388
+ meta_tools = tools.meta_tools()
389
+
390
+ # Search for relevant tools using natural language
391
+ filter_tool = meta_tools.get_tool("meta_search_tools")
392
+ results = filter_tool.call(query="manage employees", limit=5)
393
+
394
+ # Execute discovered tools dynamically
395
+ execute_tool = meta_tools.get_tool("meta_execute_tool")
396
+ result = execute_tool.call(toolName="hris_list_employees", params={"limit": 10})
397
+ ```
398
+
399
+ ### Hybrid Search Configuration
400
+
401
+ The hybrid search combines BM25 and TF-IDF algorithms. You can customize the weighting:
402
+
403
+ ```python
404
+ # Default: hybrid_alpha=0.2 (more weight to BM25, proven optimal in testing)
405
+ meta_tools = tools.meta_tools()
406
+
407
+ # Custom alpha: 0.5 = equal weight to both algorithms
408
+ meta_tools = tools.meta_tools(hybrid_alpha=0.5)
409
+
410
+ # More BM25: higher alpha (0.8 = 80% BM25, 20% TF-IDF)
411
+ meta_tools = tools.meta_tools(hybrid_alpha=0.8)
412
+
413
+ # More TF-IDF: lower alpha (0.2 = 20% BM25, 80% TF-IDF)
414
+ meta_tools = tools.meta_tools(hybrid_alpha=0.2)
415
+ ```
416
+
417
+ **How it works:**
418
+ - **BM25**: Excellent at keyword matching and term frequency
419
+ - **TF-IDF**: Better at understanding semantic relationships
420
+ - **Hybrid**: Combines strengths of both for superior accuracy
421
+ - **Default alpha=0.2**: Optimized through validation testing for best tool discovery
422
+
423
+ ## Examples
424
+
425
+ For more examples, check out the [examples/](examples/) directory:
426
+
427
+ - [Error Handling](examples/error_handling.py)
428
+ - [StackOne Account IDs](examples/stackone_account_ids.py)
429
+ - [Available Tools](examples/available_tools.py)
430
+ - [File Uploads](examples/file_uploads.py)
431
+ - [OpenAI Integration](examples/openai_integration.py)
432
+ - [LangChain Integration](examples/langchain_integration.py)
433
+ - [CrewAI Integration](examples/crewai_integration.py)
434
+ - [LangGraph Tool Node](examples/langgraph_tool_node.py)
435
+ - [Meta Tools](examples/meta_tools_example.py)
436
+
437
+ ## License
438
+
439
+ Apache 2.0 License