navi-core 0.1.1

Local agentic engine and terminal-first coding agent.
Documentation
use anyhow::Result;
use async_trait::async_trait;
use serde_json::json;

use super::helpers;
use crate::tool::{Tool, ToolDefinition, ToolInvocation, ToolKind, ToolResult};

pub(crate) struct QuestionTool;

#[async_trait]
impl Tool for QuestionTool {
    fn definition(&self) -> ToolDefinition {
        helpers::definition(
            "question",
            "Ask the user to choose from a short list of options. Use this only when user input is needed to proceed.",
            ToolKind::Read,
            json!({
                "type": "object",
                "properties": {
                    "question": {
                        "type": "string",
                        "description": "The question shown to the user."
                    },
                    "options": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                            "oneOf": [
                                { "type": "string" },
                                {
                                    "type": "object",
                                    "properties": {
                                        "label": { "type": "string" },
                                        "description": { "type": "string" }
                                    },
                                    "required": ["label"],
                                    "additionalProperties": false
                                }
                            ]
                        },
                        "description": "Options the user can choose from. Prefer concise labels with optional descriptions."
                    },
                    "multiple": {
                        "type": "boolean",
                        "description": "When true, the user may select more than one option. Defaults to false."
                    },
                    "custom": {
                        "type": "boolean",
                        "description": "When true, allow the user to type a custom answer. Defaults to false."
                    }
                },
                "required": ["question", "options"],
                "additionalProperties": false,
            }),
        )
    }

    async fn invoke(&self, invocation: ToolInvocation) -> Result<ToolResult> {
        Ok(ToolResult {
            invocation_id: invocation.id,
            ok: false,
            output: helpers::tool_error(
                "interactive_question_unavailable",
                "question requires an interactive client",
                true,
                Some(
                    "Run this turn from the TUI or another client that supports question resolution.",
                ),
                None,
            ),
        })
    }
}