agent-relay-runner 0.68.0 → 0.69.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
|
@@ -27,6 +27,20 @@ export function obligationRequiresExplicitReply(obligation: ReplyObligation): bo
|
|
|
27
27
|
return obligation.from !== "user";
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
export function responseCaptureReplyRoute(
|
|
31
|
+
obligations: ReplyObligation[],
|
|
32
|
+
currentTurnStartedAt?: number,
|
|
33
|
+
opts: { suppressUser?: boolean } = {},
|
|
34
|
+
): { replyToMessageId?: number; to: string } | null {
|
|
35
|
+
const eligible = [...obligations].reverse()
|
|
36
|
+
.filter((o) => currentTurnStartedAt === undefined || o.createdAt <= currentTurnStartedAt);
|
|
37
|
+
const explicit = eligible.find(obligationRequiresExplicitReply);
|
|
38
|
+
if (explicit) return { replyToMessageId: explicit.messageId, to: explicit.from };
|
|
39
|
+
const user = eligible.find((o) => o.from === "user");
|
|
40
|
+
if (!user) return { to: "user" };
|
|
41
|
+
return opts.suppressUser ? null : { replyToMessageId: user.messageId, to: "user" };
|
|
42
|
+
}
|
|
43
|
+
|
|
30
44
|
type ReplyObligationFetch = () => Promise<ReplyObligation[]>;
|
|
31
45
|
|
|
32
46
|
interface ReplyObligationCacheOptions {
|
package/src/runner-core.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type { ManagedProcess, ProviderAdapter, ProviderConfig, ProviderPermissio
|
|
|
10
10
|
import { messagesWithCachedAttachments } from "./attachment-cache";
|
|
11
11
|
import { ClaimTracker } from "./claim-tracker";
|
|
12
12
|
import { startControlServer, type ControlServer } from "./control-server";
|
|
13
|
-
import { ReplyObligationCache, obligationRequiresExplicitReply } from "./reply-obligation-cache";
|
|
13
|
+
import { ReplyObligationCache, obligationRequiresExplicitReply, responseCaptureReplyRoute } from "./reply-obligation-cache";
|
|
14
14
|
import { Outbox, type OutboxRecord } from "./outbox";
|
|
15
15
|
import { extractLastAssistantTurn, extractLastAssistantTurnAfterEntry, countTranscriptEntries, extractFinalAssistantMessage, extractFinalAssistantMessageAfterEntry, extractHookAssistantMessage, extractLatestTurnSteps, stepDedupKeys, transcriptLooksComplete } from "./adapters/claude-transcript";
|
|
16
16
|
import { profileUsesHostProviderGlobals } from "./profile-home";
|
|
@@ -1336,7 +1336,7 @@ export class AgentRunner {
|
|
|
1336
1336
|
const turnId = this.currentTurnId;
|
|
1337
1337
|
this.stopReasoningTail();
|
|
1338
1338
|
// Optional correlation for threading + obligation clearing — never a capture gate.
|
|
1339
|
-
let replyToMessageId: number | undefined;
|
|
1339
|
+
let replyToMessageId: number | undefined, replyTarget = "user";
|
|
1340
1340
|
const pendingPrompt = this.pendingPromptMessageId;
|
|
1341
1341
|
if (pendingPrompt) {
|
|
1342
1342
|
replyToMessageId = pendingPrompt;
|
|
@@ -1344,8 +1344,8 @@ export class AgentRunner {
|
|
|
1344
1344
|
} else {
|
|
1345
1345
|
// Correlation-only (threading + obligation clearing) — the local snapshot is fresh
|
|
1346
1346
|
// enough and never blocks the response-capture path (#196).
|
|
1347
|
-
const
|
|
1348
|
-
replyToMessageId =
|
|
1347
|
+
const route = responseCaptureReplyRoute(this.obligationCache.get(), this.currentTurnStartedAt);
|
|
1348
|
+
replyToMessageId = route?.replyToMessageId; replyTarget = route?.to ?? "user";
|
|
1349
1349
|
}
|
|
1350
1350
|
|
|
1351
1351
|
// Grab and reset the pre-flush cursor before extraction: the cursor may be
|
|
@@ -1391,7 +1391,7 @@ export class AgentRunner {
|
|
|
1391
1391
|
this.sessionLog(`response captured for turn ${turnId ?? "?"} (${body.length} chars${replyToMessageId ? `, replyTo #${replyToMessageId}` : ", no replyTo"})`);
|
|
1392
1392
|
await this.publishSessionEvent({
|
|
1393
1393
|
from: this.agentId,
|
|
1394
|
-
to:
|
|
1394
|
+
to: replyTarget,
|
|
1395
1395
|
body,
|
|
1396
1396
|
...(replyToMessageId ? { replyTo: replyToMessageId } : {}),
|
|
1397
1397
|
session: { type: "response", origin: "provider", ...(turnId ? { turnId } : {}) },
|
|
@@ -1600,20 +1600,21 @@ export class AgentRunner {
|
|
|
1600
1600
|
}
|
|
1601
1601
|
if (event.type === "response") {
|
|
1602
1602
|
// Dashboard prompt injection is already answered by this captured App Server
|
|
1603
|
-
// response.
|
|
1604
|
-
//
|
|
1605
|
-
let replyToMessageId: number | undefined;
|
|
1603
|
+
// response. User obligations still belong to the session mirror; spawner
|
|
1604
|
+
// obligations (#413) route to the spawn-parent with replyTo to clear the debt.
|
|
1605
|
+
let replyToMessageId: number | undefined, replyTarget = "user";
|
|
1606
1606
|
const pendingPrompt = this.pendingPromptMessageId;
|
|
1607
1607
|
if (pendingPrompt) {
|
|
1608
1608
|
replyToMessageId = pendingPrompt;
|
|
1609
1609
|
this.pendingPromptMessageId = undefined;
|
|
1610
|
-
} else
|
|
1611
|
-
|
|
1612
|
-
return;
|
|
1610
|
+
} else {
|
|
1611
|
+
const route = responseCaptureReplyRoute(this.obligationCache.get(), this.currentTurnStartedAt, { suppressUser: true });
|
|
1612
|
+
if (!route) return; // The session mirror will satisfy the user obligation; don't double-post (#196).
|
|
1613
|
+
replyToMessageId = route.replyToMessageId; replyTarget = route.to;
|
|
1613
1614
|
}
|
|
1614
1615
|
await this.publishSessionEvent({
|
|
1615
1616
|
from: this.agentId,
|
|
1616
|
-
to:
|
|
1617
|
+
to: replyTarget,
|
|
1617
1618
|
body,
|
|
1618
1619
|
...(replyToMessageId ? { replyTo: replyToMessageId } : {}),
|
|
1619
1620
|
session: { type: "response", origin: event.origin ?? "provider", ...(turnId ? { turnId } : {}) },
|
|
@@ -1660,10 +1661,6 @@ export class AgentRunner {
|
|
|
1660
1661
|
return false;
|
|
1661
1662
|
}
|
|
1662
1663
|
|
|
1663
|
-
private obligationPredatesCurrentTurn(obligation: { createdAt: number }): boolean {
|
|
1664
|
-
return this.currentTurnStartedAt === undefined || obligation.createdAt <= this.currentTurnStartedAt;
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
1664
|
// Force-clear a stuck provider-turn claim directly. Unlike the idle status path
|
|
1668
1665
|
// it does NOT depend on a matching claim id (the Stop hook keys busy as
|
|
1669
1666
|
// provider-turn:provider-turn, but reconciliation has no specific id), and it
|