feat(acp): honor --toolsets and add per-session tool scoping - #45958
feat(acp): honor --toolsets and add per-session tool scoping#45958awizemann wants to merge 2 commits into
--toolsets and add per-session tool scoping#45958Conversation
|
Prior art + a design note for reviewers — re: why this threads This change serves the same per-session-isolation concern that motivated I deliberately thread
Precedence stays additive and backward-compatible: per-session override > process |
ACP sessions previously always got enabled_toolsets=["hermes-acp"]: `_make_agent` hardcoded the list and `hermes acp --toolsets` was parsed but never threaded through, so per-project tool scoping was impossible for an ACP client driving one process across many sessions. - SessionManager(default_toolsets=...) sets a process-wide default - create_session(toolsets=...) / _make_agent(toolsets=...) resolve via a new _resolved_toolsets: per-session override > process default > ["hermes-acp"] - session/new accepts an optional per-session `toolsets` (top-level or _meta) - `hermes acp --toolsets` is forwarded to the adapter and honored - tests/acp_adapter/test_acp_toolsets.py (4 tests) Backward compatible: a session specifying nothing still gets ["hermes-acp"]. Closes NousResearch#45955 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Map alan@wizemann.com -> awizemann so the Contributor Attribution Check passes for NousResearch#45958 (first contribution). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
416fc95 to
bdbad40
Compare
|
Heads up for reviewers: the failing Root cause (in The amd64 job is unaffected because it uses Possible fixes:
Happy to open a small workflow PR if that'd help. |
Promote Project to a first-class, fleet-aware entity per the Milestone-1 implementation spec. - ScarfProject (ScarfCore): canonical Codable record with lenient/additive decoding and ISO-8601 dates; deferred tool/skill scoping fields stay empty. - ProjectStore (ScarfCore): load/save the canonical <project>/.scarf/project.json plus the registry index; additive, idempotent, non-destructive derive() migration. Extend ProjectEntry with a stable `uuid` (excluded from Equatable/Hashable so selection identity stays name+path). - Invert ProjectAgentContextService.renderBlock to render from ScarfProject; SECRET-SAFE / IDEMPOTENT / BOUNDED / NON-FATAL invariants preserved. Cron line now matches [proj:<id>] and legacy [tmpl:<id>]. - ProjectCockpitView: a DashboardTab.cockpit tab reusing ProjectSessionsView and ProjectKanbanTab plus Context/Cron/Memory/Secrets/Templates panels. - ProjectScaffolder mints the UUID and writes project.json via ProjectStore. - Lazy migration wired into ProjectsView.task. Tool-scoping stays deferred (NousResearch/hermes-agent#45958); mini-apps are Milestone 2. Tests: ScarfCore 637 pass (incl. ScarfProjectTests, ProjectStoreTests); ProjectAgentContextServiceTests 13/13, ProjectScaffolderTests 3/3. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d host (Phase-1 Milestone 2) First increment of Milestone 2 (Cowork-style mini-apps): the model layer plus the sandboxed rendering host. The window.scarf bridge, permission preview sheet, and cockpit integration land in follow-on increments. - MiniAppManifest + MiniAppPermission (ScarfCore): lenient Codable manifest; default-deny permission model (parameterized `query:<kind>`, unknown→deny, sensitive-surface flags). - ScarfProject.miniApps + MiniAppRef — the M1→M2 bridge field. The portable record carries only the registry (id + `generated` provenance); permission grants are deliberately NOT portable (a clone re-approves untrusted/agent-generated content for itself). - MiniAppService: discovers/loads `.scarf/miniapps/<id>/miniapp.json` (forces id = dir name so a manifest can't redirect the scheme handler); ProjectStore.derive now populates miniApps. - MiniAppAssetResolver (ScarfCore, pure + unit-tested): `scarf-miniapp://` path containment (rejects traversal escapes), MIME, strict CSP (`connect-src 'none'`). - MiniAppSchemeHandler + MiniAppHostView (Mac): directory-scoped, read-only asset server + WKWebView host with navigation locked to the scheme. Tool-scoping stays deferred (NousResearch/hermes-agent#45958). Tests: 16 new (MiniAppTests 9, MiniAppAssetResolverTests 7); ScarfCore 8/8 full-suite parallel runs green; app builds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
teknium1
left a comment
There was a problem hiding this comment.
Thanks — the underlying hardcode is still present on current main at acp_adapter/session.py:619-622, so the feature is still needed. Two correctness gaps need resolution.
Problems
- The per-session override is used only for the initial
session/newconstruction (acp_adapter/server.py:1140-1141in this PR). A later/modelreconstructs the same session’s agent without atoolsetsargument (acp_adapter/server.py:1776-1781on current main), andSessionStatedoes not retain the override. That silently resets a scoped session to the process/default toolset. - The PR forwards
args.toolsetsincmd_acp, but current ACP command parsing is inhermes_cli/subcommands/acp.py:14-52, which has no--toolsetsoption. Thus the documentedhermes acp --toolsets ...form remains unparseable after salvage.
Suggested changes
- Retain the resolved per-session selection in
SessionStateand forward it through agent rebuilds; add a model-switch regression test. - Add the ACP-subcommand argument in
build_acp_parserand coverhermes acp --toolsets web,fileparsing/forwarding.
This is an automated hermes-sweeper review.
| ) -> NewSessionResponse: | ||
| state = self.session_manager.create_session(cwd=cwd) | ||
| toolsets = self._toolsets_from_new_session_params(kwargs) | ||
| state = self.session_manager.create_session(cwd=cwd, toolsets=toolsets) |
There was a problem hiding this comment.
This passes the override only to the first agent construction. /model later reconstructs the same session through _make_agent(...) without toolsets (acp_adapter/server.py:1776-1781 on current main), so this session silently reverts to the manager default. Store the resolved selection on SessionState and forward it on rebuilds.
| if toolsets: | ||
| if isinstance(toolsets, (list, tuple)): | ||
| toolsets = ",".join(str(t) for t in toolsets) | ||
| acp_argv.extend(["--toolsets", str(toolsets)]) |
There was a problem hiding this comment.
Forwarding is not enough for the documented hermes acp --toolsets ... form: current ACP parser construction is hermes_cli/subcommands/acp.py:14-52 and declares no --toolsets flag. Add it there during salvage and cover the post-subcommand spelling.
Closes #45955.
Problem
ACP sessions always received
enabled_toolsets=["hermes-acp"]:acp_adapter/session.py::_make_agenthardcoded the list, and thehermes acp --toolsetsflag was parsed but never threaded into the adapter. An ACP client driving a single long-livedhermes acpprocess across many sessions (e.g. a GUI with per-project chats) had no way to scope a session's tools.Change (additive, backward compatible)
SessionManager(default_toolsets=…)— a process-wide default (accepts a list or a comma/space string).create_session(toolsets=…)→_make_agent(toolsets=…)resolve through a newSessionManager._resolved_toolsets, with precedence: per-session override > process default >["hermes-acp"].session/newreads an optional per-sessiontoolsets(top-level field or under ACP_meta).hermes acp --toolsetsis forwarded (cmd_acp→entry._parse_args→HermesACPAgent(default_toolsets=…)) and finally honored.A session that specifies nothing still resolves to
["hermes-acp"], so existing behavior is unchanged.Notes / scope
toolsetsvs_meta.toolsets) — happy to align with whatever you prefer.Tests
tests/acp_adapter/test_acp_toolsets.py(4 tests) covering normalization, the resolution precedence, the resolved list feeding_expand_acp_enabled_toolsets, andsession/newparam extraction.(19 existing + 4 new; modified modules import clean.)