Commit graph

69 commits

Author SHA1 Message Date
Teknium
f944e84858 fix: close review gaps for per-model threshold overrides (#63020)
Follow-up to the salvaged contributor commit, closing the three gaps
flagged in the sweeper review:

1. Init ordering: assign compression.model_thresholds to a selected
   plugin context engine BEFORE the initial update_model() call in
   agent_init.py, so the initial model's override applies from init
   (previously it only took effect after the first /model switch).
   Base-class ContextEngine.update_model() now snapshots the
   pre-override percent once so repeated switches fall back to the
   engine's configured threshold, not a previous model's override.
2. DEFAULT_CONFIG: add compression.model_thresholds (empty map) to
   hermes_cli/config.py — additive key, no _config_version bump.
3. Docs: document the key in
   website/docs/developer-guide/context-compression-and-caching.md
   (yaml example, parameter table, dedicated section) and update the
   plugin-boundary note in context-engine-plugin.md to state the
   explicit context-engine contract for model_thresholds.

Adds tests/run_agent/test_per_model_threshold_init_ordering.py:
plugin-engine AIAgent init regression (override applies at init,
empty map unchanged), DEFAULT_CONFIG key presence, floor interaction
on the model-switch path (override below the small-context floor is
raised to the floor; above the floor wins), and base-class config
snapshot across repeated switches. Also maps @bennybuoy in
contributors/emails/.
2026-07-22 07:00:27 -07:00
Teknium
f453c50b6f test(memory): behavioral check — memory tool handler works with skip_memory=True, provider stays skipped
Follow-up for salvaged PR #65453: extend the regression test to dispatch a
real memory_tool add through the store the tool executor wires in, assert the
write persists to memories/MEMORY.md, and assert the external memory provider
(MemoryManager) is still skipped under skip_memory=True. Also map the
contributor email for attribution CI.

Fixes #65429.
2026-07-22 07:00:16 -07:00
Teknium
17fa5910be chore: map contributor wernerhp 2026-07-22 06:59:14 -07:00
Sora-bluesky
cca7b93bfe chore(contributors): register Sora-bluesky email mapping
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-22 06:58:58 -07:00
Teknium
a43ac2af65 fix(slack): sanitize outbound Block Kit payloads at the API boundary
Consolidated defensive layer for the invalid_blocks / msg_too_long bug
class (#56615, #62054, #53693): one malformed or oversized block fails
the ENTIRE chat.postMessage / chat.update call, so approval cards never
update and messages silently drop.

New block_kit.sanitize_blocks() is applied at every call site that
attaches blocks (send/edit via _maybe_blocks, send_exec_approval,
send_slash_confirm, and the approval/slash-confirm chat.update button
handlers). It:

- truncates section/context text to the 3000-char cap with an ellipsis
  (covers interaction payloads where Slack's HTML-escaping of < > &
  inflates text past the limit budgeted at send time)
- truncates header text to its 150-char cap
- drops empty blocks (no text / elements / rows)
- replaces null table column_settings entries with {} and trims
  default trailing entries (Slack requires every entry be an object)
- caps the payload at Slack's 50-block maximum
- returns None when nothing valid remains so callers fall back to the
  plain-text payload; never raises

Also registers contributor mappings for the salvaged PRs in this
cluster (tw0316, kamonspecial, sowork-skills).
2026-07-22 06:58:34 -07:00
Teknium
961b832c11 test(sessions): cover branch-seed and compression timestamp round-trips
Follow-up to the salvaged #28840 change: forward original timestamps in
_persist_branch_seed (TUI first-turn branch persist), add behavioral
round-trip tests for branch copy and compression-style replace, TUI
protocol tests asserting session.branch and _persist_branch_seed forward
timestamps, and register the contributor email mapping.
2026-07-22 06:58:27 -07:00
Teknium
7d4ed8e321 chore(release): map the3asic noreply email for contributor attribution 2026-07-22 06:58:16 -07:00
Teknium
8a580e8e31 chore: add contributor mapping for tandixit95 2026-07-22 06:57:44 -07:00
Teknium
453d0ee598 chore(contributors): map emails for slack block-text salvage (#29541, #61261, #52390) 2026-07-22 06:57:39 -07:00
Teknium
7f9956a679 chore: map contributor email for @WeiYusc 2026-07-22 06:57:33 -07:00
Teknium
ea0fd393db perf(compression): gate CJK-aware token estimation behind an ASCII fast path
The salvaged estimator ran a per-character Python loop on every
estimate_tokens_rough() call — a ~28,000,000x slowdown vs (len+3)//4 on a
1MB ASCII tool output (measured ~3.0s per call). Gate it:

- str.isascii() O(1) fast path keeps pure-ASCII text bit-identical to the
  classic (len+3)//4 rule at ~1.3x baseline cost (0.23us vs 0.17us per
  1MB call).
- Non-ASCII text counts dense CJK chars via a compiled character-class
  regex in C (len(text) - len(re.sub(''))): ~352ms/1MB hangul vs ~2.1s
  for the per-char loop.
- Non-ASCII-but-non-CJK text (accents, Cyrillic, emoji) keeps the classic
  rule.

Also: parity tests against the per-char reference implementation, and
updated two stale expectations that encoded the old behavior (CJK now
counted ~1 token/char; short string content now ceil-divided instead of
floored to 0). The continuity test now detects merged-into-tail summaries
via _is_context_summary_content.
2026-07-22 06:57:22 -07:00
Teknium
cf433a33da chore: map dombejar contributor email for PR #63870 salvage 2026-07-22 06:56:42 -07:00
Teknium
146a545491 chore(contributors): map LiangYang666 emails 2026-07-22 06:56:20 -07:00
Teknium
f1a1d2daf5 chore(release): map richkapp in AUTHOR_MAP 2026-07-22 06:56:08 -07:00
Teknium
4f0ee4d3ff feat(secrets): rework command source as a registered SecretSource — no provider selector
Reworks the salvaged command module into a CommandSource(SecretSource)
registered as the third bundled source, composing with Bitwarden and
1Password through the apply_all() orchestrator — enable any combination
simultaneously.  The original PR's secrets.provider single-selector is
deliberately dropped: multi-source is first-class and a mutually
exclusive provider switch would regress that.

- fetch() only fetches; precedence/override/conflicts/environ writes stay
  in the orchestrator.  ErrorKind classification + remediation hints.
- apply_command_secrets() kept as a legacy shim (parser/security helpers
  unchanged: HERMES_SECRET_KEY data-only key passing, cross-key misroute
  guard, base64-padding disambiguation, timeout + output cap, structured-
  fields-only failure logging, stderr discarded).
- Dispatch tests rewritten for the registry path incl. an explicit
  two-sources-compose test; selector tests removed with the selector.
- cli-config.yaml.example + docs page (command.md), secrets index entry.
- contributors mapping for mvalentin@valensys.net -> 0xr00tf3rr3t.
2026-07-22 04:39:28 -07:00
Chris Korhonen
81fc424592 fix(openviking): chunk structured session sync
Preserve ordered structured turns across OpenViking's 100-message batch limit and resume retries from the first unconfirmed message.

Based on the OpenViking batching work from commit 1a567f7067 in #58981.
2026-07-22 14:05:28 +05:30
kshitijk4poor
7078430934 fix(telegram): address review findings from PR #67816
- Update test_observed_group_context_preserves_slash_command_text_for_dispatch
  to assert user_id is preserved for COMMAND messages (new correct behavior)
- Add _coerce_allow_set helper to handle both list and comma-separated
  string allowlist inputs (prevents character-by-character iteration bug)
- Include 'channel' in chat_type checks for group-scoped authorization
- Add _telegram_extra fallback for group_allowed_chats (consistent with
  group_allow_from fallback)
- Add AUTHOR_MAP entry for nyaruko@hermes -> tsuk1nose
2026-07-22 12:47:41 +05:30
kshitijk4poor
9eb7b1a6b1 chore: AUTHOR_MAP for McHermes 2026-07-22 11:46:05 +05:30
kshitijk4poor
3e953ed815 chore: AUTHOR_MAP for tinetwork 2026-07-22 10:48:10 +05:30
kshitijk4poor
4999de8fe6 chore: map anoop.mehendale@gmail.com -> anoopmehendale-cue
For PR #69007 salvage (#69112).
2026-07-22 10:31:59 +05:30
Teknium
e2e8823f1d chore(contributors): map yingwaizhiying@gmail.com -> tianma-if (supersedes stale msh01 entry) 2026-07-21 12:56:31 -07:00
Teknium
c4e8ff4d78 chore(contributors): map diffen77 + fazerluga-creator emails
For the #66547 and #66981 salvage cherry-picks in this branch.
2026-07-21 12:43:27 -07:00
Teknium
fb5b8e4c18 chore(contributors): map eazye19@users.noreply.github.com -> eazye19 (PR #42387 salvage) 2026-07-21 12:42:07 -07:00
Teknium
5e4529c02f chore(contributors): map emails for PRs #66906, #66420, #63398 salvage 2026-07-21 12:40:48 -07:00
Teknium
50fdf136e8 chore(contributors): map jaretbottoms@gmail.com -> jbbottoms (PR #65178 salvage) 2026-07-21 12:40:21 -07:00
Joshua
a3297bd232 fix(approval): restore session approval for Tirith-flagged commands
Adds an allow_session flag to the gateway approval payload so adapters
can render the session tier independently of the permanent tier. Matrix
gains a session reaction (🌀) and a reaction legend; pure-tirith prompts
now offer once/session/deny instead of collapsing to once/deny.

Salvaged from PR #67312, adapted to the allow_permanent semantics that
landed in #68597 (Always offered when any dangerous-pattern warning is
persistable; pure-tirith prompts stay session-max).
2026-07-21 12:04:47 -07:00
Austin Pickett
d355e0e71d
feat(desktop): configure repository discovery (supersedes #67630) (#68642)
* feat(desktop): configure repository discovery

* fix(config): preserve additive default migration

* fix(desktop): stabilize session-actions-menu gateway mock for repo-scan subscribe

projects.ts now runs $gateway.subscribe(syncReposScanning) at module load, and
nanostores fires the subscriber synchronously. session-actions-menu.test.ts
reaches projects.ts transitively via the session store but mocked
@/store/gateway without $gateway, crashing the whole desktop vitest suite
("No \ export is defined"). Simply adding $gateway: atom(null) exposed a
second issue: the synchronous subscriber calls the mock's activeGateway()
during the transitive import, before the module-level const initializes (TDZ).

Hoist the mock fns via vi.hoisted() so activeGateway is defined before the
hoisted vi.mock factory runs, and add $gateway: atom(null) to the mock. Mirrors
the self-contained mock pattern already used in projects.test.ts. Also maps the
PR author's commit email for attribution.

Supersedes #67630; incorporates review feedback from that PR.

Co-authored-by: Rudimar Ronsoni <rudimar@outlook.com>

---------

Co-authored-by: Rudimar Ronsoni <rudimar@outlook.com>
Co-authored-by: Austin Pickett <austinpickett@users.noreply.github.com>
2026-07-21 10:09:31 -04:00
TARS
c44c2fbb0b fix(codex): send ChatGPT-Account-Id on /models probes
The Codex backend returns the per-account model catalog only when the
ChatGPT-Account-Id header is present. Without it, GET /backend-api/codex/models
responds 200 OK with {"models":[]} and the picker silently degrades to the
hardcoded fallback list — which is stale or wrong for the active plan
(no GPT-5.6 family, wrong context windows).

This was the upstream bug behind slow first responses and HTTP 520/120s SSE
hangs: Hermes was sending invalid slugs because the probe never saw them in
the catalog, and Codex's request builder also depends on the same JWT claim
that's now being threaded through both probe paths.

Fixes the probe-side paths in hermes_cli/codex_models.py and
agent/model_metadata.py by extracting chatgpt_account_id from the OAuth JWT
(mirroring the request-side logic already in auxiliary_client.py) and sending
it as a header.

Verified live:
- _fetch_models_from_api now returns the 10-model catalog (gpt-5.6-sol,
  gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-5.4-mini,
  gpt-5.3-codex-spark, 3x -pro variants) instead of [].
- _fetch_codex_oauth_context_lengths resolves all 8 account models to 272K
  context (matches direct API probes of the same account).
- end-to-end: hermes chat -m gpt-5.6-sol -q 'Reply with one word: pong'
  returns 'pong' cleanly via the openai-codex route.

Same class of bug as PR #64760.
2026-07-21 05:27:13 -07:00
Teknium
3ef6bbd201
chore: release v0.19.0 (2026.7.20) (#68175) 2026-07-20 11:35:21 -07:00
Teknium
086a56a028 fix(matrix): correct platform hint over-claims, add regression tests + docs
Follow-up to the salvaged #52552 and #53083 commits:

- Rework the Matrix PLATFORM_HINTS entry around what the adapter actually
  emits: headings, numbered lists, blockquotes, strikethrough-free markdown
  all render (the adapter converts them to sanctioned HTML). Keep the
  genuinely valuable guidance: no Markdown tables (Element X / Beeper /
  mobile clients don't render HTML tables — cells collapse into one line),
  no spoilers/checkboxes/~~strikethrough~~ (not converted by
  python-markdown), prefer descriptive link text.
- Regression test: hint must steer models away from tables.
- Fix test_long_response_split_preserves_thread_context to derive its
  payload size from the adapter's configurable limit instead of assuming
  the old hardcoded 4000.
- Document matrix.max_message_length in the Matrix docs page.
- Contributor mapping for RKelln.
2026-07-20 11:10:49 -07:00
Teknium
456f18b19c fix(picker): scope exact-ID resolution to lossy alias collapses only
The cherry-picked resolve_provider_full 0.5 step returned a generic
openai_chat ProviderDef for ANY registry ID, hijacking single-entry
alias rewrites like copilot -> github-copilot away from their overlay
transports (test_explicit_copilot_switch_uses_selected_model_api_mode
regression). Restrict the early return to names where MULTIPLE registry
providers collapse to one canonical (kimi-coding + kimi-coding-cn +
kimi + moonshot -> kimi-for-coding) — the only case where alias
resolution actually loses information.

Also maps Almurat123's contributor email.
2026-07-20 10:17:57 -07:00
Teknium
17a99f6b15 chore: map contributor ly-wang19 for #49551 salvage 2026-07-20 09:21:08 -07:00
Teknium
977884e6cd chore: add contributor email mappings for PR #58019 / #29552 salvage 2026-07-20 09:19:24 -07:00
Teknium
25eafd7d71 fix(models): complete kimi-k3 rollout across Kimi-direct catalog surfaces
Follow-up widening for salvaged PRs #67115, #67685, #67620:

- _PROVIDER_MODELS: add kimi-k3 atop kimi-coding / moonshot / opencode-go
  curated lists (kimi-coding-cn covered by cherry-picked #67620)
- setup.py _DEFAULT_PROVIDER_MODELS: kimi-k3 for kimi-coding(-cn) + opencode-go
- model_metadata: align DEFAULT_CONTEXT_LENGTHS kimi-k3 entry to 1,048,576
  (matches endpoint-scoped override, models.dev, and OpenRouter live metadata)
- anthropic_adapter: classify the bare Coding Plan slug 'k3' (and k3.x/k3-*)
  as Kimi family so adaptive thinking applies on proxied endpoints
- moonshot_schema: is_moonshot_model matches bare 'k3' so tool-schema
  sanitization runs on the chat-completions path
- contributor mappings for githubespresso407, datachainsystems, Punyko8

Tests: 582 passed across 11 targeted files; hermetic E2E verifies picker
order (kimi-k3 first), no dupes, and 1M context resolution.
2026-07-20 08:47:55 -07:00
Teknium
31c08a9aad chore: map contributor email for context probe 2026-07-20 05:49:44 -07:00
Teknium
330b224525 chore: map logical-and contributor for #62873 salvage 2026-07-20 05:39:09 -07:00
Teknium
3b86af90ed chore: map geo-prefix contributor emails 2026-07-20 05:38:45 -07:00
Teknium
c8027d5e60 chore: map contributor email for whitespace-block fix 2026-07-20 03:27:38 -07:00
Teknium
7120f9cba9 chore: map bedrock-cluster contributor emails 2026-07-20 03:27:28 -07:00
Teknium
c1af3772fc chore: map salvage contributor deepujain 2026-07-20 03:06:02 -07:00
Teknium
2ec1e81036 chore: add contributor email mapping for GottZ 2026-07-20 02:25:57 -07:00
Teknium
d587048fca chore: map salvage contributor emails to GitHub logins 2026-07-20 02:25:44 -07:00
Teknium
d46b3bdeb4 chore: map salvage contributors 2026-07-20 00:41:01 -07:00
Teknium
9fc35e0a31 chore: add contributor email mapping for Dhravya 2026-07-20 00:40:40 -07:00
Teknium
39b30bacf7 docs(x_search): comment out reasoning_effort in sample config blocks
The copy-paste config sample had reasoning_effort: low active, which
would silently downshift effort for anyone pasting the block. Keep it
commented like other optional keys. Also add the contributor email
mapping for the salvage.
2026-07-19 23:58:33 -07:00
kshitijk4poor
0144743b21 chore: add contributor email mapping for kshitijk4poor 2026-07-20 12:13:37 +05:30
Austin Pickett
3d97893571
feat(desktop): custom endpoint settings (supersedes #42745) (#67759)
* feat(desktop): add custom endpoint settings (supersedes #42745)

Salvages PR #42745 (elashera:custom-endpoints-desktop), which could no
longer merge cleanly against main. Re-integrated the work onto current
main and reconciled the conflicts:

- Settings nav: wired the new 'Custom Endpoints' provider sub-view into
  main's data-driven navGroups/OverlayNav layout (PR predated that
  refactor) and added it to PROVIDER_VIEWS.
- providers-settings: kept BOTH main's LocalEndpointRow affordance and
  the PR's fuller CRUD panel; unified ProvidersSettingsProps to carry
  onClose + onConfigSaved + onMainModelChanged.
- web_server: kept main's _normalize_main_model_assignment + api_key
  propagation AND the PR's provider base_url lookup in
  _apply_model_assignment_sync.
- model_switch: dropped the PR's bare direct-custom-config picker block;
  main already implements it (source='model-config', with live model
  discovery). Updated the salvaged test to assert main's behavior.
- Merged additive import/type blocks in hermes.ts and types/hermes.ts.

Backend endpoints, i18n labels (en/ja/zh/zh-hant), and the
custom-endpoints-settings.tsx panel carried over. 28 custom-endpoint
tests pass.

Co-authored-by: elashera <emilio.jesus.lasheras.romero@nttdata.com>

* chore(contributors): map elashera's commit email

Salvage of #42745 (superseded by #67759) preserves @elashera's
authorship, whose corporate commit email had no contributor mapping.
Adds contributors/emails/ mapping so check-attribution passes.
Verified: GitHub user 'elashera' id=135239963 matches their own
noreply commit email (135239963+elashera@users.noreply.github.com).

---------

Co-authored-by: elashera <emilio.jesus.lasheras.romero@nttdata.com>
2026-07-19 19:59:46 -04:00
Austin Pickett
bc6839aa37
fix(desktop): stop hard-failing pack on non-git checkouts + fix ZIP-path autocrlf (supersedes #67643) (#67730)
* fix(desktop): allow write-build-stamp from non-git checkouts

Stop hard-failing npm pack when neither GITHUB_SHA nor git HEAD is
available (ZIP installs / broken .git). Emit an explicit fallback stamp
instead so local Windows desktop builds can finish (#50823).

* fix(desktop): treat fallback stamps as unpinned; harden Windows install

Keep all-zero fallback commits out of -Commit/--commit pins and fetch
install.ps1 by branch instead. After bootstrap, pin the marker to the
checkout HEAD so isBootstrapComplete accepts it. On Windows, force ZIP
checkout, seed GITHUB_SHA (ASCII-only install.ps1), and avoid the pack
stamp failure.

* fix(install): pin core.autocrlf=false before ZIP-path checkout (#50823 review)

The ZIP-fallback path added in #67643 runs `git checkout -f FETCH_HEAD`
before core.autocrlf gets pinned (which only happened later, on the
shared clone-path config). On Git for Windows -- where core.autocrlf
defaults to true -- that renormalizes the repo's LF text files to CRLF in
the working tree during checkout, leaving the freshly-created managed
checkout dirty versus HEAD and aborting the next `hermes update`. That is
the exact "dirty tree the user never touched" failure the surrounding
code already guards against (install.ps1:1461-1469, 1750-1753).

Move the `config core.autocrlf false` pin to run immediately after
`git init`, before the fetch/checkout. The later idempotent pin on the
shared clone path is retained so git-clone installs are unaffected.

Addresses teknium1's review on #67643 and supersedes it, preserving the
original author's two commits.

Co-authored-by: HexLab98 <8422520+HexLab98@users.noreply.github.com>

* chore(contributors): map austinpickett commit email for attribution

The check-attribution CI gate flagged austinpickett@users.noreply.github.com
as an unmapped commit-author email (introduced by the autocrlf fix commit
on this PR). Add the per-email mapping file as the gate instructs (the
legacy AUTHOR_MAP in scripts/release.py is frozen).

---------

Co-authored-by: HexLab98 <liruixinch@outlook.com>
Co-authored-by: austinpickett <austinpickett@users.noreply.github.com>
Co-authored-by: HexLab98 <8422520+HexLab98@users.noreply.github.com>
2026-07-19 19:29:36 -04:00
liqiping
60811ced37 feat(agent): adaptive thinking for Kimi-family Anthropic endpoints
Kimi's Anthropic-compatible endpoints (api.moonshot.cn/anthropic,
api.kimi.com/coding) implement the adaptive thinking contract — they
accept thinking.type=adaptive + output_config.effort (all of low,
medium, high, xhigh, max verified live) and return thinking blocks, and
the replay-validation 400s that originally motivated dropping the
parameter (#13848) no longer occur.

_supports_adaptive_thinking() now returns True for Kimi-family models,
so they get thinking={type: adaptive, display: summarized} +
output_config.effort via ADAPTIVE_EFFORT_MAP instead of nothing, and
the blanket drop of the thinking parameter for Kimi-family endpoints is
removed. MiniMax and other non-adaptive third parties keep the manual
budget_tokens path; Claude behavior is unchanged.
2026-07-19 12:21:59 -07:00
digitalbase
5f2bfb6631 fix(desktop): scope the cron jobs list to the active profile
Salvaged from #42654 by @digitalbase (earliest report of the leak, June 9):
the desktop sidebar and cron overlay showed EVERY profile's jobs because
GET /api/cron/jobs defaults to profile=all and the desktop never sent the
param — profileScoped() (landed in #67493) routes the backend process but
adds no endpoint filter on local pools.

- hermes.ts: getCronJobs(profile?) appends ?profile= when given; omitting
  the arg keeps the legacy unfiltered path. profileScoped() still rides
  along for process routing.
- use-session-list-actions.ts: sidebar cron refresh passes the sidebar's
  profile scope (concrete profile → own jobs; ALL_PROFILES → 'all').
- app/cron/index.tsx: the cron overlay's refresh uses the same scope so
  the overlay and sidebar (shared $cronJobs atom) always agree.
- Tests: list ?profile= contract in hermes-cron-scope.test.ts; sidebar
  scoping in use-session-list-actions.test.tsx.

Reworked onto current main per the sweeper review: threaded through the
existing profileScoped()/list-param seams instead of the original PR's
pre-refactor call sites (DesktopController has since delegated to
use-session-list-actions).
2026-07-19 12:19:22 -07:00