Skip to content

Commit e4a24ef

Browse files
committed
feat: introduce mios-window for pattern-based window control and add supporting infrastructure, configurations, and documentation.
1 parent 9a73900 commit e4a24ef

14 files changed

Lines changed: 501 additions & 58 deletions

File tree

usr/lib/mios/agent-pipe/server.py

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,14 @@
166166
if (os.environ.get("MIOS_AGENT_PIPE_BACKEND_LIGHT") or "").strip().lower()
167167
in {"1", "true", "yes", "on"}
168168
else "http://localhost:8642/v1")).rstrip("/")
169+
# True when the reasoning backend is the light llama.cpp lane DIRECTLY (the
170+
# BACKEND_LIGHT "bypass Hermes" deployment), so callers know the primary endpoint
171+
# is llama.cpp -- which 200-accepts but SILENTLY IGNORES tool_choice='required'.
172+
# Hermes (:8642) is an OpenAI gateway that DOES honor it, so this stays False then.
173+
_BACKEND_IS_LIGHT = (
174+
(os.environ.get("MIOS_AGENT_PIPE_BACKEND_LIGHT") or "").strip().lower()
175+
in {"1", "true", "yes", "on"}
176+
and not (os.environ.get("MIOS_AGENT_PIPE_BACKEND") or "").strip())
169177
BACKEND_MODEL = (os.environ.get("MIOS_AGENT_PIPE_BACKEND_MODEL")
170178
or os.environ.get("MIOS_AI_MODEL") # WS-0B: ONE owned key = [ai].model
171179
or "hermes-agent")
@@ -7659,15 +7667,36 @@ def _perm_rank(perm: str) -> int:
76597667
or "interactive").strip().lower()
76607668

76617669

