Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
221 commits
Select commit Hold shift + click to select a range
e09e485
fix(openviking): correct API endpoint paths and response parsing
catbusconductor Apr 4, 2026
5d0f55c
feat(cron): add script field for pre-run data collection (#5082)
teknium1 Apr 4, 2026
93aa01c
fix: use main provider model for auxiliary tasks on non-aggregator pr…
teknium1 Apr 4, 2026
28e1e21
fix(hindsight): overhaul hindsight memory plugin and memory setup wizard
cdbartholomew Apr 4, 2026
569e9f9
feat: execute_code runs on remote terminal backends (#5088)
teknium1 Apr 4, 2026
d86be33
feat(gateway): add MATRIX_REQUIRE_MENTION and MATRIX_AUTO_THREAD support
fxfitz Apr 4, 2026
2556cfd
fix(gateway): match Discord mention-stripping behavior in Matrix adapter
fxfitz Apr 4, 2026
55bbf8c
fix: include approval metadata in terminal tool results (#5141)
teknium1 Apr 4, 2026
96e96a7
fix: --yolo and other flags silently dropped when placed before 'chat…
teknium1 Apr 4, 2026
5879b3e
fix: move pre_llm_call plugin context to user message, preserve promp…
teknium1 Apr 4, 2026
aa475ae
feat: add exit code context for common CLI tools in terminal results …
teknium1 Apr 4, 2026
931624f
fix(security): guard cron script against path traversal and redact ou…
memosr Apr 4, 2026
ff54452
docs(skill): comprehensive claude-code skill rewrite v2.0 (#5155)
teknium1 Apr 5, 2026
c8220e6
fix: strip MEDIA: directives from streamed gateway messages (#5152)
teknium1 Apr 5, 2026
85cefc7
fix(telegram): prevent duplicate message delivery on send timeout (#5…
teknium1 Apr 5, 2026
0fd3de2
docs(skill): claude-code v2.2 — add cheat sheet commands, env vars, r…
teknium1 Apr 5, 2026
5b003ca
test(redact): add regression tests for lowercase variable redaction (…
teknium1 Apr 5, 2026
560c6ae
feat: add _should_sanitize_tool_calls() method
Apr 5, 2026
7f6e509
refactor: use _should_sanitize_tool_calls in flush_memories()
Apr 5, 2026
234c01f
refactor: use _should_sanitize_tool_calls in _handle_max_iterations()
Apr 5, 2026
d900358
refactor: use _should_sanitize_tool_calls in run_conversation()
Apr 5, 2026
9be2b18
test: add test for _should_sanitize_tool_calls()
Apr 5, 2026
8545343
test: add strict API validation tests for Fireworks compatibility
Apr 5, 2026
ed4a605
docs: update docstring to mention Fireworks strict validation
Apr 5, 2026
65952ac
Honor provider reset windows in pooled credential failover
kshitijk4poor Apr 5, 2026
4437354
Preserve numeric credential labels in auth removal
kshitijk4poor Apr 5, 2026
441ec48
style: use module-level re import instead of local import re as _re
teknium1 Apr 5, 2026
0c54da8
feat(gateway): live-stream /update output + interactive prompt button…
teknium1 Apr 5, 2026
cb63b5f
feat(skills): add popular-web-designs skill with 54 website design sy…
teknium1 Apr 5, 2026
4976a8b
feat: /model command — models.dev primary database + --provider flag …
teknium1 Apr 5, 2026
d932980
Add gitnexus-explorer optional skill (#5208)
teknium1 Apr 5, 2026
51ed7dc
feat: save oversized tool results to file instead of destructive trun…
teknium1 Apr 5, 2026
e899d6a
fix: increase default HERMES_AGENT_TIMEOUT from 10min to 30min
teknium1 Apr 5, 2026
35d280d
feat: coerce tool call arguments to match JSON Schema types (#5265)
teknium1 Apr 5, 2026
70f7980
fix: Ollama Cloud auth, /model switch persistence, and alias tab comp…
LucidPaths Apr 5, 2026
914f746
fix: add missing shutil import for Matrix E2EE setup
thakoreh Apr 5, 2026
9d7c288
fix(matrix): add filesize to nio.upload() for Synapse compatibility
pjay-io Apr 5, 2026
b65e675
fix(gateway): stop Matrix/Mattermost reconnect on permanent auth fail…
binhnt92 Apr 5, 2026
bec02f3
fix(matrix): handle encrypted media events and cache decrypted attach…
chalkers Apr 5, 2026
36e046e
fix(gateway): MIME type fallback for Matrix document uploads
dlkakbs Apr 5, 2026
c100ad8
fix(matrix): E2EE cron delivery via live adapter + HTML formatting + …
teknium1 Apr 5, 2026
20b4060
fix: web_extract fast-fail on scrape timeout + summarizer resilience
teknium1 Apr 5, 2026
534511b
feat(matrix): Tier 1 enhancement — reactions, read receipts, rich for…
nepenth Apr 5, 2026
a0a1b86
fix: accept reasoning-only responses without retries — set content to…
teknium1 Apr 5, 2026
54cb311
fix: suppress false 'Unknown toolsets' warning for MCP server names (…
teknium1 Apr 5, 2026
daa4a5a
feat: add docs links to setup wizard sections (#5283)
teknium1 Apr 5, 2026
5ff514e
fix(security): remove full traceback from cron error output to preven…
Apr 4, 2026
7f853ba
fix: use logger.exception to preserve traceback in logs and drop unus…
Apr 5, 2026
507b63f
fix(api-server): pass fallback_model to AIAgent (#4954)
bugkill3r Apr 4, 2026
4df2fca
fix(gateway): cap memory flush retries at 3 to prevent infinite loop
nibzard Apr 5, 2026
6df0f07
fix: /status command bypasses active-session guard during agent run (…
teyrebaz33 Apr 4, 2026
abf1be5
fix(deps): include telegram webhook extra in messaging installs (#4915)
bg-l2norm Apr 4, 2026
aab74b5
fix(gateway): replace deprecated launchctl start/stop with kickstart/…
tmchow Apr 3, 2026
74ff62f
fix(gateway): use kickstart -k for atomic launchd restart
tmchow Apr 5, 2026
1d2e34c
Prevent Telegram polling handoffs and flood-control send failures
kshitijk4poor Apr 5, 2026
afccbf2
fix: resolve listed messaging targets consistently
damianpdr Apr 5, 2026
4a75aec
fix(gateway): resolve Telegram's underscored /commands to skill/plugi…
Apr 5, 2026
e8053e8
fix(gateway): surface unknown /commands instead of leaking them to th…
Apr 5, 2026
6a6ae9a
fix(gateway): correct misleading log text for unknown /commands
Apr 5, 2026
0c95e91
fix: follow-up fixes for salvaged PRs
teknium1 Apr 5, 2026
6ee90a7
fix: hermes auth remove now clears env-seeded credentials permanently…
teknium1 Apr 5, 2026
914a7db
fix(acp): rename AuthMethod to AuthMethodAgent for agent-client-proto…
teknium1 Apr 5, 2026
fcdd544
fix: keep ACP stdout protocol-clean
Git-on-my-level Apr 5, 2026
c71b1d1
fix(acp): advertise slash commands via ACP protocol
NexVeridian Apr 5, 2026
e167ad8
feat(delegate): add acp_command/acp_args override to delegate_task
Mibayy Apr 5, 2026
cc2b56b
feat(api): structured run events via /v1/runs SSE endpoint
Mibayy Apr 5, 2026
c6793d6
fix(gateway): wrap cron helpers with staticmethod to prevent self-bin…
MichaelWDanko Apr 5, 2026
ef3bd3b
security(approval): fix privilege escalation in gateway once-approval…
Xowiek Apr 3, 2026
1ebc932
fix(security): validate cron deliver platform name to prevent env var…
maymuneth Apr 4, 2026
71a4582
fix(security): hoist platform allowlist to module scope as frozenset
maymuneth Apr 5, 2026
567bc79
fix: clean up cron platform allowlist — add homeassistant, fix import…
teknium1 Apr 5, 2026
12724e6
feat: progressive subdirectory hint discovery (#5291)
teknium1 Apr 5, 2026
c02c3dc
fix(honcho): plugin drift overhaul -- observation config, chunking, s…
erosika Apr 5, 2026
dd8a42b
feat(plugins): plugin CLI registration system — decouple plugin comma…
teknium1 Apr 5, 2026
b074b0b
test: add plugin CLI registration tests
teknium1 Apr 5, 2026
0f813c4
fix(plugins): only register CLI commands for the active memory provider
teknium1 Apr 5, 2026
583d9f9
fix(honcho): migration guard for observation mode default change
teknium1 Apr 5, 2026
66d0fa1
fix: avoid unnecessary Discord members intent on startup
abhey-gupta Apr 3, 2026
8d52267
fix: add missing ButtonStyle.grey to discord mock for test compatibility
teknium1 Apr 5, 2026
b63fb03
feat(browser): add JS evaluation via browser_console expression param…
teknium1 Apr 5, 2026
4494fba
feat: OSV malware check for MCP extension packages (#5305)
teknium1 Apr 5, 2026
efa03fc
docs: update honcho CLI reference + document plugin CLI registration …
teknium1 Apr 5, 2026
7409715
fix: link subagent sessions to parent and hide from session list
donrhmexe Apr 4, 2026
9d885b2
feat(skills): add manim-video skill for mathematical and technical an…
SHL0MS Apr 4, 2026
1572956
Merge pull request #4930 from SHL0MS/feat/manim-video-skill-v2
SHL0MS Apr 5, 2026
2563493
fix: improve timeout debug logging and user-facing diagnostics (#5370)
teknium1 Apr 6, 2026
e9ddfee
fix(plugins): reject plugin names that resolve to the plugins root
Dusk1e Apr 6, 2026
fc15f56
feat: warn users when loading non-agentic Hermes LLM models (#5378)
teknium1 Apr 6, 2026
8972eb0
docs: add comprehensive Discord configuration reference (#5386)
teknium1 Apr 6, 2026
fec58ad
fix(gateway): replace wall-clock agent timeout with inactivity-based …
teknium1 Apr 6, 2026
43d468c
docs: comprehensive documentation audit — fix stale info, expand thin…
teknium1 Apr 6, 2026
89c812d
feat: shared thread sessions by default — multi-user thread support (…
teknium1 Apr 6, 2026
447ec07
docs(manim-video): expand references with comprehensive Manim CE and …
SHL0MS Apr 6, 2026
084cd1f
Merge pull request #5408 from SHL0MS/feat/manim-skill-improvements
SHL0MS Apr 6, 2026
b26e7fd
fix(manim-video): recommend monospace fonts — proportional fonts have…
SHL0MS Apr 6, 2026
4e196a5
Merge pull request #5411 from SHL0MS/fix/manim-monospace-fonts
SHL0MS Apr 6, 2026
0efe7da
feat: add GPT/Codex execution discipline guidance for tool persistenc…
teknium1 Apr 6, 2026
0365f62
feat: show model pricing for OpenRouter and Nous Portal providers
jquesnelle Apr 3, 2026
3962bc8
show cache pricing as well (if supported)
jquesnelle Apr 6, 2026
38d8446
feat: implement MCP OAuth 2.1 PKCE client support (#5420)
teknium1 Apr 6, 2026
95a044a
feat(research-paper-writing): fill coverage gaps and integrate patter…
SHL0MS Apr 6, 2026
033e971
Merge pull request #5421 from NousResearch/fix/research-paper-writing…
SHL0MS Apr 6, 2026
aa56df0
fix: allow env var overrides for Nous portal/inference URLs (#5419)
teknium1 Apr 6, 2026
ab086a3
chore: remove qwen-3.6 free from nous portal model list
teknium1 Apr 6, 2026
7869709
fix(cli): add missing subprocess.run() timeouts in gateway CLI (#5424)
teknium1 Apr 6, 2026
9ca954a
fix: mem0 API v2 compat, prefetch context fencing, secret redaction (…
teknium1 Apr 6, 2026
dce5f51
feat: config structure validation — detect malformed YAML at startup …
teknium1 Apr 6, 2026
9e820dd
Add request-scoped plugin lifecycle hooks
kshitijk4poor Mar 29, 2026
f530ef1
feat(plugins): pre_api_request/post_api_request with narrow payloads
kshitijk4poor Apr 6, 2026
38bcaa1
chore: remove langfuse doc, smoketest script, and installed-plugin test
kshitijk4poor Apr 6, 2026
dc9c3ca
chore: remove redundant local import of normalize_usage
teknium1 Apr 6, 2026
d6ef7fd
fix(cron): replace wall-clock timeout with inactivity-based timeout (…
teknium1 Apr 6, 2026
89db3ae
fix(cron): add delivery guidance to cron prompt — stop send_message t…
teknium1 Apr 6, 2026
9c96f66
feat: centralized logging, instrumentation, hermes logs CLI, gateway …
teknium1 Apr 6, 2026
a2a9ad7
fix: hermes update kills freshly-restarted gateway service
kshitijk4poor Apr 6, 2026
d3d5b89
refactor: simplify _get_service_pids — dedupe systemd scopes, fix sel…
kshitijk4poor Apr 6, 2026
6c12999
fix: bridge tool-calls in copilot-acp adapter
MestreY0d4-Uninter Apr 6, 2026
6df4860
fix(retaindb): fix API routes, add write queue, dialectic, agent mode…
Apr 6, 2026
ea8ec27
fix(retaindb): make project optional, default to 'default' project
Apr 6, 2026
5747590
fix: follow-up improvements for salvaged PR #5456
teknium1 Apr 6, 2026
6f1cb46
fix: register /queue, /background, /btw as native Discord slash comma…
teknium1 Apr 6, 2026
79aeaa9
fix: re-order providers,Quick Install, subscription polling
austinpickett Apr 2, 2026
eceb89b
Merge pull request #4664 from NousResearch/fix/various-qa
austinpickett Apr 6, 2026
85973e0
fix(nous): don't use OAuth access_token as inference API key
SHL0MS Apr 6, 2026
6dfab35
feat(providers): add Google AI Studio (Gemini) as a first-class provider
teknium1 Apr 6, 2026
cc7136b
fix: update Gemini model catalog + wire models.dev as live model source
teknium1 Apr 6, 2026
a912cd4
docs(manim-video): add 5 new reference files — design thinking, updat…
SHL0MS Apr 6, 2026
0bac07d
Merge pull request #5588 from SHL0MS/feat/manim-skill-deep-expansion
SHL0MS Apr 6, 2026
582dbbb
feat: add grok to TOOL_USE_ENFORCEMENT_MODELS for direct xAI usage (#…
teknium1 Apr 6, 2026
f77be22
Fix #5211: Preserve dots in OpenCode Go model names
ClintonEmok Apr 6, 2026
214e60c
fix: sanitize Telegram command names to strip invalid characters
kshitijk4poor Apr 6, 2026
17e2a27
feat(skills): add p5js creative coding skill
SHL0MS Apr 6, 2026
5e88eb2
fix(signal): implement send_image_file, send_voice, and send_video fo…
kshitijk4poor Apr 6, 2026
3d08a2f
fix: extract MEDIA: tags from cron delivery before sending (#5598)
teknium1 Apr 6, 2026
0afa3a8
Merge pull request #5600 from SHL0MS/feat/p5js-skill
SHL0MS Apr 6, 2026
92c1992
feat: add xAI prompt caching via x-grok-conv-id header
julientalbot-ergonomia Apr 6, 2026
8ffd44a
feat(discord): register skills as native slash commands via shared ga…
teknium1 Apr 6, 2026
da02a4e
fix: auxiliary client payment fallback — retry with next provider on …
teknium1 Apr 6, 2026
7d0953d
security(gateway): isolate env/credential registries using ContextVars
Apr 6, 2026
878b1d3
fix(cron): harden scheduler against path traversal and env leaks
Apr 6, 2026
261e2ee
fix: restore Path import in env_passthrough.py (removed by #5526)
teknium1 Apr 6, 2026
537a2b8
docs: add WSL2 networking guide for local model servers (#5616)
teknium1 Apr 6, 2026
af9a9f7
fix(security): sanitize workdir parameter in terminal tool backends
entropidelic Apr 6, 2026
1a2f109
Ensure atomic writes for gateway channel directory cache to prevent t…
Dusk1e Apr 6, 2026
96f85b0
fix: handle launchctl kickstart exit code 113 in launchd_start()
A-kamal Apr 6, 2026
ff655de
fix: model alias fallback uses authenticated providers instead of har…
donrhmexe Apr 6, 2026
ad567c9
fix: subagent toolset inheritance when parent enabled_toolsets is None
BongSuCHOI Apr 6, 2026
2c814d7
fix: /model --global writes model.name instead of model.default
donrhmexe Apr 6, 2026
9afb9a6
fix: clear session-scoped model overrides during session reset
mikiilis Apr 6, 2026
29b5ec2
fix: clear session-scoped model after session reset
mikiilis Apr 6, 2026
150f70f
feat(skills): add skill config interface + llm-wiki skill (#5635)
teknium1 Apr 6, 2026
7b12963
feat(tools): add Firecrawl cloud browser provider (#5628)
alt-glitch Apr 6, 2026
e651e04
fix(nix): read version, regen uv.lock, fix packages.nix to add hermes…
alt-glitch Apr 6, 2026
5396299
docs(llm-wiki): add Obsidian Headless setup for servers (#5660)
teknium1 Apr 6, 2026
9201370
feat(plugins): prompt for required env vars during hermes plugins ins…
kshitijk4poor Apr 6, 2026
631d159
fix: use display_hermes_home() for profile-aware paths in plugin env …
teknium1 Apr 6, 2026
4f03b9a
feat(webhook): add {__raw__} template token and thread_id passthrough…
Apr 5, 2026
f071b18
docs: document rich requires_env format and install-time prompting
teknium1 Apr 6, 2026
e769852
fix(openviking): add atexit safety net for session commit
dagbs Apr 6, 2026
e131f13
fix(doctor): use recall_mode instead of memory_mode on HonchoClientCo…
techguysimon Apr 6, 2026
7761096
Lower Telegram fallback activation log to info
MadKangYu Apr 6, 2026
3b4dfc8
fix(tools): portable base64 encoding for image reading on macOS
CharlieKerfoot Apr 6, 2026
ea16949
fix(cron): suppress delivery when [SILENT] appears anywhere in response
auspic7 Apr 6, 2026
0f9aa57
fix: silent memory flush failure on /new and /resume commands
ryanautomated Apr 6, 2026
3282b70
fix(mattermost): set message type to DOCUMENT when post has file atta…
nericervin Apr 6, 2026
f3ae249
fix: detect correct message type from file mime instead of blanket DO…
nericervin Apr 6, 2026
c1818b7
fix(tools): redact query secrets in send_message errors
WAXLYY Apr 6, 2026
e9b5864
fix: multiple platform adaptors concurrency
CharlieKerfoot Apr 6, 2026
b26e85b
Fix compaction summary retries for temperature-restricted models
MadKangYu Apr 6, 2026
1c0183e
fix(gateway): sanitize media URLs in base platform logs
WAXLYY Apr 6, 2026
83df001
fix: allow google-workspace skill scripts to run directly
xinbenlv Apr 6, 2026
190471f
docs: use HERMES_HOME in google-workspace skill examples
xinbenlv Apr 6, 2026
40527ff
fix(auth): actionable error message when Codex refresh token is reused
tymrtn Apr 6, 2026
05f9267
fix(matrix): hard-fail E2EE when python-olm missing + stable MATRIX_D…
kshitijk4poor Apr 6, 2026
8a29b49
fix(cli): handle CJK wide chars in TUI input height
Apr 6, 2026
abd24d3
Implement comprehensive browser path discovery for Windows
Ruzzgar Apr 6, 2026
7cf4bd0
fix(gateway): fix Feishu reconnect message drops and shutdown hang
jtuki Apr 5, 2026
7d0bf15
feat(gateway): add configurable Feishu websocket reconnect timing
jtuki Apr 5, 2026
ea31d90
feat(gateway): add Feishu websocket ping timing overrides
jtuki Apr 5, 2026
157d618
fix(gateway): make Feishu websocket overrides effective at runtime
jtuki Apr 5, 2026
18727ca
refactor(gateway): simplify Feishu websocket config helpers
jtuki Apr 5, 2026
57abc99
feat(gateway): add per-group access control for Feishu
jtuki Apr 6, 2026
adb418f
fix: cross-platform browser test path separators
teknium1 Apr 6, 2026
8cf013e
fix: replace stale 'hermes login' refs with 'hermes auth' + fix crede…
teknium1 Apr 7, 2026
dc4c07e
fix: codex OAuth credential pool disconnect + expired token import (#…
teknium1 Apr 7, 2026
e5aaa38
fix: sync openai-codex pool entry from ~/.codex/auth.json on exhausti…
GratefulDave Apr 7, 2026
0e336b0
fix: backfill codex stream output from output_item.done events (#5689)
teknium1 Apr 7, 2026
2021442
fix: cover remaining codex empty-output gaps in fallback + normalizer…
teknium1 Apr 7, 2026
21b48b2
fix: backfill empty codex output in auxiliary client (#5730)
teknium1 Apr 7, 2026
a23fcae
docs: add 'setup' command to docker run example
mrhwick Apr 7, 2026
bccd7d0
docs: add post-update validation guidance
submit77 Apr 7, 2026
9ce8d59
docs: add local LLM on Mac guide (llama.cpp + MLX)
omniwired Apr 7, 2026
43cf680
docs: fix signal-cli install instructions
AndrianAQZ Apr 7, 2026
9b6e5f6
fix(gateway): Apply markdown-to-mrkdwn conversion in edit_message
eizus Apr 6, 2026
4ec615b
feat(gateway): Enable Slack thread replies without explicit @mentions
eizus Apr 6, 2026
888dc1e
fix: harden auxiliary codex adapter — dict-shaped items + tool call g…
teknium1 Apr 7, 2026
972482e
docs: guides section overhaul — fix existing + add 3 new tutorials (#…
teknium1 Apr 7, 2026
76f1977
feat(memory): add Supermemory memory provider
Apr 5, 2026
dc33338
docs(memory): add Supermemory PR draft and cleanup
Apr 5, 2026
4fc7f3e
fix(memory): clean up supermemory provider threads
Apr 5, 2026
ac80d59
chore(memory): remove supermemory PR scaffolding
Apr 6, 2026
88bba31
fix: use get_hermes_home() for profile-scoped storage, fix README
teknium1 Apr 7, 2026
c776813
docs: add Supermemory to memory providers docs, env vars, CLI reference
teknium1 Apr 7, 2026
bff47ee
fix: HERMES_PORTAL_BASE_URL env var ignored during Nous login
benbarclay Apr 7, 2026
5a2cf28
feat: interactive model picker for Telegram and Discord (#5742)
teknium1 Apr 7, 2026
8dee82e
fix: stream consumer creates new message after tool boundaries (#5739)
teknium1 Apr 7, 2026
f2c11ff
fix(delegate): share credential pools with subagents + per-task leasing
Apr 7, 2026
c706568
fix(delegate): pass workspace path hints to child agents
Apr 7, 2026
8e64f79
fix: stale OAuth credentials block OpenRouter users on auto-detect (#…
teknium1 Apr 7, 2026
2b79569
fix(discord): remove default selection from model picker provider dro…
teknium1 Apr 7, 2026
3bc2fe8
feat(telegram): paginated model picker with Next/Prev navigation
teknium1 Apr 7, 2026
f609bf2
feat: update blogwatcher skill to JulienTant's fork (#5759)
teknium1 Apr 7, 2026
9e84416
fix(credential_pool): auto-detect Z.AI endpoint via probe and cache
SeeYangZhi Apr 6, 2026
eb7c408
fix(gateway): /stop and /new bypass Level 1 active-session guard (#5765)
teknium1 Apr 7, 2026
302240d
Merge pull request #5745 from NousResearch/fix/portal-env-var-ignored…
benbarclay Apr 7, 2026
d9e7e42
fix(approval): load permanent command allowlist on startup (#5076)
teknium1 Apr 7, 2026
1c425f2
fix(cli): defer response content until reasoning block completes (#5773)
teknium1 Apr 7, 2026
e120d2a
feat: notify_on_complete for background processes (#5779)
teknium1 Apr 7, 2026
cafdfd3
fix: sync bundled skills to default profile when updating from a name…
teknium1 Apr 7, 2026
8b861b7
refactor: remove browser_close tool — auto-cleanup handles it (#5792)
teknium1 Apr 7, 2026
937720b
fix: gracefully handle missing systemctl in container environments
dashed Apr 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 10 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@
# LLM_MODEL is no longer read from .env — this line is kept for reference only.
# LLM_MODEL=anthropic/claude-opus-4.6

# =============================================================================
# LLM PROVIDER (Google AI Studio / Gemini)
# =============================================================================
# Native Gemini API via Google's OpenAI-compatible endpoint.
# Get your key at: https://aistudio.google.com/app/apikey
# GOOGLE_API_KEY=your_google_ai_studio_key_here
# GEMINI_API_KEY=your_gemini_key_here # alias for GOOGLE_API_KEY
# Optional base URL override (default: Google's OpenAI-compatible endpoint)
# GEMINI_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai

# =============================================================================
# LLM PROVIDER (z.ai / GLM)
# =============================================================================
Expand Down
12 changes: 8 additions & 4 deletions acp_adapter/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,18 @@ def make_tool_progress_cb(

Signature expected by AIAgent::

tool_progress_callback(name: str, preview: str, args: dict)
tool_progress_callback(event_type: str, name: str, preview: str, args: dict, **kwargs)

Emits ``ToolCallStart`` for each tool invocation and tracks IDs in a FIFO
Emits ``ToolCallStart`` for ``tool.started`` events and tracks IDs in a FIFO
queue per tool name so duplicate/parallel same-name calls still complete
against the correct ACP tool call.
against the correct ACP tool call. Other event types (``tool.completed``,
``reasoning.available``) are silently ignored.
"""

def _tool_progress(name: str, preview: str, args: Any = None) -> None:
def _tool_progress(event_type: str, name: str = None, preview: str = None, args: Any = None, **kwargs) -> None:
# Only emit ACP ToolCallStart for tool.started; ignore other event types
if event_type != "tool.started":
return
if isinstance(args, str):
try:
args = json.loads(args)
Expand Down
150 changes: 134 additions & 16 deletions acp_adapter/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
from acp.schema import (
AgentCapabilities,
AuthenticateResponse,
AuthMethod,
AvailableCommand,
AvailableCommandsUpdate,
ClientCapabilities,
EmbeddedResourceContentBlock,
ForkSessionResponse,
Expand All @@ -37,9 +38,16 @@
SessionListCapabilities,
SessionInfo,
TextContentBlock,
UnstructuredCommandInput,
Usage,
)

# AuthMethodAgent was renamed from AuthMethod in agent-client-protocol 0.9.0
try:
from acp.schema import AuthMethodAgent
except ImportError:
from acp.schema import AuthMethod as AuthMethodAgent # type: ignore[attr-defined]

from acp_adapter.auth import detect_provider, has_provider
from acp_adapter.events import (
make_message_cb,
Expand Down Expand Up @@ -84,6 +92,48 @@ def _extract_text(
class HermesACPAgent(acp.Agent):
"""ACP Agent implementation wrapping Hermes AIAgent."""

_SLASH_COMMANDS = {
"help": "Show available commands",
"model": "Show or change current model",
"tools": "List available tools",
"context": "Show conversation context info",
"reset": "Clear conversation history",
"compact": "Compress conversation context",
"version": "Show Hermes version",
}

_ADVERTISED_COMMANDS = (
{
"name": "help",
"description": "List available commands",
},
{
"name": "model",
"description": "Show current model and provider, or switch models",
"input_hint": "model name to switch to",
},
{
"name": "tools",
"description": "List available tools with descriptions",
},
{
"name": "context",
"description": "Show conversation message counts by role",
},
{
"name": "reset",
"description": "Clear conversation history",
},
{
"name": "compact",
"description": "Compress conversation context",
},
{
"name": "version",
"description": "Show Hermes version",
},
)

def __init__(self, session_manager: SessionManager | None = None):
super().__init__()
self.session_manager = session_manager or SessionManager()
Expand Down Expand Up @@ -177,7 +227,7 @@ async def initialize(
auth_methods = None
if provider:
auth_methods = [
AuthMethod(
AuthMethodAgent(
id=provider,
name=f"{provider} runtime credentials",
description=f"Authenticate Hermes using the currently configured {provider} runtime credentials.",
Expand Down Expand Up @@ -219,6 +269,7 @@ async def new_session(
state = self.session_manager.create_session(cwd=cwd)
await self._register_session_mcp_servers(state, mcp_servers)
logger.info("New session %s (cwd=%s)", state.session_id, cwd)
self._schedule_available_commands_update(state.session_id)
return NewSessionResponse(session_id=state.session_id)

async def load_session(
Expand All @@ -234,6 +285,7 @@ async def load_session(
return None
await self._register_session_mcp_servers(state, mcp_servers)
logger.info("Loaded session %s", session_id)
self._schedule_available_commands_update(session_id)
return LoadSessionResponse()

async def resume_session(
Expand All @@ -249,6 +301,7 @@ async def resume_session(
state = self.session_manager.create_session(cwd=cwd)
await self._register_session_mcp_servers(state, mcp_servers)
logger.info("Resumed session %s", state.session_id)
self._schedule_available_commands_update(state.session_id)
return ResumeSessionResponse()

async def cancel(self, session_id: str, **kwargs: Any) -> None:
Expand All @@ -274,6 +327,8 @@ async def fork_session(
if state is not None:
await self._register_session_mcp_servers(state, mcp_servers)
logger.info("Forked session %s -> %s", session_id, new_id)
if new_id:
self._schedule_available_commands_update(new_id)
return ForkSessionResponse(session_id=new_id)

async def list_sessions(
Expand Down Expand Up @@ -411,15 +466,50 @@ def _run_agent() -> dict:

# ---- Slash commands (headless) -------------------------------------------

_SLASH_COMMANDS = {
"help": "Show available commands",
"model": "Show or change current model",
"tools": "List available tools",
"context": "Show conversation context info",
"reset": "Clear conversation history",
"compact": "Compress conversation context",
"version": "Show Hermes version",
}
@classmethod
def _available_commands(cls) -> list[AvailableCommand]:
commands: list[AvailableCommand] = []
for spec in cls._ADVERTISED_COMMANDS:
input_hint = spec.get("input_hint")
commands.append(
AvailableCommand(
name=spec["name"],
description=spec["description"],
input=UnstructuredCommandInput(hint=input_hint)
if input_hint
else None,
)
)
return commands

async def _send_available_commands_update(self, session_id: str) -> None:
"""Advertise supported slash commands to the connected ACP client."""
if not self._conn:
return

try:
await self._conn.session_update(
session_id=session_id,
update=AvailableCommandsUpdate(
sessionUpdate="available_commands_update",
availableCommands=self._available_commands(),
),
)
except Exception:
logger.warning(
"Failed to advertise ACP slash commands for session %s",
session_id,
exc_info=True,
)

def _schedule_available_commands_update(self, session_id: str) -> None:
"""Send the command advertisement after the session response is queued."""
if not self._conn:
return
loop = asyncio.get_running_loop()
loop.call_soon(
asyncio.create_task, self._send_available_commands_update(session_id)
)

def _handle_slash_command(self, text: str, state: SessionState) -> str | None:
"""Dispatch a slash command and return the response text.
Expand Down Expand Up @@ -539,11 +629,39 @@ def _cmd_compact(self, args: str, state: SessionState) -> str:
return "Nothing to compress — conversation is empty."
try:
agent = state.agent
if hasattr(agent, "compress_context"):
agent.compress_context(state.history)
self.session_manager.save_session(state.session_id)
return f"Context compressed. Messages: {len(state.history)}"
return "Context compression not available for this agent."
if not getattr(agent, "compression_enabled", True):
return "Context compression is disabled for this agent."
if not hasattr(agent, "_compress_context"):
return "Context compression not available for this agent."

from agent.model_metadata import estimate_messages_tokens_rough

original_count = len(state.history)
approx_tokens = estimate_messages_tokens_rough(state.history)
original_session_db = getattr(agent, "_session_db", None)

try:
# ACP sessions must keep a stable session id, so avoid the
# SQLite session-splitting side effect inside _compress_context.
agent._session_db = None
compressed, _ = agent._compress_context(
state.history,
getattr(agent, "_cached_system_prompt", "") or "",
approx_tokens=approx_tokens,
task_id=state.session_id,
)
finally:
agent._session_db = original_session_db

state.history = compressed
self.session_manager.save_session(state.session_id)

new_count = len(state.history)
new_tokens = estimate_messages_tokens_rough(state.history)
return (
f"Context compressed: {original_count} -> {new_count} messages\n"
f"~{approx_tokens:,} -> ~{new_tokens:,} tokens"
)
except Exception as e:
return f"Compression failed: {e}"

Expand Down
18 changes: 17 additions & 1 deletion acp_adapter/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import copy
import json
import logging
import sys
import uuid
from dataclasses import dataclass, field
from threading import Lock
Expand All @@ -21,6 +22,17 @@
logger = logging.getLogger(__name__)


def _acp_stderr_print(*args, **kwargs) -> None:
"""Best-effort human-readable output sink for ACP stdio sessions.

ACP reserves stdout for JSON-RPC frames, so any incidental CLI/status output
from AIAgent must be redirected away from stdout. Route it to stderr instead.
"""
kwargs = dict(kwargs)
kwargs.setdefault("file", sys.stderr)
print(*args, **kwargs)


def _register_task_cwd(task_id: str, cwd: str) -> None:
"""Bind a task/session id to the editor's working directory for tools."""
if not task_id:
Expand Down Expand Up @@ -458,4 +470,8 @@ def _make_agent(
logger.debug("ACP session falling back to default provider resolution", exc_info=True)

_register_task_cwd(session_id, cwd)
return AIAgent(**kwargs)
agent = AIAgent(**kwargs)
# ACP stdio transport requires stdout to remain protocol-only JSON-RPC.
# Route any incidental human-readable agent output to stderr instead.
agent._print_fn = _acp_stderr_print
return agent
1 change: 0 additions & 1 deletion acp_adapter/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
"browser_scroll": "execute",
"browser_press": "execute",
"browser_back": "execute",
"browser_close": "execute",
"browser_get_images": "read",
# Agent internals
"delegate_task": "execute",
Expand Down
Loading
Loading