agent-relay-runner 0.65.0 → 0.65.2
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/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/hooks/relay-status.sh +38 -0
- package/plugins/claude/hooks/stop.sh +7 -1
- package/src/adapter.ts +1 -1
- package/src/claim-tracker.ts +1 -1
- package/src/control-server.ts +5 -5
- package/src/runner-core.ts +2 -1
package/package.json
CHANGED
|
@@ -31,6 +31,44 @@ relay_post_status_clearing_subagents() {
|
|
|
31
31
|
relay_post_status "$1" "${2:-}" "${3:-}" "${4:-}" "${5:-}" "${6:-}" subagent
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
# #502: count the background shells still running at the moment this turn ends.
|
|
35
|
+
# Claude's Stop payload carries a `background_tasks` array (CC v2.1.157+) listing
|
|
36
|
+
# the shells launched with run_in_background that have not yet finished. It is a
|
|
37
|
+
# full live snapshot, so reporting it each turn-end can never wedge: a completed
|
|
38
|
+
# task wakes Claude, the next Stop re-reports the (now smaller/empty) set. Older
|
|
39
|
+
# Claude builds omit the field → count 0 → graceful no-op (no false busy).
|
|
40
|
+
relay_background_task_count() {
|
|
41
|
+
local input="${1:-}"
|
|
42
|
+
[ -z "$input" ] && { printf '0'; return 0; }
|
|
43
|
+
if command -v jq >/dev/null 2>&1; then
|
|
44
|
+
local n
|
|
45
|
+
n="$(printf '%s' "$input" | jq -r '(.background_tasks // []) | length' 2>/dev/null)"
|
|
46
|
+
case "$n" in ''|*[!0-9]*) printf '0' ;; *) printf '%s' "$n" ;; esac
|
|
47
|
+
return 0
|
|
48
|
+
fi
|
|
49
|
+
# jq-less fallback: a non-empty array literal means at least one is running.
|
|
50
|
+
if printf '%s' "$input" | tr -d '[:space:]' | grep -q '"background_tasks":\[{'; then
|
|
51
|
+
printf '1'
|
|
52
|
+
else
|
|
53
|
+
printf '0'
|
|
54
|
+
fi
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# #502: end the provider turn (idle) clearing any stale subagent work — the
|
|
58
|
+
# critical path (#199) — then report the live background-script snapshot so an
|
|
59
|
+
# agent whose turn ended while a `run_in_background` shell keeps running stays
|
|
60
|
+
# busy instead of falsely reading idle. A single full-snapshot post per turn-end:
|
|
61
|
+
# >0 → busy(background-script); 0 → idle(background-script) which clears any prior.
|
|
62
|
+
relay_post_turn_end_status() {
|
|
63
|
+
local bg_count="${1:-0}"
|
|
64
|
+
relay_post_status_clearing_subagents idle
|
|
65
|
+
case "$bg_count" in
|
|
66
|
+
''|0|*[!0-9]*) relay_post_status idle background-script background-tasks ;;
|
|
67
|
+
1) relay_post_status busy background-script background-tasks "1 background task" ;;
|
|
68
|
+
*) relay_post_status busy background-script background-tasks "${bg_count} background tasks" ;;
|
|
69
|
+
esac
|
|
70
|
+
}
|
|
71
|
+
|
|
34
72
|
# Report a provider usage/rate-limit hold to the runner (#286). The runner turns
|
|
35
73
|
# this into a `providerState: blocked` (reason rate_limit), posts a chat notice,
|
|
36
74
|
# and auto-resumes the agent once the window resets. reset_time (unix seconds,
|
|
@@ -8,10 +8,16 @@ relay_install_hook_guard stop
|
|
|
8
8
|
# exception is the reply-obligation block path, which deliberately keeps the agent
|
|
9
9
|
# busy to answer — it opts out via the flag before exiting.
|
|
10
10
|
_relay_clear_idle_on_exit=1
|
|
11
|
-
|
|
11
|
+
# bg_count is read from the payload below and consumed by the trap at exit time
|
|
12
|
+
# (#502): the turn-end status carries the live background-script snapshot so an
|
|
13
|
+
# agent whose turn ended while a run_in_background shell keeps running stays busy
|
|
14
|
+
# instead of falsely reading idle.
|
|
15
|
+
bg_count=0
|
|
16
|
+
trap '[ "${_relay_clear_idle_on_exit:-0}" = "1" ] && relay_post_turn_end_status "${bg_count:-0}"' EXIT
|
|
12
17
|
|
|
13
18
|
payload="$(cat || true)"
|
|
14
19
|
stop_hook_active="$(relay_json_bool_field stop_hook_active "$payload")"
|
|
20
|
+
bg_count="$(relay_background_task_count "$payload")"
|
|
15
21
|
|
|
16
22
|
# Session-mirror capture is orthogonal to reply-obligation gating (#332): a recursive Stop
|
|
17
23
|
# (stop_hook_active=true) must NOT suppress capturing this turn's response, or the live mirror
|
package/src/adapter.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { SessionEvent } from "./session-insights";
|
|
|
4
4
|
import { messageBodyMaxCharsFromEnv } from "./config";
|
|
5
5
|
|
|
6
6
|
export type SemanticStatus = "idle" | "busy" | "offline" | "error";
|
|
7
|
-
type ProviderWorkKind = "provider-turn" | "subagent";
|
|
7
|
+
type ProviderWorkKind = "provider-turn" | "subagent" | "background-script";
|
|
8
8
|
|
|
9
9
|
export interface ProviderStatusEvent {
|
|
10
10
|
status: SemanticStatus;
|
package/src/claim-tracker.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
type ClaimKind = "message" | "task" | "command";
|
|
2
|
-
type RunnerWorkKind = "provider-turn" | "subagent";
|
|
2
|
+
type RunnerWorkKind = "provider-turn" | "subagent" | "background-script";
|
|
3
3
|
type RunnerBusyReason = RunnerWorkKind | ClaimKind;
|
|
4
4
|
type RunnerSemanticStatus = "idle" | "busy" | "offline" | "error";
|
|
5
5
|
|
package/src/control-server.ts
CHANGED
|
@@ -439,12 +439,12 @@ async function handleStatus(req: Request, options: ControlServerOptions): Promis
|
|
|
439
439
|
return Response.json({ error: "status must be idle, busy, offline, or error" }, { status: 400 });
|
|
440
440
|
}
|
|
441
441
|
const reason = body?.reason;
|
|
442
|
-
if (reason !== undefined && reason !== "provider-turn" && reason !== "subagent") {
|
|
443
|
-
return Response.json({ error: "reason must be provider-turn or
|
|
442
|
+
if (reason !== undefined && reason !== "provider-turn" && reason !== "subagent" && reason !== "background-script") {
|
|
443
|
+
return Response.json({ error: "reason must be provider-turn, subagent, or background-script" }, { status: 400 });
|
|
444
444
|
}
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
445
|
+
const isWorkKind = (item: unknown): item is "provider-turn" | "subagent" | "background-script" =>
|
|
446
|
+
item === "provider-turn" || item === "subagent" || item === "background-script";
|
|
447
|
+
const clear = Array.isArray(body?.clear) ? body.clear.filter(isWorkKind) : undefined;
|
|
448
448
|
const timeline = statusTimelineEvent(body);
|
|
449
449
|
const update: ProviderStatusEvent = {
|
|
450
450
|
status,
|
package/src/runner-core.ts
CHANGED
|
@@ -919,6 +919,7 @@ export class AgentRunner {
|
|
|
919
919
|
this.claims.clearTerminalStatus();
|
|
920
920
|
this.claims.clearWorkKind("provider-turn");
|
|
921
921
|
this.claims.clearWorkKind("subagent");
|
|
922
|
+
this.claims.clearWorkKind("background-script");
|
|
922
923
|
if (this.stopped) return;
|
|
923
924
|
this.process = await this.spawnProvider();
|
|
924
925
|
this.processStartedAt = Date.now();
|
|
@@ -997,7 +998,7 @@ export class AgentRunner {
|
|
|
997
998
|
status,
|
|
998
999
|
reason: "provider-turn",
|
|
999
1000
|
id: `provider-exit-${this.providerSessionId}`,
|
|
1000
|
-
clear: ["provider-turn", "subagent"],
|
|
1001
|
+
clear: ["provider-turn", "subagent", "background-script"],
|
|
1001
1002
|
});
|
|
1002
1003
|
return;
|
|
1003
1004
|
}
|