Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
129 commits
Select commit Hold shift + click to select a range
3337bcf
feat: Enable MCP tools for subagents
Apr 2, 2026
61ed851
fix: Resolve ruff linting errors
Apr 2, 2026
fd5593d
feat: Enable read-only memory access for subagents
Apr 2, 2026
ae538f6
oikos: patches for unprivileged LXC + Podman deployment
Apr 2, 2026
805b649
feat: Enable read-only memory access for subagents (Option C implemen…
Apr 2, 2026
d1ca7a5
feat: Add automatic cleanup of orphaned containers on gateway startup
Apr 2, 2026
463671b
oikos: replace upstream GitHub workflows with Gitea CI
Apr 2, 2026
361aae0
fix: configure insecure registry for HTTP Gitea in CI
Apr 2, 2026
a45c215
fix: skip docker login, host Podman has auth + insecure registry
Apr 2, 2026
55f8d35
fix: add --load to docker build for buildx compatibility
Apr 2, 2026
b7e3075
fix: disable buildx, use classic builder for Podman compat
Apr 2, 2026
29a11e8
feat: Complete read-only memory access for subagents
Apr 2, 2026
2f4f75d
fix: add podman-remote login before push
Apr 2, 2026
f4d0ec0
Use podman-remote for builds, drop DOCKER_BUILDKIT=0 workaround
Apr 3, 2026
2ae474d
ci: use built-in GITEA_TOKEN for registry push (no stored secrets)
Apr 3, 2026
6408bf3
ci: revert to REGISTRY_USER/REGISTRY_TOKEN secrets
Apr 3, 2026
29e1ac3
ci: remove podman-remote install step (pre-baked in runner image)
Apr 3, 2026
2ea3ef2
fix: add subagent_memory_mode param to AIAgent.__init__
Apr 3, 2026
40f9018
fix: wire docker_forward_env, subagent_memory_mode, shim logging, ext…
Apr 3, 2026
ffb0785
fix: cleanup function placement, use find_docker(), downgrade exec lo…
Apr 3, 2026
48a584c
feat: add docker_network config option to terminal docker backend
Apr 3, 2026
6b6af7c
fix: pass LITELLM_KEY env fallback in fetch_endpoint_model_metadata
Apr 4, 2026
e79fc14
fix: wire docker_network config key through to sandbox containers
Apr 4, 2026
0934e81
Apply PR #4350 and #4673 fixes for docker_image config and invalid wo…
malaiwah Apr 4, 2026
f695497
feat: Add gnupg package for GPG email signing
Apr 4, 2026
1205230
ci: re-trigger build for gnupg package
Apr 4, 2026
122f014
fix: correct backslash escaping in Containerfile
Apr 4, 2026
d810ebb
refactor: Remove gnupg from hermes-agent container
Apr 4, 2026
5240f4c
feat(agent): add in-session user progress messages
Apr 4, 2026
1b15311
fix(agent): scope in-session user updates
Apr 4, 2026
5abefa4
fix(config): handle locked config writes safely
Apr 5, 2026
d2766b2
ci: add tests workflow for PRs and pushes to main
Apr 5, 2026
c8fd968
ci: add OCI labels, /etc/hermes-release, and entrypoint provenance di…
Apr 5, 2026
da6b54f
feat(gateway): resume interrupted sessions after restart
Apr 5, 2026
9f734c3
ci: add AI peer review workflow with cross-tool routing
Apr 5, 2026
fdb21e9
feat(terminal): add guarded gateway-local escape hatch
Apr 5, 2026
9946a61
fix(terminal): forward gateway-local approval args
Apr 5, 2026
ab55dd9
fix(gateway): set HERMES_GATEWAY_SESSION in _set_session_env
Apr 5, 2026
4903275
fix(gateway): use resolved runtime for BOOT.md
Apr 5, 2026
23ea855
fix: wire docker_forward_env, subagent_memory_mode, shim logging, ext…
Apr 3, 2026
b26e1ce
feat(delegation): add subagent workspace visibility
Apr 4, 2026
fa4e89d
refactor(delegation): drop temp_rw workspace visibility mode
Apr 5, 2026
761d7e7
fix(delegation): fall back to HERMES_HOME as workspace root
Apr 5, 2026
98a8c54
fix(gateway): persist /sethome to .env instead of config.yaml
Apr 5, 2026
b8737bc
feat(gateway): add one-shot self nudge tool
Apr 5, 2026
c2f1912
fix(tools): hide clarify outside cli
Apr 5, 2026
8dcfc4a
fix(skills): respect local skill dir in skill manager
Apr 5, 2026
456fc5a
fix(gateway): avoid shadowing run message
Apr 5, 2026
7ff29da
fix(gateway): tolerate missing hidden-turn queue
Apr 5, 2026
2d92ba0
test(cli): force linux update restart path
Apr 5, 2026
500477a
fix(tests): refresh gateway and sandbox coverage
Apr 5, 2026
cb0aa1c
fix(tests): isolate terminal runtime state
Apr 5, 2026
f288bd0
fix(tests): isolate runner env from CI
Apr 5, 2026
eb921aa
test(cli): stub system unit identity on linux
Apr 5, 2026
963635a
test(cli): capture custom model save calls
Apr 5, 2026
b95738a
feat: add docker_extra_hosts config option (--add-host support for sa…
Apr 6, 2026
584a1b9
feat: add docker_env_files config option for file-based env injection
Apr 6, 2026
e8f3e46
fix: add docker_extra_hosts and docker_env_files to _get_env_config()
Apr 6, 2026
ec5af97
fix: wire docker_env from config.yaml through to container spawn
Apr 6, 2026
acf8311
feat(webhook): add Gitea support (signature, event header, delivery I…
Apr 7, 2026
1daa37b
fix(gateway): wire LLM token usage into session store for /status
Apr 7, 2026
846dfb6
feat(docker): add docker_user config option for sandbox user
Apr 7, 2026
71e6b78
feat(send_user_message): parse MEDIA: directives for file delivery
Apr 7, 2026
d9e6f87
feat(api_server): btw-mode fast path for Open WebUI meta-requests
Apr 8, 2026
78b1935
feat(webhook): payload_filter, emoji reactions, issue/comment routes
Apr 8, 2026
ee86c16
feat(webhook): per_event config merging for single-URL multi-event ro…
Apr 8, 2026
558f8cd
fix(webhook): payload_exclude denylist to break bot feedback loops
Apr 8, 2026
7233529
temp: log extra message fields to identify Open WebUI fingerprint
Apr 8, 2026
eaf0e61
chore: remove temp fingerprint debug log
Apr 8, 2026
de6dad0
fix(api_server): handle OpenAI multimodal content without crashing
Apr 8, 2026
0bf9398
feat(api_server): forward image attachments via vision_analyze paths
Apr 8, 2026
0e16981
fix(display): show named custom_providers in /model CLI display
Mar 26, 2026
e51c766
feat(gateway): add /models slash command for model discovery
dlkakbs Mar 28, 2026
aadce73
fix(models-cmd): inline custom provider name normalization — avoid fr…
dlkakbs Mar 28, 2026
7fced18
test(models-cmd): add unit tests for /models slash command
dlkakbs Mar 28, 2026
976500c
fix(terminal): persistent sandbox envs survive between turns
Apr 9, 2026
25e41d6
Merge pull request 'fix(terminal): persistent sandbox envs survive be…
malaiwah Apr 9, 2026
9ed3a26
feat: make no-new-privileges flag configurable via SANDBOX_NO_NEW_PRIVS
Apr 9, 2026
df933cb
fix(delegate): restore _resolve_workspace_hint function removed in b2…
Apr 9, 2026
be4c3b5
fix(docker): gate --pids-limit on cgroup availability + make configur…
Apr 9, 2026
70244cc
feat(docker): re-read docker_env_files on every exec, not only at spawn
Apr 9, 2026
269000d
fix(container): enable unbuffered stdout for live logs
Apr 9, 2026
2f8ac84
fix(security): add security-only apt upgrade during build
Apr 9, 2026
66a5de5
Merge pull request 'fix(docker): gate --pids-limit on cgroup availabi…
Apr 9, 2026
3ba1a2d
Merge pull request 'feat(docker): re-read docker_env_files on every e…
Apr 9, 2026
0cf288f
refactor(docker_env_files): hook + validation + tests for upstream re…
Apr 9, 2026
c8e2610
Merge pull request 'refactor(docker_env_files): hook + validation + t…
Apr 9, 2026
02105e6
fix(docker): mask rotating credentials in 'docker exec cmd:' log lines
Apr 9, 2026
08fabc6
Merge pull request 'fix(docker): mask rotating credentials in 'docker…
Apr 9, 2026
79458de
fix(gateway): /status Tokens: 0 — two bugs in token accounting
Apr 9, 2026
09554a1
Merge pull request 'fix(gateway): /status Tokens: 0 — two bugs in tok…
Apr 9, 2026
bdbd7f8
fix(gateway): /status reads token totals from SessionDB (adopt #5989)
Apr 9, 2026
38081b6
Merge pull request 'fix(gateway): /status reads token totals from Ses…
Apr 9, 2026
cb0d4ed
fix(delegate): workspace_path → workspace_note kwarg mismatch
Apr 10, 2026
2d8fe90
Merge pull request 'fix(delegate): workspace_path → workspace_note kw…
Apr 10, 2026
b9b8835
fix(delegate): restore credential pool lease release in finally block
Apr 10, 2026
c7a6ee2
Merge pull request 'fix(delegate): restore credential pool lease rele…
Apr 10, 2026
8977316
sync: merge upstream/main (140 commits, 242 files)
Apr 10, 2026
595edc6
Merge pull request 'sync: merge upstream/main (140 commits, 242 files…
Apr 10, 2026
ea90c39
fix(terminal): add missing notify_on_complete parameter + schema prop…
Apr 10, 2026
7e557c0
Merge pull request 'fix(terminal): add missing notify_on_complete par…
Apr 10, 2026
d080c3b
fix(delegate): make max_concurrent_children configurable + error on e…
Apr 10, 2026
11af564
Merge pull request 'fix(delegate): make max_concurrent_children confi…
Apr 10, 2026
544ff0a
feat(ci): ai-review via Qwen 3.5 on aibeast + uv + apt-cacher-ng
Apr 10, 2026
4afbd4c
Merge pull request 'feat(ci): ai-review via Qwen 3.5 on aibeast + uv …
Apr 10, 2026
a3503a1
fix(ci): remove unused opencode install step from ai-review
Apr 10, 2026
c2f9963
fix(build): add --break-system-packages for uv on Debian 13 (PEP 668)
Apr 10, 2026
70884d0
fix(delegate): re-export MAX_CONCURRENT_CHILDREN for run_agent.py gua…
Apr 10, 2026
8332c25
fix(delegate): agent-loop guardrail uses configurable limit, not hard…
Apr 10, 2026
c3d40e8
refactor(delegate): remove MAX_CONCURRENT_CHILDREN constant, use _get…
Apr 10, 2026
aea0bb4
fix(docker): add all missing imports lost in upstream merge
Apr 10, 2026
d1f0fc4
fix(delegate): add missing tool_error import + update truncation test
Apr 10, 2026
210fd92
fix(docker): --init for zombie reaping + sleep infinity for idle-base…
Apr 10, 2026
4efb4ac
fix(gateway): restore self-nudge system lost in upstream merge
Apr 10, 2026
ed12081
fix(gateway): add missing uuid import for self-nudge + resume
Apr 10, 2026
64a3b07
fix(gateway): send typing indicator during self-nudge hidden turns
Apr 10, 2026
94f63f2
fix(gateway): deliver self-nudge response to the user
Apr 10, 2026
c8f15ba
chore: confirm ffmpeg for TTS voice bubbles (trigger gateway rebuild)
Apr 11, 2026
fa0ecb8
Log smart model routing decisions
Apr 11, 2026
baf14eb
feat(delegate): allow agent to choose model per delegation
Apr 11, 2026
e11ca1e
feat(delegate): model tiers + list_models tool
Apr 11, 2026
e6d4a6e
fix: add list_models dispatch to concurrent tool execution path
Apr 11, 2026
fbd6e34
fix: add list_models to all composite toolsets
Apr 11, 2026
54ef2b0
feat: configurable local_endpoints + DNS resolution for is_local_endp…
Apr 11, 2026
eff1d20
feat: treat unqualified hostnames as local endpoints
Apr 11, 2026
adc2a4f
feat: context-aware smart model routing
Apr 11, 2026
cec3b3b
feat: optional context trimming for smart model routing
Apr 11, 2026
aa73349
fix: UnboundLocalError on history variable in smart routing trim
Apr 11, 2026
ebd41be
fix(docker): respect HERMES_HOME env var in entrypoint
Apr 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 176 additions & 0 deletions .gitea/scripts/ai_review.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
#!/usr/bin/env python3
"""AI peer review script.

Uses Qwen 3.5 397B MoE on aibeast (10.15.0.166:8000) via the OpenAI-
compatible vLLM endpoint. The model has a 524K context window, so even
large diffs fit without truncation in most cases.

Usage:
Normal: python ai_review.py
Dry run: python ai_review.py --dry-run
"""
import os
import re
import subprocess
import sys

import httpx
from openai import OpenAI

DRY_RUN = "--dry-run" in sys.argv

base_sha = os.environ["BASE_SHA"]
head_sha = os.environ["HEAD_SHA"]

# ── Gather diff ───────────────────────────────────────────────────────────────

diff = subprocess.check_output(["git", "diff", base_sha, head_sha], text=True)
changed = subprocess.check_output(
["git", "diff", "--name-only", base_sha, head_sha], text=True
).strip()

MAX_DIFF = 200_000 # 200K chars — Qwen 3.5 has 524K context
truncated = len(diff) > MAX_DIFF
if truncated:
diff = diff[:MAX_DIFF] + "\n\n[diff truncated at 200K chars]"

if not diff.strip():
print("Empty diff — nothing to review.")
sys.exit(0)

# ── Gather extra context for key changed files ────────────────────────────────

# Read the full content of up to 5 key changed files so the reviewer can
# see imports, callers, and surrounding code — not just the diff hunks.
context_files = ""
key_extensions = {".py", ".yml", ".yaml", ".sh", ".toml"}
files_added = 0
for fname in changed.split("\n"):
if files_added >= 5:
break
fname = fname.strip()
if not fname:
continue
if not any(fname.endswith(ext) for ext in key_extensions):
continue
if not os.path.isfile(fname):
continue
try:
content = open(fname).read()
if len(content) > 20_000:
content = content[:20_000] + "\n[file truncated at 20K chars]"
context_files += f"\n\n--- {fname} (full file) ---\n{content}"
files_added += 1
except Exception:
pass

PROMPT = f"""You are peer-reviewing code changes. Be thorough and constructively critical.

Changed files:
{changed}

Diff:
{diff}
{context_files}

Structure your review as:

## Summary
Brief overview of what changed and why.

## Issues
- 🚨 CRITICAL: security holes, data loss, broken logic, race conditions
- ⚠️ WARNING: bugs, bad patterns, missing error handling, test gaps
- 💡 SUGGESTION: improvements, simplifications, naming

If there are no issues in a category, omit it.

## Verdict
One of: APPROVED | NEEDS_WORK | CRITICAL_ISSUES
"""

# ── Call Qwen 3.5 397B MoE on aibeast ────────────────────────────────────────

print(f"Reviewing {len(changed.split(chr(10)))} files "
f"({len(diff):,} chars diff) with Qwen 3.5 397B MoE...")

client = OpenAI(
api_key=os.environ.get("OPENAI_API_KEY", "not-needed"),
base_url=os.environ.get("OPENAI_BASE_URL", "http://10.15.0.166:8000/v1"),
)

try:
response = client.chat.completions.create(
model="qwen35-397b",
messages=[
{
"role": "system",
"content": (
"You are an expert code reviewer. Be thorough, specific, "
"and cite file:line when pointing out issues. Focus on "
"correctness, security, and maintainability."
),
},
{"role": "user", "content": PROMPT},
],
max_tokens=8192,
temperature=0.7,
# Qwen 3.5 MoE supports extended thinking
extra_body={
"chat_template_kwargs": {
"enable_thinking": True,
},
},
)
review = response.choices[0].message.content or ""

# Strip thinking blocks if the model returned them
review = re.sub(r"<think>.*?</think>", "", review, flags=re.DOTALL).strip()

except Exception as e:
review = f"API Error: {e}"

if not review.strip():
print("Reviewer produced no output — skipping comment.")
sys.exit(0)

# ── Format comment ────────────────────────────────────────────────────────────

body = f"## 🤖 Qwen 3.5 Peer Review\n\n{review}"
if truncated:
body += "\n\n> ⚠️ Diff exceeded 200K chars and was truncated."

# Add model info footer
usage = getattr(response, "usage", None)
if usage:
body += (
f"\n\n<sub>Model: Qwen 3.5 397B MoE on aibeast | "
f"Tokens: {usage.prompt_tokens:,} in / {usage.completion_tokens:,} out</sub>"
)

print(body)

if DRY_RUN:
print("\n[dry-run] Gitea comment not posted.")
sys.exit(0)

# ── Post comment ──────────────────────────────────────────────────────────────

r = httpx.post(
f"{os.environ['GITEA_API']}/repos/{os.environ['REPO']}/issues"
f"/{os.environ['PR_NUMBER']}/comments",
headers={
"Authorization": f"token {os.environ['GITEA_TOKEN']}",
"Content-Type": "application/json",
},
json={"body": body},
timeout=120,
)
r.raise_for_status()
print(f"\nComment posted (id={r.json()['id']})")

# ── Verdict ───────────────────────────────────────────────────────────────────

if "CRITICAL_ISSUES" in review or "🚨 CRITICAL:" in review:
print("Critical issues flagged — failing check.")
sys.exit(1)
36 changes: 36 additions & 0 deletions .gitea/workflows/ai-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: AI Peer Review

on:
pull_request:
types: [opened, synchronize, reopened]

concurrency:
group: ai-review-${{ github.ref }}
cancel-in-progress: true

jobs:
review:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install uv
uses: astral-sh/setup-uv@v5

- name: Run AI review
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
GITEA_API: http://10.15.0.6:3300/api/v1
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
# Qwen 3.5 397B MoE on aibeast via OpenAI-compatible vLLM
OPENAI_API_KEY: not-needed
OPENAI_BASE_URL: http://10.15.0.166:8000/v1
run: |
uv run --with openai --with httpx \
python .gitea/scripts/ai_review.py
35 changes: 35 additions & 0 deletions .gitea/workflows/build-push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Build and Push Image

on:
push:
branches: [main]

env:
REGISTRY: 10.15.0.6:3300
IMAGE: 10.15.0.6:3300/angelos/hermes-agent

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Build
run: |
podman-remote build --network=host \
--build-arg GIT_COMMIT=${{ github.sha }} \
--build-arg GIT_REF=${{ github.ref_name }} \
--build-arg BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
--build-arg IMAGE_SOURCE=$IMAGE \
-t $IMAGE:latest \
-t $IMAGE:${{ github.sha }} \
.

- name: Push
run: |
podman-remote login --tls-verify=false \
-u "${{ secrets.REGISTRY_USER }}" -p "${{ secrets.REGISTRY_TOKEN }}" \
$REGISTRY
podman-remote push --tls-verify=false $IMAGE:latest
podman-remote push --tls-verify=false $IMAGE:${{ github.sha }}
40 changes: 40 additions & 0 deletions .gitea/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Tests

on:
push:
branches: [main]
pull_request:
branches: [main]

concurrency:
group: tests-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5

- name: Set up Python 3.11
run: uv python install 3.11

- name: Install dependencies
run: |
uv venv .venv --python 3.11
source .venv/bin/activate
uv pip install -e ".[all,dev]"

- name: Run tests
run: |
source .venv/bin/activate
python -m pytest tests/ -q --ignore=tests/integration --ignore=tests/e2e --tb=short -n auto
env:
OPENROUTER_API_KEY: ""
OPENAI_API_KEY: ""
NOUS_API_KEY: ""
74 changes: 0 additions & 74 deletions .github/workflows/deploy-site.yml

This file was deleted.

Loading