7662-
def _hitl_block_reason(tool: str) -> "Optional[str]":
7670+
def _effective_perm(tool: str, args: "Optional[dict]" = None) -> str:
7671+
"""The permission tier that actually governs THIS call. Umbrella verbs that
7672+
dispatch to a NAMED sub-action with its own permission (os_recipe -> a named
7673+
[recipes.*]) must be gated by the RECIPE's tier, not the umbrella verb's
7674+
worst-case 'interactive' -- otherwise HITL block-mode neutralizes even the
7675+
read-only recipes (service-status / show-network / disk-usage / os-control-
7676+
health) the agent needs for routine OS introspection. Falls back to the
7677+
verb's own permission. Degrade-open: any lookup miss -> the verb tier."""
7678+
vperm = str((_VERB_CATALOG.get(tool) or {}).get("permission", "read")).lower()
7679+
try:
7680+
if tool == "os_recipe" and args:
7681+
rn = str((args or {}).get("name") or "").strip().replace("_", "-")
7682+
rc = _RECIPE_CATALOG.get(rn)
7683+
if rc:
7684+
return str(rc.get("permission", vperm)).lower()
7685+
except Exception: # noqa: BLE001 -- degrade-open
7686+
pass
7687+
return vperm
7688+
7689+
7690+
def _hitl_block_reason(tool: str, args: "Optional[dict]" = None) -> "Optional[str]":
76637691
"""#62: in BLOCK mode return a human-readable refusal reason if `tool` is a
76647692
high-risk (tier >= [ai].hitl_threshold) action requiring approval, else None.
76657693
AUDIT mode logs the high-risk action and returns None (proceed). OFF returns
7666-
None immediately. Degrade-open: never raises, never gates on error."""
7694+
None immediately. Degrade-open: never raises, never gates on error. For
7695+
os_recipe the effective tier is the NAMED recipe's, not the umbrella verb's."""
76677696
if _HITL_MODE not in ("audit", "block"):
76687697
return None
76697698
try:
7670-
vperm = str((_VERB_CATALOG.get(tool) or {}).get("permission", "read")).lower()
7699+
vperm = _effective_perm(tool, args)
76717700
if _perm_rank(vperm) < _perm_rank(_HITL_THRESHOLD):
76727701
return None # below the gate threshold -> not human-gated
76737702
if _HITL_MODE == "audit":
@@ -7700,7 +7729,7 @@ async def _hitl_arbiter_verdict(tool: str, args: dict) -> "Optional[str]":
77007729
if not _HITL_ARBITER_URL:
77017730
return None
77027731
try:
7703-
vperm = str((_VERB_CATALOG.get(tool) or {}).get("permission", "read")).lower()
7732+
vperm = _effective_perm(tool, args)
77047733
if _perm_rank(vperm) < _perm_rank(_HITL_THRESHOLD):
77057734
return None # below the threshold -> arbiter not consulted
77067735
client = await _get_client()
@@ -9576,7 +9605,12 @@ async def _firecrawl(url: str) -> tuple:
95769605
# backend). A THIRD fetch engine raced beside extract + crawl4ai so the
95779606
# pipeline uses ALL web tools (operator) -- richest wins in _fetch_all.
95789607
# Returns (markdown, links).
9579-
if not _is_port_open(3002) or not _is_port_open(6379):
9608+
# Gate ONLY on :3002 (the host-published Firecrawl proxy mios-firecrawl
9609+
# targets). Redis :6379 is the firecrawl pod's INTERNAL job queue, reached
9610+
# only by the firecrawl-api/worker containers -- never from this host-side
9611+
# broker -- so probing it here always failed and silently dropped the
9612+
# firecrawl engine out of the _fetch_all race once the pod was deployed.
9613+
if not _is_port_open(3002):
95809614
return "", []
95819615
try:
95829616
p = await asyncio.create_subprocess_exec(
@@ -17898,7 +17932,7 @@ async def dispatch_mios_verb(
1789817932
# #62 HITL gate (off by default -> the helper early-returns, ~zero overhead).
1789917933
# In block mode a high-risk verb is REFUSED here (never executed) pending human
1790017934
# approval; audit mode logs + proceeds. Keys off the resolved verb above.
17901-
_hitl_reason = _hitl_block_reason(tool)
17935+
_hitl_reason = _hitl_block_reason(tool, args)
1790217936
if _hitl_reason is None and _HITL_ARBITER_URL:
1790317937
_hitl_reason = await _hitl_arbiter_verdict(tool, args) # #62 out-of-process arbiter
1790417938
if _hitl_reason is not None:
@@ -28440,6 +28474,25 @@ async def _finalize(emit=None):
2844028474
# refusal instead of calling discord_send). An action domain MUST act.
2844128475
if not isinstance(pb.get("tool_choice"), dict):
2844228476
pb["tool_choice"] = "required"
28477+
# PRIMARY force-tool opt-out (mirrors the council/secondary downgrade at
28478+
# _sec_body): llama.cpp 200-ACCEPTS but SILENTLY IGNORES tool_choice, so
28479+
# 'required'/named reaches :11450 un-forcing -- the force-tool guard is a
28480+
# no-op on the BACKEND_LIGHT primary path. Downgrade required->auto when the
28481+
# resolved primary endpoint doesn't honor it (llama.cpp still emits real
28482+
# tool_calls under 'auto'); leave SGLang/vLLM heavy lanes that DO honor it
28483+
# untouched. The BACKEND-light lane carries no api='llamacpp' in target_cfg,
28484+
# so synthesize that cfg from the SSOT flag so the helper recognizes it.
28485+
_pc = pb.get("tool_choice")
28486+
if _pc not in ("none", "auto", None):
28487+
_prim_cfg = ({"api": "llamacpp"}
28488+
if (_BACKEND_IS_LIGHT
28489+
and str(target_endpoint).rstrip("/")
28490+
== str(BACKEND).rstrip("/"))
28491+
else target_cfg)
28492+
if not _endpoint_supports_tool_choice(
28493+
str(target_endpoint or ""), _prim_cfg,
28494+
_agent_offload_engine(_prim_cfg)):
28495+
pb["tool_choice"] = "auto"
2844328496
# Universal agent contract FIRST (operator 2026-05-30 ".md presented
2844428497
# to every agent"): the primary + every council secondary lead with
2844528498
# the overlay contract (global tools, live internet, delegation, no

usr/lib/tmpfiles.d/mios-shim-links.conf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,13 @@ L+ /usr/local/bin/mios-window-active - - - - /usr/libexec/mios/mios-window
124124
L+ /usr/local/sbin/mios-window-active - - - - /usr/libexec/mios/mios-window-active
125125
L+ /usr/local/bin/mios-pc-control - - - - /usr/libexec/mios/mios-pc-control
126126
L+ /usr/local/sbin/mios-pc-control - - - - /usr/libexec/mios/mios-pc-control
127+
# mios-pc-vision: the VLM screen-grounding FALLBACK for cu_ground -- used when
128+
# AT-SPI can't name a target element (canvas / Electron surfaces, exactly what
129+
# vision exists to cover). The binary + the VLM (qwen3-vl on :11450) are both
130+
# present, but cu_ground does shutil.which("mios-pc-vision") and dies if the
131+
# shim is absent. MUST be on PATH alongside its mios-pc-control sibling.
132+
L+ /usr/local/bin/mios-pc-vision - - - - /usr/libexec/mios/mios-pc-vision
133+
L+ /usr/local/sbin/mios-pc-vision - - - - /usr/libexec/mios/mios-pc-vision
127134
# mios-computer-use: the Linux/Wayland desktop-control executor (cu_* verb
128135
# backend; env-adaptive: bare-metal GNOME/KDE portal+uinput, WSLg delegate to
129136
# mios-pc-control, or federation-route to a remote desktop). MUST be on PATH so

usr/libexec/mios/mios-everything

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,13 @@ fi
130130
# slower -- 8s ceiling so a cold first call isn't killed mid-spawn. stderr is
131131
# CAPTURED (not discarded) so a connection failure is reported, not silenced.
132132
_ES_ERR="$(mktemp 2>/dev/null || echo /tmp/mios-es-err.$$)"
133-
RAW=$(timeout 8 "$ES_BIN" -n "$MAX" "$QUERY" 2>"$_ES_ERR" | tr -d '\r')
133+
# `|| true`: this script runs under `set -euo pipefail`, and a nonzero es.exe
134+
# (e.g. exit 8 "IPC window not found" when es.exe is version-mismatched to the
135+
# running Everything) would otherwise abort the WHOLE script here -- BEFORE the
136+
# unreachable-vs-no-match JSON envelope below runs -- so the agent got a bare
137+
# exit code instead of the structured error. stderr is captured separately into
138+
# $_ES_ERR, so the IPC-detection grep + both envelopes still fire correctly.
139+
RAW=$(timeout 8 "$ES_BIN" -n "$MAX" "$QUERY" 2>"$_ES_ERR" | tr -d '\r') || true
134140
_ES_STDERR="$(tr -d '\r' < "$_ES_ERR" 2>/dev/null)"; rm -f "$_ES_ERR"
135141

136142
if [ -z "$RAW" ]; then

usr/libexec/mios/mios-firecrawl

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,13 @@ def scrape(url: str, max_chars: int, timeout: float) -> dict:
4949
"""POST /v1/scrape -> clean markdown of the page. Firecrawl renders the
5050
page (JS) server-side and strips chrome/nav, so the markdown is article
5151
text ready to ground on."""
52-
if not _is_port_open(3002) or not _is_port_open(6379):
53-
raise ConnectionError("Firecrawl (3002) or Redis (6379) port is closed")
52+
# Gate ONLY on the Firecrawl API port this CLI actually talks to. Redis
53+
# (6379) is the firecrawl pod's INTERNAL job queue -- reachable only by the
54+
# firecrawl-api/worker containers inside the pod netns, never from this
55+
# host-side CLI -- so probing it here ALWAYS failed and wrongly forced the
56+
# healthy Firecrawl primary down to web_extract_fallback after deploy.
57+
if not _is_port_open(3002):
58+
raise ConnectionError("Firecrawl (3002) port is closed")
5459

5560
payload = {
5661
"url": url,
@@ -76,14 +81,19 @@ def scrape(url: str, max_chars: int, timeout: float) -> dict:
7681
if job_id:
7782
poll_start = time.time()
7883
while time.time() - poll_start < timeout:
79-
status_req = urllib.request.Request(f"{FIRECRAWL_URL}/v1/crawl/status/{job_id}")
84+
# A scrape job_id polls the SCRAPE-status endpoint (v1.0.0:
85+
# GET /v1/scrape/{job_id}), NOT the crawl-status one -- a scrape job
86+
# is not a crawl job. v1.0.0 may also return the scraped data
87+
# directly (no crawl-style status=="completed"), so treat a payload
88+
# that already carries data/markdown as complete.
89+
status_req = urllib.request.Request(f"{FIRECRAWL_URL}/v1/scrape/{job_id}")
8090
try:
8191
with urllib.request.urlopen(status_req, timeout=10.0) as r:
8292
status_d = json.loads(r.read().decode("utf-8", "replace"))
8393
if not isinstance(status_d, dict):
8494
break
8595
status = str(status_d.get("status") or "").lower()
86-
if status == "completed":
96+
if status == "completed" or status_d.get("data") or status_d.get("markdown"):
8797
d = status_d
8898
break
8999
elif status == "failed":

usr/libexec/mios/mios-knowledge-search

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,25 @@ def _pgvector_knowledge_fallback(query: str, top_k: int, threshold: float,
115115
"FROM knowledge WHERE emb IS NOT NULL "
116116
f"ORDER BY emb <=> '{qv}'::vector LIMIT {int(top_k)}")
117117
hits = []
118+
# Independent relevance FLOOR for this degrade-open fallback. The pg
119+
# `knowledge` table holds agent CHAT Q&A memories, NOT the curated doc
120+
# corpus this verb claims to search, so an unrelated query can surface
121+
# low-score off-topic rows (~0.51-0.53 observed) and present them as an
122+
# answer. Gate on max(caller threshold, floor) so an unrelated query
123+
# returns an honest empty result. Tunable via MIOS_KNOWLEDGE_FALLBACK_FLOOR.
124+
try:
125+
import os as _os
126+
_floor = float(_os.environ.get("MIOS_KNOWLEDGE_FALLBACK_FLOOR", "0.62"))
127+
except Exception: # noqa: BLE001
128+
_floor = 0.62
129+
_gate = max(threshold or 0.0, _floor)
118130
for r in rows:
119131
if len(r) >= 3:
120132
try:
121133
sc = float(r[2])
122134
except (ValueError, TypeError):
123135
sc = 0.0
124-
if sc >= (threshold or 0.0):
136+
if sc >= _gate:
125137
hits.append({"q": r[0], "answer": r[1], "score": sc})
126138
env = {"ok": True, "query": query,
127139
"source": "pgvector_knowledge_fallback",

0 commit comments

Comments
 (0)