agent-relay-runner 0.57.1 → 0.58.0
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-relay-runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.58.0",
|
|
4
4
|
"description": "Unified provider lifecycle runner for Agent Relay",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"directory": "runner"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"agent-relay-sdk": "0.2.
|
|
23
|
+
"agent-relay-sdk": "0.2.34"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/bun": "latest",
|
package/src/control-server.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Server, ServerWebSocket } from "bun";
|
|
|
2
2
|
import type { Message, ReplyObligation } from "agent-relay-sdk";
|
|
3
3
|
import { errMessage, isRecord } from "agent-relay-sdk";
|
|
4
4
|
import type { ProviderPermissionDecisionInput, ProviderStatusEvent, SemanticStatus, TerminalAttachSpec } from "./adapter";
|
|
5
|
+
import { obligationRequiresExplicitReply } from "./reply-obligation-cache";
|
|
5
6
|
import { logger, parseLogLevel, LOG_LEVELS } from "./logger";
|
|
6
7
|
import { buildRateLimitProviderState } from "./rate-limit";
|
|
7
8
|
|
|
@@ -199,7 +200,13 @@ function replyObligationSummary(obligations: ReplyObligation[]): Record<string,
|
|
|
199
200
|
}
|
|
200
201
|
|
|
201
202
|
function replyObligationStopDecision(obligations: ReplyObligation[]): Record<string, unknown> {
|
|
202
|
-
|
|
203
|
+
// #418 — never block the turn to nag for a `user` obligation: the operator already receives
|
|
204
|
+
// this turn via the session mirror, so an explicit /reply double-delivers. Only agent↔agent /
|
|
205
|
+
// spawner obligations (#413) gate the turn here; the mirror's replyTo-linking clears the user
|
|
206
|
+
// one. (The /reply-obligations summary endpoint is left unfiltered — the obligation IS pending
|
|
207
|
+
// until the mirror lands, so observability stays accurate.)
|
|
208
|
+
const enforceable = obligations.filter(obligationRequiresExplicitReply);
|
|
209
|
+
const summary = replyObligationSummary(enforceable);
|
|
203
210
|
if (summary.pending !== true) return {};
|
|
204
211
|
return {
|
|
205
212
|
decision: "block",
|
|
@@ -16,6 +16,17 @@ import { logger } from "./logger";
|
|
|
16
16
|
// - A background interval keeps the snapshot warm; `markDirty()` requests an extra,
|
|
17
17
|
// debounced refresh when state likely just changed (a message arrived, a turn ended).
|
|
18
18
|
|
|
19
|
+
// #418 — the human `user` sink is NOT delivered via an explicit relay reply: the agent's
|
|
20
|
+
// turn is mirrored to the dashboard chat by the session-mirror lane (always, for managed
|
|
21
|
+
// agents). So an explicit `/reply` to `user` double-delivers — the operator sees the mirrored
|
|
22
|
+
// turn AND the explicit copy. Only agent↔agent / spawner obligations (#413) need an explicit
|
|
23
|
+
// reply to clear and reach their recipient. This is the single home for that distinction —
|
|
24
|
+
// both the Claude Stop-hook nag (control-server) and the non-claude re-injection (runner)
|
|
25
|
+
// gate on it, so the rule must not drift between them.
|
|
26
|
+
export function obligationRequiresExplicitReply(obligation: ReplyObligation): boolean {
|
|
27
|
+
return obligation.from !== "user";
|
|
28
|
+
}
|
|
29
|
+
|
|
19
30
|
type ReplyObligationFetch = () => Promise<ReplyObligation[]>;
|
|
20
31
|
|
|
21
32
|
interface ReplyObligationCacheOptions {
|
package/src/runner.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { messagesWithCachedAttachments } from "./attachment-cache";
|
|
|
11
11
|
import { resolveProjectName } from "./config";
|
|
12
12
|
import { ClaimTracker } from "./claim-tracker";
|
|
13
13
|
import { startControlServer, type ControlServer } from "./control-server";
|
|
14
|
-
import { ReplyObligationCache } from "./reply-obligation-cache";
|
|
14
|
+
import { ReplyObligationCache, obligationRequiresExplicitReply } from "./reply-obligation-cache";
|
|
15
15
|
import { Outbox, type OutboxRecord } from "./outbox";
|
|
16
16
|
import { extractLastAssistantTurn, extractFinalAssistantMessage, extractHookAssistantMessage, extractLatestTurnSteps, stepDedupKeys, transcriptLooksComplete } from "./adapters/claude-transcript";
|
|
17
17
|
import { computeContextRatio } from "./session-insights";
|
|
@@ -1215,9 +1215,11 @@ export class AgentRunner {
|
|
|
1215
1215
|
// stop.sh hook; every other provider needs this in-process nudge.
|
|
1216
1216
|
private async reInjectPendingObligation(): Promise<void> {
|
|
1217
1217
|
if (!this.process) return;
|
|
1218
|
-
// Filter to spawner obligations only
|
|
1219
|
-
//
|
|
1220
|
-
|
|
1218
|
+
// Filter to spawner obligations only — user obligations go through the existing codex
|
|
1219
|
+
// prompt-capture path (publishProviderSessionEvent) and the session mirror (#418), never
|
|
1220
|
+
// an explicit /reply. Shared predicate so this rule stays in lockstep with the Claude
|
|
1221
|
+
// Stop-hook nag exemption (control-server.replyObligationStopDecision).
|
|
1222
|
+
const obligations = this.obligationCache.get().filter(obligationRequiresExplicitReply);
|
|
1221
1223
|
if (!obligations.length) return;
|
|
1222
1224
|
const MAX_REINJECTIONS = 3;
|
|
1223
1225
|
for (const obligation of obligations) {
|