feat: port holistic node refinement contract

This commit is contained in:
“BeeRad”
2026-04-11 21:37:52 +10:00
parent 35f9ecf89c
commit 3ae46245ec
119 changed files with 6596 additions and 10982 deletions
+86
View File
@@ -0,0 +1,86 @@
import { describe, expect, it, vi } from 'vitest';
vi.mock('@/services/database/nodes', () => ({
nodeService: {
getNodeById: vi.fn(),
},
}));
vi.mock('@/services/database/edges', () => ({
edgeService: {
edgeExists: vi.fn(),
createEdge: vi.fn(),
},
}));
import { nodeService } from '@/services/database/nodes';
import { edgeService } from '@/services/database/edges';
import { createEdgeTool } from '@/tools/database/createEdge';
// Helper to call tool execute with proper AI SDK signature
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const executeCreateEdge = async (params: any) => {
const result = await createEdgeTool.execute!(params, { toolCallId: 'test', messages: [] });
return result as { success: boolean; error?: string; data?: { id: number } };
};
describe('createEdgeTool', () => {
it('rejects invalid from_node_id', async () => {
const result = await executeCreateEdge({
from_node_id: 0,
to_node_id: 2,
source: 'ai',
});
expect(result.success).toBe(false);
expect(result.error).toMatch(/from_node_id/);
});
it('returns error when edge already exists', async () => {
vi.mocked(nodeService.getNodeById).mockResolvedValueOnce({
id: 1, title: 'From', created_at: '', updated_at: ''
});
vi.mocked(nodeService.getNodeById).mockResolvedValueOnce({
id: 2, title: 'To', created_at: '', updated_at: ''
});
vi.mocked(edgeService.edgeExists).mockResolvedValueOnce(true);
const result = await executeCreateEdge({
from_node_id: 1,
to_node_id: 2,
explanation: 'Source node references the target node directly.',
source: 'ai',
});
expect(result.success).toBe(false);
expect(result.error).toMatch(/already exists/i);
});
it('creates edge when valid and not existing', async () => {
vi.mocked(nodeService.getNodeById).mockResolvedValueOnce({
id: 1, title: 'From', created_at: '', updated_at: ''
});
vi.mocked(nodeService.getNodeById).mockResolvedValueOnce({
id: 2, title: 'To', created_at: '', updated_at: ''
});
vi.mocked(edgeService.edgeExists).mockResolvedValueOnce(false);
vi.mocked(edgeService.createEdge).mockResolvedValueOnce({
id: 10,
from_node_id: 1,
to_node_id: 2,
source: 'helper_name',
context: {},
created_at: '',
});
const result = await executeCreateEdge({
from_node_id: 1,
to_node_id: 2,
explanation: 'Episode belongs to the podcast represented by the target node.',
source: 'ai',
});
expect(result.success).toBe(true);
expect(result.data?.id).toBe(10);
});
});
+71
View File
@@ -0,0 +1,71 @@
import { describe, expect, it, vi, beforeEach } from 'vitest';
import { createNodeTool } from '@/tools/database/createNode';
const fetchMock = vi.fn();
global.fetch = fetchMock as typeof fetch;
// Helper to call tool execute with proper AI SDK signature
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const executeCreateNode = async (params: any) => {
const result = await createNodeTool.execute!(params, { toolCallId: 'test', messages: [] });
return result as { success: boolean; error?: string; data?: { formatted_display: string } };
};
describe('createNodeTool', () => {
beforeEach(() => {
fetchMock.mockReset();
});
it('creates nodes without requiring dimensions', async () => {
fetchMock.mockResolvedValueOnce({
ok: true,
json: async () => ({
data: { id: 1, title: 'Test' },
}),
});
const result = await executeCreateNode({
title: 'Test',
description: 'Note capturing a concrete test artifact and why it matters.',
});
expect(result.success).toBe(true);
expect(fetchMock).toHaveBeenCalled();
expect(JSON.parse(fetchMock.mock.calls[0][1].body as string)).not.toHaveProperty('dimensions');
expect(result.data?.formatted_display).toContain('[NODE:1');
});
it('returns error when API fails', async () => {
fetchMock.mockResolvedValueOnce({
ok: false,
json: async () => ({ error: 'Failed' }),
});
const result = await executeCreateNode({
title: 'Bad',
description: 'Note capturing a failing API case and why the error matters.',
});
expect(result.success).toBe(false);
expect(result.error).toContain('Failed');
});
it('accepts explicit test node descriptions', async () => {
fetchMock.mockResolvedValueOnce({
ok: true,
json: async () => ({
data: { id: 2, title: 'Eval Edge B' },
}),
});
const result = await executeCreateNode({
title: 'Eval Edge B',
description: 'This is a test node used as the target in an evaluation of edge creation. It matters because it verifies relationship storage and retrieval.',
});
expect(result.success).toBe(true);
expect(fetchMock).toHaveBeenCalledOnce();
});
});
+92
View File
@@ -0,0 +1,92 @@
import { describe, expect, it, vi } from 'vitest';
vi.mock('@/services/database/edges', () => ({
edgeService: {
getEdgeById: vi.fn(),
getNodeConnections: vi.fn(),
getEdges: vi.fn(),
},
}));
import { edgeService } from '@/services/database/edges';
import { queryEdgeTool } from '@/tools/database/queryEdge';
// Helper to call tool execute with proper AI SDK signature
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const executeQueryEdge = async (params: any) => {
const result = await queryEdgeTool.execute!(params, { toolCallId: 'test', messages: [] });
return result as { success: boolean; data?: { edges: any[]; connections?: any[] } };
};
describe('queryEdgeTool', () => {
it('returns empty list when no edges for from_node_id', async () => {
vi.mocked(edgeService.getEdges).mockResolvedValueOnce([]);
const result = await executeQueryEdge({ filters: { from_node_id: 1, limit: 10 } });
expect(result.success).toBe(true);
expect(result.data?.edges).toHaveLength(0);
});
it('returns edges when found for from_node_id', async () => {
vi.mocked(edgeService.getEdges).mockResolvedValueOnce([
{ id: 1, from_node_id: 1, to_node_id: 2, source: 'user', created_at: '' },
]);
const result = await executeQueryEdge({ filters: { from_node_id: 1, limit: 10 } });
expect(result.success).toBe(true);
expect(result.data?.edges).toHaveLength(1);
});
it('returns edge by ID when edge_id provided', async () => {
vi.mocked(edgeService.getEdgeById).mockResolvedValueOnce({
id: 9,
from_node_id: 1,
to_node_id: 2,
source: 'user',
created_at: '',
});
const result = await executeQueryEdge({ filters: { edge_id: 9, limit: 10 } });
expect(result.success).toBe(true);
expect(result.data?.edges).toHaveLength(1);
});
it('returns compact connection payloads for node traversal', async () => {
vi.mocked(edgeService.getNodeConnections).mockResolvedValueOnce([
{
edge: {
id: 42,
from_node_id: 1,
to_node_id: 2,
source: 'user',
created_at: '',
context: {
type: 'related_to',
explanation: 'A'.repeat(300),
confidence: 0.8,
},
},
connected_node: {
id: 2,
title: 'Connected node',
description: 'B'.repeat(250),
notes: 'Hidden notes should not be returned',
chunk: 'Hidden chunk should not be returned',
},
},
] as any);
const result = await executeQueryEdge({ filters: { node_id: 1, limit: 20 } });
expect(result.success).toBe(true);
expect(result.data?.edges).toHaveLength(1);
expect(result.data?.connections).toHaveLength(1);
expect(result.data?.connections?.[0].connected_node.notes).toBeUndefined();
expect(result.data?.connections?.[0].connected_node.chunk).toBeUndefined();
expect(result.data?.connections?.[0].connected_node.description.length).toBeLessThanOrEqual(140);
expect(result.data?.edges?.[0].context.explanation.length).toBeLessThanOrEqual(180);
});
});
+64
View File
@@ -0,0 +1,64 @@
import { describe, expect, it, vi } from 'vitest';
vi.mock('@/services/database/nodes', () => ({
nodeService: {
getNodeById: vi.fn(),
getNodes: vi.fn(),
},
}));
import { nodeService } from '@/services/database/nodes';
import { queryNodesTool } from '@/tools/database/queryNodes';
// Helper to call tool execute with proper AI SDK signature
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const executeQueryNodes = async (params: any) => {
const result = await queryNodesTool.execute!(params, { toolCallId: 'test', messages: [] });
return result as { success: boolean; data?: { nodes: { id: number }[]; count: number } };
};
describe('queryNodesTool', () => {
it('returns a single node when search is numeric and node exists', async () => {
vi.mocked(nodeService.getNodeById).mockResolvedValueOnce({
id: 123,
title: 'Test Node',
created_at: '',
updated_at: '',
});
const result = await executeQueryNodes({
filters: { search: '123', limit: 5 },
});
expect(result.success).toBe(true);
expect(result.data?.nodes).toHaveLength(1);
expect(result.data?.nodes[0].id).toBe(123);
});
it('returns empty when search is numeric and node is missing', async () => {
vi.mocked(nodeService.getNodeById).mockResolvedValueOnce(null);
const result = await executeQueryNodes({
filters: { search: '999', limit: 5 },
});
expect(result.success).toBe(true);
expect(result.data?.nodes).toHaveLength(0);
expect(result.data?.count).toBe(0);
});
it('respects limit and reports total count', async () => {
vi.mocked(nodeService.getNodes).mockResolvedValueOnce([
{ id: 1, title: 'A', created_at: '', updated_at: '' },
{ id: 2, title: 'B', created_at: '', updated_at: '' },
]);
const result = await executeQueryNodes({
filters: { limit: 1 },
});
expect(result.success).toBe(true);
expect(result.data?.nodes).toHaveLength(1);
expect(result.data?.count).toBe(2);
});
});