feat(memory): bind operator plugin to agent sessions #739
@@ -12,18 +12,24 @@ type AgentServiceInternals = {
|
||||
creating: Map<string, Promise<AgentSession>>;
|
||||
};
|
||||
|
||||
function makeService(): AgentService {
|
||||
function makeService(operatorMemory: unknown = null): AgentService {
|
||||
return new AgentService(
|
||||
{} as never,
|
||||
{
|
||||
getDefaultModel: vi.fn(() => null),
|
||||
getRegistry: vi.fn(() => ({})),
|
||||
findModel: vi.fn(),
|
||||
listAvailableModels: vi.fn(() => []),
|
||||
} as never,
|
||||
{} as never,
|
||||
{} as never,
|
||||
{ available: false } as never,
|
||||
{} as never,
|
||||
{} as never,
|
||||
{} as never,
|
||||
{ getToolDefinitions: vi.fn(() => []) } as never,
|
||||
{ loadForSession: vi.fn(async () => ({ metaTools: [], promptAdditions: [] })) } as never,
|
||||
null,
|
||||
null,
|
||||
{ collect: vi.fn().mockResolvedValue(undefined) } as never,
|
||||
operatorMemory as never,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -120,6 +126,37 @@ describe('AgentService owner/tenant scope enforcement', () => {
|
||||
expect(internals(service).sessions.has(CONVERSATION_ID)).toBe(false);
|
||||
});
|
||||
|
||||
it('derives the operator-memory scope on the createSession production path', async () => {
|
||||
const plugin = { capture: vi.fn(), search: vi.fn() };
|
||||
const service = makeService(plugin);
|
||||
const buildTools = vi.spyOn(service as never, 'buildToolsForSandbox').mockReturnValue([]);
|
||||
|
||||
// Session construction reaches the real scope derivation before the intentionally incomplete
|
||||
// Pi test double rejects later in createAgentSession.
|
||||
await service.createSession(CONVERSATION_ID, OWNER_SCOPE).catch(() => undefined);
|
||||
|
||||
expect(buildTools).toHaveBeenCalledWith(expect.any(String), OWNER_SCOPE.userId, {
|
||||
tenantId: OWNER_SCOPE.tenantId,
|
||||
ownerId: OWNER_SCOPE.userId,
|
||||
sessionId: CONVERSATION_ID,
|
||||
});
|
||||
});
|
||||
|
||||
it('denies a foreign actor before it can obtain another session operator-memory scope', async () => {
|
||||
const plugin = { capture: vi.fn(), search: vi.fn() };
|
||||
const service = makeService(plugin);
|
||||
internals(service).sessions.set(CONVERSATION_ID, makeSession());
|
||||
const buildTools = vi.spyOn(service as never, 'buildToolsForSandbox');
|
||||
|
||||
await expect(service.createSession(CONVERSATION_ID, FOREIGN_SCOPE)).rejects.toBeInstanceOf(
|
||||
ForbiddenException,
|
||||
);
|
||||
|
||||
expect(buildTools).not.toHaveBeenCalled();
|
||||
expect(plugin.capture).not.toHaveBeenCalled();
|
||||
expect(plugin.search).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('checks owner/tenant scope before returning an in-flight session creation', async () => {
|
||||
const service = makeService();
|
||||
const session = makeSession();
|
||||
|
||||
Reference in New Issue
Block a user