Add Discord-native hybrid front-end for Jarvis (bot + bridge)
Some checks failed
Release / semantic-release (push) Successful in 59s
tests / Unit tests (Linux, Python 3.11) (push) Successful in 13m45s
Release / build-linux (push) Failing after 7m47s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled

Transform isair/jarvis into a Discord-controlled voice assistant running on
the Ubuntu VNC desktop, keeping the mature ~39k-line Python brain intact.

- bot/ (Node + bun, discord.js): /자비스 slash commands (ephemeral),
  voice channel join + voice receive/playback, pluggable VNC screen broadcast
  (selfbot live / noVNC / screenshot)
- bridge/ (Python, Flask): wraps jarvis STT + run_reply_engine + Piper TTS
  behind a thin localhost HTTP API
- .env.example, scripts/ (start_bridge/start_bot/dev), README rewrite,
  docs/language-comparison.md and docs/vnc-xfce-setup.md

Language decision: hybrid (Python brain + Node/bun Discord layer) because
Discord blocks bot video; native screen broadcast only works via a Node
selfbot library.
This commit is contained in:
javis-bot
2026-06-09 14:51:05 +09:00
parent a5bf8d1826
commit c4abf63f38
308 changed files with 94135 additions and 1 deletions

116
src/jarvis/tools/base.py Normal file
View File

@@ -0,0 +1,116 @@
"""Base tool interface for Jarvis tools.
This module defines the common interface that all tools must implement,
ensuring consistency with MCP tool format and enabling dictionary-based execution.
"""
from abc import ABC, abstractmethod
from typing import Dict, Any, Optional, Callable
from .types import ToolExecutionResult
class ToolContext:
"""Context object containing all the resources a tool might need."""
def __init__(
self,
db,
cfg,
system_prompt: str,
original_prompt: str,
redacted_text: str,
max_retries: int,
user_print: Callable[[str], None],
language: Optional[str] = None,
):
self.db = db
self.cfg = cfg
self.system_prompt = system_prompt
self.original_prompt = original_prompt
self.redacted_text = redacted_text
self.max_retries = max_retries
self.user_print = user_print
# ISO-639-1 code of the language Whisper auto-detected for the current
# utterance (e.g. "en", "tr", "de"). None when the tool is invoked
# outside the voice path (evals, unit tests, text entry) — tools must
# treat absence as "no signal" and fall back to their own default
# rather than assuming English.
self.language = language
class Tool(ABC):
"""Base class for all Jarvis tools.
This interface matches the MCP tool format with name, description, and inputSchema
properties, while providing a simple execution interface focused on tool logic.
Implementation guideline:
- Put all operational logic directly in the `run` method.
- Keep helper functions module-level only when they provide clear reuse (e.g. nutrition
extraction helpers used by multiple code paths / tests). Otherwise inline.
- `run` receives validated args (per schema) and a `ToolContext` giving access to db, cfg,
prompts, redacted_text, retry allowance, and a user_print callable.
"""
@property
@abstractmethod
def name(self) -> str:
"""The canonical tool identifier (camelCase)."""
pass
@property
@abstractmethod
def description(self) -> str:
"""Human-readable description of what the tool does."""
pass
@property
@abstractmethod
def inputSchema(self) -> Dict[str, Any]:
"""JSON Schema for tool arguments (matches MCP format)."""
pass
@abstractmethod
def run(self, args: Optional[Dict[str, Any]], context: ToolContext) -> ToolExecutionResult:
"""Execute the tool with the given arguments and context.
This is the only method tools need to implement. All common concerns
like user printing, database access, config, etc. are provided via context.
Args:
args: Dictionary containing tool arguments (validated against inputSchema)
context: ToolContext with db, cfg, user_print, etc.
Returns:
ToolExecutionResult with execution results
"""
pass
def execute(
self,
db,
cfg,
tool_args: Optional[Dict[str, Any]],
system_prompt: str,
original_prompt: str,
redacted_text: str,
max_retries: int,
user_print: Callable[[str], None],
language: Optional[str] = None,
) -> ToolExecutionResult:
"""Execute the tool (internal method used by registry).
This method creates the context and calls the tool's run method.
Tools should implement run(), not this method.
"""
context = ToolContext(
db=db,
cfg=cfg,
system_prompt=system_prompt,
original_prompt=original_prompt,
redacted_text=redacted_text,
max_retries=max_retries,
user_print=user_print,
language=language,
)
return self.run(tool_args, context)