Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
227 commits
Select commit Hold shift + click to select a range
95dc9aa
feat: add managed tool gateway and Nous subscription support
rewbs Mar 26, 2026
e95965d
Merge branch 'main' into rewbs/tool-use-charge-to-subscription
rewbs Mar 26, 2026
1cbb1b9
Gate tool-gateway behind an env var, so it's not in users' faces unti…
rewbs Mar 30, 2026
8210e7a
Optimize Dockerfile: combine RUN commands, clear caches, add .dockeri…
Mar 30, 2026
fdef045
Merge branch 'NousResearch:main' into docker-optimization
bcross Mar 30, 2026
48942c8
Further npm optimizations
bcross Mar 30, 2026
5de312c
Simplify dockerignore
bcross Mar 30, 2026
4f4d7c4
Merge branch 'NousResearch:main' into docker-optimization
bcross Mar 30, 2026
3a1e489
Add build-essential to Dockerfile dependencies
bcross Mar 30, 2026
0287597
Optimize Playwright install
Mar 30, 2026
6e4598c
Merge branch 'main' into rewbs/tool-use-charge-to-subscription
rewbs Mar 30, 2026
1126284
Merge branch 'main' into rewbs/tool-use-charge-to-subscription
rewbs Mar 31, 2026
1b7473e
Fixes and refactors enabled by recent updates to main.
rewbs Mar 31, 2026
289df5d
Merge branch 'NousResearch:main' into docker-optimization
bcross Mar 31, 2026
6dcc333
fix(security): add missing GitHub OAuth token patterns and snapshot r…
dlkakbs Mar 30, 2026
fad3f33
fix: patch _REDACT_ENABLED in test fixture for module-level snapshot
teknium1 Mar 31, 2026
cca0996
fix(browser): skip SSRF check for local backends (Camofox, headless C…
teknium1 Mar 31, 2026
84a541b
feat: support * wildcard in platform allowlists and improve WhatsApp …
teknium1 Mar 31, 2026
49d7210
fix(gateway): parse thread_id from delivery target format
MacroAnarchy Mar 30, 2026
c1606ae
fix(cli): allow empty strings and falsy values in config set
dsr-restyn Mar 31, 2026
0240baa
fix: strip orphaned think/reasoning tags from user-facing responses
arasovic Mar 31, 2026
5762532
docs+feat: comprehensive local LLM provider guides and context length…
teknium1 Mar 31, 2026
143b74e
fix: first-run guard stuck in loop when provider configured via confi…
teknium1 Mar 31, 2026
161acb0
fix: credential pool 401 recovery rotates to next credential after fa…
teknium1 Mar 31, 2026
e75964d
fix: harden codex responses transport handling
curtitoo Mar 31, 2026
cac9d20
test: add codex transport drop regression
curtitoo Mar 31, 2026
7f670a0
feat: add --max-turns CLI flag to hermes chat
teknium1 Mar 31, 2026
08171c1
fix: allow voice mode in WSL when PulseAudio bridge is configured
0xbyt4 Mar 30, 2026
0f2ea20
fix(profiles): validate tar archive member paths on import
Mar 31, 2026
a97641b
fix(security): reject path traversal in credential file registration
Mar 30, 2026
7f78dee
fix: apply same path traversal checks to config-based credential files
teknium1 Mar 31, 2026
c94a5fa
fix(cli): use atomic write in save_config_value to prevent config los…
binhnt92 Mar 31, 2026
655eea2
fix(security): protect .docker, .azure, and .config/gh from read and …
Mar 31, 2026
d3f1987
fix(security): add .config/gh to read protection for @file references…
teknium1 Mar 31, 2026
e3f8347
feat(file_tools): harden read_file with size guard, dedup, and device…
teknium1 Mar 31, 2026
1b62ad9
fix: root-level provider in config.yaml no longer overrides model.pro…
teknium1 Mar 31, 2026
f5cc597
fix: add CAMOFOX_PORT=9377 to Docker commands for camofox-browser (#4…
teknium1 Mar 31, 2026
f049860
feat(file_tools): detect stale files on write and patch (#4345)
teknium1 Mar 31, 2026
b118f60
feat(skills): unify hermes-agent and hermes-agent-setup into single s…
teknium1 Mar 31, 2026
f8cb54b
fix(cli): anchor input prompt near bottom of terminal after responses…
teknium1 Mar 31, 2026
c36aa5f
Merge pull request #4034 from bcross/docker-optimization
benbarclay Mar 31, 2026
3604665
feat: add qwen/qwen3.6-plus-preview:free to OpenRouter and Nous model…
teknium1 Apr 1, 2026
0a6d366
fix(security): redact secrets from execute_code sandbox output
teknium1 Apr 1, 2026
f4d44c7
feat(discord): only create threads and reactions for authorized users
lbatalha Mar 31, 2026
83dec2b
fix: skip empty/whitespace text in Telegram send to prevent 400 errors
SHL0MS Mar 31, 2026
ef2ae3e
fix(file_tools): refresh staleness timestamp after writes (#4390)
teknium1 Apr 1, 2026
a7f7e87
fix: preserve credential_pool through smart routing and defer eager f…
teknium1 Apr 1, 2026
9b99ea1
fix(cli): initialize ctx_len before compact banner path
Johannnnn506 Mar 31, 2026
efa327a
fix: add missing provider attrs to cli_obj test fixture
teknium1 Apr 1, 2026
7baee0b
fix(docs): restrict backdrop-filter to desktop to fix mobile sidebar
xsmyile Mar 31, 2026
8327f7c
fix(docs): use compound selector instead of media query
xsmyile Mar 31, 2026
9a581bb
fix(gateway): resume agent after /approve executes blocked command
Mar 31, 2026
afa75a6
fix(client): handle is_closed as method in OpenAI SDK
Bartok9 Apr 1, 2026
996250d
fix(cli): pin entire TUI to bottom of terminal on startup (#4412)
teknium1 Apr 1, 2026
f04977f
fix(cli): support exporting the default root profile (#4366)
devorun Mar 31, 2026
68fc4ae
fix: comprehensive default profile export exclusions and import guard
teknium1 Apr 1, 2026
935137f
feat: add inline diff previews for write actions
kshitijk4poor Apr 1, 2026
c9dc6c4
fix(insights): show cache tokens in overview so total adds up (#4428)
teknium1 Apr 1, 2026
85e96a4
fix(skills): move unified hermes-agent skill into autonomous-ai-agent…
teknium1 Apr 1, 2026
70744ad
feat(browser): add persistent Camofox sessions and VNC URL discovery …
teknium1 Apr 1, 2026
f6ada27
feat(skills): size limits for agent writes + fuzzy matching for patch…
teknium1 Apr 1, 2026
e0abf24
fix: restore _config_version to 11 (reverted by stale-branch merge in…
teknium1 Apr 1, 2026
e905768
fix(gateway): remap HERMES_HOME to target user in system service unit
deankerr Apr 1, 2026
3400098
fix: update fetch_transcript.py for youtube-transcript-api v1.x
Apr 1, 2026
5bd01b8
fix(gateway): wire -v/-q flags to stderr logging
alanjds Apr 1, 2026
bacc86d
fix: use RedactingFormatter on stderr handler, update types and test …
teknium1 Apr 1, 2026
d435acc
fix(security): exclude auth.json and .env from profile exports
dieutx Apr 1, 2026
b267516
fix: also exclude .env from default profile exports
teknium1 Apr 1, 2026
3ff9e01
fix(skill_utils): add type check for metadata field in extract_skill_…
Apr 1, 2026
bf19623
feat(api-server): support X-Hermes-Session-Id header for session cont…
txchen Mar 31, 2026
7e91009
fix: lazy-init SessionDB on adapter instance instead of per-request
teknium1 Apr 1, 2026
712aa44
security: block secret exfiltration via browser URLs and auxiliary LL…
0xbyt4 Mar 31, 2026
127a4e5
security: redact secrets from auxiliary and vision LLM responses
0xbyt4 Mar 31, 2026
1515e8c
fix: rewrite test mock secrets and add redaction fixture
teknium1 Apr 1, 2026
16d9f58
fix(gateway): persist memory flush state to prevent redundant re-flus…
teknium1 Apr 1, 2026
9a23abf
fix(security): cherry-pick upstream security hardening
claude Apr 1, 2026
c59ab8b
fix: profile model.model promoted to model.default when default not set
teknium1 Apr 1, 2026
3628ccc
feat: use 'developer' role for GPT-5 and Codex models (#4498)
teknium1 Apr 1, 2026
7a7684b
fix(security): restore missing browser_camofox_state module
jecruz Apr 1, 2026
de9bba8
fix: remove hardcoded OpenRouter/opus defaults
teknium1 Apr 1, 2026
ba48cfe
test(e2e): add telegram gateway e2e test infrastructure
pefontana Apr 1, 2026
bff34b1
test(e2e): add telegram slash command e2e tests
pefontana Apr 1, 2026
67e1170
ci: add e2e test workflow
pefontana Apr 1, 2026
b209dc0
test(e2e): add intentional failure to verify CI detection
pefontana Apr 1, 2026
ecd9bf2
test(e2e): revert intentional failure after CI verification
pefontana Apr 1, 2026
04e60cf
test(e2e): add authorization, session lifecycle, and resilience tests
pefontana Apr 1, 2026
1f1297f
ci: merge e2e into tests workflow as separate job
pefontana Apr 1, 2026
99e6f44
test(e2e): remove unused imports and duplicate fixtures
pefontana Apr 1, 2026
bd9e0b6
test(e2e): remove section separator comments
pefontana Apr 1, 2026
a2e56d0
Merge branch 'main' into rewbs/tool-use-charge-to-subscription
benbarclay Apr 2, 2026
647f99d
fix: resolve post-merge issues in auxiliary_client and model flow
benbarclay Apr 2, 2026
a0f5fc2
fix(tools): add debug logging for token refresh and tighten domain check
Rafa-Ross Apr 2, 2026
5101f85
Merge pull request #3287 from NousResearch/rewbs/tool-use-charge-to-s…
benbarclay Apr 2, 2026
c91f4ef
fix(update): preserve optional extras during fallback install
kshitijk4poor Apr 2, 2026
f4bc6aa
fix: scope extras retry to [all] group only
teknium1 Apr 2, 2026
1841886
fix(cli): detect dragged file paths instead of treating them as slash…
rolme Apr 2, 2026
c4e626b
refactor: extract _detect_file_drop() + add 28 tests
rolme Apr 2, 2026
9825cd7
fix(state): quote dotted terms in FTS5 queries
Mar 31, 2026
e4db72e
fix: merge dotted+hyphenated FTS5 quoting into single pass
teknium1 Apr 2, 2026
835defe
fix: invalidate update cache for all profiles, not just current
teknium1 Apr 2, 2026
e94b4b2
fix: preserve allowed_users during setup reconfigure and quiet unconf…
kshitijk4poor Apr 2, 2026
8cb3596
fix(gateway): seed DM thread sessions with parent transcript to prese…
garygcchiu Apr 2, 2026
64584a9
cleanup: use _generate_session_key for parent key, fix trailing white…
teknium1 Apr 2, 2026
624ad58
fix: make gateway approval block agent thread like CLI does (#4557)
teknium1 Apr 2, 2026
fee8074
chore: merge upstream/main into fix/upstream-security-v5
jecruz Apr 2, 2026
acea9ee
fix(tests): fix 11 real test failures + major cascade poisoner (#4570)
teknium1 Apr 2, 2026
661a1b0
fix: exclude matrix from [all] extras — python-olm is upstream-broken…
teknium1 Apr 2, 2026
18c156a
feat(honcho): scope host and peer resolution to active Hermes profile
erosika Mar 30, 2026
d1189f2
feat(honcho): add cross-profile observability for Honcho integration
erosika Mar 30, 2026
37458e7
feat(honcho): auto-clone config to new profiles on creation
erosika Mar 30, 2026
0e90df1
feat(honcho): eager peer creation + enable/disable per profile
erosika Mar 30, 2026
f27da5f
fix(honcho): remove linkedHosts from peers table
erosika Mar 30, 2026
5f6bf2a
fix(honcho): share workspace across profiles by default
erosika Mar 30, 2026
89eab74
feat(honcho): --target-profile flag + peer card display in status
erosika Mar 30, 2026
c146631
feat(honcho): sync command + auto-sync on hermes update
erosika Mar 30, 2026
a0eae33
fix(honcho): address PR review findings
erosika Mar 30, 2026
37d73d9
fix: patch _local_config_path in tests for write isolation
erosika Mar 30, 2026
8dc5b11
fix(honcho): remove redundant local HOST import in _all_profile_host_…
teknium1 Apr 2, 2026
f4f64c4
fix(cli): ensure zero exit code on successful quiet mode queries (#4601)
devorun Apr 2, 2026
28a073e
fix: repair OpenCode model routing and selection (#4508)
teknium1 Apr 2, 2026
585855d
fix: preserve Anthropic thinking block signatures across tool-use turns
teknium1 Apr 2, 2026
20441cf
fix(insights): persist token usage for non-CLI sessions
kshitijk4poor Apr 2, 2026
b8dd059
feat(website): add skills browse and search page to docs (#4500)
IAvecilla Apr 2, 2026
918d593
chore: gitignore generated skills.json
teknium1 Apr 2, 2026
3186668
feat: per-turn primary runtime restoration and transport recovery (#4…
teknium1 Apr 2, 2026
d89cc7f
feat(prompt): add Google model operational guidance for Gemini and Ge…
teknium1 Apr 2, 2026
b9a968c
feat(slack): add reply_in_thread config option
amethystani Mar 24, 2026
241cbee
docs: add reply_in_thread config to Slack docs
teknium1 Apr 2, 2026
d2b0840
fix(agent): classify think-only empty responses before retrying
kshitijk4poor Apr 2, 2026
798a7b9
docs: add Configuration Options section to Slack docs (#4644)
teknium1 Apr 2, 2026
b86647c
Replace ml-paper-writing with research-paper-writing: full research p…
SHL0MS Apr 2, 2026
6d68fbf
Merge pull request #4654 from SHL0MS/skill/research-paper-writing
SHL0MS Apr 2, 2026
e0b2bdb
fix: webhook platform support — skip home channel prompt, disable too…
teknium1 Apr 2, 2026
924bc67
feat(memory): pluggable memory provider interface with profile isolat…
teknium1 Apr 2, 2026
9e0fc62
feat(honcho): restore full integration parity in memory provider plugin
erosika Mar 31, 2026
29c98e8
feat(honcho): add configurable observation mode (unified/directional)
erosika Apr 2, 2026
9b2fb1c
feat(acp): register client-provided MCP servers as agent tools
Jckwind Apr 1, 2026
9aa82d4
fix(acp): use raw server name as registry key, only sanitize for tool…
Jckwind Apr 1, 2026
f66b3fe
fix(acp): include tool results in step_callback for ACP tool_call_upd…
Jckwind Apr 1, 2026
21c2d32
fix(gateway): normalize step_callback prev_tools for backward compat
teknium1 Apr 2, 2026
3659e1f
test(acp): add E2E tests for MCP registration and tool-result reporting
teknium1 Apr 3, 2026
69f85a4
fix(gateway): race condition, photo media loss, and flood control in …
kshitijk4poor Apr 2, 2026
9bb83d1
fix(gateway): downgrade empty/None response log from WARNING to DEBUG
kshitijk4poor Apr 2, 2026
970042d
fix(gateway): prevent stuck sessions with agent timeout and staleness…
kshitijk4poor Apr 2, 2026
28380e7
fix(gateway): STT config resolution, stream consumer flood control fa…
kshitijk4poor Apr 2, 2026
0ed28ab
refactor: simplify and harden PR fixes after review
kshitijk4poor Apr 2, 2026
a933079
fix: move class-level attribute after docstring, clarify throttle com…
teknium1 Apr 3, 2026
4d99305
fix(cli): surface recent sessions inside /history and /resume
kshitijk4poor Apr 3, 2026
23addf4
fix: allow running gateway service as root for LXC/container environm…
teknium1 Apr 3, 2026
714e494
fix(whatsapp): enforce require_mention in group chats
kshitijk4poor Apr 3, 2026
7165eff
fix(whatsapp): add free_response_chats, mention stripping, and intera…
kshitijk4poor Apr 3, 2026
988ecc7
fix(update): avoid launchd restart race on macOS
davetist Mar 30, 2026
c66c688
fix: remove redundant restart message from update launchd path
teknium1 Apr 3, 2026
0109547
fix(update): handle conflicted git index during hermes update (#4735)
teknium1 Apr 3, 2026
6b0022b
Add fork detection and upstream sync to hermes update
francip Apr 1, 2026
67ae7a7
fix: use get_hermes_home(), consolidate git_cmd, update tests
teknium1 Apr 3, 2026
388241f
docs(acp): fix zed config
NexVeridian Mar 20, 2026
470c3ea
fix: handle Anthropic long-context tier 429 by reducing to 200k
teknium1 Apr 3, 2026
26d6083
fix: correct qwen3.6-plus model slug
teknium1 Apr 3, 2026
8fd9faf
fix: handle Anthropic Sonnet long-context tier 429 by reducing to 200…
teknium1 Apr 3, 2026
f374ae4
fix: prevent compression death spiral from API disconnects (#2153) (#…
teknium1 Apr 3, 2026
cc54818
fix(mcp): stability fix pack — reload timeout, shutdown cleanup, even…
teknium1 Apr 3, 2026
d50e5be
fix: handle None mcp_servers in _get_platform_tools()
teknium1 Apr 3, 2026
93334b2
docs: add community FAQ entries — multi-model workflows, WhatsApp bin…
teknium1 Apr 3, 2026
b6f9b70
fix(gateway): route /approve and /deny through running-agent guard (#…
teknium1 Apr 3, 2026
5db630a
fix: respect per-platform disabled skills in Telegram menu and gatewa…
teknium1 Apr 3, 2026
aecbf7f
fix(discord): register /approve and /deny slash commands, wire up but…
teknium1 Apr 3, 2026
67e3620
fix: persist API server sessions to shared SessionDB (state.db) (#4802)
teknium1 Apr 3, 2026
e492420
fix: route memory provider tools in sequential execution path (#4803)
teknium1 Apr 3, 2026
abf1e98
chore: release v0.7.0 (2026.4.3) (#4812)
teknium1 Apr 3, 2026
5bfe0e2
Merge remote-tracking branch 'upstream/main' into fix/upstream-securi…
jecruz Apr 3, 2026
b3319b1
fix(memory): Fix ByteRover plugin - run brv query synchronously befor…
DatPham-6996 Apr 3, 2026
6d357bb
fix: regenerate uv.lock to sync with pyproject.toml v0.7.0 (#4842)
teknium1 Apr 3, 2026
a09fa69
fix: resolve critical stability issues in core, web, and browser tools
Dusk1e Apr 3, 2026
4979d77
fix: complete browser_tool profile isolation — replace remaining 3 ha…
teknium1 Apr 3, 2026
8a38462
fix(memory): profile-scoped memory isolation and clone support (#4845)
teknium1 Apr 3, 2026
b175608
feat: add .zip document support and auto-mount cache dirs into remote…
teknium1 Apr 3, 2026
de5aacd
fix: normalise \r\n and \r line endings in pasted text
iRonin Apr 3, 2026
7def061
feat: add arcee-ai/trinity-large-thinking to recommended models
teknium1 Apr 3, 2026
52ddd6b
refactor(skills): consolidate code verification skills into one (#4854)
teknium1 Apr 3, 2026
84a875c
fix: scope gateway stop/restart to current profile, --all for global …
teknium1 Apr 3, 2026
bef895b
fix(memory): preserve holographic prompt and trust score rendering
hermes-agent Apr 3, 2026
6bf5946
fix: filter transcript-only roles from chat-completions payload (#4715)
kagura-agent Apr 3, 2026
3f21800
fix: also filter session_meta in /session switch restore path
teknium1 Apr 3, 2026
92dcdbf
fix: clarify interrupt re-queue label, document busy_input_mode behav…
teknium1 Apr 3, 2026
37e2ef6
fix: protect profile-scoped google workspace oauth tokens
kshitijk4poor Apr 3, 2026
5359921
refactor: simplify scope validation helpers in google workspace scripts
kshitijk4poor Apr 3, 2026
3bfb39a
fix(gateway): isolate approval session key per turn
Tranquil-Flow Apr 3, 2026
fb654c1
fix: add type hints to session key helpers, extend context-local key …
teknium1 Apr 3, 2026
1cae9ac
feat(telegram): add group_topics skill binding for supergroup forum t…
clawdolf Apr 3, 2026
d4bf517
test+docs: add group_topics tests and documentation
teknium1 Apr 3, 2026
36aace3
fix(opencode-go): strip trailing /v1 from base URL for Anthropic mode…
teknium1 Apr 4, 2026
cee761e
fix: prevent duplicate messages — gateway dedup + partial stream guar…
teknium1 Apr 4, 2026
287ac15
fix(gateway): write update-pending state atomically to prevent corrup…
Apr 3, 2026
fb68c22
fix(gateway): bypass active-session guard for /approve and /deny comm…
teknium1 Apr 4, 2026
8af6a08
fix: don't treat bare file paths as slash commands
teknium1 Apr 4, 2026
f1c0847
fix(gateway): restore short preview truncation for all/new tool progr…
teknium1 Apr 4, 2026
14e8732
fix(openviking): send tenant-scoping headers on every request (#4825)
Mibayy Apr 3, 2026
5e3303b
fix(mem0): merge env vars with mem0.json instead of either/or
liviaellen Apr 3, 2026
585a3b4
fix: use 'is not None and != ""' instead of truthiness for mem0.json …
teknium1 Apr 4, 2026
5a98ce5
fix: use clean user message for all memory provider operations (#4940)
teknium1 Apr 4, 2026
ad4feea
feat: wire skills.external_dirs into all remaining discovery paths
teknium1 Apr 4, 2026
34308e4
docs: improve youtube-content skill structure and workflow
teknium1 Apr 4, 2026
1c0c5d9
fix(gateway): support infinite timeout + periodic notifications + act…
teknium1 Apr 4, 2026
831067c
perf: fix O(n²) catastrophic backtracking in redact regex + reorder f…
acsezen Apr 3, 2026
f5c212f
feat: add MiniMax TTS provider support (speech-2.8)
octo-patch Apr 3, 2026
b93fa23
fix: clear ghost status-bar lines on terminal resize (#4960)
teknium1 Apr 4, 2026
a70ee1b
fix: sync OAuth tokens between credential pool and credentials file
netdust Apr 3, 2026
78ec8b0
style: add debug log for write-back failure in retry path
netdust Apr 3, 2026
43d3efd
feat: add docker_env config for explicit container environment variab…
teknium1 Apr 4, 2026
77a2aad
docs: fix stale references across 8 doc pages
teknium1 Apr 4, 2026
bc40007
Merge remote-tracking branch 'upstream/main' into fix/upstream-securi…
jecruz Apr 4, 2026
6367e1c
fix: remove stale test skips, fix regex backtracking, file search bug…
Apr 3, 2026
2aa3f19
fix(doctor): sync provider checks, add config migration, WAL and mem0…
teknium1 Apr 4, 2026
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
bbb8fa1
Merge remote-tracking branch 'upstream/main' into fix/upstream-securi…
jecruz Apr 4, 2026
b5835a2
fix(security,testing): redaction patterns, credential typing, test co…
jecruz Apr 4, 2026
e3134be
feat(testing,docs): add credential typing fix, test suite, project docs
jecruz Apr 4, 2026
3d657ee
chore: merge origin/main into fix/upstream-security-v5
jecruz Apr 4, 2026
570cb61
chore(ci): opt into Node.js 24 for GitHub Actions runner
jecruz Apr 4, 2026
1bb5916
fix: patch get_all_skills_dirs and fix voice restart on no-speech
jecruz Apr 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/deploy-site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:
paths:
- 'website/**'
- 'landingpage/**'
- 'skills/**'
- 'optional-skills/**'
- '.github/workflows/deploy-site.yml'
workflow_dispatch:

Expand Down Expand Up @@ -34,6 +36,16 @@ jobs:
cache: npm
cache-dependency-path: website/package-lock.json

- uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install PyYAML for skill extraction
run: pip install pyyaml

- name: Extract skill metadata for dashboard
run: python3 website/scripts/extract-skills.py

- name: Install dependencies
run: npm ci
working-directory: website
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/docs-site-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ jobs:
with:
python-version: '3.11'

- name: Install ascii-guard
run: python -m pip install ascii-guard
- name: Install Python dependencies
run: python -m pip install ascii-guard pyyaml

- name: Extract skill metadata for dashboard
run: python3 website/scripts/extract-skills.py

- name: Lint docs diagrams
run: npm run lint:diagrams
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down Expand Up @@ -44,6 +46,8 @@ jobs:
e2e:
runs-on: ubuntu-latest
timeout-minutes: 10
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down
51 changes: 51 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Hermes Agent

Multi-provider LLM agent framework with pluggable memory, credential management, and multi-platform gateway support.

## Tech Stack

- Runtime: Python 3.10+
- Key Dependencies: httpx, pydantic, pyyaml
- Gateway Platforms: Discord, Matrix, Slack, Telegram, WhatsApp, API server
- Memory Plugins: Honcho, Mem0, Holographic, Byterover, RetainDB, OpenViking, Hindsight

## Structure

```
agent/ # Core agent logic
- credential_pool.py # Multi-credential failover
- memory_manager.py # Memory provider orchestration
- redact.py # Secret redaction
- anthropic_adapter.py # LLM provider adaptation
gateway/ # Multi-platform message ingestion
hermes_cli/ # CLI and setup
plugins/memory/ # Memory backend implementations
```

## Conventions

- **Commit style**: Conventional commits (`fix(scope):`, `feat(scope):`, etc.)
- **Tests**: pytest in `tests/`
- **Secrets**: Always redacted before logging; never committed
- **Config**: YAML-based, `hermes_cli/config.py` provides interface
- **Type hints**: Required for new code

## Scripts

- `pytest tests/ -q` — run tests
- `python run_agent.py` — run agent
- `python -m hermes_cli.main` — CLI entry point

## Setup

```bash
pip install -r requirements.txt
python -m hermes_cli.main auth login
```

## Key Decisions

- **Credential pool**: Supports multiple credentials per provider with round-robin/least-used strategies
- **Memory plugins**: Pluggable architecture with standardized interface
- **Redaction**: Snapshots env at import time to prevent runtime bypass
- **Gateway delivery**: Event-driven, platform-agnostic message handling
290 changes: 290 additions & 0 deletions RELEASE_v0.7.0.md

Large diffs are not rendered by default.

73 changes: 73 additions & 0 deletions acp_adapter/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
InitializeResponse,
ListSessionsResponse,
LoadSessionResponse,
McpServerHttp,
McpServerSse,
McpServerStdio,
NewSessionResponse,
PromptResponse,
ResumeSessionResponse,
Expand Down Expand Up @@ -93,6 +96,71 @@ def on_connect(self, conn: acp.Client) -> None:
self._conn = conn
logger.info("ACP client connected")

async def _register_session_mcp_servers(
self,
state: SessionState,
mcp_servers: list[McpServerStdio | McpServerHttp | McpServerSse] | None,
) -> None:
"""Register ACP-provided MCP servers and refresh the agent tool surface."""
if not mcp_servers:
return

try:
from tools.mcp_tool import register_mcp_servers

config_map: dict[str, dict] = {}
for server in mcp_servers:
name = server.name
if isinstance(server, McpServerStdio):
config = {
"command": server.command,
"args": list(server.args),
"env": {item.name: item.value for item in server.env},
}
else:
config = {
"url": server.url,
"headers": {item.name: item.value for item in server.headers},
}
config_map[name] = config

await asyncio.to_thread(register_mcp_servers, config_map)
except Exception:
logger.warning(
"Session %s: failed to register ACP MCP servers",
state.session_id,
exc_info=True,
)
return

try:
from model_tools import get_tool_definitions

enabled_toolsets = getattr(state.agent, "enabled_toolsets", None) or ["hermes-acp"]
disabled_toolsets = getattr(state.agent, "disabled_toolsets", None)
state.agent.tools = get_tool_definitions(
enabled_toolsets=enabled_toolsets,
disabled_toolsets=disabled_toolsets,
quiet_mode=True,
)
state.agent.valid_tool_names = {
tool["function"]["name"] for tool in state.agent.tools or []
}
invalidate = getattr(state.agent, "_invalidate_system_prompt", None)
if callable(invalidate):
invalidate()
logger.info(
"Session %s: refreshed tool surface after ACP MCP registration (%d tools)",
state.session_id,
len(state.agent.tools or []),
)
except Exception:
logger.warning(
"Session %s: failed to refresh tool surface after ACP MCP registration",
state.session_id,
exc_info=True,
)

# ---- ACP lifecycle ------------------------------------------------------

async def initialize(
Expand Down Expand Up @@ -149,6 +217,7 @@ async def new_session(
**kwargs: Any,
) -> NewSessionResponse:
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)
return NewSessionResponse(session_id=state.session_id)

Expand All @@ -163,6 +232,7 @@ async def load_session(
if state is None:
logger.warning("load_session: session %s not found", session_id)
return None
await self._register_session_mcp_servers(state, mcp_servers)
logger.info("Loaded session %s", session_id)
return LoadSessionResponse()

Expand All @@ -177,6 +247,7 @@ async def resume_session(
if state is None:
logger.warning("resume_session: session %s not found, creating new", session_id)
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)
return ResumeSessionResponse()

Expand All @@ -200,6 +271,8 @@ async def fork_session(
) -> ForkSessionResponse:
state = self.session_manager.fork_session(session_id, cwd=cwd)
new_id = state.session_id if state else ""
if state is not None:
await self._register_session_mcp_servers(state, mcp_servers)
logger.info("Forked session %s -> %s", session_id, new_id)
return ForkSessionResponse(session_id=new_id)

Expand Down
72 changes: 70 additions & 2 deletions agent/anthropic_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- Claude Code credentials (~/.claude.json or ~/.claude/.credentials.json) → Bearer auth
"""

import copy
import json
import logging
import os
Expand Down Expand Up @@ -949,6 +950,69 @@ def _convert_content_part_to_anthropic(part: Any) -> Optional[Dict[str, Any]]:
return block


def _to_plain_data(value: Any, *, _depth: int = 0, _path: Optional[set] = None) -> Any:
"""Recursively convert SDK objects to plain Python data structures.

Guards against circular references (``_path`` tracks ``id()`` of objects
on the *current* recursion path) and runaway depth (capped at 20 levels).
Uses path-based tracking so shared (but non-cyclic) objects referenced by
multiple siblings are converted correctly rather than being stringified.
"""
_MAX_DEPTH = 20
if _depth > _MAX_DEPTH:
return str(value)

if _path is None:
_path = set()

obj_id = id(value)
if obj_id in _path:
return str(value)

if hasattr(value, "model_dump"):
_path.add(obj_id)
result = _to_plain_data(value.model_dump(), _depth=_depth + 1, _path=_path)
_path.discard(obj_id)
return result
if isinstance(value, dict):
_path.add(obj_id)
result = {k: _to_plain_data(v, _depth=_depth + 1, _path=_path) for k, v in value.items()}
_path.discard(obj_id)
return result
if isinstance(value, (list, tuple)):
_path.add(obj_id)
result = [_to_plain_data(v, _depth=_depth + 1, _path=_path) for v in value]
_path.discard(obj_id)
return result
if hasattr(value, "__dict__"):
_path.add(obj_id)
result = {
k: _to_plain_data(v, _depth=_depth + 1, _path=_path)
for k, v in vars(value).items()
if not k.startswith("_")
}
_path.discard(obj_id)
return result
return value


def _extract_preserved_thinking_blocks(message: Dict[str, Any]) -> List[Dict[str, Any]]:
"""Return Anthropic thinking blocks previously preserved on the message."""
raw_details = message.get("reasoning_details")
if not isinstance(raw_details, list):
return []

preserved: List[Dict[str, Any]] = []
for detail in raw_details:
if not isinstance(detail, dict):
continue
block_type = str(detail.get("type", "") or "").strip().lower()
if block_type not in {"thinking", "redacted_thinking"}:
continue
preserved.append(copy.deepcopy(detail))
return preserved


def _convert_content_to_anthropic(content: Any) -> Any:
"""Convert OpenAI-style multimodal content arrays to Anthropic blocks."""
if not isinstance(content, list):
Expand Down Expand Up @@ -995,7 +1059,7 @@ def convert_messages_to_anthropic(
continue

if role == "assistant":
blocks = []
blocks = _extract_preserved_thinking_blocks(m)
if content:
if isinstance(content, list):
converted_content = _convert_content_to_anthropic(content)
Expand Down Expand Up @@ -1279,13 +1343,17 @@ def normalize_anthropic_response(
"""
text_parts = []
reasoning_parts = []
reasoning_details = []
tool_calls = []

for block in response.content:
if block.type == "text":
text_parts.append(block.text)
elif block.type == "thinking":
reasoning_parts.append(block.thinking)
block_dict = _to_plain_data(block)
if isinstance(block_dict, dict):
reasoning_details.append(block_dict)
elif block.type == "tool_use":
name = block.name
if strip_tool_prefix and name.startswith(_MCP_TOOL_PREFIX):
Expand Down Expand Up @@ -1316,7 +1384,7 @@ def normalize_anthropic_response(
tool_calls=tool_calls or None,
reasoning="\n\n".join(reasoning_parts) if reasoning_parts else None,
reasoning_content=None,
reasoning_details=None,
reasoning_details=reasoning_details or None,
),
finish_reason,
)
Loading
Loading