Skip to content

feat:include available connectors in search/execute tool descriptions#165

Merged
shashi-stackone merged 8 commits intomainfrom
feat/dynamic-connector-descriptions
Apr 7, 2026
Merged

feat:include available connectors in search/execute tool descriptions#165
shashi-stackone merged 8 commits intomainfrom
feat/dynamic-connector-descriptions

Conversation

@shashi-stackone
Copy link
Copy Markdown
Contributor

@shashi-stackone shashi-stackone commented Apr 2, 2026

Summary

  • _build_tools() now discovers available connectors via fetch_tools() and injects them into the tool_search and tool_execute descriptions
  • LLM sees which connectors are available before calling search, improving trigger reliability

A recurring issue with Search/Execute is that search doesn't reliably trigger in the first place the LLM doesn't know what's searchable. By dynamically listing connector keys in the tool
description (e.g. "Available connectors: bamboohr, calendly, jotform"), the LLM has the context it needs to trigger search confidently.

Connector discovery is best-effort if it fails, descriptions remain generic.

New things

  • Add configurable HTTP timeout for tool execution (default 60s, was httpx's 5s default)
  • Timeout can be set top-level StackOneToolSet(timeout=120) or in execute config execute={"timeout": 120}
  • Fix account_ids propagation from execute config to internal tools (fixes ExecuteToolsConfig account_ids not propagated to _account_ids — tool_search fails with 400 #167)
  • Inject available connector names into tool_search/tool_execute descriptions for better LLM accuracy
  • Add Workday integration example demonstrating timeout and account scoping

Resolves:
#166
StackOneHQ/stackone-ai-node#355


Summary by cubic

Include available connectors in tool_search/tool_execute descriptions and add a configurable execution timeout with account-scoped execution. Added a Workday example and updated examples to pass STACKONE_API_KEY; discovery is best-effort and the default timeout is 60s.

  • New Features

    • Append “Available connectors: …” to tool descriptions via fetch_tools() with safe fallback and debug logging.
    • Add timeout to StackOneToolSet(...) and execute.timeout; top-level param takes precedence and is applied to httpx.request.
    • Add examples/workday_integration.py; update examples/test_examples.py to include it; simplify search_tool_example.py to new SDK API and pass STACKONE_API_KEY.
  • Bug Fixes

    • Respect execute.account_ids when building and executing tools.

Written for commit 04b8bd0. Summary will update on new commits.

Copilot AI review requested due to automatic review settings April 2, 2026 13:12
@shashi-stackone shashi-stackone changed the title include available connectors in search/execute tool descriptions [WIP]include available connectors in search/execute tool descriptions Apr 2, 2026
cubic-dev-ai[bot]
cubic-dev-ai bot previously approved these changes Apr 2, 2026
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Auto-approved: The changes are low-risk, primarily enhancing LLM tool descriptions with dynamic connector information. The discovery logic includes a safe try-except fallback to prevent breaking tool initialization.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves LLM trigger reliability for the tool_search / tool_execute “search_and_execute” mode by dynamically injecting the set of available connector keys into the tools’ descriptions, so the model knows what is searchable/executable up front.

Changes:

  • Extend _create_search_tool() and _create_execute_tool() to optionally append an “Available connectors: …” line to each tool’s description.
  • Update StackOneToolSet._build_tools() to best-effort discover connectors via fetch_tools() and pass them into the tool constructors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +652 to +655
all_tools = self.fetch_tools(account_ids=self._account_ids)
connectors = sorted(all_tools.get_connectors())
if connectors:
connectors_str = ", ".join(connectors)
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_build_tools() now calls fetch_tools() during tool definition building. This introduces an eager network call (and potentially a large /mcp catalog fetch) even before the LLM decides to use tool_search/tool_execute, and it will likely be repeated again when tool_execute runs (since _ExecuteTool fetches tools on first execute). Consider caching connector discovery results (e.g., per account_ids) and/or seeding execute_tool’s internal tools cache from the already-fetched all_tools to avoid duplicate catalog fetches.

Suggested change
all_tools = self.fetch_tools(account_ids=self._account_ids)
connectors = sorted(all_tools.get_connectors())
if connectors:
connectors_str = ", ".join(connectors)
# Cache connector discovery results per account_ids to avoid
# repeated catalog fetches when building tools.
if not hasattr(self, "_connector_cache"):
self._connector_cache = {}
cache_key = (
tuple(sorted(self._account_ids)) if self._account_ids else None
)
if cache_key in self._connector_cache:
connectors_str = self._connector_cache[cache_key]
else:
all_tools = self.fetch_tools(account_ids=self._account_ids)
connectors = sorted(all_tools.get_connectors())
if connectors:
connectors_str = ", ".join(connectors)
self._connector_cache[cache_key] = connectors_str

Copilot uses AI. Check for mistakes.
if connectors:
connectors_str = ", ".join(connectors)
except Exception:
logger.debug("Could not discover connectors for tool descriptions")
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The connector discovery exception handler logs a generic debug message but drops the underlying exception/context. Including the exception (and stack trace via exc_info) would make it much easier to diagnose discovery failures without changing the best-effort behavior.

Suggested change
logger.debug("Could not discover connectors for tool descriptions")
logger.debug(
"Could not discover connectors for tool descriptions",
exc_info=True,
)

Copilot uses AI. Check for mistakes.
Comment on lines +210 to +215
connector_line = f" Available connectors: {connectors}." if connectors else ""
description = (
"Search for available tools by describing what you need. "
"Returns matching tool names, descriptions, and parameter schemas. "
"Use the returned parameter schemas to know exactly what to pass "
"when calling tool_execute."
f"when calling tool_execute.{connector_line}"
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The connectors string is appended verbatim into the tool description with no length/size cap. If an account has many connectors, this can bloat tool definitions and may exceed downstream tool-description limits or increase prompt size unnecessarily. Consider truncating/limiting the number of connectors included (e.g., first N + “and X more”).

Copilot uses AI. Check for mistakes.
Comment on lines +265 to +270
connector_line = f" Available connectors: {connectors}." if connectors else ""
description = (
"Execute a tool by name with the given parameters. "
"Use tool_search first to find available tools. "
"The parameters field must match the parameter schema returned "
"by tool_search. Pass parameters as a nested object matching "
"the schema structure."
f"by tool_search. Pass parameters as a nested object matching the schema structure.{connector_line}"
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as tool_search: the connectors list is appended into this tool’s description without any bounding/truncation. If connector count is high, this can significantly increase tool definition size and potentially exceed provider limits; consider limiting the rendered list and/or total description length.

Copilot uses AI. Check for mistakes.
@shashi-stackone shashi-stackone changed the title [WIP]include available connectors in search/execute tool descriptions feat:include available connectors in search/execute tool descriptions Apr 2, 2026
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="stackone_ai/toolset.py">

<violation number="1" location="stackone_ai/toolset.py:602">
P2: Top-level timeout precedence is value-dependent, so explicitly passing `timeout=60.0` is ignored when `execute.timeout` is set.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 2 files (changes from recent commits).

Requires human review: Auto-approval blocked by 1 unresolved issue from previous reviews.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 1 file (changes from recent commits).

Requires human review: Auto-approval blocked by 1 unresolved issue from previous reviews.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="examples/search_tool_example.py">

<violation number="1" location="examples/search_tool_example.py:30">
P2: This example now runs API calls on import instead of behind a main entrypoint, causing side effects and import-time failures in unconfigured environments.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 1 file (changes from recent commits).

Requires human review: Auto-approval blocked by 1 unresolved issue from previous reviews.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 3 files (changes from recent commits).

Requires human review: Modifies core tool initialization logic, introduces dynamic description updates, and adds HTTP timeouts. Includes significant refactoring of example files.

@@ -1,24 +1,15 @@
#!/usr/bin/env python
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing example code as its not needed fr new API .. Most of the code not needed to avoid duplication.

print(f"Top {len(results_limited)} matches from the full catalog:")
for r in results_limited:
print(f" [{r.similarity_score:.2f}] {r.id}")
print(f" {r.description}")
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not aligned to new SDK API

# Get all available tools using MCP-backed fetch_tools()
all_tools = toolset.fetch_tools(account_ids=_account_ids)
print(f"Total tools available: {len(all_tools)}")
def main() -> None:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't we just want to have STACKONE_API_KEY= as the default config

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example is old one and trimmed to use new API .. Can we delete this example altogether?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Only API KEY can be enough but refering to the issue #167 we should be able to pass it here too (Optionally)

Copy link
Copy Markdown

@willleeney willleeney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we using the account_ids as the default credentials rather than the STACKONE_API_KEY

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 2 files (changes from recent commits).

Requires human review: Modifies core toolset initialization and execution logic, including dynamic tool description generation and new timeout configurations that impact production HTTP requests.

@shashi-stackone
Copy link
Copy Markdown
Contributor Author

why are we using the account_ids as the default credentials rather than the STACKONE_API_KEY

@willleeney We are using STACKONE_API_KEY as default but in the search_tools_exampe and workday_integration example need to demonstrate account ID can be used as well. Assumed the StackOne API Key is pre-requisite but added now.

@shashi-stackone shashi-stackone merged commit 544f41e into main Apr 7, 2026
16 checks passed
@shashi-stackone shashi-stackone deleted the feat/dynamic-connector-descriptions branch April 7, 2026 14:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ExecuteToolsConfig account_ids not propagated to _account_ids — tool_search fails with 400

3 participants