diff --git a/src/components/Root.tsx b/src/components/Root.tsx
index 0daf8f0ad..dd5163b06 100644
--- a/src/components/Root.tsx
+++ b/src/components/Root.tsx
@@ -51,6 +51,10 @@ import { MemoryEventListScreen } from "../handlers/memory/event/list/screen.tsx"
import { MemoryRecordScreen } from "../handlers/memory/record/screen.tsx";
import { MemoryRecordGetScreen } from "../handlers/memory/record/get/screen.tsx";
import { MemoryRecordListScreen } from "../handlers/memory/record/list/screen.tsx";
+import { MemoryActorScreen } from "../handlers/memory/actor/screen.tsx";
+import { MemoryActorListScreen } from "../handlers/memory/actor/list/screen.tsx";
+import { MemorySessionScreen } from "../handlers/memory/session/screen.tsx";
+import { MemorySessionListScreen } from "../handlers/memory/session/list/screen.tsx";
import { IdentityScreen } from "../handlers/identity/screen.tsx";
import { ApiKeyCredentialProviderScreen } from "../handlers/identity/api-key-credential-provider/screen.tsx";
import { ApiKeyCredentialProviderListScreen } from "../handlers/identity/api-key-credential-provider/list/screen.tsx";
@@ -414,6 +418,34 @@ export function Root({ path, ctx, core, queryClient }: RootProps) {
path="agentcore/memory/record/list/:memoryId/:scopeKind/:scope"
element={}
/>
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
} />
= {}): MemorySummary {
+ return {
+ arn: "arn:aws:bedrock-agentcore:us-east-1:123456789012:memory/memory-1",
+ id: "memory-1",
+ status: "ACTIVE",
+ createdAt: new Date("2026-07-19T01:02:03.000Z"),
+ updatedAt: new Date("2026-07-20T12:34:56.000Z"),
+ ...overrides,
+ };
+}
+
+function actor(overrides: Partial = {}): ActorSummary {
+ return {
+ actorId: "actor-1",
+ ...overrides,
+ };
+}
+
+function session(overrides: Partial = {}): SessionSummary {
+ return {
+ sessionId: "session-1",
+ actorId: "actor-1",
+ createdAt: new Date("2026-08-02T10:20:30.000Z"),
+ ...overrides,
+ };
+}
+
+describe("Memory actor list flow", () => {
+ test("uses the Memory picker, lists actors, then opens the actor's sessions", async () => {
+ const memoryId = "memory/blue one";
+ const actorId = "actor/blue one";
+ const core = new TestCoreClient();
+ core.memory.setListResponse({ memories: [memorySummary({ id: memoryId })] });
+ core.memory.setListActorsResponse({ actorSummaries: [actor({ actorId })] });
+ core.memory.setListSessionsResponse({
+ sessionSummaries: [session({ actorId })],
+ });
+ const screen = renderScreen("/agentcore/memory/actor/list", { core });
+
+ await waitForText(screen.lastFrame, memoryId);
+ await screen.press("return");
+ await waitForText(screen.lastFrame, actorId);
+ await screen.press("return");
+ await waitForText(screen.lastFrame, "session-1");
+
+ expect(core.memory.calls.find((call) => call.method === "listActors")).toEqual({
+ method: "listActors",
+ args: [
+ {
+ memoryId,
+ maxResults: expect.any(Number),
+ nextToken: undefined,
+ },
+ { region: "us-east-1" },
+ ],
+ });
+ expect(core.memory.calls.find((call) => call.method === "listSessions")).toEqual({
+ method: "listSessions",
+ args: [
+ {
+ memoryId,
+ actorId,
+ maxResults: expect.any(Number),
+ nextToken: undefined,
+ },
+ { region: "us-east-1" },
+ ],
+ });
+
+ await screen.press("escape");
+ await waitForText(screen.lastFrame, "choose an actor to list sessions for");
+ await screen.press("escape");
+ await waitForText(screen.lastFrame, "choose a Memory to list actors for");
+ });
+
+ test("shows empty and retry states for actor lists", async () => {
+ const empty = renderScreen("/agentcore/memory/actor/list/memory-1");
+ await waitForText(empty.lastFrame, "No actors found for Memory memory-1.");
+ empty.unmount();
+
+ const core = new TestCoreClient();
+ core.memory.setError(new Error("actors unavailable"));
+ const failed = renderScreen("/agentcore/memory/actor/list/memory-1", { core });
+
+ await waitForText(failed.lastFrame, "actors unavailable");
+ core.memory.setError(undefined);
+ core.memory.setListActorsResponse({ actorSummaries: [actor()] });
+ await failed.write("r");
+ await waitFor(() => failed.lastFrame()?.includes("actor-1") ?? false);
+ });
+});
diff --git a/src/handlers/memory/actor/index.tsx b/src/handlers/memory/actor/index.tsx
new file mode 100644
index 000000000..293d9ff8d
--- /dev/null
+++ b/src/handlers/memory/actor/index.tsx
@@ -0,0 +1,11 @@
+import { Router } from "../../../router";
+import { renderTui } from "../../../tui";
+import type { AppIO } from "../../../io";
+import type { Core } from "../../types";
+import { createListMemoryActorsHandler } from "./list";
+
+export function createMemoryActorHandler(core: Core, io: AppIO): Router {
+ return new Router("actor", "inspect actors in AgentCore Memories")
+ .default(renderTui(core, io))
+ .handler(createListMemoryActorsHandler(core));
+}
diff --git a/src/handlers/memory/actor/list/index.tsx b/src/handlers/memory/actor/list/index.tsx
new file mode 100644
index 000000000..b8e978cc5
--- /dev/null
+++ b/src/handlers/memory/actor/list/index.tsx
@@ -0,0 +1,33 @@
+import z from "zod";
+import { InputValidationError } from "../../../../errors";
+import { createHandler, flag } from "../../../../router";
+import { JsonRendererKey } from "../../../../tui";
+import type { Core } from "../../../types";
+import { coreOptsFromCtx } from "../../../utils";
+
+export const createListMemoryActorsHandler = (core: Core) =>
+ createHandler({
+ name: "list",
+ description: "list actors in an AgentCore Memory",
+ flags: [
+ flag("memory", "the ID of the Memory", z.string().optional()),
+ flag("max-results", "maximum number of actors to return", z.number().optional()),
+ flag("next-token", "pagination token returned by a previous request", z.string().optional()),
+ ],
+ handle: async (ctx, flags) => {
+ if (!flags.memory) {
+ throw new InputValidationError("required option '--memory ' not specified");
+ }
+
+ const response = await core.memory.listActors(
+ {
+ memoryId: flags.memory,
+ maxResults: flags["max-results"],
+ nextToken: flags["next-token"],
+ },
+ coreOptsFromCtx(ctx),
+ );
+
+ ctx.require(JsonRendererKey).renderJson(response);
+ },
+ });
diff --git a/src/handlers/memory/actor/list/screen.tsx b/src/handlers/memory/actor/list/screen.tsx
new file mode 100644
index 000000000..e3f49eb2c
--- /dev/null
+++ b/src/handlers/memory/actor/list/screen.tsx
@@ -0,0 +1,35 @@
+import { useNavigate, useParams } from "react-router";
+import { MemoryPicker } from "../../../../components/MemoryPicker";
+import type { ScreenProps } from "../../../types";
+import { MemoryActorPicker } from "../../listPickers";
+
+export function MemoryActorListScreen(props: ScreenProps) {
+ const navigate = useNavigate();
+ const { memoryId } = useParams();
+
+ if (!memoryId) {
+ return (
+ navigate(`/agentcore/memory/actor/list/${encodeURIComponent(id)}`)}
+ />
+ );
+ }
+
+ return (
+
+ navigate(
+ `/agentcore/memory/session/list/${encodeURIComponent(memoryId)}/${encodeURIComponent(actorId)}`,
+ )
+ }
+ onBack={() => navigate(-1)}
+ />
+ );
+}
diff --git a/src/handlers/memory/actor/screen.tsx b/src/handlers/memory/actor/screen.tsx
new file mode 100644
index 000000000..a832104b3
--- /dev/null
+++ b/src/handlers/memory/actor/screen.tsx
@@ -0,0 +1,6 @@
+import { RouterScreen } from "../../../components/RouterScreen";
+import type { ScreenProps } from "../../types";
+
+export function MemoryActorScreen(props: ScreenProps) {
+ return ;
+}
diff --git a/src/handlers/memory/event/list/screen.tsx b/src/handlers/memory/event/list/screen.tsx
index 71fd1ab64..f203ee0b9 100644
--- a/src/handlers/memory/event/list/screen.tsx
+++ b/src/handlers/memory/event/list/screen.tsx
@@ -1,4 +1,4 @@
-import type { ActorSummary, Event, SessionSummary } from "@aws-sdk/client-bedrock-agentcore";
+import type { Event } from "@aws-sdk/client-bedrock-agentcore";
import { useNavigate, useParams } from "react-router";
import { MemoryPicker } from "../../../../components/MemoryPicker";
import { PaginatedTablePicker } from "../../../../components/PaginatedTablePicker";
@@ -6,41 +6,7 @@ import { formatTimestamp } from "../../../../components/formatTimestamp";
import type { DataTableColumn } from "../../../../components/ui/data-table";
import type { ScreenProps } from "../../../types";
import { coreOptsFromCtx } from "../../../utils";
-
-interface ActorRow extends Record {
- actorId: string;
-}
-
-const actorColumns = [
- { key: "actorId", header: "actor id", flex: true },
-] satisfies DataTableColumn[];
-
-function toActorRow(actor: ActorSummary): ActorRow {
- return { actorId: actor.actorId ?? "" };
-}
-
-interface SessionRow extends Record {
- sessionId: string;
- createdAt: string;
-}
-
-const sessionColumns = [
- { key: "sessionId", header: "session id", flex: true },
- {
- key: "createdAt",
- header: "created UTC",
- width: 16,
- minWidth: 11,
- render: formatTimestamp,
- },
-] satisfies DataTableColumn[];
-
-function toSessionRow(session: SessionSummary): SessionRow {
- return {
- sessionId: session.sessionId ?? "",
- createdAt: session.createdAt?.toISOString() ?? "-",
- };
-}
+import { MemoryActorPicker, MemorySessionPicker } from "../../listPickers";
interface EventRow extends Record {
eventId: string;
@@ -68,87 +34,6 @@ function toEventRow(event: Event): EventRow {
};
}
-interface ActorPickerProps extends ScreenProps {
- memoryId: string;
-}
-
-function ActorPicker({ ctx, core, memoryId }: ActorPickerProps) {
- const opts = coreOptsFromCtx(ctx);
- const navigate = useNavigate();
-
- return (
- {
- const response = await core.memory.listActors(
- { memoryId, maxResults: pageSize, nextToken: token },
- opts,
- );
- return {
- items: response.actorSummaries ?? [],
- nextToken: response.nextToken,
- };
- }}
- toRow={toActorRow}
- columns={actorColumns}
- getValue={(row) => row.actorId}
- onSelect={(actorId) =>
- navigate(
- `/agentcore/memory/event/list/${encodeURIComponent(memoryId)}/${encodeURIComponent(actorId)}`,
- )
- }
- onBack={() => navigate(-1)}
- loadingMessage={`Loading actors for Memory ${memoryId}...`}
- errorMessage={(error) => `Error loading actors for Memory ${memoryId}: ${error.message}`}
- emptyMessage={`No actors found for Memory ${memoryId}.`}
- emptyPageMessage={`No actors on this page for Memory ${memoryId}.`}
- />
- );
-}
-
-interface SessionPickerProps extends ScreenProps {
- memoryId: string;
- actorId: string;
-}
-
-function SessionPicker({ ctx, core, memoryId, actorId }: SessionPickerProps) {
- const opts = coreOptsFromCtx(ctx);
- const navigate = useNavigate();
-
- return (
- {
- const response = await core.memory.listSessions(
- { memoryId, actorId, maxResults: pageSize, nextToken: token },
- opts,
- );
- return {
- items: response.sessionSummaries ?? [],
- nextToken: response.nextToken,
- };
- }}
- toRow={toSessionRow}
- columns={sessionColumns}
- getValue={(row) => row.sessionId}
- onSelect={(sessionId) =>
- navigate(
- `/agentcore/memory/event/list/${encodeURIComponent(memoryId)}/${encodeURIComponent(actorId)}/${encodeURIComponent(sessionId)}`,
- )
- }
- onBack={() => navigate(-1)}
- loadingMessage={`Loading sessions for actor ${actorId}...`}
- errorMessage={(error) => `Error loading sessions for actor ${actorId}: ${error.message}`}
- emptyMessage={`No sessions found for actor ${actorId}.`}
- emptyPageMessage={`No sessions on this page for actor ${actorId}.`}
- />
- );
-}
-
interface EventPickerProps extends ScreenProps {
memoryId: string;
actorId: string;
@@ -212,11 +97,38 @@ export function MemoryEventListScreen(props: ScreenProps) {
}
if (!actorId) {
- return ;
+ return (
+
+ navigate(
+ `/agentcore/memory/event/list/${encodeURIComponent(memoryId)}/${encodeURIComponent(id)}`,
+ )
+ }
+ onBack={() => navigate(-1)}
+ />
+ );
}
if (!sessionId) {
- return ;
+ return (
+
+ navigate(
+ `/agentcore/memory/event/list/${encodeURIComponent(memoryId)}/${encodeURIComponent(actorId)}/${encodeURIComponent(id)}`,
+ )
+ }
+ onBack={() => navigate(-1)}
+ />
+ );
}
return ;
diff --git a/src/handlers/memory/get/screen.tsx b/src/handlers/memory/get/screen.tsx
index 765dc9946..1904fde3e 100644
--- a/src/handlers/memory/get/screen.tsx
+++ b/src/handlers/memory/get/screen.tsx
@@ -21,6 +21,16 @@ const ACTIONS = [
description: "list this Memory's records",
to: (id: string) => `/agentcore/memory/record/list/${encodeURIComponent(id)}`,
},
+ {
+ name: "actors",
+ description: "list this Memory's actors",
+ to: (id: string) => `/agentcore/memory/actor/list/${encodeURIComponent(id)}`,
+ },
+ {
+ name: "sessions",
+ description: "choose an actor to list this Memory's sessions",
+ to: (id: string) => `/agentcore/memory/session/list/${encodeURIComponent(id)}`,
+ },
] as const;
function useMemoryDetail({ ctx, core }: ScreenProps, memoryId: string | undefined) {
diff --git a/src/handlers/memory/index.tsx b/src/handlers/memory/index.tsx
index 3fde18341..533cea491 100644
--- a/src/handlers/memory/index.tsx
+++ b/src/handlers/memory/index.tsx
@@ -3,10 +3,12 @@ import { Router } from "../../router";
import { renderTui } from "../../tui";
import type { AppIO } from "../../io";
import type { Core } from "../types";
+import { createMemoryActorHandler } from "./actor";
import { createMemoryEventHandler } from "./event";
import { createGetMemoryHandler } from "./get";
import { createListMemoriesHandler } from "./list";
import { createMemoryRecordHandler } from "./record";
+import { createMemorySessionHandler } from "./session";
export function createMemoryHandler(core: Core, io: AppIO): Router {
return new Router("memory", "manage AgentCore Memories")
@@ -15,5 +17,7 @@ export function createMemoryHandler(core: Core, io: AppIO): Router {
.handler(createGetMemoryHandler(core))
.handler(createListMemoriesHandler(core))
.handler(createMemoryEventHandler(core, io))
- .handler(createMemoryRecordHandler(core, io));
+ .handler(createMemoryRecordHandler(core, io))
+ .handler(createMemoryActorHandler(core, io))
+ .handler(createMemorySessionHandler(core, io));
}
diff --git a/src/handlers/memory/listPickers.tsx b/src/handlers/memory/listPickers.tsx
new file mode 100644
index 000000000..02cedb49f
--- /dev/null
+++ b/src/handlers/memory/listPickers.tsx
@@ -0,0 +1,137 @@
+import type { ActorSummary, SessionSummary } from "@aws-sdk/client-bedrock-agentcore";
+import { PaginatedTablePicker } from "../../components/PaginatedTablePicker";
+import { formatTimestamp } from "../../components/formatTimestamp";
+import type { DataTableColumn } from "../../components/ui/data-table";
+import type { ScreenProps } from "../types";
+import { coreOptsFromCtx } from "../utils";
+
+interface MemoryActorRow extends Record {
+ actorId: string;
+}
+
+const actorColumns = [
+ { key: "actorId", header: "actor id", flex: true },
+] satisfies DataTableColumn[];
+
+function toActorRow(actor: ActorSummary): MemoryActorRow {
+ return { actorId: actor.actorId ?? "" };
+}
+
+export interface MemoryActorPickerProps extends ScreenProps {
+ memoryId: string;
+ breadcrumb: string[];
+ description: string;
+ onSelect: (actorId: string) => void;
+ onBack: () => void;
+}
+
+export function MemoryActorPicker({
+ ctx,
+ core,
+ memoryId,
+ breadcrumb,
+ description,
+ onSelect,
+ onBack,
+}: MemoryActorPickerProps) {
+ const opts = coreOptsFromCtx(ctx);
+
+ return (
+ {
+ const response = await core.memory.listActors(
+ { memoryId, maxResults: pageSize, nextToken: token },
+ opts,
+ );
+ return {
+ items: response.actorSummaries ?? [],
+ nextToken: response.nextToken,
+ };
+ }}
+ toRow={toActorRow}
+ columns={actorColumns}
+ getValue={(row) => row.actorId}
+ onSelect={onSelect}
+ onBack={onBack}
+ loadingMessage={`Loading actors for Memory ${memoryId}...`}
+ errorMessage={(error) => `Error loading actors for Memory ${memoryId}: ${error.message}`}
+ emptyMessage={`No actors found for Memory ${memoryId}.`}
+ emptyPageMessage={`No actors on this page for Memory ${memoryId}.`}
+ />
+ );
+}
+
+interface MemorySessionRow extends Record {
+ sessionId: string;
+ createdAt: string;
+}
+
+const sessionColumns = [
+ { key: "sessionId", header: "session id", flex: true },
+ {
+ key: "createdAt",
+ header: "created UTC",
+ width: 16,
+ minWidth: 11,
+ render: formatTimestamp,
+ },
+] satisfies DataTableColumn[];
+
+function toSessionRow(session: SessionSummary): MemorySessionRow {
+ return {
+ sessionId: session.sessionId ?? "",
+ createdAt: session.createdAt?.toISOString() ?? "-",
+ };
+}
+
+export interface MemorySessionPickerProps extends ScreenProps {
+ memoryId: string;
+ actorId: string;
+ breadcrumb: string[];
+ description: string;
+ onSelect: (sessionId: string) => void;
+ onBack: () => void;
+}
+
+export function MemorySessionPicker({
+ ctx,
+ core,
+ memoryId,
+ actorId,
+ breadcrumb,
+ description,
+ onSelect,
+ onBack,
+}: MemorySessionPickerProps) {
+ const opts = coreOptsFromCtx(ctx);
+
+ return (
+ {
+ const response = await core.memory.listSessions(
+ { memoryId, actorId, maxResults: pageSize, nextToken: token },
+ opts,
+ );
+ return {
+ items: response.sessionSummaries ?? [],
+ nextToken: response.nextToken,
+ };
+ }}
+ toRow={toSessionRow}
+ columns={sessionColumns}
+ getValue={(row) => row.sessionId}
+ onSelect={onSelect}
+ onBack={onBack}
+ loadingMessage={`Loading sessions for actor ${actorId}...`}
+ errorMessage={(error) => `Error loading sessions for actor ${actorId}: ${error.message}`}
+ emptyMessage={`No sessions found for actor ${actorId}.`}
+ emptyPageMessage={`No sessions on this page for actor ${actorId}.`}
+ />
+ );
+}
diff --git a/src/handlers/memory/memory.screen.test.tsx b/src/handlers/memory/memory.screen.test.tsx
index 9b064fbdf..9922768f0 100644
--- a/src/handlers/memory/memory.screen.test.tsx
+++ b/src/handlers/memory/memory.screen.test.tsx
@@ -66,7 +66,7 @@ function coreWithMemories(memories: MemorySummary[]): TestCoreClient {
}
describe("Memory picker", () => {
- test("shows event and record commands in the Memory TUI menu", async () => {
+ test("shows event, record, actor, and session commands in the Memory TUI menu", async () => {
const screen = renderScreen("/agentcore/memory");
await waitForText(screen.lastFrame, "manage AgentCore Memories");
@@ -75,6 +75,8 @@ describe("Memory picker", () => {
expect(frame).toContain("list");
expect(frame).toContain("event");
expect(frame).toContain("record");
+ expect(frame).toContain("actor");
+ expect(frame).toContain("session");
});
test("renders Memory identity, status, and update time", async () => {
@@ -190,6 +192,8 @@ describe("Memory detail", () => {
expect(frame).toMatch(/eventExpiryDays\s+30/);
expect(frame).toMatch(/strategies\s+1/);
expect(frame).toContain("arn:aws:bedrock-agentcore");
+ expect(frame).toContain("list this Memory's actors");
+ expect(frame).toContain("choose an actor to list this Memory's sessions");
expect(core.memory.calls.find((call) => call.method === "getMemory")).toEqual({
method: "getMemory",
args: [
diff --git a/src/handlers/memory/memory.test.tsx b/src/handlers/memory/memory.test.tsx
index 905de985a..cca52184e 100644
--- a/src/handlers/memory/memory.test.tsx
+++ b/src/handlers/memory/memory.test.tsx
@@ -1,15 +1,19 @@
import { describe, expect, test } from "bun:test";
import { join } from "node:path";
import type {
+ ActorSummary,
Event,
EventMetadataFilterExpression,
GetEventOutput,
GetMemoryRecordOutput,
+ ListActorsOutput,
ListEventsOutput,
ListMemoryRecordsOutput,
+ ListSessionsOutput,
MemoryMetadataFilterExpression,
MemoryRecord,
MemoryRecordSummary,
+ SessionSummary,
} from "@aws-sdk/client-bedrock-agentcore";
import { CoreClient } from "../../core";
import {
@@ -39,6 +43,16 @@ const SESSION_ID = "session-1";
const EVENT_ID = "event-1";
const RECORD_ID = "record-1";
+const actorSummary: ActorSummary = {
+ actorId: ACTOR_ID,
+};
+
+const sessionSummary: SessionSummary = {
+ actorId: ACTOR_ID,
+ sessionId: SESSION_ID,
+ createdAt: new Date("2026-08-03T12:00:00.000Z"),
+};
+
const event: Event = {
memoryId: EVENT_MEMORY_ID,
actorId: ACTOR_ID,
@@ -105,6 +119,8 @@ describe("memory command hierarchy", () => {
const memory = root.children().find((child) => child.name() === "memory");
const event = memory?.children().find((child) => child.name() === "event");
const record = memory?.children().find((child) => child.name() === "record");
+ const actor = memory?.children().find((child) => child.name() === "actor");
+ const session = memory?.children().find((child) => child.name() === "session");
expect(memory?.flags().map((flag) => flag.name)).not.toContain("interactive");
expect(memory?.children().map((child) => child.name())).toEqual([
@@ -112,9 +128,13 @@ describe("memory command hierarchy", () => {
"list",
"event",
"record",
+ "actor",
+ "session",
]);
expect(event?.children().map((child) => child.name())).toEqual(["get", "list"]);
expect(record?.children().map((child) => child.name())).toEqual(["get", "list"]);
+ expect(actor?.children().map((child) => child.name())).toEqual(["list"]);
+ expect(session?.children().map((child) => child.name())).toEqual(["list"]);
});
test("keeps an omitted get view undefined for empty-flag routing", () => {
@@ -140,6 +160,8 @@ describe("memory TUI dispatch", () => {
["event list", ["memory", "event", "list"]],
["record get", ["memory", "record", "get"]],
["record list", ["memory", "record", "list"]],
+ ["actor list", ["memory", "actor", "list"]],
+ ["session list", ["memory", "session", "list"]],
] as const)("opens the TUI for a bare Memory %s leaf", async (_label, args) => {
const { core, route } = testMemoryCommand();
@@ -420,6 +442,106 @@ describe("memory event commands", () => {
});
});
+describe("memory actor commands", () => {
+ test("lists actors with pagination options", async () => {
+ const response: ListActorsOutput = {
+ actorSummaries: [actorSummary],
+ nextToken: "page-3",
+ };
+ const core = new TestCoreClient();
+ core.memory.setListActorsResponse(response, "page-2");
+ const command = testMemoryCommand(core);
+
+ await command.route([
+ "memory",
+ "actor",
+ "list",
+ "--memory",
+ EVENT_MEMORY_ID,
+ "--max-results",
+ "1",
+ "--next-token",
+ "page-2",
+ ]);
+
+ expect(core.memory.calls).toEqual([
+ {
+ method: "listActors",
+ args: [
+ {
+ memoryId: EVENT_MEMORY_ID,
+ maxResults: 1,
+ nextToken: "page-2",
+ },
+ { region: REGION },
+ ],
+ },
+ ]);
+ expect(JSON.parse(command.stdout())).toEqual(JSON.parse(JSON.stringify(response)));
+ });
+
+ test("rejects a missing Memory selector for actor list", async () => {
+ const command = testMemoryCommand();
+
+ await expect(command.route(["memory", "actor", "list", "--json"])).rejects.toThrow(
+ "--memory ",
+ );
+ expect(command.core.memory.calls).toEqual([]);
+ });
+});
+
+describe("memory session commands", () => {
+ test("lists an actor's sessions with pagination options", async () => {
+ const response: ListSessionsOutput = {
+ sessionSummaries: [sessionSummary],
+ nextToken: "page-3",
+ };
+ const core = new TestCoreClient();
+ core.memory.setListSessionsResponse(response, "page-2");
+ const command = testMemoryCommand(core);
+
+ await command.route([
+ "memory",
+ "session",
+ "list",
+ "--memory",
+ EVENT_MEMORY_ID,
+ "--actor-id",
+ ACTOR_ID,
+ "--max-results",
+ "1",
+ "--next-token",
+ "page-2",
+ ]);
+
+ expect(core.memory.calls).toEqual([
+ {
+ method: "listSessions",
+ args: [
+ {
+ memoryId: EVENT_MEMORY_ID,
+ actorId: ACTOR_ID,
+ maxResults: 1,
+ nextToken: "page-2",
+ },
+ { region: REGION },
+ ],
+ },
+ ]);
+ expect(JSON.parse(command.stdout())).toEqual(JSON.parse(JSON.stringify(response)));
+ });
+
+ test.each([
+ ["memory", ["--json"], "--memory "],
+ ["actor", ["--memory", EVENT_MEMORY_ID, "--json"], "--actor-id "],
+ ] as const)("rejects a missing %s selector for session list", async (_name, flags, expected) => {
+ const command = testMemoryCommand();
+
+ await expect(command.route(["memory", "session", "list", ...flags])).rejects.toThrow(expected);
+ expect(command.core.memory.calls).toEqual([]);
+ });
+});
+
describe("memory record commands", () => {
test("gets a record and renders the response unchanged", async () => {
const response: GetMemoryRecordOutput = { memoryRecord };
diff --git a/src/handlers/memory/session/index.tsx b/src/handlers/memory/session/index.tsx
new file mode 100644
index 000000000..fd6624ba6
--- /dev/null
+++ b/src/handlers/memory/session/index.tsx
@@ -0,0 +1,11 @@
+import { Router } from "../../../router";
+import { renderTui } from "../../../tui";
+import type { AppIO } from "../../../io";
+import type { Core } from "../../types";
+import { createListMemorySessionsHandler } from "./list";
+
+export function createMemorySessionHandler(core: Core, io: AppIO): Router {
+ return new Router("session", "inspect sessions in AgentCore Memories")
+ .default(renderTui(core, io))
+ .handler(createListMemorySessionsHandler(core));
+}
diff --git a/src/handlers/memory/session/list/index.tsx b/src/handlers/memory/session/list/index.tsx
new file mode 100644
index 000000000..511b7bf99
--- /dev/null
+++ b/src/handlers/memory/session/list/index.tsx
@@ -0,0 +1,38 @@
+import z from "zod";
+import { InputValidationError } from "../../../../errors";
+import { createHandler, flag } from "../../../../router";
+import { JsonRendererKey } from "../../../../tui";
+import type { Core } from "../../../types";
+import { coreOptsFromCtx } from "../../../utils";
+
+export const createListMemorySessionsHandler = (core: Core) =>
+ createHandler({
+ name: "list",
+ description: "list sessions in an AgentCore Memory",
+ flags: [
+ flag("memory", "the ID of the Memory", z.string().optional()),
+ flag("actor-id", "the ID of the actor", z.string().optional()),
+ flag("max-results", "maximum number of sessions to return", z.number().optional()),
+ flag("next-token", "pagination token returned by a previous request", z.string().optional()),
+ ],
+ handle: async (ctx, flags) => {
+ if (!flags.memory) {
+ throw new InputValidationError("required option '--memory ' not specified");
+ }
+ if (!flags["actor-id"]) {
+ throw new InputValidationError("required option '--actor-id ' not specified");
+ }
+
+ const response = await core.memory.listSessions(
+ {
+ memoryId: flags.memory,
+ actorId: flags["actor-id"],
+ maxResults: flags["max-results"],
+ nextToken: flags["next-token"],
+ },
+ coreOptsFromCtx(ctx),
+ );
+
+ ctx.require(JsonRendererKey).renderJson(response);
+ },
+ });
diff --git a/src/handlers/memory/session/list/screen.tsx b/src/handlers/memory/session/list/screen.tsx
new file mode 100644
index 000000000..e6658ce3d
--- /dev/null
+++ b/src/handlers/memory/session/list/screen.tsx
@@ -0,0 +1,53 @@
+import { useNavigate, useParams } from "react-router";
+import { MemoryPicker } from "../../../../components/MemoryPicker";
+import type { ScreenProps } from "../../../types";
+import { MemoryActorPicker, MemorySessionPicker } from "../../listPickers";
+
+export function MemorySessionListScreen(props: ScreenProps) {
+ const navigate = useNavigate();
+ const { memoryId, actorId } = useParams();
+
+ if (!memoryId) {
+ return (
+ navigate(`/agentcore/memory/session/list/${encodeURIComponent(id)}`)}
+ />
+ );
+ }
+
+ if (!actorId) {
+ return (
+
+ navigate(
+ `/agentcore/memory/session/list/${encodeURIComponent(memoryId)}/${encodeURIComponent(id)}`,
+ )
+ }
+ onBack={() => navigate(-1)}
+ />
+ );
+ }
+
+ return (
+
+ navigate(
+ `/agentcore/memory/event/list/${encodeURIComponent(memoryId)}/${encodeURIComponent(actorId)}/${encodeURIComponent(id)}`,
+ )
+ }
+ onBack={() => navigate(-1)}
+ />
+ );
+}
diff --git a/src/handlers/memory/session/screen.tsx b/src/handlers/memory/session/screen.tsx
new file mode 100644
index 000000000..45d94202f
--- /dev/null
+++ b/src/handlers/memory/session/screen.tsx
@@ -0,0 +1,6 @@
+import { RouterScreen } from "../../../components/RouterScreen";
+import type { ScreenProps } from "../../types";
+
+export function MemorySessionScreen(props: ScreenProps) {
+ return ;
+}
diff --git a/src/handlers/memory/session/session.screen.test.tsx b/src/handlers/memory/session/session.screen.test.tsx
new file mode 100644
index 000000000..91782f1b0
--- /dev/null
+++ b/src/handlers/memory/session/session.screen.test.tsx
@@ -0,0 +1,69 @@
+import { afterEach, describe, expect, test } from "bun:test";
+import type { Event, SessionSummary } from "@aws-sdk/client-bedrock-agentcore";
+import { cleanupScreens, renderScreen, TestCoreClient, waitForText } from "../../../testing";
+
+afterEach(cleanupScreens);
+
+function session(overrides: Partial = {}): SessionSummary {
+ return {
+ sessionId: "session-1",
+ actorId: "actor-1",
+ createdAt: new Date("2026-08-02T10:20:30.000Z"),
+ ...overrides,
+ };
+}
+
+function event(overrides: Partial = {}): Event {
+ return {
+ memoryId: "memory-1",
+ actorId: "actor-1",
+ sessionId: "session-1",
+ eventId: "event-1",
+ eventTimestamp: new Date("2026-08-03T12:34:56.000Z"),
+ payload: [],
+ ...overrides,
+ };
+}
+
+describe("Memory session list flow", () => {
+ test("renders session details and opens the selected session's events", async () => {
+ const memoryId = "memory-1";
+ const actorId = "actor-1";
+ const sessionId = "session blue";
+ const core = new TestCoreClient();
+ core.memory.setListSessionsResponse({
+ sessionSummaries: [session({ actorId, sessionId })],
+ });
+ core.memory.setListEventsResponse({
+ events: [event({ memoryId, actorId, sessionId })],
+ });
+ const screen = renderScreen(`/agentcore/memory/session/list/${memoryId}/${actorId}`, { core });
+
+ await waitForText(screen.lastFrame, sessionId);
+ const frame = screen.lastFrame()!;
+ expect(frame).toContain("session id");
+ expect(frame).toContain("created UTC");
+ expect(frame).toContain("2026-08-02 10:20");
+
+ await screen.press("return");
+ await waitForText(screen.lastFrame, "event-1");
+ await screen.press("escape");
+ await waitForText(screen.lastFrame, "choose a session to list events for");
+ });
+
+ test("shows empty and retry states for session lists", async () => {
+ const empty = renderScreen("/agentcore/memory/session/list/memory-1/actor-1");
+ await waitForText(empty.lastFrame, "No sessions found for actor actor-1.");
+ empty.unmount();
+
+ const core = new TestCoreClient();
+ core.memory.setError(new Error("sessions unavailable"));
+ const failed = renderScreen("/agentcore/memory/session/list/memory-1/actor-1", { core });
+
+ await waitForText(failed.lastFrame, "sessions unavailable");
+ core.memory.setError(undefined);
+ core.memory.setListSessionsResponse({ sessionSummaries: [session()] });
+ await failed.write("r");
+ await waitForText(failed.lastFrame, "session-1");
+ });
+});