mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
time to cook
This commit is contained in:
parent
05c01af68c
commit
5a346903d2
17 changed files with 49 additions and 676 deletions
164
.github/workflows/upload_to_pypi.yml
vendored
164
.github/workflows/upload_to_pypi.yml
vendored
|
|
@ -1,164 +0,0 @@
|
|||
name: Publish to PyPI
|
||||
|
||||
# Triggered by CalVer tag pushes from scripts/release.py (e.g. v2026.5.15)
|
||||
# Can also be triggered manually from the Actions tab as an escape hatch.
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v20*" # CalVer tags: v2026.5.15, v2026.5.15.2, etc.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
confirm_tag:
|
||||
description: "Tag to publish (e.g. v2026.5.15). Must already exist."
|
||||
required: true
|
||||
type: string
|
||||
|
||||
# Restrict default token to read-only; each job escalates as needed.
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Prevent overlapping publishes (e.g. two same-day tags pushed quickly).
|
||||
concurrency:
|
||||
group: pypi-publish
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build distribution 📦
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
# On workflow_dispatch, check out the confirmed tag.
|
||||
ref: ${{ inputs.confirm_tag || github.ref }}
|
||||
fetch-tags: true
|
||||
|
||||
- name: Validate tag exists
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
run: |
|
||||
if ! git tag -l "${{ inputs.confirm_tag }}" | grep -q .; then
|
||||
echo "::error::Tag '${{ inputs.confirm_tag }}' does not exist in the repo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # 8.2.0
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
- name: Build web dashboard
|
||||
run: cd web && npm ci && npm run build
|
||||
|
||||
- name: Build TUI bundle
|
||||
run: cd ui-tui && npm ci && npm run build
|
||||
|
||||
- name: Bundle TUI into hermes_cli
|
||||
run: |
|
||||
mkdir -p hermes_cli/tui_dist
|
||||
cp ui-tui/dist/entry.js hermes_cli/tui_dist/entry.js
|
||||
|
||||
- name: Verify frontend assets exist
|
||||
run: |
|
||||
test -f hermes_cli/web_dist/index.html || { echo "ERROR: web_dist not built"; exit 1; }
|
||||
test -f hermes_cli/tui_dist/entry.js || { echo "ERROR: tui_dist not built"; exit 1; }
|
||||
|
||||
- name: Bundle install scripts into wheel
|
||||
run: |
|
||||
mkdir -p hermes_cli/scripts
|
||||
cp scripts/install.sh hermes_cli/scripts/install.sh
|
||||
cp scripts/install.ps1 hermes_cli/scripts/install.ps1
|
||||
|
||||
- name: Build wheel and sdist
|
||||
run: uv build --sdist --wheel
|
||||
|
||||
- name: Upload distribution artifacts
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
|
||||
publish:
|
||||
name: Publish to PyPI
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: pypi
|
||||
url: https://pypi.org/p/hermes-agent
|
||||
permissions:
|
||||
id-token: write # OIDC trusted publishing
|
||||
|
||||
steps:
|
||||
- name: Download distribution artifacts
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
|
||||
- name: Publish to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
|
||||
with:
|
||||
skip-existing: true
|
||||
|
||||
sign:
|
||||
name: Sign and attach to GitHub Release
|
||||
# Only runs on tag pushes — release.py creates the GitHub Release,
|
||||
# and workflow_dispatch won't have a matching release to attach to.
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
needs: publish
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write # attach assets to the existing release
|
||||
id-token: write # sigstore signing
|
||||
|
||||
steps:
|
||||
- name: Download distribution artifacts
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
|
||||
- name: Wait for GitHub Release to exist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
# release.py creates the GitHub Release after pushing the tag,
|
||||
# but this workflow starts from the tag push — wait for it.
|
||||
run: |
|
||||
for i in $(seq 1 30); do
|
||||
if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
|
||||
echo "Release $GITHUB_REF_NAME found"
|
||||
exit 0
|
||||
fi
|
||||
echo "Waiting for release... ($i/30)"
|
||||
sleep 10
|
||||
done
|
||||
echo "::warning::Release $GITHUB_REF_NAME not found after 5 minutes — skipping signature upload"
|
||||
echo "skip_sign=true" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Sign with Sigstore
|
||||
if: env.skip_sign != 'true'
|
||||
uses: sigstore/gh-action-sigstore-python@04cffa1d795717b140764e8b640de88853c92acc # v3.3.0
|
||||
with:
|
||||
inputs: >-
|
||||
./dist/*.tar.gz
|
||||
./dist/*.whl
|
||||
|
||||
- name: Attach signed artifacts to GitHub Release
|
||||
if: env.skip_sign != 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
# release.py already created the GitHub Release — just upload
|
||||
# the Sigstore signatures alongside the existing assets.
|
||||
run: >-
|
||||
gh release upload
|
||||
"$GITHUB_REF_NAME" dist/*.sigstore.json
|
||||
--repo "$GITHUB_REPOSITORY"
|
||||
--clobber
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"id": "hermes-agent",
|
||||
"name": "Hermes Agent",
|
||||
"version": "0.18.0",
|
||||
"description": "Self-improving open-source AI agent by Nous Research with ACP editor integration, persistent memory, skills, and rich tool support.",
|
||||
"repository": "https://github.com/NousResearch/hermes-agent",
|
||||
"website": "https://hermes-agent.nousresearch.com/docs/user-guide/features/acp",
|
||||
"authors": ["Nous Research"],
|
||||
"license": "MIT",
|
||||
"distribution": {
|
||||
"uvx": {
|
||||
"package": "hermes-agent[acp]==0.18.0",
|
||||
"args": ["hermes-acp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" fill="none">
|
||||
<path d="M8 1.5v13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M8 3.25c-2.35-1.4-4.7-.95-6.25.35 1.85-.2 3.8.2 5.55 1.55" stroke="currentColor" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8 3.25c2.35-1.4 4.7-.95 6.25.35-1.85-.2-3.8.2-5.55 1.55" stroke="currentColor" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8 13.25c-2.3-1-3.05-2.65-1.35-4.15-2 .8-2.35 2.95-.35 4" stroke="currentColor" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8 13.25c2.3-1 3.05-2.65 1.35-4.15 2 .8 2.35 2.95.35 4" stroke="currentColor" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="8" cy="1.8" r="1.1" fill="currentColor"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 882 B |
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
"""Welcome banner, ASCII art, skills summary, and update check for the CLI.
|
||||
|
||||
Pure display functions with no HermesCLI state dependency.
|
||||
|
|
@ -882,6 +884,7 @@ def build_welcome_banner(console: "Console", model: str, cwd: str,
|
|||
from hermes_cli.config import (
|
||||
detect_install_method,
|
||||
format_unsupported_install_warning,
|
||||
get_project_root,
|
||||
is_unsupported_install_method,
|
||||
get_project_root
|
||||
)
|
||||
|
|
|
|||
|
|
@ -548,12 +548,14 @@ def recommended_update_command() -> str:
|
|||
#
|
||||
# pip/PyPI and Homebrew are NOT an officially supported distribution method
|
||||
# (see website/docs/getting-started/platform-support.md, "Unsupported"
|
||||
# section). pip exists on PyPI for internal/CI reasons, not end-user installs;
|
||||
# Homebrew is a legacy packaging path. Unlike NixOS/Homebrew "managed mode"
|
||||
# (which hard-blocks config writes), this is a warn-don't-block deprecation
|
||||
# notice surfaced everywhere the user might see install-method state: the CLI
|
||||
# banner, the TUI/desktop session info panel, and ``hermes update``. NixOS
|
||||
# stays fully supported (Tier 2) and must never hit this path.
|
||||
# section). Hermes Agent is no longer published to PyPI or packaged for
|
||||
# Homebrew — existing installs from either keep running on whatever version
|
||||
# they last pulled, but will never see a newer one. Unlike NixOS/Homebrew
|
||||
# "managed mode" (which hard-blocks config writes), this is a warn-don't-block
|
||||
# deprecation notice surfaced everywhere the user might see install-method
|
||||
# state: the CLI banner, the TUI/desktop session info panel, and
|
||||
# ``hermes update``. NixOS stays fully supported (Tier 2) and must never hit
|
||||
# this path.
|
||||
|
||||
PLATFORM_SUPPORT_DOCS_URL = "https://hermes-agent.nousresearch.com/docs/getting-started/platform-support"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
Homebrew packaging notes for Hermes Agent.
|
||||
|
||||
Use `packaging/homebrew/hermes-agent.rb` as a tap or `homebrew-core` starting point.
|
||||
|
||||
Key choices:
|
||||
- Stable builds should target the semver-named sdist asset attached to each GitHub release, not the CalVer tag tarball.
|
||||
- `faster-whisper` now lives in the `voice` extra, which keeps wheel-only transitive dependencies out of the base Homebrew formula.
|
||||
- The wrapper exports `HERMES_BUNDLED_SKILLS`, `HERMES_OPTIONAL_SKILLS`, and `HERMES_MANAGED=homebrew` so packaged installs keep runtime assets and defer upgrades to Homebrew.
|
||||
|
||||
Typical update flow:
|
||||
1. Bump the formula `url`, `version`, and `sha256`.
|
||||
2. Refresh Python resources with `brew update-python-resources --print-only hermes-agent`.
|
||||
3. Keep `ignore_packages: %w[certifi cryptography pydantic]`.
|
||||
4. Verify `brew audit --new --strict hermes-agent` and `brew test hermes-agent`.
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
class HermesAgent < Formula
|
||||
include Language::Python::Virtualenv
|
||||
|
||||
desc "Self-improving AI agent that creates skills from experience"
|
||||
homepage "https://hermes-agent.nousresearch.com"
|
||||
# Stable source should point at the semver-named sdist asset attached by
|
||||
# scripts/release.py, not the CalVer tag tarball.
|
||||
url "https://github.com/NousResearch/hermes-agent/releases/download/v2026.3.30/hermes_agent-0.6.0.tar.gz"
|
||||
sha256 "<replace-with-release-asset-sha256>"
|
||||
license "MIT"
|
||||
|
||||
depends_on "certifi" => :no_linkage
|
||||
depends_on "cryptography" => :no_linkage
|
||||
depends_on "libyaml"
|
||||
depends_on "python@3.14"
|
||||
|
||||
pypi_packages ignore_packages: %w[certifi cryptography pydantic]
|
||||
|
||||
# Refresh resource stanzas after bumping the source url/version:
|
||||
# brew update-python-resources --print-only hermes-agent
|
||||
|
||||
def install
|
||||
venv = virtualenv_create(libexec, "python3.14")
|
||||
venv.pip_install resources
|
||||
venv.pip_install buildpath
|
||||
|
||||
pkgshare.install "skills", "optional-skills"
|
||||
|
||||
%w[hermes hermes-agent hermes-acp].each do |exe|
|
||||
next unless (libexec/"bin"/exe).exist?
|
||||
|
||||
(bin/exe).write_env_script(
|
||||
libexec/"bin"/exe,
|
||||
HERMES_BUNDLED_SKILLS: pkgshare/"skills",
|
||||
HERMES_OPTIONAL_SKILLS: pkgshare/"optional-skills",
|
||||
HERMES_MANAGED: "homebrew"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
test do
|
||||
assert_match "Hermes Agent v#{version}", shell_output("#{bin}/hermes version")
|
||||
|
||||
managed = shell_output("#{bin}/hermes update 2>&1")
|
||||
assert_match "managed by Homebrew", managed
|
||||
assert_match "brew upgrade hermes-agent", managed
|
||||
end
|
||||
end
|
||||
|
|
@ -576,7 +576,6 @@ def main(argv: list[str]) -> int:
|
|||
REPO_ROOT / "plugins",
|
||||
REPO_ROOT / "scripts",
|
||||
REPO_ROOT / "acp_adapter",
|
||||
REPO_ROOT / "acp_registry",
|
||||
]
|
||||
roots = [r for r in roots if r.exists()]
|
||||
elif args.diff:
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ Usage:
|
|||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
|
|
@ -34,11 +33,6 @@ REPO_ROOT = Path(__file__).resolve().parent.parent
|
|||
VERSION_FILE = REPO_ROOT / "hermes_cli" / "__init__.py"
|
||||
PYPROJECT_FILE = REPO_ROOT / "pyproject.toml"
|
||||
|
||||
# ACP Registry manifest must stay version-locked with pyproject.toml.
|
||||
# tests/acp/test_registry_manifest.py enforces this lockstep so the release
|
||||
# bump touches both files atomically.
|
||||
ACP_REGISTRY_MANIFEST = REPO_ROOT / "acp_registry" / "agent.json"
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
# Git email → GitHub username mapping
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
|
|
@ -1973,70 +1967,6 @@ def update_version_files(semver: str, calver_date: str):
|
|||
)
|
||||
desktop_pkg.write_text(pkg_text, encoding="utf-8")
|
||||
|
||||
# Update ACP Registry manifest + npm launcher (must stay version-locked
|
||||
# with pyproject — enforced by tests/acp/test_registry_manifest.py).
|
||||
_update_acp_registry_versions(semver)
|
||||
|
||||
|
||||
def _update_acp_registry_versions(semver: str) -> None:
|
||||
"""Bump the ACP Registry manifest's version + uvx package pin in lockstep
|
||||
with pyproject.
|
||||
|
||||
Skips silently if the manifest is missing — older release branches predate
|
||||
the ACP Registry assets.
|
||||
"""
|
||||
if ACP_REGISTRY_MANIFEST.exists():
|
||||
manifest = json.loads(ACP_REGISTRY_MANIFEST.read_text(encoding="utf-8"))
|
||||
manifest["version"] = semver
|
||||
uvx = manifest.get("distribution", {}).get("uvx", {})
|
||||
if "package" in uvx:
|
||||
uvx["package"] = f"hermes-agent[acp]=={semver}"
|
||||
# Preserve trailing newline + 2-space indent the file already uses.
|
||||
ACP_REGISTRY_MANIFEST.write_text(
|
||||
json.dumps(manifest, indent=2) + "\n", encoding="utf-8"
|
||||
)
|
||||
|
||||
|
||||
def build_release_artifacts(semver: str) -> list[Path]:
|
||||
"""Build sdist/wheel artifacts for the current release.
|
||||
|
||||
Tries ``uv build`` first (matching the CI workflow), falls back to
|
||||
``python -m build`` if uv is unavailable.
|
||||
"""
|
||||
dist_dir = REPO_ROOT / "dist"
|
||||
shutil.rmtree(dist_dir, ignore_errors=True)
|
||||
|
||||
# Prefer uv build (matches CI workflow), fall back to python -m build.
|
||||
uv_bin = shutil.which("uv")
|
||||
if uv_bin:
|
||||
cmd = [uv_bin, "build", "--sdist", "--wheel"]
|
||||
else:
|
||||
cmd = [sys.executable, "-m", "build", "--sdist", "--wheel"]
|
||||
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
cwd=str(REPO_ROOT),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
print(" ⚠ Could not build Python release artifacts.")
|
||||
stderr = result.stderr.strip()
|
||||
stdout = result.stdout.strip()
|
||||
if stderr:
|
||||
print(f" {stderr.splitlines()[-1]}")
|
||||
elif stdout:
|
||||
print(f" {stdout.splitlines()[-1]}")
|
||||
print(" Install uv or the 'build' package to attach sdist/wheel assets.")
|
||||
return []
|
||||
|
||||
artifacts = sorted(p for p in dist_dir.iterdir() if p.is_file())
|
||||
matching = [p for p in artifacts if semver in p.name]
|
||||
if not matching:
|
||||
print(" ⚠ Built artifacts did not match the expected release version.")
|
||||
return []
|
||||
return matching
|
||||
|
||||
|
||||
def resolve_author(name: str, email: str) -> str:
|
||||
"""Resolve a git author to a GitHub @mention."""
|
||||
|
|
@ -2376,8 +2306,6 @@ def main():
|
|||
|
||||
# Commit version bump
|
||||
add_files = [str(VERSION_FILE), str(PYPROJECT_FILE)]
|
||||
if ACP_REGISTRY_MANIFEST.exists():
|
||||
add_files.append(str(ACP_REGISTRY_MANIFEST))
|
||||
add_result = git_result("add", *add_files)
|
||||
if add_result.returncode != 0:
|
||||
print(f" ✗ Failed to stage version files: {add_result.stderr.strip()}")
|
||||
|
|
@ -2410,14 +2338,6 @@ def main():
|
|||
print(" Continue manually after fixing access:")
|
||||
print(" git push origin HEAD --tags")
|
||||
|
||||
# Build semver-named Python artifacts so downstream packagers
|
||||
# (e.g. Homebrew) can target them without relying on CalVer tag names.
|
||||
artifacts = build_release_artifacts(new_version)
|
||||
if artifacts:
|
||||
print(" ✓ Built release artifacts:")
|
||||
for artifact in artifacts:
|
||||
print(f" - {artifact.relative_to(REPO_ROOT)}")
|
||||
|
||||
# Create GitHub release
|
||||
changelog_file = REPO_ROOT / ".release_notes.md"
|
||||
changelog_file.write_text(changelog, encoding="utf-8")
|
||||
|
|
@ -2427,7 +2347,6 @@ def main():
|
|||
"--title", f"Hermes Agent v{new_version} ({calver_date})",
|
||||
"--notes-file", str(changelog_file),
|
||||
]
|
||||
gh_cmd.extend(str(path) for path in artifacts)
|
||||
|
||||
gh_bin = shutil.which("gh")
|
||||
if gh_bin:
|
||||
|
|
@ -2452,9 +2371,9 @@ def main():
|
|||
print(f" Tag was created locally. Create the release manually:")
|
||||
print(
|
||||
f" gh release create {tag_name} --title 'Hermes Agent v{new_version} ({calver_date})' "
|
||||
f"--notes-file .release_notes.md {' '.join(str(path) for path in artifacts)}"
|
||||
f"--notes-file .release_notes.md"
|
||||
)
|
||||
print(f"\n ✓ Release artifacts prepared for manual publish: v{new_version} ({tag_name})")
|
||||
print(f"\n ✓ Release prepared for manual publish: v{new_version} ({tag_name})")
|
||||
else:
|
||||
print(f"\n{'='*60}")
|
||||
print(f" Dry run complete. To publish, add --publish")
|
||||
|
|
|
|||
|
|
@ -37,23 +37,26 @@ set -euo pipefail
|
|||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
if [ -z "$HERMES_PYTHON" ]; then
|
||||
# ── Activate venv ───────────────────────────────────────────────────────────
|
||||
VENV=""
|
||||
for candidate in "$REPO_ROOT/.venv" "$REPO_ROOT/venv" "$HOME/.hermes/hermes-agent/venv"; do
|
||||
if [ -f "$candidate/bin/activate" ]; then
|
||||
VENV="$candidate"
|
||||
break
|
||||
VENV=""
|
||||
for candidate in "$REPO_ROOT/.venv" "$REPO_ROOT/venv" "$HOME/.hermes/hermes-agent/venv"; do
|
||||
if [ -f "$candidate/bin/activate" ]; then
|
||||
VENV="$candidate"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$VENV" ]; then
|
||||
echo "error: no virtualenv found in $REPO_ROOT/.venv or $REPO_ROOT/venv" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$VENV" ]; then
|
||||
echo "error: no virtualenv found in $REPO_ROOT/.venv or $REPO_ROOT/venv" >&2
|
||||
exit 1
|
||||
PYTHON="$VENV/bin/python"
|
||||
else
|
||||
PYTHON=$HERMES_PYTHON
|
||||
fi
|
||||
|
||||
PYTHON="$VENV/bin/python"
|
||||
|
||||
|
||||
# ── Live-gateway plugin (computed before we drop env) ───────────────────────
|
||||
EXTRA_PYTHONPATH=""
|
||||
EXTRA_PYTEST_PLUGINS=""
|
||||
|
|
|
|||
|
|
@ -1,90 +0,0 @@
|
|||
"""Tests for ACP Registry metadata shipped with Hermes."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
MANIFEST = ROOT / "acp_registry" / "agent.json"
|
||||
ICON = ROOT / "acp_registry" / "icon.svg"
|
||||
FORBIDDEN_MANIFEST_KEYS = {"schema_version", "display_name"}
|
||||
ALLOWED_DISTRIBUTIONS = {"binary", "npx", "uvx"}
|
||||
|
||||
|
||||
def _manifest() -> dict:
|
||||
return json.loads(MANIFEST.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def _pyproject_version() -> str:
|
||||
data = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))
|
||||
return data["project"]["version"]
|
||||
|
||||
|
||||
def test_agent_json_matches_official_registry_required_fields():
|
||||
data = _manifest()
|
||||
|
||||
assert FORBIDDEN_MANIFEST_KEYS.isdisjoint(data)
|
||||
assert data["id"] == "hermes-agent"
|
||||
assert re.fullmatch(r"[a-z][a-z0-9-]*", data["id"])
|
||||
assert data["name"] == "Hermes Agent"
|
||||
assert data["description"]
|
||||
assert data["repository"] == "https://github.com/NousResearch/hermes-agent"
|
||||
assert data["website"].startswith("https://hermes-agent.nousresearch.com/")
|
||||
assert data["authors"] == ["Nous Research"]
|
||||
assert data["license"] == "MIT"
|
||||
assert set(data["distribution"]) <= ALLOWED_DISTRIBUTIONS
|
||||
|
||||
|
||||
def test_agent_json_uses_uvx_distribution_without_local_command_fields():
|
||||
data = _manifest()
|
||||
|
||||
assert set(data["distribution"]) == {"uvx"}
|
||||
uvx = data["distribution"]["uvx"]
|
||||
# Schema allows {package, args, env}; we use {package, args}.
|
||||
assert set(uvx) <= {"package", "args", "env"}
|
||||
assert "package" in uvx
|
||||
assert uvx["package"] == f"hermes-agent[acp]=={data['version']}"
|
||||
assert uvx["args"] == ["hermes-acp"]
|
||||
# Old command-shape fields must not leak back in.
|
||||
assert "type" not in data["distribution"]
|
||||
assert "command" not in data["distribution"]
|
||||
|
||||
|
||||
def test_agent_json_version_matches_pyproject():
|
||||
assert _manifest()["version"] == _pyproject_version()
|
||||
|
||||
|
||||
def test_agent_json_pins_uvx_package_to_pyproject_version():
|
||||
"""The registry CI rejects ``@latest`` and floating pins; the manifest must
|
||||
always reference the exact PyPI version listed in pyproject.toml."""
|
||||
assert _manifest()["distribution"]["uvx"]["package"] == (
|
||||
f"hermes-agent[acp]=={_pyproject_version()}"
|
||||
)
|
||||
|
||||
|
||||
def test_icon_svg_is_16x16_current_color():
|
||||
root = ET.fromstring(ICON.read_text(encoding="utf-8"))
|
||||
|
||||
assert root.attrib["viewBox"] == "0 0 16 16"
|
||||
assert root.attrib["width"] == "16"
|
||||
assert root.attrib["height"] == "16"
|
||||
|
||||
|
||||
def test_icon_svg_has_no_hardcoded_colors_or_gradients():
|
||||
text = ICON.read_text(encoding="utf-8")
|
||||
|
||||
assert "linearGradient" not in text
|
||||
assert "radialGradient" not in text
|
||||
assert "url(#" not in text
|
||||
assert not re.search(r"#[0-9a-fA-F]{3,8}\b", text)
|
||||
|
||||
root = ET.fromstring(text)
|
||||
for element in root.iter():
|
||||
for attr in ("fill", "stroke"):
|
||||
value = element.attrib.get(attr)
|
||||
if value is not None:
|
||||
assert value in {"currentColor", "none"}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
"""Tests for the ACP Registry version-lockstep bump in scripts/release.py.
|
||||
|
||||
The official ACP Registry manifest must match ``pyproject.toml`` exactly —
|
||||
``tests/acp/test_registry_manifest.py`` enforces this at lint time, and the
|
||||
upstream registry CI rejects ``@latest`` / floating pins. The release script
|
||||
is the single place that bumps the manifest in lockstep with pyproject; if
|
||||
that bump ever silently breaks, weekly releases fail the manifest test
|
||||
until someone hand-edits the JSON.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _load_release_module(monkeypatch, tmp_root: Path):
|
||||
"""Import scripts/release.py with REPO_ROOT pinned to a temp tree."""
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"_release_under_test",
|
||||
Path(__file__).resolve().parents[2] / "scripts" / "release.py",
|
||||
)
|
||||
assert spec and spec.loader
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
monkeypatch.setattr(module, "REPO_ROOT", tmp_root)
|
||||
monkeypatch.setattr(
|
||||
module, "ACP_REGISTRY_MANIFEST", tmp_root / "acp_registry" / "agent.json"
|
||||
)
|
||||
return module
|
||||
|
||||
|
||||
def _write_manifest(root: Path, version: str) -> None:
|
||||
manifest_dir = root / "acp_registry"
|
||||
manifest_dir.mkdir(parents=True)
|
||||
(manifest_dir / "agent.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"id": "hermes-agent",
|
||||
"name": "Hermes Agent",
|
||||
"version": version,
|
||||
"description": "test",
|
||||
"distribution": {
|
||||
"uvx": {
|
||||
"package": f"hermes-agent[acp]=={version}",
|
||||
"args": ["hermes-acp"],
|
||||
}
|
||||
},
|
||||
},
|
||||
indent=2,
|
||||
)
|
||||
+ "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
def test_update_acp_registry_versions_bumps_manifest_and_pin(monkeypatch, tmp_path):
|
||||
_write_manifest(tmp_path, "0.13.0")
|
||||
module = _load_release_module(monkeypatch, tmp_path)
|
||||
|
||||
module._update_acp_registry_versions("0.14.0")
|
||||
|
||||
manifest = json.loads(
|
||||
(tmp_path / "acp_registry" / "agent.json").read_text(encoding="utf-8")
|
||||
)
|
||||
assert manifest["version"] == "0.14.0"
|
||||
assert manifest["distribution"]["uvx"]["package"] == "hermes-agent[acp]==0.14.0"
|
||||
# args stay untouched so we don't accidentally rewrite them.
|
||||
assert manifest["distribution"]["uvx"]["args"] == ["hermes-acp"]
|
||||
|
||||
|
||||
def test_update_acp_registry_versions_is_silent_when_manifest_missing(
|
||||
monkeypatch, tmp_path
|
||||
):
|
||||
"""Older release branches predate the ACP Registry asset — must no-op."""
|
||||
module = _load_release_module(monkeypatch, tmp_path)
|
||||
|
||||
# No fixture written; function should not raise.
|
||||
module._update_acp_registry_versions("0.14.0")
|
||||
|
||||
|
||||
def test_update_version_files_bumps_manifest_alongside_pyproject(
|
||||
monkeypatch, tmp_path
|
||||
):
|
||||
"""End-to-end: update_version_files() is the function release.py actually
|
||||
calls, so it must drive the manifest bump too."""
|
||||
_write_manifest(tmp_path, "0.13.0")
|
||||
(tmp_path / "pyproject.toml").write_text(
|
||||
'[project]\nname = "hermes-agent"\nversion = "0.13.0"\n', encoding="utf-8"
|
||||
)
|
||||
version_dir = tmp_path / "hermes_cli"
|
||||
version_dir.mkdir()
|
||||
(version_dir / "__init__.py").write_text(
|
||||
'__version__ = "0.13.0"\n__release_date__ = "2026-05-14"\n',
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
module = _load_release_module(monkeypatch, tmp_path)
|
||||
monkeypatch.setattr(module, "VERSION_FILE", version_dir / "__init__.py")
|
||||
monkeypatch.setattr(module, "PYPROJECT_FILE", tmp_path / "pyproject.toml")
|
||||
|
||||
module.update_version_files("0.14.0", "2026-05-21")
|
||||
|
||||
pyproject_text = (tmp_path / "pyproject.toml").read_text(encoding="utf-8")
|
||||
assert 'version = "0.14.0"' in pyproject_text
|
||||
|
||||
manifest = json.loads(
|
||||
(tmp_path / "acp_registry" / "agent.json").read_text(encoding="utf-8")
|
||||
)
|
||||
assert manifest["version"] == "0.14.0"
|
||||
assert manifest["distribution"]["uvx"]["package"] == "hermes-agent[acp]==0.14.0"
|
||||
|
|
@ -17,7 +17,6 @@ Key implementation files:
|
|||
- `acp_adapter/permissions.py`
|
||||
- `acp_adapter/tools.py`
|
||||
- `acp_adapter/auth.py`
|
||||
- `acp_registry/agent.json`
|
||||
|
||||
## Boot flow
|
||||
|
||||
|
|
@ -31,8 +30,6 @@ hermes acp / hermes-acp / python -m acp_adapter
|
|||
-> acp.run_agent(agent, use_unstable_protocol=True)
|
||||
```
|
||||
|
||||
The Zed ACP Registry path launches the same adapter through `uvx --from 'hermes-agent[acp]==<version>' hermes-acp`, pointed at the `hermes-agent` PyPI release.
|
||||
|
||||
Stdout is reserved for ACP JSON-RPC transport. Human-readable logs go to stderr.
|
||||
|
||||
## Major components
|
||||
|
|
@ -149,7 +146,7 @@ Instead it reuses Hermes' runtime resolver:
|
|||
- `acp_adapter/auth.py`
|
||||
- `hermes_cli/runtime_provider.py`
|
||||
|
||||
So ACP advertises and uses the currently configured Hermes provider/credentials. It also always advertises a terminal setup auth method (`hermes-setup`, args `--setup`) so first-run registry clients can open Hermes' interactive model/provider configuration before starting a normal ACP session.
|
||||
So ACP advertises and uses the currently configured Hermes provider/credentials. It also always advertises a terminal setup auth method (`hermes-setup`, args `--setup`) so first-run clients can open Hermes' interactive model/provider configuration before starting a normal ACP session.
|
||||
|
||||
## Working directory binding
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ PRs to fix them will _not_ be accepted, and any code that keeps compatibility wi
|
|||
|
||||
- installs via the AUR (we might upstream patches if it helps out <3)
|
||||
- macOS on x86 (Intel) processors
|
||||
- installs via `pypi` (e.g. `uv tool install hermes-agent`, `pip install hermse-agent`, etc.)
|
||||
- installs via `brew` (`brew install hermes-agent`)
|
||||
- installs via `pypi` (e.g. `uv tool install hermes-agent`, `pip install hermse-agent`, etc.) — Hermes Agent is no longer published to PyPI, so these installs will not receive further updates
|
||||
- installs via `brew` (`brew install hermes-agent`) — Hermes Agent is no longer packaged for Homebrew, so these installs will not receive further updates
|
||||
|
||||
If you are using an unsupported distribution method, please read the [the installation guide](./installation.md) to learn how to switch to a supported one.
|
||||
|
|
|
|||
|
|
@ -45,14 +45,6 @@ This installs the `agent-client-protocol` dependency and enables:
|
|||
- `hermes-acp`
|
||||
- `python -m acp_adapter`
|
||||
|
||||
For Zed registry installs, Zed launches Hermes through the official ACP Registry entry. That entry uses a `uvx` distribution that runs:
|
||||
|
||||
```bash
|
||||
uvx --from 'hermes-agent[acp]==<version>' hermes-acp
|
||||
```
|
||||
|
||||
Make sure `uv` is available on `PATH` before using the registry install path.
|
||||
|
||||
## Launching the ACP server
|
||||
|
||||
Any of the following starts Hermes in ACP mode:
|
||||
|
|
@ -89,7 +81,7 @@ hermes acp --setup-browser # interactive (prompts before ~400 MB downl
|
|||
hermes acp --setup-browser --yes # accept the download non-interactively
|
||||
```
|
||||
|
||||
This is the standalone command. The Zed registry's terminal-auth flow (`hermes acp --setup`) also offers the browser bootstrap as a follow-up question after model selection, so most users never need to run `--setup-browser` directly.
|
||||
This is the standalone command. Hermes' terminal-auth flow (`hermes acp --setup`) also offers the browser bootstrap as a follow-up question after model selection, so most users never need to run `--setup-browser` directly.
|
||||
|
||||
What it does:
|
||||
|
||||
|
|
@ -126,19 +118,7 @@ If you want to define Hermes manually, add it through VS Code settings under `ac
|
|||
|
||||
### Zed
|
||||
|
||||
Zed v0.221.x and newer installs external agents through the official ACP Registry.
|
||||
|
||||
1. Open the Agent Panel.
|
||||
2. Click **Add Agent**, or run the `zed: acp registry` command.
|
||||
3. Search for **Hermes Agent**.
|
||||
4. Install it and start a new Hermes external-agent thread.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Configure Hermes provider credentials first with `hermes model`, or set them in `~/.hermes/.env` / `~/.hermes/config.yaml`.
|
||||
- Install `uv` so the registry launcher can run `uvx --from 'hermes-agent[acp]==<version>' hermes-acp`.
|
||||
|
||||
For local development before the registry entry is available, use a custom agent server in Zed settings:
|
||||
Zed supports external agents via a custom agent server entry in Zed settings:
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -152,32 +132,11 @@ For local development before the registry entry is available, use a custom agent
|
|||
}
|
||||
```
|
||||
|
||||
Configure Hermes provider credentials first with `hermes model`, or set them in `~/.hermes/.env` / `~/.hermes/config.yaml`.
|
||||
|
||||
### JetBrains
|
||||
|
||||
Use an ACP-compatible plugin and point it at:
|
||||
|
||||
```text
|
||||
/path/to/hermes-agent/acp_registry
|
||||
```
|
||||
|
||||
## Registry manifest
|
||||
|
||||
The source copy of Hermes' official ACP Registry metadata lives at:
|
||||
|
||||
```text
|
||||
acp_registry/agent.json
|
||||
acp_registry/icon.svg
|
||||
```
|
||||
|
||||
The upstream registry PR copies those files into the top-level `hermes-agent/` directory in `agentclientprotocol/registry`.
|
||||
|
||||
The registry entry uses a `uvx` distribution that points directly at the `hermes-agent` PyPI release:
|
||||
|
||||
```text
|
||||
uvx --from 'hermes-agent[acp]==<version>' hermes-acp
|
||||
```
|
||||
|
||||
The registry CI verifies that the pinned version exists on PyPI, so the manifest's `version` and uvx `package` pin must always match `pyproject.toml`. `scripts/release.py` keeps them in lockstep automatically.
|
||||
Use an ACP-compatible plugin and point it at the local `hermes acp` command (see the VS Code / Zed `command`/`args` examples above — the same shape applies).
|
||||
|
||||
## Configuration and credentials
|
||||
|
||||
|
|
@ -188,7 +147,7 @@ ACP mode uses the same Hermes configuration as the CLI:
|
|||
- `~/.hermes/skills/`
|
||||
- `~/.hermes/state.db`
|
||||
|
||||
Provider resolution uses Hermes' normal runtime resolver, so ACP inherits the currently configured provider and credentials. Hermes also advertises a terminal auth method (`--setup`) for first-run registry clients; this opens Hermes' interactive model/provider setup.
|
||||
Provider resolution uses Hermes' normal runtime resolver, so ACP inherits the currently configured provider and credentials. Hermes also advertises a terminal auth method (`--setup`) so first-run clients can open Hermes' interactive model/provider setup.
|
||||
|
||||
## Session behavior
|
||||
|
||||
|
|
@ -239,11 +198,9 @@ The ACP bridge maps these options onto Hermes' internal approval semantics — `
|
|||
|
||||
Check:
|
||||
|
||||
- In Zed, open the ACP Registry with `zed: acp registry` and search for **Hermes Agent**.
|
||||
- For manual/local development, verify the custom `agent_servers` command points to `hermes acp`.
|
||||
- Verify the custom `agent_servers` (Zed) or equivalent editor config points to `hermes acp`.
|
||||
- Hermes is installed and on your PATH.
|
||||
- The ACP extra is installed (`pip install -e '.[acp]'`).
|
||||
- `uv` is installed if launching from the official Zed registry entry.
|
||||
|
||||
### ACP starts but immediately errors
|
||||
|
||||
|
|
@ -264,11 +221,7 @@ ACP mode uses Hermes' existing provider setup. Configure credentials with:
|
|||
hermes model
|
||||
```
|
||||
|
||||
or by editing `~/.hermes/.env`. Registry clients can also trigger Hermes' terminal auth flow, which runs the same interactive provider/model setup.
|
||||
|
||||
### Zed registry launcher cannot find uv
|
||||
|
||||
Install `uv` from the official uv installation docs, then retry the Hermes Agent thread from Zed.
|
||||
or by editing `~/.hermes/.env`. ACP clients can also trigger Hermes' terminal auth flow, which runs the same interactive provider/model setup.
|
||||
|
||||
## See also
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ ACP 适配器将 Hermes 的同步 `AIAgent` 封装为异步 JSON-RPC stdio 服
|
|||
- `acp_adapter/permissions.py`
|
||||
- `acp_adapter/tools.py`
|
||||
- `acp_adapter/auth.py`
|
||||
- `acp_registry/agent.json`
|
||||
|
||||
## 启动流程
|
||||
|
||||
|
|
@ -31,8 +30,6 @@ hermes acp / hermes-acp / python -m acp_adapter
|
|||
-> acp.run_agent(agent, use_unstable_protocol=True)
|
||||
```
|
||||
|
||||
Zed ACP Registry 路径通过 `uvx --from 'hermes-agent[acp]==<version>' hermes-acp` 启动同一适配器,指向 `hermes-agent` PyPI 发布包。
|
||||
|
||||
stdout 保留用于 ACP JSON-RPC 传输。人类可读的日志输出至 stderr。
|
||||
|
||||
## 主要组件
|
||||
|
|
@ -149,7 +146,7 @@ ACP 不实现自己的认证存储。
|
|||
- `acp_adapter/auth.py`
|
||||
- `hermes_cli/runtime_provider.py`
|
||||
|
||||
因此 ACP 通告并使用当前配置的 Hermes provider/凭据。它还始终通告一个终端 setup 认证方法(`hermes-setup`,参数 `--setup`),以便首次运行的 registry 客户端在启动正常 ACP 会话前可以打开 Hermes 的交互式模型/provider 配置。
|
||||
因此 ACP 通告并使用当前配置的 Hermes provider/凭据。它还始终通告一个终端 setup 认证方法(`hermes-setup`,参数 `--setup`),以便首次运行的客户端在启动正常 ACP 会话前可以打开 Hermes 的交互式模型/provider 配置。
|
||||
|
||||
## 工作目录绑定
|
||||
|
||||
|
|
|
|||
|
|
@ -45,14 +45,6 @@ pip install -e '.[acp]'
|
|||
- `hermes-acp`
|
||||
- `python -m acp_adapter`
|
||||
|
||||
对于 Zed registry 安装,Zed 通过官方 ACP Registry 条目启动 Hermes。该条目使用 `uvx` 发行版运行:
|
||||
|
||||
```bash
|
||||
uvx --from 'hermes-agent[acp]==<version>' hermes-acp
|
||||
```
|
||||
|
||||
使用 registry 安装路径前,请确保 `uv` 已在 `PATH` 中可用。
|
||||
|
||||
## 启动 ACP 服务器
|
||||
|
||||
以下任意命令均可以 ACP 模式启动 Hermes:
|
||||
|
|
@ -87,7 +79,7 @@ hermes acp --setup-browser # 交互式(下载约 400 MB 前会提示
|
|||
hermes acp --setup-browser --yes # 非交互式接受下载
|
||||
```
|
||||
|
||||
这是独立命令。Zed registry 的终端认证流程(`hermes acp --setup`)在模型选择后也会将浏览器引导作为后续问题提供,因此大多数用户无需直接运行 `--setup-browser`。
|
||||
这是独立命令。Hermes 的终端认证流程(`hermes acp --setup`)在模型选择后也会将浏览器引导作为后续问题提供,因此大多数用户无需直接运行 `--setup-browser`。
|
||||
|
||||
具体操作:
|
||||
|
||||
|
|
@ -124,19 +116,7 @@ hermes acp --setup-browser --yes # 非交互式接受下载
|
|||
|
||||
### Zed
|
||||
|
||||
Zed v0.221.x 及更新版本通过官方 ACP Registry 安装外部 agent。
|
||||
|
||||
1. 打开 Agent 面板。
|
||||
2. 点击 **Add Agent**,或运行 `zed: acp registry` 命令。
|
||||
3. 搜索 **Hermes Agent**。
|
||||
4. 安装后启动新的 Hermes 外部 agent 线程。
|
||||
|
||||
前提条件:
|
||||
|
||||
- 先通过 `hermes model` 配置 Hermes provider 凭据,或在 `~/.hermes/.env` / `~/.hermes/config.yaml` 中设置。
|
||||
- 安装 `uv`,以便 registry 启动器可以运行 `uvx --from 'hermes-agent[acp]==<version>' hermes-acp`。
|
||||
|
||||
在 registry 条目可用之前进行本地开发时,在 Zed 设置中使用自定义 agent 服务器:
|
||||
Zed 通过 Zed 设置中的自定义 agent 服务器条目支持外部 agent:
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -150,32 +130,11 @@ Zed v0.221.x 及更新版本通过官方 ACP Registry 安装外部 agent。
|
|||
}
|
||||
```
|
||||
|
||||
先通过 `hermes model` 配置 Hermes provider 凭据,或在 `~/.hermes/.env` / `~/.hermes/config.yaml` 中设置。
|
||||
|
||||
### JetBrains
|
||||
|
||||
使用兼容 ACP 的插件并将其指向:
|
||||
|
||||
```text
|
||||
/path/to/hermes-agent/acp_registry
|
||||
```
|
||||
|
||||
## Registry 清单
|
||||
|
||||
Hermes 官方 ACP Registry 元数据的源文件位于:
|
||||
|
||||
```text
|
||||
acp_registry/agent.json
|
||||
acp_registry/icon.svg
|
||||
```
|
||||
|
||||
上游 registry PR 将这些文件复制到 `agentclientprotocol/registry` 中的顶层 `hermes-agent/` 目录。
|
||||
|
||||
Registry 条目使用直接指向 `hermes-agent` PyPI 发行版的 `uvx` 发行版:
|
||||
|
||||
```text
|
||||
uvx --from 'hermes-agent[acp]==<version>' hermes-acp
|
||||
```
|
||||
|
||||
Registry CI 会验证固定版本是否存在于 PyPI,因此清单的 `version` 和 uvx `package` 固定版本必须始终与 `pyproject.toml` 匹配。`scripts/release.py` 会自动保持它们同步。
|
||||
使用兼容 ACP 的插件,并将其指向本地的 `hermes acp` 命令(参见上面 VS Code / Zed 的 `command`/`args` 示例——形式相同)。
|
||||
|
||||
## 配置与凭据
|
||||
|
||||
|
|
@ -186,7 +145,7 @@ ACP 模式使用与 CLI 相同的 Hermes 配置:
|
|||
- `~/.hermes/skills/`
|
||||
- `~/.hermes/state.db`
|
||||
|
||||
Provider 解析使用 Hermes 的正常运行时解析器,因此 ACP 继承当前配置的 provider 和凭据。Hermes 还为首次运行的 registry 客户端提供终端认证方法(`--setup`);这将打开 Hermes 的交互式模型/provider 设置。
|
||||
Provider 解析使用 Hermes 的正常运行时解析器,因此 ACP 继承当前配置的 provider 和凭据。Hermes 还提供终端认证方法(`--setup`),以便首次运行的客户端打开 Hermes 的交互式模型/provider 设置。
|
||||
|
||||
## 会话行为
|
||||
|
||||
|
|
@ -237,11 +196,9 @@ ACP 桥接将这些选项映射到 Hermes 的内部审批语义——`allow_alwa
|
|||
|
||||
检查:
|
||||
|
||||
- 在 Zed 中,使用 `zed: acp registry` 打开 ACP Registry 并搜索 **Hermes Agent**。
|
||||
- 对于手动/本地开发,验证自定义 `agent_servers` 命令是否指向 `hermes acp`。
|
||||
- 验证自定义 `agent_servers`(Zed)或等效的编辑器配置是否指向 `hermes acp`。
|
||||
- Hermes 已安装且在 PATH 中。
|
||||
- ACP 扩展已安装(`pip install -e '.[acp]'`)。
|
||||
- 如果从官方 Zed registry 条目启动,`uv` 已安装。
|
||||
|
||||
### ACP 启动后立即报错
|
||||
|
||||
|
|
@ -262,14 +219,10 @@ ACP 模式使用 Hermes 现有的 provider 设置。通过以下方式配置凭
|
|||
hermes model
|
||||
```
|
||||
|
||||
或编辑 `~/.hermes/.env`。Registry 客户端也可以触发 Hermes 的终端认证流程,该流程运行相同的交互式 provider/模型设置。
|
||||
|
||||
### Zed registry 启动器找不到 uv
|
||||
|
||||
从官方 uv 安装文档安装 `uv`,然后从 Zed 重试 Hermes Agent 线程。
|
||||
或编辑 `~/.hermes/.env`。ACP 客户端也可以触发 Hermes 的终端认证流程,该流程运行相同的交互式 provider/模型设置。
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- [ACP 内部机制](../../developer-guide/acp-internals.md)
|
||||
- [Provider 运行时解析](../../developer-guide/provider-runtime.md)
|
||||
- [工具运行时](../../developer-guide/tools-runtime.md)
|
||||
- [工具运行时](../../developer-guide/tools-runtime.md)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue