424 Commits

Author SHA1 Message Date
jaberjaber23
605ce747ec fix: 6 bugs (#962, #939, #983, #987, #970, #882)
- #962: WebSocket auth now URL-decodes token before comparison. API keys with +/=/
  characters (base64-derived) now work correctly for WS streaming.
- #939: Clippy bool_comparison lint fixed in web_fetch.rs test.
- #983: Dockerfile adds perl and make for openssl-sys compilation on slim-bookworm.
- #987: Nextcloud chat poll endpoint corrected from api/v4/room/{token}/chat to
  api/v1/chat/{token}/ matching the send endpoint.
- #970: Moonshot Kimi K2/K2.5 models now redirect to api.moonshot.cn/v1 instead of
  api.moonshot.ai/v1. The .ai domain only serves legacy moonshot-v1-* models.
- #882: Closed as resolved by v0.5.7 custom hand persistence fix (#984).
- #926: Verified already fixed (rmcp builder API from previous session).

All tests passing. 8 files changed, 75 insertions.
2026-04-10 16:35:31 +03:00
zhujg007
34a27de85e Fix: Safe char boundary handling for UTF-8 string slicing 2026-04-10 20:51:36 +08:00
Liu
3e7d57b095 fix(comms): align task and send modals to center 2026-04-10 15:42:10 +08:00
Matteo De Agazio
e988572c82 fix: clippy bool_comparison in web_fetch test 2026-04-09 17:31:28 +02:00
Matteo De Agazio
2d94963627 chore: gitignore personal deploy script 2026-04-09 17:16:39 +02:00
Matteo De Agazio
d94508e72e feat: add free_response_channels support for Discord
Allow certain Discord channel IDs to respond without requiring @mention,
similar to Hermes gateway's free_response_channels.

- Add free_response_channels field to DiscordConfig
- Add free_response_channels method to ChannelBridgeHandle trait
- Implement free_response_channels in KernelBridgeAdapter
- Modify dispatch_message to bypass mention_only policy for free channels
- Add test for free_response_channels deserialization
2026-04-09 17:10:21 +02:00
Brandon Freeman
af51f6c971 chore: don't fail silently, leave a debug message. 2026-04-09 17:10:21 +02:00
Brandon Freeman
e1790b5380 fix: add explicit crypto provider 2026-04-09 17:10:21 +02:00
Dmitry Butko
be1c4dba47 fix: revert Claude-specific strip, keep empty-only + empty tool name fix
The model-aware assistant strip caused infinite agent loops for Claude.
Reverted to empty-only strip which is safe for all models. The
Telegram prefill issue needs to be fixed in the agent loop, not the
driver.

Remaining openai.rs changes:
- strip_trailing_empty_assistant: strips truly empty trailing messages
- Skip tool calls with empty ID or name from streaming responses

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 21:23:55 +10:00
Liu
51a5f7983c fix(analytics): correct style attribute binding to ensure it takes effect 2026-04-09 19:17:30 +08:00
Vít Rozsíval
760f35f9de test(channels): add assert for Signal default output formatter 2026-04-09 13:16:06 +02:00
Dmitry Butko
64b1ec5a7e fix: model-aware assistant message stripping for Claude via Copilot
The Copilot proxy for Claude enforces Anthropic's rule that conversations
must end with a user message. For Claude models, strip any trailing
assistant message without tool_calls (including non-empty ones). For
other models, only strip truly empty assistant messages.

This fixes the 'assistant message prefill not supported' error seen
in Telegram and other channel adapters when using Claude via Copilot,
without causing infinite agent loops for other models.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 21:07:14 +10:00
Dmitry Butko
dc6119d2cc fix: revert aggressive assistant strip, keep empty-only version
The aggressive strip (all trailing assistant messages) caused infinite
agent loops by removing non-empty responses the agent loop needs.
Reverted to only strip truly empty assistant messages (no content,
no tool_calls). The Telegram prefill issue needs a different fix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 21:00:16 +10:00
Dmitry Butko
a8b4d3b48d fix: strip all trailing assistant messages without tool_calls
Strengthens the strip to remove any trailing assistant message (not
just empty ones) when it has no tool_calls. The Copilot proxy for
Claude rejects conversations ending with any assistant message as
unsupported prefill. This fixes the Telegram bot channel where the
agent loop appends an assistant message with content.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 20:37:56 +10:00
Vít Rozsíval
36ba675f02 chore(clippy): fix warning 2026-04-09 12:34:40 +02:00
Vít Rozsíval
546816f692 chore(cargo): fix formatting 2026-04-09 12:27:18 +02:00
Vít Rozsíval
80af18a174 feat(channels): use plain text as default output formatter for Signal 2026-04-09 12:26:54 +02:00
Dmitry Butko
abeaaf5446 fix: skip tool calls with empty ID or name from streaming response
The Copilot API proxy can sometimes deliver streaming tool call chunks
without a function name, resulting in empty-name tool calls stored in
conversation history. When replayed to the API, these cause
'tool call must have a tool call ID and function name' errors.

Skip malformed tool calls (empty ID or name) during streaming response
finalization and log a warning.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 19:13:43 +10:00
Dmitry Butko
3854e3eb89 chore: remove debug logging, keep defensive strip_trailing_empty_assistant
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 19:01:23 +10:00
Dmitry Butko
73d50c0284 debug: add OAI message logging for tool call investigation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 18:55:43 +10:00
Dmitry Butko
6403871aa1 fix: strip trailing empty assistant messages for Claude/Gemini via Copilot proxy
The Copilot API proxy rejects conversations ending with an empty
assistant message as unsupported 'assistant message prefill' when
proxying Claude and Gemini models. GPT models are unaffected.

Strips trailing empty assistant messages (no content, no tool calls)
before sending the request. Applied in both complete() and stream()
paths.

Also reverts unused fixup_request method from copilot.rs since the
fix belongs in the OpenAI driver layer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 17:38:28 +10:00
default
df22a3db64 fix(kernel): preserve cron jobs across hand reactivation
Bug: in activate_hand(), kill_agent() is called on the existing agent
BEFORE the new agent is spawned. kill_agent() invokes
cron_scheduler.remove_agent_jobs() which deletes all cron jobs from memory
AND persists [] to cron_jobs.json. The reassign_agent_jobs() call further
down was meant to migrate jobs from old to new (per #461), but it always
runs as a no-op because the jobs are already gone — the order of
operations defeats the fix.

Symptom: every daemon restart silently destroys cron jobs for hand-style
agents. cron_jobs.json is rewritten as []. /api/cron/jobs returns empty.
No error message.

Fix: snapshot the cron jobs into a local Vec BEFORE kill_agent (same
pattern as saved_triggers above), then re-add them under the new agent_id
AFTER spawn_agent_with_parent. Runtime state (next_run, last_run) is
reset so jobs get a fresh start. The existing reassign_agent_jobs()
block is kept as a defensive safety net but is now redundant in the
common path.

Verified with cargo check -p openfang-kernel --lib (clean compile, no
warnings).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 07:18:44 +00:00
Dmitry Butko
c1a14e884e fix: rewrite Copilot driver with OAuth device flow authentication
The Copilot LLM driver was broken - it expected users to provide a
GITHUB_TOKEN env var, but no standard token type (PAT, gh CLI token)
works with the Copilot token exchange endpoint.

Changes:
- Full rewrite of copilot.rs with OAuth device flow using Copilot's
  client ID (Iv1.b507a08c87ecfe98)
- Three-layer token chain: ghu_ (8h) -> Copilot API token (30min),
  with automatic caching and refresh
- Dynamic model fetching from Copilot API on daemon startup and on
  model_not_supported error
- Init wizard: TUI auth screen with device code display, live model
  picker after authentication
- set-key command: interactive device flow for github-copilot provider
- Doctor: detects Copilot auth via persisted token file
- Removed static Copilot model entries (now fetched dynamically)
- Simplified driver instantiation (no env vars needed)

Tested end-to-end with Copilot Enterprise: auth, token exchange,
43 models fetched, completions working with claude-opus-4.6-1m.

Closes #1014

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 13:01:07 +10:00
诺墨
77bef773e5 Merge branch 'main' into feat-ux-optimize 2026-04-09 04:43:52 +08:00
jaberjaber23
a26f762635 v0.5.7: multi-instance hands + 8 critical fixes
## Headline feature
- Multi-instance Hands via optional instance_name (customer ask + #878).
  Web UI, CLI (--name / -n), API, kernel, registry all threaded. Two
  clip-youtube + clip-tiktok instances now coexist. Backward compatible
  when instance_name is omitted.

## Critical bug fixes
- #919 [SECURITY] rm bypass closed. process_start tool now validates against
  exec_policy allowlist and rejects shell metacharacters in both command
  and args. Added 5 regression tests.
- #1013 session_repair phase ordering — dedup now runs BEFORE synthetic
  result insertion, fixing Moonshot's non-unique tool_call_id format
  (function_name:index). Added regression test.
- #1003 global [[fallback_providers]] now actually used at runtime.
  resolve_driver wraps primary in FallbackDriver with global fallback
  chain. Network errors escalate to fallback instead of infinite retry.
- #937 Discord gateway heartbeat. Spawns interval task, tracks sequence,
  handles ACKs, detects zombie connections, force-closes on missing ACK.
  Credits @hello-world-bfree (PR #938) for the diagnosis.
- #935 System prompt leak in Web UI. get_agent_session now filters
  Role::System by default (?include_system=true for debug). Defense in
  depth client-side filter too.
- #984 Custom hands persistence. install_from_path copies to
  ~/.openfang/hands/. Kernel loads them on startup.
- #884 Workspace version bump 0.5.5 -> 0.5.7. Binaries now correctly
  report --version as 0.5.7 instead of stale 0.5.5.

## Cleanup
- rmcp 1.3 builder API adopted (credits @jefflower PR #986) for
  StreamableHttpClientTransportConfig. Drops unused Arc import.

## Stats
- 22 files changed, all workspace tests passing (1800+)
- Live-tested with daemon: v0.5.7 reported, multi-instance hands
  verified end-to-end, Groq round-trip PONG confirmed
v0.5.7
2026-04-08 22:59:56 +03:00
AlexZander85
62b6aa4eb8 feat(i18n): add Russian localization and i18n framework
- Add complete i18n framework with en.json and ru.json locale files
- Add i18n.js with language loading, detection, and fallback logic
- Localize chat.js: slash commands, Toast messages, welcome message
- Localize agents.js: personality presets, profile descriptions
- Localize wizard.js: step labels, channel options, suggestions, profiles
- Localize skills.js: 18 skill categories, uninstall confirm
- Localize sessions.js: delete session/key confirm dialogs

Provides full Russian translation for OpenFang UI as first non-English locale.
2026-04-08 18:30:59 +05:00
诺墨
c000392093 refactor(ui): replace HTML entity icons with inline SVGs for consistent rendering
- Replace `&times;` close icons with SVG X icons across all modals and panels
- Replace `&#10003;` checkmarks with SVG check icons in setup checklist, step indicators, and success states
- Replace `&bull;` and `&middot;` separators with small SVG dot icons for better visual consistency
- Improve icon sizing, alignment, and stroke properties for crisp rendering

Signed-off-by: 诺墨 <normal@normalcoder.com>
2026-04-07 19:13:38 +08:00
诺墨
ae32af1b06 fix(manifest): align the logo.png with the icon size to resolve browser loading issues.
Signed-off-by: 诺墨 <normal@normalcoder.com>
2026-04-07 18:54:02 +08:00
诺墨
d3972b23c0 refactor(ui): introduce CSS theme tokens for consistent accent text contrast
- Add `--text-on-accent` CSS variable (white) for text on accent backgrounds
- Replace hardcoded `var(--bg-primary)` with `--text-on-accent` across components
- Update dark theme surface, border, and text color tokens for better contrast
- Adjust dark mode surface colors (`#1F1D1C` → `#242221`) for improved depth
- Refine border and text-muted colors for better visual hierarchy

Signed-off-by: 诺墨 <normal@normalcoder.com>
2026-04-07 18:38:47 +08:00
诺墨
ded95f3180 refactor(ui): restructure navigation sidebar with Overview as primary entry
- Move Overview to first navigation item for better UX
- Consolidate `Chat` into `Agents` section
- Increase chevron and section title font sizes for improved readability
- Adjust section title padding for better visual spacing

Signed-off-by: 诺墨 <normal@normalcoder.com>
2026-04-07 18:19:48 +08:00
Liu
09ec6f5549 fix(comms): OpenFangAPI.baseUrl is undefined 2026-04-07 17:07:17 +08:00
Liu
47c743f17c fix: avoid Alpine SVG template rendering errors in cost charts 2026-04-07 16:59:22 +08:00
Liu
489fc1312c fix(chat): prevent duplicate message keys on first chat welcome message 2026-04-07 15:20:55 +08:00
default
0408d65d8f fix: capture text from intermediate tool_use iterations
When an LLM produces text alongside tool_use blocks (e.g., a chat
message followed by memory_store calls), the text was lost if the
final EndTurn iteration returned empty text. The empty-response guard
would activate and return "[Task completed — the agent executed tools
but did not produce a text summary.]" even though the agent DID
produce text in an earlier iteration.

This is a common pattern when agents are instructed to respond to
users AND persist state via memory_store in the same turn.

Fix: accumulate text content from all ToolUse iterations. When the
final EndTurn has empty text, use accumulated text as fallback before
triggering the empty-response guard.

Applied to both sync and streaming agent loop paths.
2026-04-05 11:17:10 +00:00
chris-young
8d14d0c225 fix: new agents default to configured model instead of hardcoded groq
Built-in templates and the spawn wizard both hardcoded
provider = "groq" / model = "llama-3.3-70b-versatile" in the
manifest TOML sent to the API. The kernel's default_model overlay
only activates when provider/model are empty or "default", so
hardcoded values bypassed the user's configured default entirely.

Fixes #967
2026-04-02 18:04:54 -07:00
jaberjaber23
07963779be fix: install script skips empty releases, finds latest with binary assets 2026-04-03 03:52:46 +03:00
t4min0
28d01acf91 fix(nix): add perl to buildInputs for openssl-sys vendored build
Since v0.5.4, native-tls uses features = ["vendored"], which compiles OpenSSL from source via openssl-sys. This requires perl for the OpenSSL Configure script, but perl was missing from the flake's buildInputs.

Mirrors the Dockerfile fix in #952. Fixes #894.
2026-04-03 00:10:54 +02:00
chris-young
be149597e6 Set GHCR package visibility to public on every release
GHCR defaults new packages to private, so docker pull
ghcr.io/rightnow-ai/openfang:... returned 401 for unauthenticated
users despite the repo being public.

Two changes to the docker job in release.yml:

1. Add OCI labels to the build — links the package to the repo so
   GHCR associates it correctly, and is standard practice for
   container images.

2. After each push, call the GitHub Packages API (PATCH
   /orgs/RightNow-AI/packages/container/openfang) to set visibility
   to public. The workflow already holds packages: write, which is
   the required scope. This runs on every release tag so visibility
   cannot regress if the package is ever reset.

Fixes #961
2026-04-02 11:31:41 -07:00
nldhuyen0047
3b21494867 fix: inject default items schema for array parameters in Gemini normalization 2026-04-02 17:08:46 +07:00
Felix
4565988e2e fix: Fix panic due to UTF-8 character boundary errors 2026-04-01 18:57:03 +08:00
Alex-wuhu
4714efb9e4 test: add unit tests for Novita provider defaults, alias, and driver creation
- test_provider_defaults_novita: verify base_url, api_key_env, key_required
- test_provider_defaults_novita_ai_alias: verify "novita-ai" alias resolves
- test_novita_provider_with_env_key: driver creation succeeds with env key
- test_novita_provider_no_key_errors: driver creation fails without key

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 14:26:49 +08:00
Alex-wuhu
365bec868c Add Novita AI as LLM provider
- Add NOVITA_BASE_URL constant to model_catalog.rs
- Register novita provider in provider_defaults() with OpenAI-compatible endpoint
- Add novita to known_providers() list
- Add novita to detect_available_provider() auto-detection probe
- Document NOVITA_API_KEY in .env.example

Novita AI uses an OpenAI-compatible API at https://api.novita.ai/openai/v1
Default model: moonshotai/kimi-k2.5
2026-03-31 12:47:41 +08:00
Jaber Jaber
a78299ed3d Merge pull request #753 from RamXX/fix/dashboard-password-argon2
Replace SHA256 password hashing with Argon2id for dashboard auth
2026-03-31 02:22:02 +03:00
Jaber Jaber
eebb83c79a Merge pull request #877 from pbranchu/fix/silent-reinforcement
Fix silent reinforcement: recognize [SILENT] token
2026-03-31 02:21:59 +03:00
Jaber Jaber
0b59205b0c Merge pull request #881 from pbranchu/fix/token-estimation-tooluse
Fix token estimation: include ToolUse arguments in text_length
2026-03-31 02:21:55 +03:00
Jaber Jaber
3f8ceabc51 Merge pull request #897 from tytsxai/pr/upstream-nested-xml
feat(runtime): recover nested XML tool call parameters
2026-03-31 02:21:51 +03:00
Jaber Jaber
4921ee5ece Merge pull request #898 from tytsxai/pr/upstream-generic-fixes
channels: add startup timeout for Telegram control-plane calls
2026-03-31 02:21:47 +03:00
Jaber Jaber
0c4769a07f Merge pull request #900 from neo-wanderer/fix/agent-skills-reload
Fix/agent skills reload
2026-03-31 02:21:44 +03:00
Jaber Jaber
167b37f10e Merge pull request #917 from lc-soft/fix/alpine-exp-error
fix: Alpine Expression Error in settings page caused by x-show
2026-03-31 02:21:40 +03:00
Jaber Jaber
545e710abb Merge pull request #920 from norci/add-searxng-search-provider
feat: add SearXNG search provider with custom URL and JSON output
2026-03-31 02:21:36 +03:00