Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/api/tauri/rpc/procedures/agentSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ export const agentSession = {
.input(schemas.agentSession.SessionIdInput)
.output(schemas.agentSession.SessionInfoSchema.nullable())
.build(),
getTurnIntentStatus: defineProcedure("agent_turn_intent_status")
.input(schemas.turnIntent.TurnIntentStatusInputSchema)
.output(schemas.turnIntent.TurnIntentStatusReceiptSchema.nullable())
.build(),
manualCompact: defineProcedure("agent_session_manual_compact")
.input(schemas.agentSession.ManualCompactInput)
.output(schemas.agentSession.ManualCompactResultSchema)
Expand Down
35 changes: 35 additions & 0 deletions src/api/tauri/rpc/schemas/__tests__/turnIntent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { describe, expect, it } from "vitest";

import {
TurnIntentStatusInputSchema,
TurnIntentStatusReceiptSchema,
} from "../turnIntent";

describe("turn-intent RPC schemas", () => {
it("accepts an origin lookup and backend-selected effective identity", () => {
expect(
TurnIntentStatusInputSchema.parse({
sessionId: "sdeagent-1",
turnIntentId: "intent-x",
})
).toEqual({ sessionId: "sdeagent-1", turnIntentId: "intent-x" });
expect(
TurnIntentStatusReceiptSchema.parse({
status: "queued",
effectiveTurnIntentId: "wir-y",
})
).toEqual({ status: "queued", effectiveTurnIntentId: "wir-y" });
});

it("fails closed for unknown status or empty identity", () => {
expect(() =>
TurnIntentStatusReceiptSchema.parse({
status: "maybe-running",
effectiveTurnIntentId: "wir-y",
})
).toThrow();
expect(() =>
TurnIntentStatusInputSchema.parse({ sessionId: "", turnIntentId: "" })
).toThrow();
});
});
14 changes: 3 additions & 11 deletions src/api/tauri/rpc/schemas/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { z } from "zod/v4";

import { ActivityChunkSchema } from "@src/api/realtime/websocket/schemas";

import { TurnIntentStatusSchema } from "./turnIntent";

export const CliMessageRequestSchema = z.object({
sessionId: z.string().min(1),
content: z.string(),
Expand All @@ -24,17 +26,7 @@ export const CliRunReceiptSchema = z.object({
sessionId: z.string(),
turnIntentId: z.string(),
effectiveTurnIntentId: z.string().min(1),
status: z.enum([
"optimistic",
"queued",
"running",
"completed",
"failed",
"cancelled",
"stale",
"coalesced",
"rejected",
]),
status: TurnIntentStatusSchema,
duplicate: z.boolean(),
});

Expand Down
1 change: 1 addition & 0 deletions src/api/tauri/rpc/schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ export * as flow from "./flow";
export * as humanSession from "./humanSession";
export * as sessionCore from "./sessionCore";
export * as cli from "./cli";
export * as turnIntent from "./turnIntent";
23 changes: 23 additions & 0 deletions src/api/tauri/rpc/schemas/turnIntent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { z } from "zod/v4";

export const TurnIntentStatusSchema = z.enum([
"optimistic",
"queued",
"running",
"completed",
"failed",
"cancelled",
"stale",
"coalesced",
"rejected",
]);

export const TurnIntentStatusInputSchema = z.object({
sessionId: z.string().min(1),
turnIntentId: z.string().min(1),
});

export const TurnIntentStatusReceiptSchema = z.object({
status: TurnIntentStatusSchema,
effectiveTurnIntentId: z.string().min(1),
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { beforeEach, describe, expect, it } from "vitest";

import {
getTurnIntentDispatch,
publishTurnIntentDispatch,
publishTurnIntentDispatchAlias,
resetTurnIntentDispatchLifecycleForTests,
retireSessionTurnIntentDispatches,
retireTurnIntentDispatch,
} from "../turnIntentDispatchLifecycle";

describe("turnIntentDispatchLifecycle", () => {
beforeEach(() => resetTurnIntentDispatchLifecycleForTests());

it("never evicts a live long-running identity under recent-turn churn", () => {
publishTurnIntentDispatch("long-running", {
sessionId: "long-session",
generation: 1,
});

for (let index = 0; index < 250; index += 1) {
const sessionId = `short-session-${index}`;
publishTurnIntentDispatch(`short-${index}`, {
sessionId,
generation: 1,
});
retireTurnIntentDispatch(sessionId, 1);
}

expect(getTurnIntentDispatch("long-running")).toEqual({
sessionId: "long-session",
generation: 1,
});
});

it("retires only the exact generation and keeps it in bounded history", () => {
publishTurnIntentDispatch("first", {
sessionId: "session",
generation: 1,
});
publishTurnIntentDispatch("second", {
sessionId: "session",
generation: 2,
});

retireTurnIntentDispatch("session", 1);

expect(getTurnIntentDispatch("first")).toEqual({
sessionId: "session",
generation: 1,
});
expect(getTurnIntentDispatch("second")).toEqual({
sessionId: "session",
generation: 2,
});
});

it("removes live identities when their session is deleted", () => {
publishTurnIntentDispatch("intent", {
sessionId: "deleted-session",
generation: 1,
});

retireSessionTurnIntentDispatches("deleted-session");

expect(getTurnIntentDispatch("intent")).toBeUndefined();
});

it("binds a backend-selected alias to the exact local generation", () => {
publishTurnIntentDispatch("composer-intent", {
sessionId: "session",
generation: 7,
});

expect(
publishTurnIntentDispatchAlias("wir_effective", {
sessionId: "session",
generation: 7,
})
).toBe(true);
expect(getTurnIntentDispatch("wir_effective")).toEqual({
sessionId: "session",
generation: 7,
});
});

it("fails closed instead of overwriting a conflicting alias", () => {
publishTurnIntentDispatch("wir_conflict", {
sessionId: "other-session",
generation: 3,
});

expect(
publishTurnIntentDispatchAlias("wir_conflict", {
sessionId: "session",
generation: 7,
})
).toBe(false);
expect(getTurnIntentDispatch("wir_conflict")).toEqual({
sessionId: "other-session",
generation: 3,
});
});
});
Loading
Loading