feat: session source in session_meta and an Automated sidebar folder (#40)
Co-authored-by: Alice <alice@prismshadow.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
30 files changed
+1023
-74
No files matched your search
@@ -77,7 +77,12 @@ async function writeTraceFile(
|
||||
return file;
|
||||
}
|
||||
|
||||
function metaFor(sessionId: string, workspaceDir: string, model = MODEL): OmniMessage {
|
||||
function metaFor(
|
||||
sessionId: string,
|
||||
workspaceDir: string,
|
||||
model = MODEL,
|
||||
source?: "subagent" | "schedule",
|
||||
): OmniMessage {
|
||||
return sessionMeta({
|
||||
session_id: sessionId,
|
||||
provider: model.provider,
|
||||
@@ -88,6 +93,7 @@ function metaFor(sessionId: string, workspaceDir: string, model = MODEL): OmniMe
|
||||
thinking_level: "default",
|
||||
agent_state: "/agent/state",
|
||||
workspace: workspaceDir,
|
||||
...(source !== undefined ? { source } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -116,6 +122,43 @@ describe("agent.resumeSession", () => {
|
||||
expect(texts).toEqual(["hello", "hi there"]);
|
||||
});
|
||||
|
||||
it("preserves the stored session source across resume (and its absence for user sessions)", async () => {
|
||||
const agent = await createAgent({});
|
||||
await writeTraceFile(tmpRoot, SID, [
|
||||
metaFor(SID, workspace, MODEL, "subagent"),
|
||||
userText("child task"),
|
||||
requestBegin(),
|
||||
assistantText("done"),
|
||||
requestEnd("completed"),
|
||||
]);
|
||||
const session = await agent.resumeSession({ sessionId: SID });
|
||||
// The rebuilt session_meta carries the origin over (a rotated Trace file must re-record it).
|
||||
expect((session.metaMessage.payload as { source?: string }).source).toBe("subagent");
|
||||
session.dispose();
|
||||
|
||||
// A user-created session's meta has no source key, and resume must not invent one.
|
||||
const SID2 = "session-2026-07-06-11-00-00-abcdef02";
|
||||
await writeTraceFile(tmpRoot, SID2, [metaFor(SID2, workspace), userText("hi")]);
|
||||
const plain = await agent.resumeSession({ sessionId: SID2 });
|
||||
expect("source" in (plain.metaMessage.payload as unknown as Record<string, unknown>)).toBe(
|
||||
false,
|
||||
);
|
||||
plain.dispose();
|
||||
|
||||
// On-disk values are untrusted: a junk source written by a third party is dropped on
|
||||
// resume (only the exact known origins pass), not cast through into the rebuilt meta.
|
||||
const SID3 = "session-2026-07-06-12-00-00-abcdef03";
|
||||
await writeTraceFile(tmpRoot, SID3, [
|
||||
metaFor(SID3, workspace, MODEL, "weird-origin" as unknown as "subagent"),
|
||||
userText("hi"),
|
||||
]);
|
||||
const junk = await agent.resumeSession({ sessionId: SID3 });
|
||||
expect("source" in (junk.metaMessage.payload as unknown as Record<string, unknown>)).toBe(
|
||||
false,
|
||||
);
|
||||
junk.dispose();
|
||||
});
|
||||
|
||||
it("keeps abort events in resumed render history", async () => {
|
||||
const agent = await createAgent({});
|
||||
await writeTraceFile(tmpRoot, SID, [
|
||||
|
||||
Reference in new issue
Block a user