18 Commits

Author SHA1 Message Date
Xubin Ren
799db33517 fix(heartbeat): record proactive deliveries in channel sessions
Route heartbeat, cron, and message-tool deliveries through one gateway helper so user-visible proactive messages are available when the channel replies.

Made-with: Cursor
2026-04-26 20:08:21 +08:00
Peixian Gong
dd26b4407d fix(providers): make GitHub Copilot backend work with GPT-5/o-series models
Calling GitHub Copilot with `gpt-5.*` / `o*` models (e.g.
`github_copilot/gpt-5.4`, `github_copilot/gpt-5.4-mini`) failed with a
chain of misleading errors:

  1. `Unsupported parameter: 'max_tokens' is not supported with this
     model. Use 'max_completion_tokens' instead.`
  2. `model "gpt-5.4-mini" is not accessible via the /chat/completions
     endpoint` (`unsupported_api_for_model`).
  3. `The requested model is not supported.` (`model_not_supported`)
     even after routing to /responses.

Root causes (each one masked the next):

  * The `github_copilot` ProviderSpec did not opt into
    `supports_max_completion_tokens`, so `_build_kwargs` always sent the
    legacy `max_tokens` parameter that GPT-5/o-series reject.
  * `_should_use_responses_api` was hard-gated to
    `spec.name == "openai"` plus a direct-OpenAI base URL, so the
    GitHub Copilot backend always went through /chat/completions even
    for models the Copilot gateway exposes only via /responses
    (e.g. `gpt-5.4-mini`).
  * When /responses did fail on github_copilot, the existing
    "compatibility marker" heuristic silently fell back to
    /chat/completions — which can never succeed for these models — so
    the real upstream error was hidden.
  * `_build_responses_body` did not honour `spec.strip_model_prefix`,
    so the request body sent `model="github_copilot/gpt-5.4-mini"`
    (with the routing prefix), which the Copilot gateway rejects with
    `model_not_supported`. (`_build_kwargs` already stripped it; this
    branch was missed.)

Fix:

  * registry.py: set `supports_max_completion_tokens=True` on the
    `github_copilot` spec so requests use `max_completion_tokens`.
  * openai_compat_provider.py:
      - `_should_use_responses_api` now also allows the
        `github_copilot` spec, and skips the direct-OpenAI base check
        for it (the Copilot gateway is its own base URL).
      - `_build_responses_body` now strips the model routing prefix
        when `spec.strip_model_prefix` is set, matching `_build_kwargs`.
      - `chat` / `chat_stream` no longer fall back from /responses to
        /chat/completions on the `github_copilot` spec: the fallback
        cannot succeed for GPT-5/o-series and would mask the real
        gateway error.

Tests:

  * tests/cli/test_commands.py: switched the
    `test_github_copilot_provider_refreshes_client_api_key_before_chat`
    fixture model from `gpt-5.1` to `gpt-4` so it continues to exercise
    the /chat/completions code path it was designed for (gpt-5.1 now
    correctly routes to /responses on github_copilot).
  * `pytest tests/providers/ tests/cli/test_commands.py` — 314 passed.
  * Verified end-to-end against the live Copilot gateway with both
    `github_copilot/gpt-5.4` and `github_copilot/gpt-5.4-mini`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-22 14:28:19 +08:00
hussein1362
512bf59b3c fix(session): fsync sessions on graceful shutdown to prevent data loss
On filesystems with write-back caching (rclone VFS, NFS, FUSE mounts)
the OS page cache may buffer recent session writes. If the process is
killed before the cache flushes, the most recent conversation turns are
silently lost — causing the agent to "forget" recent context and
respond to stale history on the next startup.

Changes:

- session/manager.py: add fsync=True option to save() that flushes the
  file and its parent directory to durable storage. Add flush_all() that
  re-saves every cached session with fsync. Default save() behavior is
  unchanged (no fsync) to avoid performance regression in normal
  operation.

- cli/commands.py: call agent.sessions.flush_all() in the gateway
  shutdown finally block, after stopping heartbeat/cron/channels.

- tests/session/test_session_fsync.py: 8 tests covering fsync flag
  behavior, flush_all with empty/multiple/errored sessions, and
  data survival across simulated process restart.

- tests/cli/test_commands.py: add sessions attribute to _FakeAgentLoop
  so the gateway health endpoint test passes with the new shutdown
  flush.
