arkaos 2.17.0 → 2.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/VERSION +1 -1
- package/config/hooks/user-prompt-submit.ps1 +7 -1
- package/config/hooks/user-prompt-submit.sh +7 -1
- package/core/runtime/__pycache__/context_compactor.cpython-313.pyc +0 -0
- package/core/runtime/__pycache__/subagent.cpython-313.pyc +0 -0
- package/core/runtime/context_compactor.py +63 -0
- package/core/runtime/subagent.py +13 -0
- package/core/sync/__pycache__/schema.cpython-313.pyc +0 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.17.
|
|
1
|
+
2.17.1
|
|
@@ -263,8 +263,14 @@ if (-not $pythonResult) {
|
|
|
263
263
|
$pythonResult = (@($l0, $l4, $l7) | Where-Object { $_ }) -join ' '
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
+
# --- Persistent Routing Reminder -------------------------------------------
|
|
267
|
+
# High-salience tag - ensures squad routing persists across conversation turns,
|
|
268
|
+
# and enforces visible KB citation when chunks are present.
|
|
269
|
+
# See: docs/superpowers/specs/2026-04-14-persistent-routing-reminder-design.md
|
|
270
|
+
$routeReminder = '[arka:route] Every response MUST route through a department squad. No generic assistant replies. Announce the squad before responding. When [knowledge:N chunks] is present in this context, you MUST cite at least one source and acknowledge KB was consulted; if absent on a non-trivial ArkaOS topic, query Obsidian before responding.'
|
|
271
|
+
|
|
266
272
|
# --- Output ----------------------------------------------------------------
|
|
267
|
-
$additionalContext = "$syncNotice$pythonResult"
|
|
273
|
+
$additionalContext = "$syncNotice$routeReminder $pythonResult"
|
|
268
274
|
[pscustomobject]@{ additionalContext = $additionalContext } | ConvertTo-Json -Compress
|
|
269
275
|
|
|
270
276
|
# --- Metrics (JSONL append) ------------------------------------------------
|
|
@@ -193,8 +193,14 @@ if [ -f "$_HYGIENE_SCRIPT" ]; then
|
|
|
193
193
|
bash "$_HYGIENE_SCRIPT" 2>/dev/null)
|
|
194
194
|
fi
|
|
195
195
|
|
|
196
|
+
# ─── Persistent Routing Reminder ────────────────────────────────────────
|
|
197
|
+
# High-salience tag — ensures squad routing persists across conversation turns,
|
|
198
|
+
# not just on turn 1 when /arka skill content is fresh. See spec:
|
|
199
|
+
# docs/superpowers/specs/2026-04-14-persistent-routing-reminder-design.md
|
|
200
|
+
_ROUTE_REMINDER="[arka:route] Every response MUST route through a department squad. No generic assistant replies. Announce the squad before responding. When [knowledge:N chunks] is present in this context, you MUST cite at least one source and acknowledge KB was consulted; if absent on a non-trivial ArkaOS topic, query Obsidian before responding."
|
|
201
|
+
|
|
196
202
|
# ─── Output ──────────────────────────────────────────────────────────────
|
|
197
|
-
_OUT_CONTEXT="${_ARKA_GREETING:-}${_SYNC_NOTICE:-}$python_result"
|
|
203
|
+
_OUT_CONTEXT="${_ARKA_GREETING:-}${_SYNC_NOTICE:-}${_ROUTE_REMINDER} $python_result"
|
|
198
204
|
[ -n "$_HYGIENE" ] && _OUT_CONTEXT="$_OUT_CONTEXT $_HYGIENE"
|
|
199
205
|
# Escape for JSON
|
|
200
206
|
_OUT_JSON=$(python3 -c "import json,sys; print(json.dumps(sys.stdin.read()))" <<< "$_OUT_CONTEXT" 2>/dev/null)
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Rule-based context compactor for subagent handoff.
|
|
2
|
+
|
|
3
|
+
Builds a compact summary of recent conversation turns, files touched,
|
|
4
|
+
and decisions, sized to fit a token budget. No LLM calls — deterministic
|
|
5
|
+
and zero-latency. An LLM-backed variant may be added later behind a flag
|
|
6
|
+
(see spec: docs/superpowers/specs/2026-04-14-subagent-context-handoff-design.md).
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class Turn:
|
|
15
|
+
"""A single conversation turn for compaction."""
|
|
16
|
+
role: str # "user" | "assistant"
|
|
17
|
+
content: str
|
|
18
|
+
files_touched: list[str] = field(default_factory=list)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ContextCompactor:
|
|
22
|
+
"""Builds compact context summaries for subagent handoff."""
|
|
23
|
+
|
|
24
|
+
def build(self, turns: list[Turn], max_tokens: int = 600) -> str:
|
|
25
|
+
if not turns:
|
|
26
|
+
return ""
|
|
27
|
+
|
|
28
|
+
files: list[str] = []
|
|
29
|
+
for t in turns:
|
|
30
|
+
for f in t.files_touched:
|
|
31
|
+
if f not in files:
|
|
32
|
+
files.append(f)
|
|
33
|
+
|
|
34
|
+
# Walk turns from most recent backwards, fitting into budget.
|
|
35
|
+
budget = max_tokens
|
|
36
|
+
if files:
|
|
37
|
+
files_line = "Files touched: " + ", ".join(files[:20])
|
|
38
|
+
budget -= len(files_line.split())
|
|
39
|
+
else:
|
|
40
|
+
files_line = ""
|
|
41
|
+
|
|
42
|
+
recent_summaries: list[str] = []
|
|
43
|
+
for turn in reversed(turns):
|
|
44
|
+
snippet = turn.content.strip().replace("\n", " ")
|
|
45
|
+
words = snippet.split()
|
|
46
|
+
if not words:
|
|
47
|
+
continue
|
|
48
|
+
label = "USER" if turn.role == "user" else "ASSISTANT"
|
|
49
|
+
line_words = [label + ":"] + words
|
|
50
|
+
if len(line_words) > budget:
|
|
51
|
+
line_words = line_words[: max(1, budget)]
|
|
52
|
+
if len(line_words) <= 1:
|
|
53
|
+
break
|
|
54
|
+
recent_summaries.insert(0, " ".join(line_words))
|
|
55
|
+
budget -= len(line_words)
|
|
56
|
+
if budget <= 0:
|
|
57
|
+
break
|
|
58
|
+
|
|
59
|
+
parts = ["## Prior Context"]
|
|
60
|
+
if files_line:
|
|
61
|
+
parts.append(files_line)
|
|
62
|
+
parts.extend(recent_summaries)
|
|
63
|
+
return "\n".join(parts)
|
package/core/runtime/subagent.py
CHANGED
|
@@ -130,12 +130,25 @@ class SubagentDispatcher:
|
|
|
130
130
|
task_description: What the subagent should do.
|
|
131
131
|
relevant_files: File paths the subagent should read.
|
|
132
132
|
context_summary: Compacted context from prior work.
|
|
133
|
+
Required when ARKAOS_STRICT_HANDOFF=1; otherwise emits a
|
|
134
|
+
warning. Use ContextCompactor.build() to construct.
|
|
133
135
|
constraints: Boundaries for the subagent.
|
|
134
136
|
expected_output: What format/content is expected back.
|
|
135
137
|
|
|
136
138
|
Returns:
|
|
137
139
|
HandoffArtifact ready for dispatch.
|
|
138
140
|
"""
|
|
141
|
+
import os, warnings
|
|
142
|
+
if not context_summary or not context_summary.strip():
|
|
143
|
+
msg = (
|
|
144
|
+
"create_handoff called without context_summary — subagent will "
|
|
145
|
+
"lack prior conversation context. Use ContextCompactor.build() "
|
|
146
|
+
"to construct one. Set ARKAOS_STRICT_HANDOFF=1 to enforce."
|
|
147
|
+
)
|
|
148
|
+
if os.environ.get("ARKAOS_STRICT_HANDOFF") == "1":
|
|
149
|
+
raise ValueError(msg)
|
|
150
|
+
warnings.warn(msg, DeprecationWarning, stacklevel=2)
|
|
151
|
+
|
|
139
152
|
self._task_counter += 1
|
|
140
153
|
task_id = f"task-{self._task_counter}"
|
|
141
154
|
|
|
Binary file
|
package/package.json
CHANGED