Skip to content

feat(assistant-panel): add tool use / function calling#360

Draft
not-reed wants to merge 1 commit intonoctalia-dev:mainfrom
not-reed:feat/assistant-panel-tool-calling
Draft

feat(assistant-panel): add tool use / function calling#360
not-reed wants to merge 1 commit intonoctalia-dev:mainfrom
not-reed:feat/assistant-panel-tool-calling

Conversation

@not-reed
Copy link
Copy Markdown
Contributor

  • Plugin-style tool discovery: tools//spec.json + run executable
  • OpenAI and Gemini tool_calls integration with multi-turn loop
  • Confirmation system with allowlist (approve once, always allow, deny)
  • Generic tool:qualifier pattern for granular permissions (e.g. shell:ls)
  • Quote-aware shell tokenizer for safe compound command approval
  • Built-in tools: shell, read_file, clipboard, web_search
  • Tool UI: collapsible result cards, execution spinner, confirmation prompt
  • Settings: enable toggle, max iterations, timeout, discovered tools list

- Plugin-style tool discovery: tools/<name>/spec.json + run executable
- OpenAI and Gemini tool_calls integration with multi-turn loop
- Confirmation system with allowlist (approve once, always allow, deny)
- Generic tool:qualifier pattern for granular permissions (e.g. shell:ls)
- Quote-aware shell tokenizer for safe compound command approval
- Built-in tools: shell, read_file, clipboard, web_search
- Tool UI: collapsible result cards, execution spinner, confirmation prompt
- Settings: enable toggle, max iterations, timeout, discovered tools list
@github-actions
Copy link
Copy Markdown
Contributor

@j-1in - this PR modifies your plugin. Please review when you have a chance.

Copy link
Copy Markdown
Contributor

@Cleboost Cleboost left a comment

Choose a reason for hiding this comment

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

Here are some small improvements you can make 🙂 (I already did the bot work, but your PR is older than the bot deployment 😄)

applyUiScale: false

ToolTip.visible: toolCountMouse.containsMouse
ToolTip.text: (pluginApi?.tr("chat.toolsAvailable") || "Tools available") + ": " + toolCount
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When it comes to translations, you don't need to use fallback values anymore. So the following works:

// From:
pluginApi?.tr("key") || "Value"
// To this:
pluginApi?.tr("key")

}

NText {
text: pluginApi?.tr("chat.executingTools") || "Executing tools..."
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As before you don't need translation fallbacks anymore

}

NText {
text: pluginApi?.tr("chat.toolConfirmTitle") || "Tool wants to run"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As before you don't need translation fallbacks anymore

spacing: Style.marginS

NButton {
text: pluginApi?.tr("chat.approveOnce") || "Approve Once"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As before you don't need translation fallbacks anymore

// Qualified: "Allow <tool:qualifier>" button
NButton {
visible: confirmRect.hasQualifier
text: (pluginApi?.tr("chat.allowCommand") || "Allow") + " `" + confirmRect.qualifiedKey + "`"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As before you don't need translation fallbacks anymore


NText {
visible: root.qualifiedEntries.length === 0
text: pluginApi?.tr("settings.noAllowlistEntries") || "No rules yet. Rules are added when you approve tools in the chat."
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As before you don't need translation fallbacks anymore

NTextInput {
id: newAllowlistInput
Layout.fillWidth: true
placeholderText: pluginApi?.tr("settings.allowlistAddPlaceholder") || "e.g. shell:ls, shell:git, shell:*"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As before you don't need translation fallbacks anymore

}

NButton {
text: pluginApi?.tr("settings.allowlistAdd") || "Add"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As before you don't need translation fallbacks anymore

Comment on lines +462 to +463
label: pluginApi?.tr("settings.toolsDirectory") || "Tools Directory"
description: pluginApi?.tr("settings.toolsDirectoryDesc") || "Path to tools directory (leave blank for default)"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As before you don't need translation fallbacks anymore

// Tool Settings Section
// ==================
NText {
text: pluginApi?.tr("settings.toolsSection") || "Tool Use (Function Calling)"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As before you don't need translation fallbacks anymore

@ItsLemmy ItsLemmy marked this pull request as draft March 30, 2026 12:59
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.

2 participants