Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
377 commits
Select commit Hold shift + click to select a range
eef43e3
fix(delegate): close the dedicated SessionDB if child construction fa…
thatssoheil Aug 7, 2026
70704b9
fix(delegate): child's dedicated SessionDB must follow the parent's d…
kshitijk4poor Aug 8, 2026
8dc5608
fix(compression): adopt live continuation tip at flush across multi-h…
teknium1 Aug 15, 2026
0d91ab8
fix: close leaked SessionDB connections on /insights and sessions-rep…
RelaxJonh Aug 10, 2026
39e480c
fix(state): close leaked SessionDB connections on exception paths (#8…
JoaoMarcos44 Aug 11, 2026
38709ae
fix(cron): close leaked SessionDB connection when init outlives the t…
Tranquil-Flow Aug 15, 2026
dac3c44
test: fix salvage test imports; drop WAL worker-thread test supersede…
teknium1 Aug 15, 2026
547043a
fix(telegram): honor fallback disable during connect
worlldz Aug 9, 2026
ac9b058
fix(gateway): exclude service-managed PIDs from orphan reaping
RelaxJonh Aug 14, 2026
102369c
fix(gateway): spare Scheduled-Task-supervised gateway from orphan rea…
Aug 14, 2026
0dba331
fix(gateway): generalize supervised-gateway exemption in orphan reape…
teknium1 Aug 15, 2026
169ff2d
chore: add contributor email mapping for arccat-114
teknium1 Aug 15, 2026
69d1843
fix(packaging): ship bundled plugin manifests
JoaoMarcos44 Aug 10, 2026
1f6f861
fix(cli): stop hermes update from respawning orphan serve --port 0 (#…
trippyogi Aug 4, 2026
45bb486
fix(gateway): give in-flight cron work its own drain floor
JoaoMarcos44 Aug 9, 2026
4b06d9e
fix(gateway): keep the cron drain floor compatible with shutdown test…
JoaoMarcos44 Aug 9, 2026
baf7034
fix(gateway): deliver interrupted-cron notices before adapters discon…
JoaoMarcos44 Aug 9, 2026
5ecad87
fix(cron): report ownerless interrupted fires so their notices still …
teknium1 Aug 15, 2026
e88c9f0
fix(backup): restore import members atomically so a failed import can…
briandevans Aug 6, 2026
1c3c1f4
fix(backup): preserve owner on atomic import writes and close the 060…
briandevans Aug 6, 2026
60f8666
docs(backup): note that atomic_replace's cross-device fallback still …
briandevans Aug 6, 2026
66356fe
fix(backup): drop setuid/setgid from the mode restored onto imported …
briandevans Aug 11, 2026
73b35b8
test(backup): assert an imported member cannot keep a setuid target's…
briandevans Aug 11, 2026
9b3823d
fix(install): provision Node 26 so managed npm satisfies engines
Christopher-Schulze Aug 13, 2026
cf8b505
fix(desktop-update): make posix hand-off survive Electron quit teardo…
douxy1994 Aug 14, 2026
bc36d7d
fix(deps): exempt no-upload-date and exact-pinned packages from exclu…
teknium1 Aug 15, 2026
e7418f1
fix(gateway): never persist a hygiene compression that grows the tran…
dhruvkej9 Aug 10, 2026
ffaa63f
fix(compressor): never commit a compression that grows the transcript…
dhruvkej9 Aug 12, 2026
3bb83a9
chore: map contributor email for salvage
teknium1 Aug 15, 2026
24573b3
refactor: bind gateway anti-growth guard to locals, trim overlong com…
kshitijk4poor Aug 15, 2026
6fbbe18
fix(agent): reword SKILLS_GUIDANCE trigger and stop mislabelling its …
jackulau Aug 9, 2026
f57209b
fix(agent): carry the ambiguity of Anthropic's 'out of extra usage' 4…
jackulau Aug 12, 2026
ec1aa89
[verified] fix: clear running-job lock when execution creation fails
zhao0112 Aug 15, 2026
4668750
fix(cron): deliver alerts for escaped run failures
fangliquanflq Aug 14, 2026
db696c7
test(tests): cover cron fallback delivery idempotency and interrupt skip
fangliquanflq Aug 15, 2026
c2a1179
fix(cron): fall back on transient DNS during provider resolve
mollusk Aug 11, 2026
a5bb1bc
fix(cron): make transient-DNS classification platform-safe
teknium1 Aug 15, 2026
569b7a3
fix(cron): bound post-run cleanup
yuric Aug 11, 2026
5733ec0
test(cron): adapt guard-leak regression to owner-fenced dispatch on main
teknium1 Aug 15, 2026
2d81236
fix(cli): report background-dispatch cron runs without false 'failed'…
webtecnica Aug 10, 2026
0ea7948
chore: map contributor emails for cron salvage
teknium1 Aug 15, 2026
2b5a3fb
test(cron): expect tick to contain create_execution failure per-job
teknium1 Aug 15, 2026
ce658e8
fix(session-search): narrow lineage escape to reset/compression; trus…
kshitijk4poor Aug 14, 2026
1db4801
fix: close leaked SessionDB connections on exception paths (#83226)
RelaxJonh Aug 10, 2026
7a390f7
fix: __del__ delegates to close() for full cleanup
kshitijk4poor Aug 15, 2026
e42db34
fix(plugins): register deferred platform client tools at discovery (#…
thelonewander3r Aug 14, 2026
7224301
fix(toolsets): admit explicitly-configured plugin toolset keys in _ge…
Enough1122 Aug 15, 2026
7a6b891
fix(tools): recognize discovered plugin platforms
tachyon-r Jul 25, 2026
2585767
chore: map contributor email for attribution audit
teknium1 Aug 15, 2026
366fd70
fix(gateway): registered_names() honors profile scope like is_registe…
teknium1 Aug 15, 2026
d86c67d
fix(gateway): connect messaging platforms in parallel at startup (#83…
EvanProgramming Aug 11, 2026
42a4e86
fix(test): genuinely verify parallel startup connects (#83791)
EvanProgramming Aug 11, 2026
c22815f
fix(gateway): cap Telegram cold-start connect so startup reaches runn…
teknium1 Aug 15, 2026
f8d75db
test(gateway): accept keyword args in _connect_adapter_with_timeout m…
teknium1 Aug 15, 2026
e6daa7a
chore: contributor mapping
teknium1 Aug 15, 2026
059e346
fix(gateway): abort-aware parallel startup connects (restart race par…
teknium1 Aug 15, 2026
6dab031
test(installer): reproduce destructive venv fallback (#83149)
JoaoMarcos44 Aug 10, 2026
11268e7
fix(installer): make Windows venv recreation transactional (#83149)
JoaoMarcos44 Aug 10, 2026
be1e0c8
test(installer): align Windows venv process guard with transactional …
JoaoMarcos44 Aug 10, 2026
d82dcf5
docs(update): document transactional Windows venv recovery (#83149)
JoaoMarcos44 Aug 10, 2026
18b442c
fix(install): abort Windows venv recreate when rename-aside fails
HexLab98 Aug 10, 2026
737d633
test(install): lock no in-place venv gut on rename failure
HexLab98 Aug 10, 2026
aa5a960
fix(installer): hold the venv rollback source through dependency vali…
teknium1 Aug 15, 2026
cb4daf2
fix: coerce dict-valued model/default config back to string across re…
mariobgsp Aug 11, 2026
86054ef
fix: keep nested model.default provider paired through HermesCLI
mariobgsp Aug 11, 2026
998329a
fix: flatten dict-valued model.default at config load boundary
mariobgsp Aug 11, 2026
be708ff
fix: normalize managed config overlay before merge in load_config
mariobgsp Aug 11, 2026
49e3044
chore: map contributor emails for mariobgsp (PR #83902 salvage)
teknium1 Aug 15, 2026
b58fa89
refactor: centralize dict-valued model.default coercion via shared he…
kshitijk4poor Aug 15, 2026
ac2e420
fix(desktop): confirm detached updater spawn before quitting for hand…
teknium1 Aug 15, 2026
bdfdd43
fix(update): gate 'Code updated!' on HEAD actually moving (#79678)
thatssoheil Aug 5, 2026
95018b6
fix(install): surface aborted gateway restart during hermes update
PRATHAMESH75 Aug 4, 2026
517151e
fix(install): fail closed when a stopped gateway leaves an empty surv…
PRATHAMESH75 Aug 13, 2026
49d72a0
fix(update): verify Windows gateway cold-start survives before report…
chelsealong Aug 12, 2026
c6a7129
fix(update): detect updater self-lock on Windows + repair venvs whose…
Halldrix Aug 11, 2026
19cff89
fix(update): complete pending core install before any native import (…
Halldrix Aug 11, 2026
cd34661
test(update): mock gateway discovery now that the restart phase is su…
teknium1 Aug 15, 2026
0178aca
chore: map Halldrix contributor email
teknium1 Aug 15, 2026
42a1db4
fix(update): use canonical venv_bin_dir in _install_repair (no open-c…
teknium1 Aug 15, 2026
2d9f116
fix(agent): anchor ZAI/Kimi base_url host matching to avoid substring…
pierrenode Aug 14, 2026
198e2f2
fix(routing): use hostname match for azure.com endpoint detection (#7…
RelaxJonh Jul 30, 2026
4b7b2b0
fix: widen base-URL hostname identity class to remaining substring sites
teknium1 Aug 15, 2026
b32aa0b
docs: document provides_tools client-tool registration for platform p…
teknium1 Aug 15, 2026
0c9d8ab
fix(streaming): join stream worker and drain Relay scopes on interrupt
HexLab98 Aug 8, 2026
81c4f3a
test(streaming): cover interrupt join, orphan drain, and EIO paint fr…
HexLab98 Aug 8, 2026
3537ef9
fix(streaming): widen #81521 interrupt join to sibling paths and use …
teknium1 Aug 15, 2026
0b988b0
fix(relay): keep orphan drain bounded by the scope-op timeout
teknium1 Aug 15, 2026
0cbc4ce
fix(streaming): gate the interrupt worker join on live Relay managed …
teknium1 Aug 15, 2026
4b0c103
fix(desktop-update): wait for rebuilt executable before relaunch
konsisumer Aug 15, 2026
fa72a1e
fix(kanban): re-create the schema when a cached DB path loses it (#83…
JoaoMarcos44 Aug 11, 2026
4aa9f73
fix(update): rebuild Desktop after release artifact loss
konsisumer Aug 15, 2026
b9e03b4
fix(desktop): give chat images native right-click and proper save fil…
teknium1 Aug 15, 2026
2a9f57c
fix(desktop): suppress skill suggestion pill when the session already…
teknium1 Aug 15, 2026
979a200
fix(update): preserve activated extras across runtime rebuilds
hxwvaa Jul 30, 2026
b67f202
fix(update): honor lazy install opt-out during restore
hxwvaa Aug 1, 2026
d1df111
fix(update): restore Hermes Tools dependencies
hxwvaa Aug 7, 2026
5599dc0
chore: map hbasheer@student.42abudhabi.ae -> hxwvaa for contributor a…
teknium1 Aug 15, 2026
3af56c2
fix(install.ps1): surface uv installer errors and add GitHub + existi…
teknium1 Aug 15, 2026
62014d8
fix(guard): steer live-checkout block message to disk-backed scratch …
teknium1 Aug 15, 2026
2bccd6a
fix(managed_uv): fall forward to next Python minor when current line …
RelaxJonh Aug 1, 2026
471c687
test(managed_uv): cover explicit-patch fallback on the next minor lin…
teknium1 Aug 15, 2026
cee2446
fix(cache): keep prompt_cache_key warm across compression session rot…
kshitijk4poor Aug 15, 2026
96cdf19
refactor(cache): fold self-review findings on the rotation-scope fix
kshitijk4poor Aug 15, 2026
e3fab04
refactor(cache): never-raising scope resolver shared by both call sites
kshitijk4poor Aug 15, 2026
b54b052
feat(desktop): multi-connection registry — named agent sources (schem…
teknium1 Aug 15, 2026
0904f50
fix(desktop): address connections-registry review findings
teknium1 Aug 15, 2026
0807673
fmt(js): `npm run fix` on merge (#86751)
hermes-seaeye[bot] Aug 15, 2026
30c469b
fix(gateway): spare pidfile-less Scheduled-Task gateways from the orp…
EvanProgramming Aug 15, 2026
5ef5227
fix(bedrock): let aux calls omit the Converse maxTokens cap
kshitijk4poor Aug 15, 2026
8b58f9f
test(bedrock): pin stream-path cap omission; document truthiness edge
kshitijk4poor Aug 15, 2026
ce996d4
feat(delegation): raise max_concurrent_children default 3 -> 10 (+mig…
teknium1 Aug 15, 2026
dcc2f3d
fix(vision): stop capping aux vision output with hardcoded max_tokens
adikpb Jul 31, 2026
ec470d9
test(vision): assert vision aux calls carry no max_tokens cap
adikpb Jul 31, 2026
688abc5
test(vision): assert no max_tokens cap in browser and video aux kwargs
adikpb Jul 31, 2026
d2672a3
feat(gateway): optional profile param on cron.manage RPC (#86796)
teknium1 Aug 15, 2026
fbaea9b
feat(sessions): generic 'hidden' session flag (sidebar-hide, still re…
teknium1 Aug 15, 2026
6479493
docs(desktop): document Settings → Connections (multi-connection regi…
teknium1 Aug 15, 2026
96d6db1
fix(artifacts): convert DB timestamps from seconds to ms for Date()
icemeng Jun 8, 2026
021950a
fix(desktop): stop artifact over-indexing
404Dealer Aug 8, 2026
bceac69
fix(desktop): artifacts page timestamps render 1970 and local images …
thatssoheil Aug 10, 2026
18bac64
chore: map contributor email for icemeng
teknium1 Aug 15, 2026
34e05c3
fix(desktop): render pet sprite at devicePixelRatio for sharp HiDPI o…
NorethSea Aug 15, 2026
fd08722
fix(desktop): smooth-scale pet sprite frames
fanfan343 Aug 11, 2026
d474ba5
test(desktop): cover bicubic smoothing in pet sprite
fanfan343 Aug 11, 2026
5eb1d2b
fix(desktop): restore pet.info backstop after live-sync regression
Adolanium Aug 8, 2026
28d2de1
fix(desktop): surface isolated tool failures in pet state
LBeghini Aug 8, 2026
9e88289
fix(petdex): quoted 'false' now disables display.pet.enabled everywhere
thatssoheil Aug 7, 2026
343068e
fix(petdex): cover the CLI pet pane and status-line signature too
thatssoheil Aug 7, 2026
ce02f0a
fix(pets): cover the pets CLI (doctor, has-active, /pet toggle) too
thatssoheil Aug 7, 2026
8052d5d
test(pets): lock the quoted-false behavior on the CLI surfaces
thatssoheil Aug 7, 2026
4f29374
fix(gateway): send-once spritesheet semantics for pet.info (#54730)
teknium1 Aug 15, 2026
1c23c2a
chore: map contributor email for attribution audit
teknium1 Aug 15, 2026
868c400
fix(tui): stop disabled pet cell polling
bananawalnut Jul 23, 2026
f0cfe5a
perf(dashboard): bound multi-profile sidebar polling
SiteupAgencia Aug 3, 2026
4466578
fix(kanban): detect WS client disconnect on idle board, prevent zombi…
tugrulguner Aug 3, 2026
6d0d748
chore: add contributor email mapping
tugrulguner Aug 3, 2026
5bceb3e
fix(dashboard): add idle back-off to PTY pump loop (#42627)
Christopher-Schulze Aug 8, 2026
bee0d45
perf(desktop): pause background UI work while unfocused
Aug 8, 2026
67a1c1e
fix(dashboard): use a fixed sidebar cache TTL (no HERMES_* env var fo…
teknium1 Aug 15, 2026
106207c
chore: map contributor emails for attribution audit
teknium1 Aug 15, 2026
f535a4f
test(desktop): pin document.hasFocus in background-sync backstop tests
teknium1 Aug 15, 2026
edd73da
test(kanban): regression for idle-board WS disconnect detection (#77833)
teknium1 Aug 15, 2026
aa8e92f
test: pin document.hasFocus in status timer test (useViewedInterval g…
teknium1 Aug 15, 2026
3d73821
fix(agent): stop thread output descriptor leaks
Reksely Aug 8, 2026
c99a45b
fix(browser): reap leaked agent-browser daemons whose owner is still …
Aug 9, 2026
7de5a65
fix(pets): delete row strips after extracting their frames
Adolanium Jun 25, 2026
b9672ea
fix(pets): remove the non-PNG base draft after hardening
Adolanium Jun 25, 2026
aba4934
fix(agent): omit unsupported metadata on Relay scope.pop
astraltrekkin Aug 5, 2026
94ce839
fix(sessions): release active-session leases against their acquisitio…
teknium1 Aug 15, 2026
2fecf39
chore: map contributor email for Hangzian
teknium1 Aug 15, 2026
0d07fe6
fix(projects): use _branch_lane_id for non-git folders to prevent dup…
Tranquil-Flow Jun 27, 2026
f7de2ca
fix(desktop): order project-tree lanes by recency in the overview, no…
briandevans Jul 13, 2026
0fd223d
fix(desktop): stop dual main lanes for non-git project workspaces
rsk-731 Jul 20, 2026
3defb25
fix(desktop): evict stale lane entry when overlay moves session to wo…
liuhao1024 Jun 30, 2026
d40dda7
fix(desktop): preserve lane session recency order
MustafaK99 Jul 12, 2026
db1d898
fix(desktop): no-op branch switch on non-repo project lanes
Inspired-by-Atmosphere Aug 10, 2026
e89532d
fix(desktop): order async session git metadata
embwl0x Aug 2, 2026
f378a8f
fix(projects): dedup project_create by primary_path (#75820)
teknium1 Aug 15, 2026
cab6eb7
test(projects): widen lane-id derivation regression coverage
teknium1 Aug 15, 2026
e0e4d3a
chore(contributors): map salvage-branch contributor emails
teknium1 Aug 15, 2026
d16326b
test: align lost-and-found schema pins with git_metadata_generation c…
teknium1 Aug 15, 2026
f080bc3
fix(tui): steady scrollbar after transcript shrink
LeonSGP43 May 14, 2026
6b39ae4
fix(desktop): let sidebar wheel scrolling chain past the virtualized …
teknium1 Aug 15, 2026
da68ecf
design(kanban): add side-by-side dialog prototype (4 variants)
DavidMetcalfe Jun 22, 2026
7448e7a
feat(plugins): expose Dialog/ConfirmDialog/Toast/useToast/useConfirmD…
DavidMetcalfe Jun 22, 2026
08f32a6
fix(kanban): replace native browser dialogs with in-app ConfirmDialog
DavidMetcalfe Jun 22, 2026
77f35ad
fix(tui): honor destructive slash confirmation config
YuYigeng Jul 26, 2026
7d34d7d
docs(tui): clarify destructive confirm controls
YuYigeng Jul 30, 2026
8e35ff0
fix(desktop): confirm before clearing the entire Enabled Toolsets lis…
PRATHAMESH75 Jul 28, 2026
e6708af
feat(desktop): confirm before deleting a session
RichardGuan1 Aug 6, 2026
4c24629
fix(console): skip the checkpoints prune confirmation the console alr…
briandevans Aug 8, 2026
1025cb0
fix(desktop): stop deleted sessions resurrecting through racing list …
teknium1 Aug 15, 2026
eaaecbc
chore: update contributor attribution map
teknium1 Aug 15, 2026
3c2daf5
i18n(web): add kanban bulk-confirm keys to all locales (English fallb…
teknium1 Aug 15, 2026
6fb6123
test: replace any-casts with typed globalThis narrowing in plugin SDK…
teknium1 Aug 15, 2026
20beee7
fix(desktop): prevent Enter from submitting during IME composition
satotakumi Jun 2, 2026
3d51c40
fix(desktop): prevent IME submit in inline edit composer
izumi0uu Jun 6, 2026
202e5b8
fix(desktop): block Enter keyCode 229 after IME compositionend
Jun 7, 2026
39e7607
fix(desktop): recover from a stale IME composition flag that wedged t…
AIalliAI Jun 11, 2026
9f2e6d0
fix(desktop): ignore IME composition keydowns in keybind combo resolu…
baslam Aug 13, 2026
5877884
fix(desktop): extend stale-flag self-heal and keyCode 229 guard to th…
teknium1 Aug 15, 2026
aa95939
test(desktop): cover IME composition guards in keybind combo resolution
teknium1 Aug 15, 2026
27a22b8
chore: map contributor emails for IME salvage
teknium1 Aug 15, 2026
15e7c56
style: eslint --fix on salvaged IME test (curly + padding rules)
teknium1 Aug 15, 2026
084fca9
fix(tui): clear input after Korean IME submit
sweetcornna Jun 3, 2026
834a9fc
fix(tui): preserve IME text before return submit
InphinitiZ Jun 5, 2026
5dec501
fix(tui): stop Vietnamese Telex IME from dropping characters
hanhvs Jun 30, 2026
e2f7850
fix(tui): tighten IME test per teknium1 review (#55415)
hanhvs Jul 15, 2026
2af4da4
fix(dashboard): prevent React from dropping first keystroke during IM…
liuhao1024 Jun 24, 2026
278c6eb
test(dashboard): reproduce dropped dead-key composition input
dplush Aug 1, 2026
6ece2da
fix(dashboard): forward committed dead-key input to PTY
dplush Aug 1, 2026
0924e33
fix(dashboard): defer IME fallback until xterm input settles
dplush Aug 1, 2026
c066b5a
test(dashboard): cover IME fallback lifecycle
dplush Aug 1, 2026
3d9fdb2
fix(dashboard): avoid duplicate IME fallback input
dplush Aug 1, 2026
874ae74
fix(dashboard): keep mouse input out of IME fallback
dplush Aug 1, 2026
a428531
fix(dashboard): preserve consecutive IME composition input
dplush Aug 1, 2026
434f1e9
fix(dashboard): retain composition after unrelated input
dplush Aug 1, 2026
0d40955
fix(dashboard): handle chunked IME composition input
dplush Aug 8, 2026
00516e6
test(dashboard): cover delayed IME fallback after unrelated input
dplush Aug 12, 2026
daa3f66
chore: map contributor emails for IME TUI salvage
teknium1 Aug 15, 2026
29ce482
style: eslint --fix import ordering in salvaged IME tests
teknium1 Aug 15, 2026
ee9ec61
perf(state): stop selecting full message content in session search
Adolanium Aug 2, 2026
6e1bdc0
perf(session-search): adapt discovery result hydration
blunkjamie-dev Aug 9, 2026
163d7af
fix(session-search): forward detail through agent paths
blunkjamie-dev Aug 9, 2026
888807d
docs(sessions): clarify actual-message retrieval
blunkjamie-dev Aug 9, 2026
4415f91
test(session-search): lock positional parameter prefix
blunkjamie-dev Aug 9, 2026
2162d58
perf(run-agent): reuse the Anthropic request-local client instead of …
JoaoMarcos44 Aug 2, 2026
7e439db
perf: parallelize provider model-list fetches in model picker
lepetitprince716-prog Aug 6, 2026
3806f8f
fix(session-search): forward detail through the public session_search…
teknium1 Aug 15, 2026
7f84de2
chore(contributors): map lepetitprince716@gmail.com -> lepetitprince7…
teknium1 Aug 15, 2026
b587681
fix: keep historical thinking collapsed in tui
LeonSGP43 Jun 8, 2026
2b0b4a2
feat(tui): auto-collapse reasoning blocks only when the reasoning pha…
JElfferich Aug 8, 2026
10bf145
feat(desktop): collapse thinking by default
isak-ialogics Jul 22, 2026
ac0d0f8
fix(desktop): flip zone collapse chevron to action direction
chillerno1 Jul 29, 2026
c6ec8a9
test(desktop): cover docked zone chevron direction
chillerno1 Jul 30, 2026
505f289
feat(web): add collapse toggle for the chat side panel
Eros-ITA Aug 10, 2026
a33ac1e
feat(desktop): add session list density modes
DavidMetcalfe Aug 15, 2026
8ea53d7
chore: map contributor emails for salvage attribution
teknium1 Aug 15, 2026
865e4e7
fix(desktop): default session list density to compact
teknium1 Aug 15, 2026
29c2813
style(desktop): prettier/eslint pass on salvaged files
teknium1 Aug 15, 2026
ddf6456
test: stub virtualizer.measure in virtual-session-list mock (density …
teknium1 Aug 15, 2026
6da30f7
fix(tui_gateway): fall back to session id when session_key is NULL in…
jdgg777 Aug 15, 2026
a654c52
chore: map contributor email (audit_pr_attribution)
teknium1 Aug 15, 2026
1ef7a0b
fix(desktop): recover empty model catalogs
mjolley9 Aug 12, 2026
20e5d78
fix(desktop): recover failed gateway catalogs
mjolley9 Aug 12, 2026
73e9b1a
docs(desktop): align getGateway docstring with $gateway atom subscrip…
mjolley9 Aug 15, 2026
101740e
chore: map contributor email (audit_pr_attribution)
teknium1 Aug 15, 2026
b066f2b
fix(history): isolate branch transcripts from parent updates
DannyFengTianYu Aug 2, 2026
07b9090
fix(desktop): preserve complete history when branching
DannyFengTianYu Aug 2, 2026
8a22220
chore: map contributor email (audit_pr_attribution)
teknium1 Aug 15, 2026
ee1731b
perf(cli): re-export decomposed command modules lazily, ~60ms off eve…
Adolanium Jul 29, 2026
473490a
perf(cli): stop per-keystroke config re-reads in slash completers
spfcraze Aug 3, 2026
4bd746c
perf(cli): memoise default-hermes-root resolution and global auth-sto…
spfcraze Aug 3, 2026
47400fe
test: make memo pins pre-fix-safe (raising=False resets)
spfcraze Aug 3, 2026
2a5093e
docs(auth): note get_default_hermes_root in the global-store memo doc…
spfcraze Aug 3, 2026
7b45d1d
perf(toolsets): memoise resolve_toolset keyed on registry generation
spfcraze Aug 3, 2026
e25cafc
perf(agent): cache per-turn display-flag config reads
spfcraze Aug 3, 2026
b9f7525
test(agent): pin measured-work regression for display-flag config cache
spfcraze Aug 3, 2026
2f54ad4
perf(cli): skip launcher-side plugin discovery for TUI handoff
jackoconner45 Aug 7, 2026
46fe44f
test(cli): stub portable-MCP lookup in completer read test; bound res…
teknium1 Aug 15, 2026
aa27edd
chore(contributors): map jackoconner55@icloud.com
teknium1 Aug 15, 2026
3c570c6
fix(desktop): preserve copy image for large remote media
locker95 Jul 16, 2026
0bc7070
fix(desktop): gate image copy on decoded contents
locker95 Jul 16, 2026
d5a8658
fix(desktop): save remote gateway files natively
PaulBlackSwan Jul 13, 2026
27b0039
fix(desktop): stream native gateway downloads + 404 data-url fallback
PaulBlackSwan Jul 16, 2026
03c85a1
test(desktop): port gateway-file-download tests to vitest electron pr…
teknium1 Aug 15, 2026
0930133
chore: map contributor email for PaulBlackSwan
teknium1 Aug 15, 2026
af585de
fmt(js): `npm run fix` on merge (#86801)
hermes-seaeye[bot] Aug 15, 2026
901f4bc
Sync upstream hermes-agent main into NousAI-Assistant (375 commits, t…
claude Aug 15, 2026
4df11ee
fix(tests): align lost-and-found sessions pin with the 56-column layout
claude Aug 15, 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 CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,16 @@ auto-merge (squash) at PR creation instead of watch-and-merge.
- `hermes_cli/web_server.py` (one `nousai` row in `_BUILTIN_DASHBOARD_THEMES`)
- Deliberately NOT forked: `ui-tui/` default theme/content (runtime skin
already themes the TUI; upstream tests hardcode the Hermes brand there).
- **Temporary divergence (user-approved 2026-08-15, PR #58)**:
`tests/hermes_cli/test_session_recovery_lost_and_found.py` carries a
fork fix bumping the sessions-schema width 55 -> 56 in four coupled
places (the `assert len(sessions_columns)` pin, `max_fields`, the
current-layout `insert(...)`, and its comment). Upstream's
`d16326bb25` bumped its own pin for `git_metadata_generation` but
landed on a tree that already had the `hidden` column, leaving the pin
one short and `main` red. The correct value is objectively fixed by the
schema, so when upstream re-aligns it the next sync takes UPSTREAM's
version of these hunks and drops ours; delete this note in that sync.
- If the `check-attribution` CI job flags unmapped upstream author emails, map
them with `python3 scripts/add_contributor.py <email> <github-login>` —
verify the login from the commit's linked author via the GitHub API, don't
Expand Down
6 changes: 5 additions & 1 deletion agent/agent_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -2272,7 +2272,11 @@ def _parse_prune_int(raw, default):
# overrides consistent with them and let provider metadata resolve the
# active model's window instead.
if _config_context_length is not None and isinstance(_model_cfg, dict):
_configured_default_model = str(_model_cfg.get("default") or "").strip()
_default = _model_cfg.get("default")
if isinstance(_default, dict):
from hermes_cli.config import split_model_config_default
_default, _ = split_model_config_default(_default)
_configured_default_model = str(_default or "").strip()
_configured_default_runtime_model = _configured_default_model
_active_runtime_model = agent.model
if _configured_default_model:
Expand Down
84 changes: 74 additions & 10 deletions agent/agent_runtime_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,22 @@ def _is_verification_candidate(m: Dict) -> bool:
prev["tool_calls"] = prev_calls + new_calls
elif prev_calls:
prev["tool_calls"] = prev_calls
else:
# Neither turn carries tool calls, but the surviving turn may
# still carry a stale ``tool_calls: []`` from the earlier
# message. An empty array is semantically "no tool calls",
# yet strict OpenAI-compatible providers (DeepSeek v4,
# Moonshot/Kimi) reject it with HTTP 400 ("Invalid
# 'messages[N].tool_calls': empty array..."). Drop the key
# HERE, at the source: ``sanitize_api_messages`` only fixes
# the per-call wire copy, so a ``[]`` left on the repaired
# turn survives in the live/persisted trajectory returned to
# callers (gateway/WebUI transcripts, session resume,
# subagents, cron) and is replayed on the next turn — which
# is how #58755 kept reproducing after the chokepoint fix
# (#77921). Popping is non-destructive: an empty array
# carries no information.
prev.pop("tool_calls", None)
# Concatenate plain-text content; leave multimodal (list)
# content on either side alone to avoid mangling attachment
# blocks — fall back to keeping the existing content.
Expand Down Expand Up @@ -930,6 +946,7 @@ def recover_with_credential_pool(
has_retried_429: bool,
classified_reason: Optional[FailoverReason] = None,
error_context: Optional[Dict[str, Any]] = None,
billing_unverified: bool = False,
) -> tuple[bool, bool]:
"""Attempt credential recovery via pool rotation.

Expand All @@ -944,6 +961,12 @@ def recover_with_credential_pool(
providers that surface billing/rate-limit/auth conditions under a
different status code, such as Anthropic returning HTTP 400 for
"out of extra usage".

`billing_unverified` marks a billing verdict that rests on an ambiguous
body (``ClassifiedError.billing_unverified``, #82154): the pool persists
it as ``billing_unverified`` so the exhausted entry gets a short cooldown
instead of the one-hour billing bench — the same 400 can be a
content-filter rejection that leaves the credential healthy.
"""
pool = agent._credential_pool
if pool is None:
Expand Down Expand Up @@ -1036,7 +1059,13 @@ def _rotate_failed_credential(rotate_status: int):
# cooldowns — the pool can only tell them apart if we say which.
# ``effective_reason`` is resolved below; this closure runs after.
if effective_reason is not None:
kwargs["failure_reason"] = effective_reason.value
_failure_reason = effective_reason.value
if effective_reason == FailoverReason.billing and billing_unverified:
# Ambiguous billing body (#82154): persist the ambiguity so
# the cooldown is sized as transient, not a 1-hour bench.
from agent.credential_pool import FAILURE_REASON_BILLING_UNVERIFIED
_failure_reason = FAILURE_REASON_BILLING_UNVERIFIED
kwargs["failure_reason"] = _failure_reason
return pool.mark_exhausted_and_rotate(**kwargs)

effective_reason = classified_reason
Expand Down Expand Up @@ -2206,6 +2235,9 @@ def anthropic_prompt_cache_policy(
logger.debug("MoA aggregator cache-policy resolution failed: %s", _moa_exc)
return False, False

if isinstance(eff_model, dict):
eff_model = eff_model.get('model') or eff_model.get('default') or ''
eff_model = eff_model if isinstance(eff_model, str) else str(eff_model or '')
model_lower = eff_model.lower()
provider_lower = eff_provider.lower()
is_claude = "claude" in model_lower
Expand All @@ -2224,7 +2256,7 @@ def anthropic_prompt_cache_policy(
# Nous Portal proxies to OpenRouter behind the scenes — identical
# OpenAI-wire envelope cache_control semantics. Treat it as an
# OpenRouter-equivalent endpoint for caching layout purposes.
is_nous_portal = "nousresearch" in eff_base_url.lower()
is_nous_portal = base_url_host_matches(eff_base_url, "nousresearch.com")
is_anthropic_wire = eff_api_mode == "anthropic_messages"
is_native_anthropic = (
is_anthropic_wire
Expand Down Expand Up @@ -2354,6 +2386,17 @@ def create_openai_client(agent, client_kwargs: dict, *, reason: str, shared: boo
# copy locks the contract so future transport/keepalive work can't reintroduce
# the same class of bug.
client_kwargs = dict(client_kwargs)
# The MoA virtual provider has no real OpenAI wire endpoint - the facade
# *is* the client. Rebuilding a native OpenAI client while
# agent.provider == "moa" (client replacement, stream-retry pool cleanup,
# credential rotation, fallback+restore) drops the facade: the next primary
# call either raises a `_moa_prepared_request` TypeError (#78382) or, when
# _client_kwargs carry an unrelated relay base_url, leaks the request to a
# foreign gateway. Rebuild the facade instead (build_moa_facade also
# re-wires the reference relay, see #53802).
if (getattr(agent, "provider", "") or "").strip().lower() == "moa":
from agent.moa_loop import build_moa_facade
return build_moa_facade(agent, getattr(agent, "model", None) or "default")
ssl_ca_cert = client_kwargs.pop("ssl_ca_cert", None)
ssl_verify_cfg = client_kwargs.pop("ssl_verify", None)
httpx_verify = resolve_httpx_verify(ca_bundle=ssl_ca_cert, ssl_verify=ssl_verify_cfg)
Expand Down Expand Up @@ -3033,6 +3076,7 @@ def _execute(next_args: dict) -> Any:
around_message_id=next_args.get("around_message_id"),
window=next_args.get("window", 5),
sort=next_args.get("sort"),
detail=next_args.get("detail", "adaptive"),
db=session_db,
current_session_id=agent.session_id,
),
Expand Down Expand Up @@ -3570,8 +3614,10 @@ def sanitize_api_messages(messages: List[Dict[str, Any]]) -> List[Dict[str, Any]
if cid:
seen_assistant_call_ids.add(cid)
kept_tcs.append(tc)
if len(kept_tcs) != len(msg.get("tool_calls") or []):
if kept_tcs:
msg = {**msg, "tool_calls": kept_tcs}
elif len(kept_tcs) != len(msg.get("tool_calls") or []):
msg = {k: v for k, v in msg.items() if k != "tool_calls"}
deduped.append(msg)
elif role == "tool":
cid = (msg.get("tool_call_id") or "").strip()
Expand Down Expand Up @@ -3860,7 +3906,9 @@ def _iter_pool_sockets(client: Any):
traversal defensive because these are private transport internals and
vary across httpx/httpcore releases.

Also walks ``httpx`` mount transports — see ``_iter_httpx_pool_objects``.
Also walks ``httpx`` mount transports — see ``_iter_httpx_pool_objects``
— and in-flight httpcore ``PoolRequest.connection`` objects, which stay
reachable even when ``_connections`` is empty during checkout (#85252).
"""
try:
http_client = getattr(client, "_client", None)
Expand All @@ -3877,12 +3925,18 @@ def _iter_pool_sockets(client: Any):

seen: set[int] = set()
for pool in pools:
connections = (
getattr(pool, "_connections", None)
or getattr(pool, "_pool", None)
or []
)
for conn in list(connections):
# Empty-list is falsy: use ``is None`` so an empty ``_connections``
# still lets us walk in-flight ``_requests`` rather than skipping
# the pool entirely.
raw_conns = getattr(pool, "_connections", None)
if raw_conns is None:
raw_conns = getattr(pool, "_pool", None)
connections = list(raw_conns or [])
for pool_req in list(getattr(pool, "_requests", None) or []):
conn = getattr(pool_req, "connection", None)
if conn is not None:
connections.append(conn)
for conn in connections:
for candidate in _connection_candidates(conn):
stream = (
getattr(candidate, "_network_stream", None)
Expand Down Expand Up @@ -4157,6 +4211,16 @@ def force_close_tcp_sockets(client: Any) -> int:
try:
for sock in _iter_pool_sockets(client):
try:
# Clear a blocking timeout first so a hung SSL_read on the
# owner thread notices the shutdown. Some stacks ignore
# SHUT_RDWR alone while recv is blocked with timeout=None
# (#85252). Still no close() — that is the #29507 race.
settimeout = getattr(sock, "settimeout", None)
if callable(settimeout):
try:
settimeout(0)
except OSError:
pass
sock.shutdown(_socket.SHUT_RDWR)
except OSError:
# Already shut down / not connected / FD invalid — all benign.
Expand Down
21 changes: 20 additions & 1 deletion agent/anthropic_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2814,7 +2814,26 @@ def convert_messages_to_anthropic(
p.get("cache_control") for p in content if isinstance(p, dict)
)
if has_cache:
system = [p for p in content if isinstance(p, dict)]
# Copy blocks before coercing so the caller's message
# dicts are never mutated, then replace blank/whitespace
# text with the shared non-whitespace placeholder —
# Anthropic rejects a blank system text block with the
# same HTTP 400 as message blocks ("text content blocks
# must contain non-whitespace text"), and a blank block
# carrying a cache_control breakpoint cannot simply be
# dropped (#70909).
system = []
for p in content:
if not isinstance(p, dict):
continue
if (
p.get("type") == "text"
and isinstance(p.get("text"), str)
and not p["text"].strip()
):
p = dict(p)
p["text"] = _EMPTY_TEXT_PLACEHOLDER
system.append(p)
else:
system = "\n".join(
p["text"] for p in content if p.get("type") == "text"
Expand Down
Loading
Loading