

























@@ -296,3 +296,145 @@ test("sessions.reset emits before_reset for the entry actually reset in the writ
296296sessionId: "sess-new",
297297});
298298});
299+300+test("sessions.create with emitCommandHooks=true fires command:new hook against parent (#76957)", async () => {
301+const { dir } = await createSessionStoreDir();
302+await writeSingleLineSession(dir, "sess-parent", "hello from parent");
303+304+await writeSessionStore({
305+entries: {
306+main: sessionStoreEntry("sess-parent"),
307+},
308+});
309+310+const result = await directSessionReq<{ ok: boolean; key: string }>("sessions.create", {
311+parentSessionKey: "main",
312+emitCommandHooks: true,
313+});
314+expect(result.ok).toBe(true);
315+316+const commandNewEvents = (
317+sessionHookMocks.triggerInternalHook.mock.calls as unknown as Array<[unknown]>
318+)
319+.map((call) => call[0])
320+.filter(
321+(event): event is { type: string; action: string; context?: { commandSource?: string } } =>
322+Boolean(event) &&
323+typeof event === "object" &&
324+(event as { type?: unknown }).type === "command" &&
325+(event as { action?: unknown }).action === "new",
326+);
327+expect(commandNewEvents).toHaveLength(1);
328+expect(commandNewEvents[0]).toMatchObject({
329+type: "command",
330+action: "new",
331+context: { commandSource: "webchat" },
332+});
333+});
334+335+test("sessions.create with emitCommandHooks=true emits reset lifecycle hooks against parent (#76957)", async () => {
336+const { dir } = await createSessionStoreDir();
337+const transcriptPath = path.join(dir, "sess-parent-hooks.jsonl");
338+await fs.writeFile(
339+transcriptPath,
340+`${JSON.stringify({
341+ type: "message",
342+ id: "m1",
343+ message: { role: "user", content: "remember this before new" },
344+ })}\n`,
345+"utf-8",
346+);
347+348+await writeSessionStore({
349+entries: {
350+main: {
351+sessionId: "sess-parent-hooks",
352+sessionFile: transcriptPath,
353+updatedAt: Date.now(),
354+},
355+},
356+});
357+358+beforeResetHookState.hasBeforeResetHook = true;
359+360+const result = await directSessionReq<{ ok: boolean; key: string }>("sessions.create", {
361+parentSessionKey: "main",
362+emitCommandHooks: true,
363+});
364+expect(result.ok).toBe(true);
365+366+expect(beforeResetHookMocks.runBeforeReset).toHaveBeenCalledTimes(1);
367+const [beforeResetEvent, beforeResetContext] = (
368+beforeResetHookMocks.runBeforeReset.mock.calls as unknown as Array<[unknown, unknown]>
369+)[0] ?? [undefined, undefined];
370+expect(beforeResetEvent).toMatchObject({
371+sessionFile: transcriptPath,
372+reason: "new",
373+messages: [
374+{
375+role: "user",
376+content: "remember this before new",
377+},
378+],
379+});
380+expect(beforeResetContext).toMatchObject({
381+agentId: "main",
382+sessionKey: "agent:main:main",
383+sessionId: "sess-parent-hooks",
384+});
385+386+expect(sessionLifecycleHookMocks.runSessionEnd).toHaveBeenCalledTimes(1);
387+expect(sessionLifecycleHookMocks.runSessionStart).toHaveBeenCalledTimes(1);
388+const [endEvent] = (
389+sessionLifecycleHookMocks.runSessionEnd.mock.calls as unknown as Array<[unknown, unknown]>
390+)[0] ?? [undefined, undefined];
391+const [startEvent] = (
392+sessionLifecycleHookMocks.runSessionStart.mock.calls as unknown as Array<[unknown, unknown]>
393+)[0] ?? [undefined, undefined];
394+expect(endEvent).toMatchObject({
395+sessionId: "sess-parent-hooks",
396+sessionKey: "agent:main:main",
397+reason: "new",
398+nextSessionId: (startEvent as { sessionId?: string } | undefined)?.sessionId,
399+nextSessionKey: (startEvent as { sessionKey?: string } | undefined)?.sessionKey,
400+});
401+expect(startEvent).toMatchObject({
402+resumedFrom: "sess-parent-hooks",
403+});
404+expect((startEvent as { sessionId?: string } | undefined)?.sessionId).toEqual(expect.any(String));
405+expect((startEvent as { sessionKey?: string } | undefined)?.sessionKey).toMatch(
406+/^agent:main:dashboard:/,
407+);
408+});
409+410+test("sessions.create without emitCommandHooks does not fire command:new hook (#76957)", async () => {
411+const { dir } = await createSessionStoreDir();
412+await writeSingleLineSession(dir, "sess-parent2", "hello from parent 2");
413+414+await writeSessionStore({
415+entries: {
416+main: sessionStoreEntry("sess-parent2"),
417+},
418+});
419+420+const result = await directSessionReq<{ ok: boolean; key: string }>("sessions.create", {
421+parentSessionKey: "main",
422+});
423+expect(result.ok).toBe(true);
424+425+const commandNewEvents = (
426+sessionHookMocks.triggerInternalHook.mock.calls as unknown as Array<[unknown]>
427+)
428+.map((call) => call[0])
429+.filter(
430+(event): event is { type: string; action: string } =>
431+Boolean(event) &&
432+typeof event === "object" &&
433+(event as { type?: unknown }).type === "command" &&
434+(event as { action?: unknown }).action === "new",
435+);
436+expect(commandNewEvents).toHaveLength(0);
437+expect(beforeResetHookMocks.runBeforeReset).not.toHaveBeenCalled();
438+expect(sessionLifecycleHookMocks.runSessionEnd).not.toHaveBeenCalled();
439+expect(sessionLifecycleHookMocks.runSessionStart).not.toHaveBeenCalled();
440+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。