2026-04-22 13:19:53 +08:00
chengyongru
79821a571f fix: suppress intermediate progress output in cron jobs
Cron jobs now pass on_progress=_silent to process_direct, matching
the heartbeat pattern. Previously, tool hints and streaming deltas
were published to the user channel via bus during execution, but the
final response could be rejected by evaluate_response — leaving users
with confusing partial output and no conclusion.

Closes #3319
2026-04-20 11:43:54 +08:00
Xubin Ren
b3049f7323 fix(webui): stabilize empty session history state 2026-04-19 13:38:47 +00:00
Xubin Ren
384bad17b4 Merge origin/main into fix/config-default-api-base
Made-with: Cursor
2026-04-18 20:08:21 +00:00
Xubin Ren
2b8e90d8fd test(config): cover LM Studio nullable api key 2026-04-16 02:49:54 +08:00
Xubin Ren
e4b3f9bd28 security(gateway): keep health endpoint local by default
Bind the gateway health listener to localhost by default and reduce the probe response to a minimal status payload so accidental public exposure leaks less information.

Made-with: Cursor
2026-04-14 07:19:38 +00:00
Xubin Ren
4999e2f734 Merge origin/main into feat/health-endpoint
Keep the gateway health endpoint patch current with the latest gateway runtime changes, and lock the new HTTP routes in with CLI regression coverage and README guidance.

Made-with: Cursor
2026-04-14 06:32:31 +00:00
moranfong
0750d1f182 fix(config): return provider default api base in config resolution 2026-04-13 23:42:58 +08:00
Xubin Ren
c9d4b7b905 Merge remote-tracking branch 'origin/main' into pr-2449
Made-with: Cursor

# Conflicts:
#	nanobot/utils/evaluator.py
2026-04-06 06:30:11 +00:00
Ben Lenarts
202938ae73 feat: support ${VAR} env var interpolation in config secrets
Allow config.json to reference environment variables via ${VAR_NAME}
syntax. Variables are resolved at runtime by resolve_config_env_vars(),
keeping the raw templates in the Pydantic model so save_config()
preserves them. This lets secrets live in a separate env file
(e.g. loaded by systemd EnvironmentFile=) instead of plain text
in config.json.
2026-04-06 13:43:26 +08:00
RongLei
c5f0997381 fix: refresh copilot token before requests
Address PR review feedback by avoiding an async method reference as the OpenAI client api_key.

Initialize the client with a placeholder key, refresh the Copilot token before each chat/chat_stream call, and update the runtime client api_key before dispatch.

Add a regression test that verifies the client api_key is refreshed to a real string before chat requests.

Generated with GitHub Copilot, GPT-5.4.
2026-04-02 03:46:40 +08:00
RongLei
a37bc26ed3 fix: restore GitHub Copilot auth flow
Implement the real GitHub device flow and Copilot token exchange for the GitHub Copilot provider.

Also route github-copilot models through a dedicated backend and strip the provider prefix before API requests.

Add focused regression coverage for provider wiring and model normalization.

Generated with GitHub Copilot, GPT-5.4.
2026-04-02 03:46:40 +08:00
Xubin Ren
5635907e33 feat(api): load serve settings from config
Read serve host, port, and timeout from config by default, keep CLI flags higher priority, and bind the API to localhost by default for safer local usage.
2026-03-29 15:32:33 +00:00
MrBob
b26a93c14a fix: preserve cron reminder context for notifications 2026-03-24 15:56:23 -03:00
Xubin Ren
3dfdab704e refactor: replace litellm with native openai + anthropic SDKs
- Remove litellm dependency entirely (supply chain risk mitigation)
- Add AnthropicProvider (native SDK) and OpenAICompatProvider (unified)
- Merge CustomProvider into OpenAICompatProvider, delete custom_provider.py
- Add ProviderSpec.backend field for declarative provider routing
- Remove _resolve_model, find_gateway, find_by_model (dead heuristics)
- Pass resolved spec directly into provider — zero internal lookups
- Stub out litellm-dependent model database (cli/models.py)
- Add anthropic>=0.45.0 to dependencies, remove litellm
- 593 tests passed, net -1034 lines
2026-03-25 01:58:48 +08:00
chengyongru
72acba5d27 refactor(tests): optimize unit test structure 2026-03-24 15:12:22 +08:00