agent-relay-runner 0.10.25 → 0.10.26
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
package/src/adapter.ts
CHANGED
|
@@ -97,6 +97,37 @@ export function extractLastAssistantTurn(jsonl: string): string {
|
|
|
97
97
|
return collected.join("\n\n").trim();
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Returns only the text from the LAST assistant entry in the current turn.
|
|
102
|
+
* Unlike extractLastAssistantTurn which collects all intermediate text between
|
|
103
|
+
* tool calls, this returns just the final response — what the user sees as the
|
|
104
|
+
* concluding message.
|
|
105
|
+
*/
|
|
106
|
+
export function extractFinalAssistantMessage(jsonl: string): string {
|
|
107
|
+
const lines = jsonl.split("\n");
|
|
108
|
+
let lastText = "";
|
|
109
|
+
let pastLastUserPrompt = false;
|
|
110
|
+
for (const line of lines) {
|
|
111
|
+
const trimmed = line.trim();
|
|
112
|
+
if (!trimmed) continue;
|
|
113
|
+
let entry: TranscriptEntry;
|
|
114
|
+
try {
|
|
115
|
+
entry = JSON.parse(trimmed) as TranscriptEntry;
|
|
116
|
+
} catch {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (isRealUserPrompt(entry)) {
|
|
120
|
+
pastLastUserPrompt = true;
|
|
121
|
+
lastText = "";
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (!pastLastUserPrompt) continue;
|
|
125
|
+
const text = assistantText(entry);
|
|
126
|
+
if (text) lastText = text;
|
|
127
|
+
}
|
|
128
|
+
return lastText.trim();
|
|
129
|
+
}
|
|
130
|
+
|
|
100
131
|
/**
|
|
101
132
|
* Extract text from the `last_assistant_message` field in the Stop hook
|
|
102
133
|
* payload. This is the content of the final assistant message — either a plain
|
package/src/config.ts
CHANGED
|
@@ -33,6 +33,7 @@ export function defaultProviderConfig(provider: string): ProviderConfig {
|
|
|
33
33
|
defaultCapabilities: ["chat", "code", "review"],
|
|
34
34
|
defaultApprovalMode: "guarded",
|
|
35
35
|
defaultTags: [],
|
|
36
|
+
chatCaptureMode: "final",
|
|
36
37
|
headless: {
|
|
37
38
|
tmuxPrefix: `${provider}-relay`,
|
|
38
39
|
shutdownTimeoutMs: 10_000,
|
|
@@ -63,6 +64,7 @@ export function loadProviderConfig(provider: string, home = agentRelayHome()): L
|
|
|
63
64
|
defaultCapabilities: stringArray(raw.defaultCapabilities) ?? defaults.defaultCapabilities,
|
|
64
65
|
defaultApprovalMode: stringValue(raw.defaultApprovalMode) ?? defaults.defaultApprovalMode,
|
|
65
66
|
defaultTags: stringArray(raw.defaultTags) ?? defaults.defaultTags,
|
|
67
|
+
chatCaptureMode: enumValue(raw.chatCaptureMode, ["final", "full"]) ?? defaults.chatCaptureMode,
|
|
66
68
|
headless: {
|
|
67
69
|
tmuxPrefix: stringValue(recordValue(raw.headless).tmuxPrefix) ?? defaults.headless.tmuxPrefix,
|
|
68
70
|
shutdownTimeoutMs: positiveInteger(recordValue(raw.headless).shutdownTimeoutMs) ?? defaults.headless.shutdownTimeoutMs,
|
|
@@ -88,6 +90,7 @@ export function providerConfigPublic(config: LoadedProviderConfig): Record<strin
|
|
|
88
90
|
defaultCapabilities: config.defaultCapabilities,
|
|
89
91
|
defaultApprovalMode: config.defaultApprovalMode,
|
|
90
92
|
defaultTags: config.defaultTags,
|
|
93
|
+
chatCaptureMode: config.chatCaptureMode,
|
|
91
94
|
headless: config.headless,
|
|
92
95
|
};
|
|
93
96
|
}
|
|
@@ -120,6 +123,10 @@ function positiveInteger(value: unknown): number | undefined {
|
|
|
120
123
|
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
121
124
|
}
|
|
122
125
|
|
|
126
|
+
function enumValue<T extends string>(value: unknown, allowed: T[]): T | undefined {
|
|
127
|
+
return typeof value === "string" && allowed.includes(value as T) ? (value as T) : undefined;
|
|
128
|
+
}
|
|
129
|
+
|
|
123
130
|
function stringArray(value: unknown): string[] | undefined {
|
|
124
131
|
return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : undefined;
|
|
125
132
|
}
|
package/src/runner.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { ManagedProcess, ProviderAdapter, ProviderConfig, ProviderPermissio
|
|
|
9
9
|
import { messagesWithCachedAttachments } from "./attachment-cache";
|
|
10
10
|
import { ClaimTracker } from "./claim-tracker";
|
|
11
11
|
import { startControlServer, type ControlServer } from "./control-server";
|
|
12
|
-
import { extractLastAssistantTurn, extractHookAssistantMessage, transcriptLooksComplete } from "./adapters/claude-transcript";
|
|
12
|
+
import { extractLastAssistantTurn, extractFinalAssistantMessage, extractHookAssistantMessage, transcriptLooksComplete } from "./adapters/claude-transcript";
|
|
13
13
|
import { agentProfileProjectionReport } from "./profile-projection";
|
|
14
14
|
import { profileUsesHostProviderGlobals } from "./profile-home";
|
|
15
15
|
import { runtimeMetadata } from "./version";
|
|
@@ -702,7 +702,8 @@ export class AgentRunner {
|
|
|
702
702
|
try { jsonl = await readFile(input.transcriptPath, "utf8"); } catch { return; }
|
|
703
703
|
}
|
|
704
704
|
if (!transcriptLooksComplete(jsonl)) continue;
|
|
705
|
-
|
|
705
|
+
const extract = this.options.providerConfig.chatCaptureMode === "full" ? extractLastAssistantTurn : extractFinalAssistantMessage;
|
|
706
|
+
body = extract(jsonl);
|
|
706
707
|
if (body) break;
|
|
707
708
|
}
|
|
708
709
|
// Fallback: use last_assistant_message from the Stop hook payload directly.
|