agent-relay-runner 0.71.0 → 0.72.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 +2 -2
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/src/adapter.ts +7 -1
- package/src/adapters/claude-delivery.ts +5 -1
- package/src/adapters/codex.ts +1 -1
- package/src/reply-obligation-cache.ts +1 -0
- package/src/response-capture-report.ts +6 -2
- package/src/runner-core.ts +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-relay-runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.72.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.47"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/bun": "latest",
|
package/src/adapter.ts
CHANGED
|
@@ -41,6 +41,8 @@ export interface ProviderSessionEvent {
|
|
|
41
41
|
body: string;
|
|
42
42
|
origin?: "chat" | "terminal" | "provider";
|
|
43
43
|
turnId?: string;
|
|
44
|
+
/** True only when this response is the completed provider turn, not an intermediate flush. */
|
|
45
|
+
final?: boolean;
|
|
44
46
|
label?: string;
|
|
45
47
|
status?: "running" | "completed" | "failed";
|
|
46
48
|
streaming?: boolean;
|
|
@@ -267,9 +269,13 @@ export function isNotificationMessage(message: Message): boolean {
|
|
|
267
269
|
return isPersistedRelayMessage(message) && message.replyExpected === false;
|
|
268
270
|
}
|
|
269
271
|
|
|
272
|
+
function isSpawnObligationMessage(message: Message): boolean {
|
|
273
|
+
return isRecord(message.payload) && message.payload.source === "spawn-obligation";
|
|
274
|
+
}
|
|
275
|
+
|
|
270
276
|
function latestReplyableMessage(messages: Message[]): Message | undefined {
|
|
271
277
|
return messages
|
|
272
|
-
.filter((message) => isPersistedRelayMessage(message) && !isMemoryInjection(message) && !isReactionNotification(message) && message.replyExpected !== false)
|
|
278
|
+
.filter((message) => isPersistedRelayMessage(message) && !isMemoryInjection(message) && !isReactionNotification(message) && !isSpawnObligationMessage(message) && message.replyExpected !== false)
|
|
273
279
|
.at(-1);
|
|
274
280
|
}
|
|
275
281
|
|
|
@@ -39,6 +39,10 @@ function isReactionNotification(message: Message): boolean {
|
|
|
39
39
|
return message.payload?.reactionNotification === true || event?.type === "message.reaction";
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
function isSpawnObligationMessage(message: Message): boolean {
|
|
43
|
+
return isRecord(message.payload) && message.payload.source === "spawn-obligation";
|
|
44
|
+
}
|
|
45
|
+
|
|
42
46
|
function isPersistedRelayMessage(message: Message): boolean {
|
|
43
47
|
return Number.isSafeInteger(message.id) && message.id > 0;
|
|
44
48
|
}
|
|
@@ -60,7 +64,7 @@ function shouldShowReplyReminder(deliveryCount: number): boolean {
|
|
|
60
64
|
|
|
61
65
|
function latestReplyableMessage(messages: Message[]): Message | undefined {
|
|
62
66
|
return messages
|
|
63
|
-
.filter((message) => isPersistedRelayMessage(message) && !isMemoryInjection(message) && !isReactionNotification(message) && message.replyExpected !== false)
|
|
67
|
+
.filter((message) => isPersistedRelayMessage(message) && !isMemoryInjection(message) && !isReactionNotification(message) && !isSpawnObligationMessage(message) && message.replyExpected !== false)
|
|
64
68
|
.at(-1);
|
|
65
69
|
}
|
|
66
70
|
|
package/src/adapters/codex.ts
CHANGED
|
@@ -620,7 +620,7 @@ export class CodexAdapter implements ProviderAdapter {
|
|
|
620
620
|
const joined = this.captureMode === "full" ? messages.join("\n\n") : messages[messages.length - 1]!;
|
|
621
621
|
this.turnMessages = [];
|
|
622
622
|
const text = joined.trim();
|
|
623
|
-
if (text) this.sessionEventCb({ type: "response", origin: "provider", body: text, ...(this.activeTurnId ? { turnId: this.activeTurnId } : {}) });
|
|
623
|
+
if (text) this.sessionEventCb({ type: "response", origin: "provider", body: text, final: true, ...(this.activeTurnId ? { turnId: this.activeTurnId } : {}) });
|
|
624
624
|
}
|
|
625
625
|
|
|
626
626
|
private finishMainTurn(): void {
|
|
@@ -24,6 +24,7 @@ import { logger } from "./logger";
|
|
|
24
24
|
// both the Claude Stop-hook nag (control-server) and the non-claude re-injection (runner)
|
|
25
25
|
// gate on it, so the rule must not drift between them.
|
|
26
26
|
export function obligationRequiresExplicitReply(obligation: ReplyObligation): boolean {
|
|
27
|
+
if (obligation.source === "spawn-obligation") return false;
|
|
27
28
|
return obligation.from !== "user";
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -12,6 +12,10 @@ type SessionPublisher = (input: {
|
|
|
12
12
|
replyTo?: number;
|
|
13
13
|
}) => void | Promise<void>;
|
|
14
14
|
|
|
15
|
+
function finalSession(session: MessageSessionMeta): MessageSessionMeta {
|
|
16
|
+
return { ...session, final: true };
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
export async function publishCapturedResponse(input: {
|
|
16
20
|
publishSessionEvent: SessionPublisher;
|
|
17
21
|
outbox: ReportOutbox;
|
|
@@ -27,7 +31,7 @@ export async function publishCapturedResponse(input: {
|
|
|
27
31
|
to: input.to,
|
|
28
32
|
body: input.body,
|
|
29
33
|
...(input.replyTo ? { replyTo: input.replyTo } : {}),
|
|
30
|
-
session: input.session,
|
|
34
|
+
session: finalSession(input.session),
|
|
31
35
|
});
|
|
32
36
|
enqueueCapturedResponseReport(input);
|
|
33
37
|
}
|
|
@@ -53,7 +57,7 @@ export function enqueueCapturedResponseReport(input: {
|
|
|
53
57
|
kind: "chat",
|
|
54
58
|
body: input.body,
|
|
55
59
|
replyExpected: false,
|
|
56
|
-
payload: { responseCapture: { provider: input.provider, ...input.session } },
|
|
60
|
+
payload: { responseCapture: { provider: input.provider, ...finalSession(input.session) } },
|
|
57
61
|
},
|
|
58
62
|
});
|
|
59
63
|
}
|
package/src/runner-core.ts
CHANGED
|
@@ -1391,7 +1391,7 @@ export class AgentRunner {
|
|
|
1391
1391
|
}
|
|
1392
1392
|
|
|
1393
1393
|
this.sessionLog(`response captured for turn ${turnId ?? "?"} (${body.length} chars${replyToMessageId ? `, replyTo #${replyToMessageId}` : ", no replyTo"})`);
|
|
1394
|
-
await publishCapturedResponse({ publishSessionEvent: (event) => this.publishSessionEvent(event), outbox: this.sessionOutbox, provider: this.options.provider, from: this.agentId, to: replyTarget, body, replyTo: replyToMessageId, session: { type: "response", origin: "provider", ...(turnId ? { turnId } : {}) } });
|
|
1394
|
+
await publishCapturedResponse({ publishSessionEvent: (event) => this.publishSessionEvent(event), outbox: this.sessionOutbox, provider: this.options.provider, from: this.agentId, to: replyTarget, body, replyTo: replyToMessageId, session: { type: "response", origin: "provider", final: true, ...(turnId ? { turnId } : {}) } });
|
|
1395
1395
|
// The agent's reply may have cleared an obligation — refresh the snapshot so the next
|
|
1396
1396
|
// turn-end doesn't re-prompt for a message already answered (#196).
|
|
1397
1397
|
if (replyToMessageId) this.obligationCache.markDirty();
|
|
@@ -1625,6 +1625,7 @@ export class AgentRunner {
|
|
|
1625
1625
|
...(event.status ? { status: event.status } : {}),
|
|
1626
1626
|
...(event.streaming !== undefined ? { streaming: event.streaming } : {}),
|
|
1627
1627
|
...(event.stepId ? { stepId: event.stepId } : {}),
|
|
1628
|
+
...(event.final ? { final: true } : {}),
|
|
1628
1629
|
},
|
|
1629
1630
|
});
|
|
1630
1631
|
}
|