refactor: pass subagent transcript scopes

This commit is contained in:
Peter Steinberger
2026-05-09 20:17:22 +01:00
parent 579de04324
commit ff08a34fdb
5 changed files with 25 additions and 31 deletions

View File

@@ -2,7 +2,6 @@ import type { AgentMessage } from "@mariozechner/pi-agent-core";
import { formatAcpErrorChain } from "../../acp/runtime/errors.js";
import { normalizeReplyPayload } from "../../auto-reply/reply/normalize-reply.js";
import type { ThinkLevel, VerboseLevel } from "../../auto-reply/thinking.js";
import { createSqliteSessionTranscriptLocator } from "../../config/sessions/paths.js";
import { appendSessionTranscriptMessage } from "../../config/sessions/transcript-append.js";
import {
readTailAssistantTextFromSessionTranscript,

View File

@@ -2,7 +2,6 @@ import crypto from "node:crypto";
import { promises as fs } from "node:fs";
import { isAcpRuntimeSpawnAvailable } from "../acp/runtime/availability.js";
import { resolveThreadBindingSpawnPolicy } from "../channels/thread-bindings-policy.js";
import { createSqliteSessionTranscriptLocator } from "../config/sessions/paths.js";
import type { SessionEntry } from "../config/sessions/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { SubagentSpawnPreparation } from "../context-engine/types.js";
@@ -440,18 +439,12 @@ async function prepareContextEngineSubagentSpawn(params: {
childSessionKey: params.childSessionKey,
contextMode: params.context.mode,
parentSessionId,
parentTranscriptLocator: parentSessionId
? createSqliteSessionTranscriptLocator({
agentId: parentAgentId,
sessionId: parentSessionId,
})
parentTranscriptScope: parentSessionId
? { agentId: parentAgentId, sessionId: parentSessionId }
: undefined,
childSessionId,
childTranscriptLocator: childSessionId
? createSqliteSessionTranscriptLocator({
agentId: childAgentId,
sessionId: childSessionId,
})
childTranscriptScope: childSessionId
? { agentId: childAgentId, sessionId: childSessionId }
: undefined,
ttlMs: params.runTimeoutSeconds > 0 ? params.runTimeoutSeconds * 1000 : undefined,
});

View File

@@ -2,7 +2,6 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { createSqliteSessionTranscriptLocator } from "../../config/sessions/paths.js";
import {
loadSqliteSessionTranscriptEvents,
replaceSqliteSessionTranscriptEvents,
@@ -48,6 +47,10 @@ function seedTranscript(params: { agentId?: string; sessionId: string; events: u
});
}
function transcriptParentReference(params: { agentId: string; sessionId: string }): string {
return `agent-db:${params.agentId}:transcript_events:${params.sessionId}`;
}
function readTranscript(agentId: string, sessionId: string): unknown[] {
return loadSqliteSessionTranscriptEvents({ agentId, sessionId }).map((entry) => entry.event);
}
@@ -58,7 +61,6 @@ describe("resolveParentForkTokenCountRuntime", () => {
useStateRoot(root);
const sessionId = "parent-overflow-transcript";
const transcriptLocator = createSqliteSessionTranscriptLocator({ agentId: "main", sessionId });
const events: unknown[] = [
{
type: "session",
@@ -113,7 +115,6 @@ describe("resolveParentForkTokenCountRuntime", () => {
useStateRoot(root);
const sessionId = "parent-no-usage-transcript";
const transcriptLocator = createSqliteSessionTranscriptLocator({ agentId: "main", sessionId });
const events: unknown[] = [
{
type: "session",
@@ -153,7 +154,6 @@ describe("resolveParentForkTokenCountRuntime", () => {
useStateRoot(root);
const sessionId = "parent-multiple-usage-transcript";
const transcriptLocator = createSqliteSessionTranscriptLocator({ agentId: "main", sessionId });
seedTranscript({
sessionId,
events: [
@@ -200,7 +200,6 @@ describe("resolveParentForkTokenCountRuntime", () => {
useStateRoot(root);
const sessionId = "parent-post-usage-tail";
const transcriptLocator = createSqliteSessionTranscriptLocator({ agentId: "main", sessionId });
seedTranscript({
sessionId,
events: [
@@ -249,7 +248,7 @@ describe("forkSessionFromParentRuntime", () => {
const cwd = path.join(root, "workspace");
await fs.mkdir(cwd);
const parentSessionId = "parent-session";
const parentTranscriptLocator = createSqliteSessionTranscriptLocator({
const parentTranscriptReference = transcriptParentReference({
agentId: "main",
sessionId: parentSessionId,
});
@@ -311,7 +310,7 @@ describe("forkSessionFromParentRuntime", () => {
type: "session",
id: fork.sessionId,
cwd,
parentSession: parentTranscriptLocator,
parentSession: parentTranscriptReference,
});
expect(forkedEntries.map((entry) => entry.type)).toEqual([
"session",
@@ -330,7 +329,7 @@ describe("forkSessionFromParentRuntime", () => {
const root = await makeRoot("openclaw-parent-fork-empty-");
useStateRoot(root);
const parentSessionId = "parent-empty";
const parentTranscriptLocator = createSqliteSessionTranscriptLocator({
const parentTranscriptReference = transcriptParentReference({
agentId: "main",
sessionId: parentSessionId,
});
@@ -363,7 +362,7 @@ describe("forkSessionFromParentRuntime", () => {
expect(entries[0]).toMatchObject({
type: "session",
id: fork.sessionId,
parentSession: parentTranscriptLocator,
parentSession: parentTranscriptReference,
});
});
});

View File

@@ -7,7 +7,6 @@ import {
type SessionHeader,
} from "../../agents/transcript/session-transcript-contract.js";
import { derivePromptTokens } from "../../agents/usage.js";
import { createSqliteSessionTranscriptLocator } from "../../config/sessions/paths.js";
import {
loadSqliteSessionTranscriptEvents,
replaceSqliteSessionTranscriptEvents,
@@ -29,6 +28,10 @@ type ForkSourceTranscript = {
const FALLBACK_TRANSCRIPT_BYTES_PER_TOKEN = 4;
function formatTranscriptParentReference(scope: { agentId: string; sessionId: string }): string {
return `agent-db:${scope.agentId}:transcript_events:${scope.sessionId}`;
}
function resolvePositiveTokenCount(value: number | undefined): number | undefined {
return typeof value === "number" && Number.isFinite(value) && value > 0
? Math.floor(value)
@@ -224,7 +227,7 @@ function buildBranchLabelEntries(params: {
}
async function writeForkHeaderOnly(params: {
parentTranscriptLocator: string;
parentTranscriptReference: string;
agentId: string;
cwd: string;
}): Promise<{ sessionId: string }> {
@@ -236,7 +239,7 @@ async function writeForkHeaderOnly(params: {
id: sessionId,
timestamp,
cwd: params.cwd,
parentSession: params.parentTranscriptLocator,
parentSession: params.parentTranscriptReference,
} satisfies SessionHeader;
replaceSqliteSessionTranscriptEvents({
agentId: params.agentId,
@@ -247,7 +250,7 @@ async function writeForkHeaderOnly(params: {
}
async function writeBranchedSession(params: {
parentTranscriptLocator: string;
parentTranscriptReference: string;
source: ForkSourceTranscript;
}): Promise<{ sessionId: string }> {
const sessionId = crypto.randomUUID();
@@ -265,7 +268,7 @@ async function writeBranchedSession(params: {
id: sessionId,
timestamp,
cwd: params.source.cwd,
parentSession: params.parentTranscriptLocator,
parentSession: params.parentTranscriptReference,
} satisfies SessionHeader;
const entries = [header, ...pathWithoutLabels, ...labelEntries];
const hasAssistant = entries.some(
@@ -285,7 +288,7 @@ export async function forkSessionFromParentRuntime(params: {
parentEntry: StoreSessionEntry;
agentId: string;
}): Promise<{ sessionId: string } | null> {
const parentTranscriptLocator = createSqliteSessionTranscriptLocator({
const parentTranscriptReference = formatTranscriptParentReference({
agentId: params.agentId,
sessionId: params.parentEntry.sessionId,
});
@@ -298,9 +301,9 @@ export async function forkSessionFromParentRuntime(params: {
return null;
}
return source.leafId
? await writeBranchedSession({ parentTranscriptLocator, source })
? await writeBranchedSession({ parentTranscriptReference, source })
: await writeForkHeaderOnly({
parentTranscriptLocator,
parentTranscriptReference,
agentId: source.agentId,
cwd: source.cwd,
});

View File

@@ -315,9 +315,9 @@ export interface ContextEngine {
childSessionKey: string;
contextMode?: "isolated" | "fork";
parentSessionId?: string;
parentTranscriptLocator?: string;
parentTranscriptScope?: ContextEngineTranscriptScope;
childSessionId?: string;
childTranscriptLocator?: string;
childTranscriptScope?: ContextEngineTranscriptScope;
ttlMs?: number;
}): Promise<SubagentSpawnPreparation | undefined>;