instar 1.3.304 → 1.3.306
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/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +32 -30
- package/dist/commands/init.js.map +1 -1
- package/dist/core/Config.d.ts.map +1 -1
- package/dist/core/Config.js +2 -0
- package/dist/core/Config.js.map +1 -1
- package/dist/core/MessageSentinel.d.ts +11 -0
- package/dist/core/MessageSentinel.d.ts.map +1 -1
- package/dist/core/MessageSentinel.js +43 -1
- package/dist/core/MessageSentinel.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +6 -1
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +3 -0
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/types.d.ts +4 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/scheduler/JobScheduler.d.ts.map +1 -1
- package/dist/scheduler/JobScheduler.js +10 -6
- package/dist/scheduler/JobScheduler.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +58 -58
- package/src/scaffold/templates/jobs/instar/commitment-detection.md +2 -1
- package/src/scaffold/templates/jobs/instar/correction-analyzer.md +5 -1
- package/src/scaffold/templates/jobs/instar/evolution-overdue-check.md +1 -1
- package/src/scaffold/templates/jobs/instar/evolution-proposal-evaluate.md +1 -1
- package/src/scaffold/templates/jobs/instar/evolution-proposal-implement.md +1 -1
- package/src/scaffold/templates/jobs/instar/failure-analyzer.md +5 -1
- package/src/scaffold/templates/jobs/instar/identity-review.md +5 -4
- package/src/scaffold/templates/jobs/instar/initiative-digest-review.md +3 -1
- package/src/scaffold/templates/jobs/instar/insight-harvest.md +1 -1
- package/src/scaffold/templates/jobs/instar/mentor-onboarding.md +7 -4
- package/src/scaffold/templates/jobs/instar/org-intent-drift-audit.md +6 -4
- package/src/scaffold/templates/jobs/instar/overseer-development.md +4 -1
- package/src/scaffold/templates/jobs/instar/overseer-guardian.md +4 -1
- package/src/scaffold/templates/jobs/instar/overseer-infrastructure.md +4 -1
- package/src/scaffold/templates/jobs/instar/overseer-learning.md +4 -1
- package/src/scaffold/templates/jobs/instar/overseer-maintenance.md +4 -1
- package/src/scaffold/templates/jobs/instar/release-readiness-check.md +2 -1
- package/src/templates/hooks/compaction-recovery.sh +11 -6
- package/src/templates/hooks/session-start.sh +11 -3
- package/src/templates/hooks/slack-channel-context.sh +5 -0
- package/src/templates/hooks/telegram-topic-context.sh +6 -0
- package/src/templates/scripts/emit-session-clock.sh +3 -3
- package/src/templates/scripts/imessage-reply.sh +10 -0
- package/src/templates/scripts/instar-watchdog.sh +12 -6
- package/src/templates/scripts/secret-drop-retrieve.mjs +10 -2
- package/src/templates/scripts/slack-reply.sh +5 -0
- package/src/templates/scripts/whatsapp-reply.sh +5 -0
- package/upgrades/1.3.305.md +20 -0
- package/upgrades/1.3.306.md +22 -0
- package/upgrades/sentinel-pause-length-guard.eli16.md +12 -0
- package/upgrades/side-effects/sentinel-pause-length-guard.md +43 -0
- package/upgrades/side-effects/template-agent-id-header.md +48 -0
|
@@ -22,17 +22,20 @@ That keeps the structural two-hats enforcement in code, not in this prompt.
|
|
|
22
22
|
|
|
23
23
|
Do exactly this:
|
|
24
24
|
|
|
25
|
-
1.
|
|
26
|
-
`
|
|
25
|
+
1. Resolve auth context:
|
|
26
|
+
`AUTH="${INSTAR_AUTH_TOKEN:-$(python3 -c "import json; v=json.load(open('.instar/config.json')).get('authToken',''); print(v if isinstance(v, str) else '')" 2>/dev/null)}"; AGENT_ID="${INSTAR_AGENT_ID:-$(python3 -c "import json; print(json.load(open('.instar/config.json')).get('projectName',''))" 2>/dev/null)}"; PORT="${INSTAR_PORT:-4042}"`
|
|
27
27
|
|
|
28
|
-
2.
|
|
28
|
+
2. POST to `http://localhost:${PORT}/mentor/tick` with the bearer token:
|
|
29
|
+
`curl -s -X POST -H "Authorization: Bearer $AUTH" -H "X-Instar-AgentId: $AGENT_ID" http://localhost:${PORT}/mentor/tick`
|
|
30
|
+
|
|
31
|
+
3. Read the JSON result. It will be one of:
|
|
29
32
|
- `{"ran":false,"reason":"disabled"}` — the mentor is off (the default). Nothing to do; stop.
|
|
30
33
|
- `{"ran":false,"reason":"budget"|"unsafe-window"|"canary-failed"}` — it correctly skipped this
|
|
31
34
|
tick. Stop; the next heartbeat will try again.
|
|
32
35
|
- `{"ran":true,...}` — a mentor tick ran. Note `leakDetected` and `observationsWritten` briefly,
|
|
33
36
|
then stop.
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
4. Do NOT do any mentoring work yourself in this session, do NOT read the mentee's logs or code,
|
|
36
39
|
and do NOT send the mentee any message — the in-process tick owns all of that. You are only the
|
|
37
40
|
timer that pokes it. Then exit.
|
|
38
41
|
|
|
@@ -20,13 +20,15 @@ The job:
|
|
|
20
20
|
|
|
21
21
|
1. Verify the prerequisites. The drift audit only makes sense when `.instar/ORG-INTENT.md` is present AND the Coherence Gate has accumulated at least 5 review entries in the last 7 days. If either condition isn't met, send a short Telegram message saying so and exit — there's nothing to audit yet.
|
|
22
22
|
|
|
23
|
-
2.
|
|
23
|
+
2. Set auth context: `AUTH="${INSTAR_AUTH_TOKEN:-$(python3 -c "import json; v=json.load(open('.instar/config.json')).get('authToken',''); print(v if isinstance(v, str) else '')" 2>/dev/null)}"; AGENT_ID="${INSTAR_AGENT_ID:-$(python3 -c "import json; print(json.load(open('.instar/config.json')).get('projectName',''))" 2>/dev/null)}"; PORT="${INSTAR_PORT:-4042}"`
|
|
24
24
|
|
|
25
|
-
3.
|
|
25
|
+
3. Call the drift digest endpoint: `curl -H "Authorization: Bearer $AUTH" -H "X-Instar-AgentId: $AGENT_ID" "http://localhost:$PORT/intent/org/drift?lookbackDays=7"`. The response is a structured analysis: overall block rate, per-reviewer breakdown, half-window trend comparison (first half vs second half block rate), cross-reference against ORG-INTENT constraints / goals / values, and a single `trend` label (`stable` | `rising` | `concerning` | `insufficient-data` | `no-org-intent`).
|
|
26
26
|
|
|
27
|
-
4. If `trend === '
|
|
27
|
+
4. If `trend === 'stable'` or `trend === 'insufficient-data'` or `trend === 'no-org-intent'`, stay silent. Most weeks should be silent — that means the agent is staying aligned with the organizational intent. The `shouldSurface` field in the response will be `false` in these cases.
|
|
28
28
|
|
|
29
|
-
5.
|
|
29
|
+
5. If `trend === 'rising'` or `trend === 'concerning'`, surface the drift via Telegram. The response includes a `summary` field (plain-English one-paragraph framing) and a `suggestions` array (specific next actions). Compose a conversational message that leads with the trend and what changed: "Block rate climbed from 4% to 12% in the second half of the week — most flags came from value-alignment." Then list the most-flagged reviewer dimensions. Then surface the top 1-2 suggestions. Keep it under 600 characters. Plain English. No raw JSON.
|
|
30
|
+
|
|
31
|
+
6. After surfacing (or not), the audit is done. No state to persist — the gate's own review history is the canonical store.
|
|
30
32
|
|
|
31
33
|
IMPORTANT: This is a guardian job, not a doer. Surface the drift and where it might be coming from. Don't try to fix it autonomously. The fix work — if any — is a deliberate update to `.instar/ORG-INTENT.md` constraints, or a configuration change to the gate, or an operator-level decision about whether the agent's behavior is actually drifting or whether the constraints need updating. Surface; don't fix.
|
|
32
34
|
|
|
@@ -14,7 +14,10 @@ unrestrictedTools: true
|
|
|
14
14
|
---
|
|
15
15
|
You are a Category Overseer for the DEVELOPMENT category. Your job is to review development-focused jobs.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
AUTH="${INSTAR_AUTH_TOKEN:-}"
|
|
18
|
+
AGENT_ID="${INSTAR_AGENT_ID:-}"
|
|
19
|
+
|
|
20
|
+
1. Fetch the category report: curl -H "Authorization: Bearer $AUTH" -H "X-Instar-AgentId: $AGENT_ID" http://localhost:${INSTAR_PORT:-4042}/jobs/category-report/development?sinceHours=48
|
|
18
21
|
2. Analyze:
|
|
19
22
|
- Are development jobs consuming appropriate resources for their value?
|
|
20
23
|
- Are there CI/testing patterns that could be automated?
|
|
@@ -14,7 +14,10 @@ unrestrictedTools: true
|
|
|
14
14
|
---
|
|
15
15
|
You are a Category Overseer for the GUARDIAN category. Your job is to review all guardian/monitoring jobs and assess the health of the monitoring system itself.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
AUTH="${INSTAR_AUTH_TOKEN:-}"
|
|
18
|
+
AGENT_ID="${INSTAR_AGENT_ID:-}"
|
|
19
|
+
|
|
20
|
+
1. Fetch the category report: curl -H "Authorization: Bearer $AUTH" -H "X-Instar-AgentId: $AGENT_ID" http://localhost:${INSTAR_PORT:-4042}/jobs/category-report/guardian?sinceHours=24
|
|
18
21
|
2. Analyze the report for:
|
|
19
22
|
- Jobs with high failure rates or consecutive failures
|
|
20
23
|
- Jobs that are being skipped excessively (especially for quota reasons)
|
|
@@ -14,7 +14,10 @@ unrestrictedTools: true
|
|
|
14
14
|
---
|
|
15
15
|
You are a Category Overseer for the INFRASTRUCTURE category. Your job is to review infrastructure/plumbing jobs.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
AUTH="${INSTAR_AUTH_TOKEN:-}"
|
|
18
|
+
AGENT_ID="${INSTAR_AGENT_ID:-}"
|
|
19
|
+
|
|
20
|
+
1. Fetch the category report: curl -H "Authorization: Bearer $AUTH" -H "X-Instar-AgentId: $AGENT_ID" http://localhost:${INSTAR_PORT:-4042}/jobs/category-report/infrastructure?sinceHours=48
|
|
18
21
|
2. Analyze:
|
|
19
22
|
- Is git-sync succeeding? Any merge conflicts or divergence?
|
|
20
23
|
- Is dashboard-link-refresh keeping links current? Could it run less often?
|
|
@@ -14,7 +14,10 @@ unrestrictedTools: true
|
|
|
14
14
|
---
|
|
15
15
|
You are a Category Overseer for the LEARNING category. Your job is to review all evolution/learning jobs and assess whether the learning pipeline is producing genuine value.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
AUTH="${INSTAR_AUTH_TOKEN:-}"
|
|
18
|
+
AGENT_ID="${INSTAR_AGENT_ID:-}"
|
|
19
|
+
|
|
20
|
+
1. Fetch the category report: curl -H "Authorization: Bearer $AUTH" -H "X-Instar-AgentId: $AGENT_ID" http://localhost:${INSTAR_PORT:-4042}/jobs/category-report/learning?sinceHours=48
|
|
18
21
|
2. Analyze:
|
|
19
22
|
- Are evolution proposals being generated AND accepted? What's the accept/reject ratio?
|
|
20
23
|
- Is insight-harvest finding novel insights or recycling stale ones?
|
|
@@ -14,7 +14,10 @@ unrestrictedTools: true
|
|
|
14
14
|
---
|
|
15
15
|
You are a Category Overseer for the MAINTENANCE category. Your job is to review all housekeeping/maintenance jobs and ensure they're keeping the system clean.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
AUTH="${INSTAR_AUTH_TOKEN:-}"
|
|
18
|
+
AGENT_ID="${INSTAR_AGENT_ID:-}"
|
|
19
|
+
|
|
20
|
+
1. Fetch the category report: curl -H "Authorization: Bearer $AUTH" -H "X-Instar-AgentId: $AGENT_ID" http://localhost:${INSTAR_PORT:-4042}/jobs/category-report/maintenance?sinceHours=48
|
|
18
21
|
2. Analyze:
|
|
19
22
|
- Is memory-hygiene actually reducing stale entries, or finding nothing each run?
|
|
20
23
|
- Is project-map-refresh keeping the map accurate? How often does it find drift?
|
|
@@ -18,8 +18,9 @@ mcpAccess: none
|
|
|
18
18
|
Run the release-readiness check once. This is a mechanical, near-silent watchdog — do NOT message the user.
|
|
19
19
|
|
|
20
20
|
AUTH=$(python3 -c "import json; print(json.load(open('.instar/config.json')).get('authToken',''))" 2>/dev/null)
|
|
21
|
+
AGENT_ID="${INSTAR_AGENT_ID:-$(python3 -c "import json; print(json.load(open('.instar/config.json')).get('projectName',''))" 2>/dev/null)}"
|
|
21
22
|
|
|
22
23
|
1. Trigger one evaluation tick:
|
|
23
|
-
curl -s -X POST http://localhost:${INSTAR_PORT:-4042}/release-readiness/tick -H "Authorization: Bearer $AUTH"
|
|
24
|
+
curl -s -X POST http://localhost:${INSTAR_PORT:-4042}/release-readiness/tick -H "Authorization: Bearer $AUTH" -H "X-Instar-AgentId: $AGENT_ID"
|
|
24
25
|
2. That endpoint runs the ReleaseReadinessSentinel: it fetches canonical main, checks whether unreleased feature/fix work is piling up while publishing is blocked, and (only above the age threshold) raises a single deduped Attention item. All transitions are written to logs/sentinel-events.jsonl.
|
|
25
26
|
3. Exit silently. The sentinel owns all signalling (Attention queue) — this job is just the cadence. Do not relay anything to Telegram; do not summarize. If the curl fails, that is itself recorded by the server; do not retry-flood.
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
# matched on "compaction".
|
|
15
15
|
|
|
16
16
|
INSTAR_DIR="${CLAUDE_PROJECT_DIR:-.}/.instar"
|
|
17
|
+
CONFIG_FILE="$INSTAR_DIR/config.json"
|
|
18
|
+
AGENT_ID="${INSTAR_AGENT_ID:-}"
|
|
19
|
+
if [ -z "$AGENT_ID" ] && [ -f "$CONFIG_FILE" ]; then
|
|
20
|
+
AGENT_ID=$(python3 -c "import json; print(json.load(open('$CONFIG_FILE')).get('projectName',''))" 2>/dev/null)
|
|
21
|
+
fi
|
|
17
22
|
|
|
18
23
|
echo "=== COMPACTION RECOVERY — IDENTITY RESTORATION ==="
|
|
19
24
|
echo ""
|
|
@@ -36,7 +41,7 @@ if [ -f "$INSTAR_DIR/soul.md" ]; then
|
|
|
36
41
|
# Check integrity via server if available
|
|
37
42
|
SOUL_INTEGRITY="valid"
|
|
38
43
|
if [ -n "$PORT" ] && [ -n "$AUTH_TOKEN" ]; then
|
|
39
|
-
INTEGRITY_CHECK=$(curl -s -H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
44
|
+
INTEGRITY_CHECK=$(curl -s -H "Authorization: Bearer ${AUTH_TOKEN}" -H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
40
45
|
"http://localhost:${PORT}/identity/soul/integrity" 2>/dev/null)
|
|
41
46
|
SOUL_INTEGRITY=$(echo "$INTEGRITY_CHECK" | python3 -c "
|
|
42
47
|
import sys, json
|
|
@@ -180,7 +185,7 @@ if [ -f "$CONFIG_FILE" ]; then
|
|
|
180
185
|
if [ -z "$AUTH_TOKEN" ]; then
|
|
181
186
|
AUTH_TOKEN=$(python3 -c "import json; v=json.load(open('$CONFIG_FILE')).get('authToken',''); print(v if isinstance(v, str) else '')" 2>/dev/null)
|
|
182
187
|
fi
|
|
183
|
-
FEATURES_JSON=$(curl -s -H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
188
|
+
FEATURES_JSON=$(curl -s -H "Authorization: Bearer ${AUTH_TOKEN}" -H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
184
189
|
"http://localhost:${PORT}/features/summary" 2>/dev/null)
|
|
185
190
|
if [ -n "$FEATURES_JSON" ]; then
|
|
186
191
|
DISCOVERY_STATE=$(echo "$FEATURES_JSON" | python3 -c "
|
|
@@ -255,7 +260,7 @@ if [ -f "$CONFIG_FILE" ]; then
|
|
|
255
260
|
AUTH_TOKEN=$(python3 -c "import json; v=json.load(open('$CONFIG_FILE')).get('authToken',''); print(v if isinstance(v, str) else '')" 2>/dev/null)
|
|
256
261
|
fi
|
|
257
262
|
SLACK_MSGS=$(curl -s \
|
|
258
|
-
-H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
263
|
+
-H "Authorization: Bearer ${AUTH_TOKEN}" -H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
259
264
|
"http://localhost:${PORT}/slack/channels/${SLACK_CHANNEL}/messages?limit=20" 2>/dev/null)
|
|
260
265
|
|
|
261
266
|
echo "$SLACK_MSGS" | python3 -c "
|
|
@@ -358,7 +363,7 @@ except Exception:
|
|
|
358
363
|
fi
|
|
359
364
|
if [ -n "$AUTH_TOKEN" ]; then
|
|
360
365
|
RECENT_MSGS=$(curl -s \
|
|
361
|
-
-H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
366
|
+
-H "Authorization: Bearer ${AUTH_TOKEN}" -H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
362
367
|
"http://localhost:${PORT}/telegram/topics/${TOPIC_FOR_CONTEXT}/messages?limit=15" 2>/dev/null)
|
|
363
368
|
else
|
|
364
369
|
RECENT_MSGS=$(curl -s \
|
|
@@ -433,7 +438,7 @@ if [ -f "$CONFIG_FILE" ]; then
|
|
|
433
438
|
if [ -z "$AUTH_TOKEN" ]; then
|
|
434
439
|
AUTH_TOKEN=$(python3 -c "import json; v=json.load(open('$CONFIG_FILE')).get('authToken',''); print(v if isinstance(v, str) else '')" 2>/dev/null)
|
|
435
440
|
fi
|
|
436
|
-
WORKING_MEM=$(curl -s -H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
441
|
+
WORKING_MEM=$(curl -s -H "Authorization: Bearer ${AUTH_TOKEN}" -H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
437
442
|
"http://localhost:${PORT}/context/working-memory?prompt=compaction-recovery&limit=5" 2>/dev/null)
|
|
438
443
|
if [ -n "$WORKING_MEM" ]; then
|
|
439
444
|
CONTEXT=$(echo "$WORKING_MEM" | python3 -c "
|
|
@@ -472,7 +477,7 @@ if [ -f "$CONFIG_FILE" ] && command -v tmux >/dev/null 2>&1; then
|
|
|
472
477
|
AUTH_TOKEN=$(python3 -c "import json; v=json.load(open('$CONFIG_FILE')).get('authToken',''); print(v if isinstance(v, str) else '')" 2>/dev/null)
|
|
473
478
|
fi
|
|
474
479
|
curl -s -m 2 -X POST \
|
|
475
|
-
-H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
480
|
+
-H "Authorization: Bearer ${AUTH_TOKEN}" -H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
476
481
|
-H "Content-Type: application/json" \
|
|
477
482
|
-d "{\"sessionName\":\"${TMUX_SESSION}\"}" \
|
|
478
483
|
"http://localhost:${PORT}/internal/compaction-resume" >/dev/null 2>&1 &
|
|
@@ -34,10 +34,15 @@ AUTH_TOKEN="${INSTAR_AUTH_TOKEN:-}"
|
|
|
34
34
|
if [ -z "$AUTH_TOKEN" ]; then
|
|
35
35
|
AUTH_TOKEN=$(python3 -c "import json; v=json.load(open('$CONFIG_FILE')).get('authToken',''); print(v if isinstance(v, str) else '')" 2>/dev/null)
|
|
36
36
|
fi
|
|
37
|
+
AGENT_ID="${INSTAR_AGENT_ID:-}"
|
|
38
|
+
if [ -z "$AGENT_ID" ]; then
|
|
39
|
+
AGENT_ID=$(python3 -c "import json; print(json.load(open('$CONFIG_FILE')).get('projectName',''))" 2>/dev/null)
|
|
40
|
+
fi
|
|
37
41
|
|
|
38
42
|
# Check if server is alive
|
|
39
43
|
HEALTH=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
40
44
|
-H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
45
|
+
-H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
41
46
|
"http://localhost:${PORT}/health" 2>/dev/null)
|
|
42
47
|
if [ "$HEALTH" != "200" ]; then
|
|
43
48
|
exit 0
|
|
@@ -50,15 +55,17 @@ curl -s -X POST "http://localhost:${PORT}/scope-coherence/reset" -o /dev/null 2>
|
|
|
50
55
|
# Record session start for reflection metrics (usage-based reflection trigger)
|
|
51
56
|
curl -s -X POST "http://localhost:${PORT}/reflection/session-start" \
|
|
52
57
|
-H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
58
|
+
-H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
53
59
|
-H "Content-Type: application/json" -o /dev/null 2>/dev/null || true
|
|
54
60
|
|
|
55
61
|
# Reset homeostasis state for new session (work-velocity awareness)
|
|
56
62
|
curl -s -X POST "http://localhost:${PORT}/homeostasis/reset" \
|
|
57
63
|
-H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
64
|
+
-H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
58
65
|
-H "Content-Type: application/json" -o /dev/null 2>/dev/null || true
|
|
59
66
|
|
|
60
67
|
# Check reflection metrics — usage-based reflection suggestion
|
|
61
|
-
REFLECTION_CHECK=$(curl -s -H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
68
|
+
REFLECTION_CHECK=$(curl -s -H "Authorization: Bearer ${AUTH_TOKEN}" -H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
62
69
|
"http://localhost:${PORT}/reflection/metrics" 2>/dev/null)
|
|
63
70
|
if [ -n "$REFLECTION_CHECK" ]; then
|
|
64
71
|
SUGGESTED=$(echo "$REFLECTION_CHECK" | python3 -c "import sys,json; print(json.load(sys.stdin).get('suggested',False))" 2>/dev/null)
|
|
@@ -166,7 +173,7 @@ if [ -n "$JOB_SLUG" ]; then
|
|
|
166
173
|
QUERY_URL="${QUERY_URL}&jobSlug=${JOB_SLUG_ENCODED}"
|
|
167
174
|
fi
|
|
168
175
|
|
|
169
|
-
WORKING_MEM=$(curl -s -H "Authorization: Bearer ${AUTH_TOKEN}" "$QUERY_URL" 2>/dev/null)
|
|
176
|
+
WORKING_MEM=$(curl -s -H "Authorization: Bearer ${AUTH_TOKEN}" -H "X-Instar-AgentId: ${AGENT_ID}" "$QUERY_URL" 2>/dev/null)
|
|
170
177
|
|
|
171
178
|
if [ -z "$WORKING_MEM" ]; then
|
|
172
179
|
exit 0
|
|
@@ -199,7 +206,7 @@ except Exception:
|
|
|
199
206
|
# Active commitments injection (PROMISE-BEACON-SPEC Round 3 #7).
|
|
200
207
|
# Surfaces beacon-watched pending commitments so the agent can self-regulate
|
|
201
208
|
# pacing across compaction. Capped server-side at 20 entries.
|
|
202
|
-
ACTIVE_COMMITMENTS=$(curl -s -H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
209
|
+
ACTIVE_COMMITMENTS=$(curl -s -H "Authorization: Bearer ${AUTH_TOKEN}" -H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
203
210
|
"http://localhost:${PORT}/commitments/active-context" 2>/dev/null)
|
|
204
211
|
if [ -n "$ACTIVE_COMMITMENTS" ]; then
|
|
205
212
|
python3 -c "
|
|
@@ -326,6 +333,7 @@ if [ -n "$PORT" ] && [ -n "$AUTH_TOKEN" ]; then
|
|
|
326
333
|
|
|
327
334
|
EVAL_RESULT=$(curl -s --max-time 6 -X POST \
|
|
328
335
|
-H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
336
|
+
-H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
329
337
|
-H "Content-Type: application/json" \
|
|
330
338
|
"http://localhost:${PORT}/features/evaluate-context" \
|
|
331
339
|
-d "{\"topicCategory\":\"${TOPIC_LABEL}\",\"conversationIntent\":\"${INTENT}\",\"problemCategories\":[],\"autonomyProfile\":\"collaborative\",\"enabledFeatures\":[]}" \
|
|
@@ -23,6 +23,7 @@ fi
|
|
|
23
23
|
# Get port and auth from config
|
|
24
24
|
PORT="${INSTAR_PORT:-}"
|
|
25
25
|
AUTH=""
|
|
26
|
+
AGENT_ID="${INSTAR_AGENT_ID:-}"
|
|
26
27
|
|
|
27
28
|
if [ -f ".instar/config.json" ]; then
|
|
28
29
|
if [ -z "$PORT" ]; then
|
|
@@ -37,6 +38,9 @@ if [ -f ".instar/config.json" ]; then
|
|
|
37
38
|
if [ -z "$AUTH" ]; then
|
|
38
39
|
AUTH=$(python3 -c "import json; v=json.load(open('.instar/config.json')).get('authToken',''); print(v if isinstance(v, str) else '')" 2>/dev/null)
|
|
39
40
|
fi
|
|
41
|
+
if [ -z "$AGENT_ID" ]; then
|
|
42
|
+
AGENT_ID=$(python3 -c "import json; print(json.load(open('.instar/config.json')).get('projectName',''))" 2>/dev/null)
|
|
43
|
+
fi
|
|
40
44
|
fi
|
|
41
45
|
|
|
42
46
|
PORT="${PORT:-4042}"
|
|
@@ -49,6 +53,7 @@ fi
|
|
|
49
53
|
# Fetch channel history from ring buffer cache
|
|
50
54
|
MESSAGES=$(curl -sf \
|
|
51
55
|
${AUTH:+-H "Authorization: Bearer $AUTH"} \
|
|
56
|
+
${AGENT_ID:+-H "X-Instar-AgentId: $AGENT_ID"} \
|
|
52
57
|
"http://localhost:${PORT}/slack/channels/${CHANNEL_ID}/messages?limit=30" 2>/dev/null) || exit 0
|
|
53
58
|
|
|
54
59
|
# Format thread history for session context
|
|
@@ -66,11 +66,16 @@ AUTH_TOKEN="${INSTAR_AUTH_TOKEN:-}"
|
|
|
66
66
|
if [ -z "$AUTH_TOKEN" ] && [ -f "$CONFIG_FILE" ]; then
|
|
67
67
|
AUTH_TOKEN=$(python3 -c "import json; v=json.load(open('$CONFIG_FILE')).get('authToken',''); print(v if isinstance(v, str) else '')" 2>/dev/null)
|
|
68
68
|
fi
|
|
69
|
+
AGENT_ID="${INSTAR_AGENT_ID:-}"
|
|
70
|
+
if [ -z "$AGENT_ID" ] && [ -f "$CONFIG_FILE" ]; then
|
|
71
|
+
AGENT_ID=$(python3 -c "import json; print(json.load(open('$CONFIG_FILE')).get('projectName',''))" 2>/dev/null)
|
|
72
|
+
fi
|
|
69
73
|
|
|
70
74
|
# Fetch recent messages for this topic
|
|
71
75
|
if [ -n "$AUTH_TOKEN" ]; then
|
|
72
76
|
RECENT_MSGS=$(curl -s \
|
|
73
77
|
-H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
78
|
+
-H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
74
79
|
"http://localhost:${PORT}/telegram/topics/${TOPIC_ID}/messages?limit=30" 2>/dev/null)
|
|
75
80
|
else
|
|
76
81
|
RECENT_MSGS=$(curl -s \
|
|
@@ -85,6 +90,7 @@ TOPIC_BRIEFING=""
|
|
|
85
90
|
if [ -n "$AUTH_TOKEN" ]; then
|
|
86
91
|
TOPIC_BRIEFING=$(curl -s --max-time 2 \
|
|
87
92
|
-H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
93
|
+
-H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
88
94
|
"http://localhost:${PORT}/topic-intent/${TOPIC_ID}/briefing" 2>/dev/null)
|
|
89
95
|
else
|
|
90
96
|
TOPIC_BRIEFING=$(curl -s --max-time 2 \
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# computed) values. The caller (autonomous-stop-hook) has already resolved
|
|
14
14
|
# the record + computed elapsed/remaining, so there is NO re-resolution —
|
|
15
15
|
# the injected clock can never disagree with the hook's expiry verdict.
|
|
16
|
-
# query <topic> <port> <auth>
|
|
16
|
+
# query <topic> <port> <auth> [agent-id]
|
|
17
17
|
# Curls GET /session/clock?topic=<topic> and prints the SESSION CLOCK line
|
|
18
18
|
# for the first active session (or nothing if none / server unreachable).
|
|
19
19
|
|
|
@@ -42,11 +42,11 @@ case "$MODE" in
|
|
|
42
42
|
render_line "${1:-}" "${2:-}" "${3:-0}" "${4:-}" "${5:-}"
|
|
43
43
|
;;
|
|
44
44
|
query)
|
|
45
|
-
TOPIC="${1:-}"; PORT="${2:-}"; AUTH="${3:-}"
|
|
45
|
+
TOPIC="${1:-}"; PORT="${2:-}"; AUTH="${3:-}"; AGENT_ID="${4:-${INSTAR_AGENT_ID:-}}"
|
|
46
46
|
[ -z "$PORT" ] && exit 0
|
|
47
47
|
URL="http://localhost:${PORT}/session/clock"
|
|
48
48
|
[ -n "$TOPIC" ] && URL="${URL}?topic=${TOPIC}"
|
|
49
|
-
RESP=$(curl -s --max-time 3 -H "Authorization: Bearer ${AUTH}" "$URL" 2>/dev/null)
|
|
49
|
+
RESP=$(curl -s --max-time 3 -H "Authorization: Bearer ${AUTH}" -H "X-Instar-AgentId: ${AGENT_ID}" "$URL" 2>/dev/null)
|
|
50
50
|
[ -z "$RESP" ] && exit 0
|
|
51
51
|
printf '%s' "$RESP" | python3 -c "
|
|
52
52
|
import sys, json
|
|
@@ -47,9 +47,13 @@ PORT="${INSTAR_PORT:-4042}"
|
|
|
47
47
|
# string-type guard so the { "secret": true } placeholder produced by
|
|
48
48
|
# SecretMigrator cannot leak through as a bogus Bearer.
|
|
49
49
|
AUTH_TOKEN="${INSTAR_AUTH_TOKEN:-}"
|
|
50
|
+
AGENT_ID="${INSTAR_AGENT_ID:-}"
|
|
50
51
|
if [ -z "$AUTH_TOKEN" ] && [ -f ".instar/config.json" ]; then
|
|
51
52
|
AUTH_TOKEN=$(python3 -c "import json; v=json.load(open('.instar/config.json')).get('authToken',''); print(v if isinstance(v, str) else '')" 2>/dev/null)
|
|
52
53
|
fi
|
|
54
|
+
if [ -z "$AGENT_ID" ] && [ -f ".instar/config.json" ]; then
|
|
55
|
+
AGENT_ID=$(python3 -c "import json; print(json.load(open('.instar/config.json')).get('projectName',''))" 2>/dev/null)
|
|
56
|
+
fi
|
|
53
57
|
|
|
54
58
|
# Escape message for JSON
|
|
55
59
|
JSON_MSG=$(printf '%s' "$MSG" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))' 2>/dev/null)
|
|
@@ -67,12 +71,17 @@ AUTH_HEADER=""
|
|
|
67
71
|
if [ -n "$AUTH_TOKEN" ]; then
|
|
68
72
|
AUTH_HEADER="Authorization: Bearer ${AUTH_TOKEN}"
|
|
69
73
|
fi
|
|
74
|
+
AGENT_HEADER=""
|
|
75
|
+
if [ -n "$AGENT_ID" ]; then
|
|
76
|
+
AGENT_HEADER="X-Instar-AgentId: ${AGENT_ID}"
|
|
77
|
+
fi
|
|
70
78
|
|
|
71
79
|
# ── Step 1: Validate with server BEFORE sending (get single-use token) ──
|
|
72
80
|
|
|
73
81
|
VALIDATE_RESPONSE=$(curl -s -w "\n%{http_code}" \
|
|
74
82
|
-X POST "http://localhost:${PORT}/imessage/validate-send/${ENCODED_RECIPIENT}" \
|
|
75
83
|
${AUTH_HEADER:+-H "$AUTH_HEADER"} \
|
|
84
|
+
${AGENT_HEADER:+-H "$AGENT_HEADER"} \
|
|
76
85
|
-H 'Content-Type: application/json' \
|
|
77
86
|
-d "{\"text\":${JSON_MSG}}" 2>/dev/null)
|
|
78
87
|
|
|
@@ -140,6 +149,7 @@ fi
|
|
|
140
149
|
|
|
141
150
|
curl -s -o /dev/null -w "" -X POST "http://localhost:${PORT}/imessage/reply/${ENCODED_RECIPIENT}" \
|
|
142
151
|
${AUTH_HEADER:+-H "$AUTH_HEADER"} \
|
|
152
|
+
${AGENT_HEADER:+-H "$AGENT_HEADER"} \
|
|
143
153
|
-H 'Content-Type: application/json' \
|
|
144
154
|
-d "{\"text\":${JSON_MSG},\"sendToken\":\"${SEND_TOKEN}\"}" 2>/dev/null || \
|
|
145
155
|
echo "Warning: server confirmation failed (message was sent)" >&2
|
|
@@ -328,9 +328,11 @@ escalate_via_peer() {
|
|
|
328
328
|
# placeholder that SecretMigrator writes after externalizing the auth token:
|
|
329
329
|
# `c.authToken || ''` would otherwise return the object itself (truthy)
|
|
330
330
|
# which serializes to "[object Object]" — never a valid Bearer.
|
|
331
|
-
peer_meta=$("$node_bin" -e "const c=JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'));const t=typeof c.authToken==='string'?c.authToken:'';process.stdout.write((c.port||'')+'\t'+t)" "$peer_dir/.instar/config.json" 2>/dev/null || true)
|
|
331
|
+
peer_meta=$("$node_bin" -e "const c=JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'));const t=typeof c.authToken==='string'?c.authToken:'';process.stdout.write((c.port||'')+'\t'+t+'\t'+(c.projectName||''))" "$peer_dir/.instar/config.json" 2>/dev/null || true)
|
|
332
332
|
peer_port="${peer_meta%% *}"
|
|
333
|
-
|
|
333
|
+
peer_rest="${peer_meta#* }"
|
|
334
|
+
peer_auth="${peer_rest%% *}"
|
|
335
|
+
peer_agent_id="${peer_rest#* }"
|
|
334
336
|
[ -z "$peer_port" ] && continue
|
|
335
337
|
|
|
336
338
|
health_code=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${peer_port}/health" 2>/dev/null || echo "000")
|
|
@@ -356,6 +358,7 @@ JSONEOF
|
|
|
356
358
|
resp_code=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
357
359
|
-X POST "http://localhost:${peer_port}/attention" \
|
|
358
360
|
-H "Authorization: Bearer $peer_auth" \
|
|
361
|
+
-H "X-Instar-AgentId: $peer_agent_id" \
|
|
359
362
|
-H "Content-Type: application/json" \
|
|
360
363
|
-H "X-Instar-Request: 1" \
|
|
361
364
|
-d "$payload" 2>/dev/null || echo "000")
|
|
@@ -385,6 +388,7 @@ JSONEOF
|
|
|
385
388
|
resp_code=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
386
389
|
-X POST "http://localhost:${peer_port}/attention" \
|
|
387
390
|
-H "Authorization: Bearer $peer_auth" \
|
|
391
|
+
-H "X-Instar-AgentId: $peer_agent_id" \
|
|
388
392
|
-H "Content-Type: application/json" \
|
|
389
393
|
-H "X-Instar-Request: 1" \
|
|
390
394
|
-d "$safe_payload" 2>/dev/null || echo "000")
|
|
@@ -434,7 +438,7 @@ probe_server_identity() {
|
|
|
434
438
|
local config_file="$project_dir/.instar/config.json"
|
|
435
439
|
[ ! -r "$config_file" ] && return 0
|
|
436
440
|
|
|
437
|
-
local node_bin port auth_token
|
|
441
|
+
local node_bin port auth_token agent_id
|
|
438
442
|
node_bin=$(resolve_node || true)
|
|
439
443
|
[ -z "$node_bin" ] && return 0
|
|
440
444
|
|
|
@@ -447,9 +451,11 @@ probe_server_identity() {
|
|
|
447
451
|
# auth token — `String(c.authToken || '')` would otherwise yield
|
|
448
452
|
# "[object Object]" and the Bearer would be invalid.
|
|
449
453
|
local meta
|
|
450
|
-
meta=$("$node_bin" -e "const c=JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'));const t=process.env.INSTAR_AUTH_TOKEN||(typeof c.authToken==='string'?c.authToken:'');process.stdout.write(String(c.port||'')+'\t'+t)" "$config_file" 2>/dev/null || true)
|
|
454
|
+
meta=$("$node_bin" -e "const c=JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'));const t=process.env.INSTAR_AUTH_TOKEN||(typeof c.authToken==='string'?c.authToken:'');process.stdout.write(String(c.port||'')+'\t'+t+'\t'+(c.projectName||''))" "$config_file" 2>/dev/null || true)
|
|
451
455
|
port="${meta%% *}"
|
|
452
|
-
|
|
456
|
+
rest="${meta#* }"
|
|
457
|
+
auth_token="${rest%% *}"
|
|
458
|
+
agent_id="${rest#* }"
|
|
453
459
|
# Lifeline-only agents have no port; treat as healthy from probe POV.
|
|
454
460
|
[ -z "$port" ] && return 0
|
|
455
461
|
|
|
@@ -460,7 +466,7 @@ probe_server_identity() {
|
|
|
460
466
|
local resp http_code body project_field auth_args
|
|
461
467
|
auth_args=()
|
|
462
468
|
if [ -n "$auth_token" ]; then
|
|
463
|
-
auth_args=(-H "Authorization: Bearer $auth_token")
|
|
469
|
+
auth_args=(-H "Authorization: Bearer $auth_token" -H "X-Instar-AgentId: $agent_id")
|
|
464
470
|
fi
|
|
465
471
|
resp=$(curl -sS --max-time 5 -w '\n%{http_code}' "${auth_args[@]}" "http://localhost:${port}/health" 2>/dev/null || echo $'\n000')
|
|
466
472
|
http_code=$(echo "$resp" | tail -n1)
|
|
@@ -81,10 +81,12 @@ if (runMode && runCmd.length === 0) {
|
|
|
81
81
|
// guard so the { "secret": true } placeholder produced by SecretMigrator
|
|
82
82
|
// cannot leak through as a bogus Bearer.
|
|
83
83
|
let authToken = process.env.INSTAR_AUTH_TOKEN || '';
|
|
84
|
+
let agentId = process.env.INSTAR_AGENT_ID || '';
|
|
84
85
|
let port;
|
|
85
86
|
try {
|
|
86
87
|
const config = JSON.parse(fs.readFileSync('.instar/config.json', 'utf-8'));
|
|
87
88
|
if (!authToken && typeof config.authToken === 'string') authToken = config.authToken;
|
|
89
|
+
if (!agentId && typeof config.projectName === 'string') agentId = config.projectName;
|
|
88
90
|
port = config.port;
|
|
89
91
|
} catch (e) {
|
|
90
92
|
if (!authToken) {
|
|
@@ -104,7 +106,10 @@ if (!resolvedPort) {
|
|
|
104
106
|
const url = `http://localhost:${resolvedPort}/secrets/retrieve/${token}${consume ? '?consume=true' : ''}`;
|
|
105
107
|
const res = await fetch(url, {
|
|
106
108
|
method: 'POST',
|
|
107
|
-
headers: {
|
|
109
|
+
headers: {
|
|
110
|
+
'Authorization': `Bearer ${authToken}`,
|
|
111
|
+
...(agentId ? { 'X-Instar-AgentId': agentId } : {}),
|
|
112
|
+
},
|
|
108
113
|
});
|
|
109
114
|
|
|
110
115
|
if (!res.ok) {
|
|
@@ -160,7 +165,10 @@ async function consumeSubmission() {
|
|
|
160
165
|
try {
|
|
161
166
|
await fetch(`http://localhost:${resolvedPort}/secrets/retrieve/${token}?consume=true`, {
|
|
162
167
|
method: 'POST',
|
|
163
|
-
headers: {
|
|
168
|
+
headers: {
|
|
169
|
+
'Authorization': `Bearer ${authToken}`,
|
|
170
|
+
...(agentId ? { 'X-Instar-AgentId': agentId } : {}),
|
|
171
|
+
},
|
|
164
172
|
});
|
|
165
173
|
} catch {
|
|
166
174
|
// Non-fatal — the sliding/absolute-cap cleanup will reclaim it regardless.
|
|
@@ -38,6 +38,7 @@ fi
|
|
|
38
38
|
# Get port from env or config
|
|
39
39
|
PORT="${INSTAR_PORT:-}"
|
|
40
40
|
AUTH=""
|
|
41
|
+
AGENT_ID="${INSTAR_AGENT_ID:-}"
|
|
41
42
|
|
|
42
43
|
if [ -f ".instar/config.json" ]; then
|
|
43
44
|
if [ -z "$PORT" ]; then
|
|
@@ -52,6 +53,9 @@ if [ -f ".instar/config.json" ]; then
|
|
|
52
53
|
if [ -z "$AUTH" ]; then
|
|
53
54
|
AUTH=$(python3 -c "import json; v=json.load(open('.instar/config.json')).get('authToken',''); print(v if isinstance(v, str) else '')" 2>/dev/null)
|
|
54
55
|
fi
|
|
56
|
+
if [ -z "$AGENT_ID" ]; then
|
|
57
|
+
AGENT_ID=$(python3 -c "import json; print(json.load(open('.instar/config.json')).get('projectName',''))" 2>/dev/null)
|
|
58
|
+
fi
|
|
55
59
|
fi
|
|
56
60
|
|
|
57
61
|
PORT="${PORT:-4042}"
|
|
@@ -68,6 +72,7 @@ RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
|
|
|
68
72
|
"http://localhost:${PORT}/slack/reply/${CHANNEL_ID}" \
|
|
69
73
|
-H "Content-Type: application/json" \
|
|
70
74
|
${AUTH:+-H "Authorization: Bearer $AUTH"} \
|
|
75
|
+
${AGENT_ID:+-H "X-Instar-AgentId: $AGENT_ID"} \
|
|
71
76
|
-d "{\"text\": ${ESCAPED}}")
|
|
72
77
|
|
|
73
78
|
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
|
|
@@ -38,9 +38,13 @@ PORT="${INSTAR_PORT:-4040}"
|
|
|
38
38
|
# string-type guard so the { "secret": true } placeholder produced by
|
|
39
39
|
# SecretMigrator cannot leak through as a bogus Bearer.
|
|
40
40
|
AUTH_TOKEN="${INSTAR_AUTH_TOKEN:-}"
|
|
41
|
+
AGENT_ID="${INSTAR_AGENT_ID:-}"
|
|
41
42
|
if [ -z "$AUTH_TOKEN" ] && [ -f ".instar/config.json" ]; then
|
|
42
43
|
AUTH_TOKEN=$(python3 -c "import json; v=json.load(open('.instar/config.json')).get('authToken',''); print(v if isinstance(v, str) else '')" 2>/dev/null)
|
|
43
44
|
fi
|
|
45
|
+
if [ -z "$AGENT_ID" ] && [ -f ".instar/config.json" ]; then
|
|
46
|
+
AGENT_ID=$(python3 -c "import json; print(json.load(open('.instar/config.json')).get('projectName',''))" 2>/dev/null)
|
|
47
|
+
fi
|
|
44
48
|
|
|
45
49
|
# Escape for JSON
|
|
46
50
|
JSON_MSG=$(printf '%s' "$MSG" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))' 2>/dev/null)
|
|
@@ -53,6 +57,7 @@ if [ -n "$AUTH_TOKEN" ]; then
|
|
|
53
57
|
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "http://localhost:${PORT}/whatsapp/send/${JID}" \
|
|
54
58
|
-H 'Content-Type: application/json' \
|
|
55
59
|
-H "Authorization: Bearer ${AUTH_TOKEN}" \
|
|
60
|
+
-H "X-Instar-AgentId: ${AGENT_ID}" \
|
|
56
61
|
-d "{\"text\":${JSON_MSG}}")
|
|
57
62
|
else
|
|
58
63
|
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "http://localhost:${PORT}/whatsapp/send/${JID}" \
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The MessageSentinel's LLM layer now downgrades a 'pause' classification to normal pass-through when the message exceeds 25 words (MAX_PAUSE_DIRECTIVE_WORDS). Emergency-stop is deliberately not length-gated (safety asymmetry). The downgrade is logged and carried in the classification reason.
|
|
9
|
+
|
|
10
|
+
## What to Tell Your User
|
|
11
|
+
|
|
12
|
+
Long working messages that happen to end with phrases like "stand by" or "hold off for now" can no longer be swallowed as pause commands. Previously such a message could pause your agent's session and vanish entirely — you'd see only "Session paused" where your instructions should have landed. Short, genuine pause directives still pause as before.
|
|
13
|
+
|
|
14
|
+
## Summary of New Capabilities
|
|
15
|
+
|
|
16
|
+
- Pause classifications on messages over 25 words pass through as normal conversation; the message is delivered instead of consumed.
|
|
17
|
+
|
|
18
|
+
## Evidence
|
|
19
|
+
|
|
20
|
+
Live failures (2026-06-05, topic 1052): two ~200-word mentor coaching messages ending "…and stand by" were LLM-classified 'pause' and CONSUMED by the telegram-forward sentinel intercept — "Session paused" posted at 14:22:58Z and 14:41:24Z, the messages never routed, present in no queue or drop ledger (the third mechanism of the day's delivery-loss trilogy, after #839 inbound replay and #840 outbound purge). The classifier prompt already instructs "substantive content ⇒ NORMAL" but the closing imperative intermittently won — prompt-as-willpower; this guard is the structure. Pinned by 4 tests: long-pause downgrade, short-pause preserved, long emergency-stop preserved, exact 25/26-word boundary.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Built-in job, hook, and helper-script templates now include the agent identity header on authenticated local API calls. The scheduler and session launcher expose `INSTAR_AGENT_ID` alongside the existing local auth token so installed templates do not need to guess their identity.
|
|
9
|
+
|
|
10
|
+
## What to Tell Your User
|
|
11
|
+
|
|
12
|
+
Nothing user-visible. This quiets internal auth deprecation warnings from built-in jobs and hooks and keeps installed templates aligned with the stricter local auth contract.
|
|
13
|
+
|
|
14
|
+
## Summary of New Capabilities
|
|
15
|
+
|
|
16
|
+
- Job gates, script jobs, and spawned sessions receive `INSTAR_AGENT_ID`.
|
|
17
|
+
- Built-in local API templates send `X-Instar-AgentId` with bearer auth.
|
|
18
|
+
- A regression test scans shipped templates for bearer-only local API calls.
|
|
19
|
+
|
|
20
|
+
## Evidence
|
|
21
|
+
|
|
22
|
+
Grounded against canonical `authMiddleware`: bearer-only local API calls are still accepted during the deprecation window but log a warning; `/whoami` already requires the header. Focused validation: `npx vitest run tests/unit/template-agent-id-header.test.ts tests/unit/JobScheduler.test.ts tests/unit/JobScheduler-script-job.test.ts tests/unit/telegram-topic-context-session-clock.test.ts` passed, 41/41 tests.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# A long working message ending in "stand by" can no longer be eaten as a pause command
|
|
2
|
+
|
|
3
|
+
The message sentinel reads every inbound message and classifies it: normal conversation, a redirect, a pause command, or an emergency stop. Pause and emergency-stop classifications are intercepted — the session is paused or killed, a confirmation is posted, and **the message itself is consumed**, never delivered. That's correct for "stop everything": the message IS the command.
|
|
4
|
+
|
|
5
|
+
The failure: a ~200-word mentor coaching message — task status, instructions, and a closing "…report the numbers back here and stand by" — was classified as a **pause command**. The session paused, "Session paused. Send a message to resume." was posted, and the entire message vanished: not in any queue, not in any drop ledger, just gone. It happened twice in one afternoon on the same topic (14:22 and 14:41), both times on messages ending with "stand by". The classifier's prompt already asks for exactly the right judgment ("substantive content means NORMAL") — but a closing imperative intermittently wins anyway, and a prompt instruction is willpower, not structure.
|
|
6
|
+
|
|
7
|
+
The structural guard: a **pause** classification on a message longer than 25 words downgrades to normal pass-through, with the downgrade logged and recorded in the classification's reason. The rationale is an asymmetry the prompt itself already encodes:
|
|
8
|
+
|
|
9
|
+
- **Emergency-stop is untouched.** Stopping unnecessarily on a long panicked message is a tolerable false positive — safety first, always.
|
|
10
|
+
- **Pause is politeness, not safety.** Consuming a long message to be polite destroys real content for zero protective payoff. A genuine natural-language pause directive ("hold on, wait for me to finish reading before you continue") is well under 25 words; nobody writes a 200-word pause command.
|
|
11
|
+
|
|
12
|
+
The fast-path layer needed no change — its existing 4-word gate already keeps long messages away from pattern matches. Slash commands (/pause, /stop) are exact matches and unaffected. Four tests pin the boundary: long pause downgrades, short pause still pauses, long emergency-stop still stops, and the exact 25/26-word edge.
|