Conversation
9c75205 to
34a54c2
Compare
app/routers/ui_tools.py
Outdated
|
|
||
| # Fetch the resource from Kubernetes | ||
| try: | ||
| resource = api.get_namespaced_custom_object( |
There was a problem hiding this comment.
we should check the user have permissions to fetch UITools
There was a problem hiding this comment.
maybe even consider modifying the CRD from the UI instead of adding this new endpoints? what do you think?
There was a problem hiding this comment.
I moved the logic for the CRD updates to the UI and removed the endpoints. Let's postpone the Webhook validation to a dedicate PR.
app/routers/ui_tools.py
Outdated
| api = _init_k8s_client() | ||
|
|
||
| try: | ||
| current_resource = api.get_namespaced_custom_object( |
There was a problem hiding this comment.
same here. We should check user can update UITools
app/routers/ui_tools.py
Outdated
| detail="Missing required field: 'tools'", | ||
| ) | ||
|
|
||
| tools = body.get("tools") |
There was a problem hiding this comment.
all these validation should be moved to a webhook. Otherwise, a user can create an invalid UITool with kubectl
app/services/agent/root.py
Outdated
| "continue": "tools", | ||
| "summarize_conversation": "summarize_conversation", | ||
| "end": END, | ||
| "summarize_conversation": "ui_tools", # Route all endings to ui_tools |
There was a problem hiding this comment.
summarize_conversation won't always be called as it depends on the number of messages. We should change this to make sure ui_tools is always called.
There was a problem hiding this comment.
I fixed the workflow in parent and root nodes.
Now the ui-tools happens always before the summarize switch.
app/services/agent/root.py
Outdated
| { | ||
| "continue": "agent", | ||
| "end": END, | ||
| "end": "ui_tools", # Route to ui_tools before summarize |
There was a problem hiding this comment.
this will be called when human validation is rejected, so we should END
Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>
Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>
8e09136 to
cc335df
Compare
|
Thanks for the review @raulcabello .
I still keep this in draft as the tests are TODO. |
| kind: CustomResourceDefinition | ||
| metadata: | ||
| annotations: | ||
| controller-gen.kubebuilder.io/version: v0.17.1 |
There was a problem hiding this comment.
was this generated with kubebuilder? Can you add the go code like we do for AIAgentConfig https://github.com/rancher/rancher-ai-agent/tree/main/crd-generation?
There was a problem hiding this comment.
No it was generated manually. I just pushed the uitoolsconfig_types.go generator.
|
|
||
| Args: | ||
| tool: The UITool to register | ||
| config_name: The config this tool belongs to (default: 'default') |
There was a problem hiding this comment.
why do we want multiple configs?
There was a problem hiding this comment.
This allow us to specify multiple ui-tools configs - not required now, but in the future we want to define different tools and dynamically select them when sending the requests from the UI, basically it's a flexible approach.
It's also possible to define multiple tools for different UIs...
| description: UIToolsConfigSpec defines the desired state of UITools | ||
| properties: | ||
| tools: | ||
| description: List of UI tools |
There was a problem hiding this comment.
what are the benefits of having a list instead of a single tool per UIToolConfig resource? Have you consider only having one tool per UIToolConfig resource? I beleive that would make it easier to manage all tools
There was a problem hiding this comment.
Yes, my first approach was to have a list of UITools crd, this seems reasonable code-wise, but:
- The UI needs to check if the ui tools definition has changes before initiating a new chat. When the definition has changes compared with the values in the cluster (this can happen when you install a new UI version), they need to be updated in atomic way.
- Fetching only 1 resource it's more efficient.
| 4. Include all REQUIRED fields marked with (REQUIRED) in your input | ||
| 5. Optional fields can be omitted if not needed | ||
| 6. Output a valid JSON array at the very end with this format: | ||
| [ |
There was a problem hiding this comment.
not sure if all models would be able to create a valid JSON array. We've seen in the past that small models like gpt-oss:20b fails to create a valid json for creating k8s resources.
Have you consider using something like MCP UI to prevent this problem? https://mcpui.dev/guide/introduction
app/services/ui_tools/selector.py
Outdated
| else: | ||
| logging.debug(f"UI tool '{tool_name}' not found in available tools: {[t.name for t in available_tools]}") | ||
| except json.JSONDecodeError as e: | ||
| logging.debug(f"Failed to parse JSON array: {json_str[:100]}... Error: {e}") |
There was a problem hiding this comment.
I would log an error if it is not a valid JSON. That would mean the UITools won't work
app/services/ui_tools/registry.py
Outdated
| self.last_updated = datetime.now() | ||
| self._register_default_tools() | ||
|
|
||
| def _register_default_tools(self) -> None: |
There was a problem hiding this comment.
why empty? can we remove it ?
There was a problem hiding this comment.
Typo from previous implementation - removed
app/services/ui_tools/registry.py
Outdated
| config=self.config, | ||
| ) | ||
|
|
||
| def validate_tool_input(self, tool_name: str, input_data: Dict[str, Any], config_name: str = None) -> tuple[bool, Optional[str]]: |
There was a problem hiding this comment.
not used, can we remove it?
There was a problem hiding this comment.
Typo from previous implementation - removed
|
|
||
| # Dispatch UI tools before the interrupt, so they're available to the client | ||
| if config is not None: | ||
| logging.info(f"Dispatching UI tools before confirmation interrupt") |
There was a problem hiding this comment.
why do we want to dispatch UI tools before confirming? We will dispatch UI tools at the end, so wouldn't this dispatch it twice?
There was a problem hiding this comment.
The confirmation process generates 2 different messages in the UI:
-
Confirmation ask: The agent sends a confirmation message -
<confirmation-response>- to the UI; in this context we are dispatching the ui-tools -> the code you posted is executed.
-
The user confirms/cancels the action: The agent performs the action and return a message in case of confirmation - There are no duplicates, the agent drops the ongoing LangGraph workflow after confirmation so the UI tools node is not executed. So we are not currently sending any ui-tools after confirmation/cancel, but we should. Notice that there are no ui tools elements in the second confirmation chunk:
Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>
Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>
Related issue: rancher/rancher-ai-ui#190
Related issue: #179
UI Tools Feature
Overview
This PR introduces UI Tools, It enables the AI agent to dynamically select Ui tools declared by the UI. The agent can recommend appropriate UI tools based on the conversation context, and the LLM intelligently selects which tools to invoke with their respective parameters.
Key Features
UIToolsConfigCustom Resource Definitions (CRDs) in KubernetesArchitecture
Components
1. Registry (
app/services/ui_tools/registry.py)Central registry for managing UI tools with config-scoped namespacing.
Key Classes:
UITool: Represents a single UI tool with metadata and schemaUIToolSchema: Defines input validation schema for toolsUIToolCall: Represents a tool invocation by the agentUIToolsConfig: Configuration for a set of UI toolsUIToolsRegistry: Manages tools in a config-scoped dictionarytools_by_config[config_name][tool_name]2. Loader (
app/services/ui_tools/loader.py)Loads UI tool definitions from Kubernetes CRDs into the registry.
Key Functions:
reload_ui_tools_config(): Reload the tools from watcher updates.3. Selector (
app/services/ui_tools/selector.py)Uses LLM to intelligently select appropriate UI tools for a given context.
Key Classes:
UIToolsSelector: Main selector class that invokes LLM for tool selectionFeatures:
maxToolsdifferent tools (by unique name)tool_A(params1),tool_A(params2),tool_B✓ buttool_C✗Configuration
Kubernetes CRD: UIToolsConfig
Configuration Fields
Config-Level Settings
enabledrevisionsystemPromptmaxToolsTool-Level Settings
namecategorydescriptionpromptschemaenabledmetadatarevisionUsage
1. Define Tools in Kubernetes
2. Agent Uses Tools
The agent automatically:
Implementation Details
Tool Selection Flow
Config-Scoped Namespacing
Problem Solved: When multiple UIToolsConfig resources exist, tools with the same name could collide.
Solution: Nested dictionary structure
Revision-Gated Updates
Prevents race conditions when multiple clients update configurations:
Integration Points
1. Agent State (base.py)
_dispatch_ui_tools_event()to select tools2. WebSocket Handler (websocket.py)
3. Memory Service (memory.py)
4. Webhook validation
Testing
TODO
Future Enhancements