@keyoku/openclaw 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capture.d.ts +23 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +114 -0
- package/dist/capture.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +71 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +19 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +22 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +136 -0
- package/dist/context.js.map +1 -0
- package/dist/heartbeat-setup.d.ts +10 -0
- package/dist/heartbeat-setup.d.ts.map +1 -0
- package/dist/heartbeat-setup.js +49 -0
- package/dist/heartbeat-setup.js.map +1 -0
- package/dist/hooks.d.ts +10 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +152 -0
- package/dist/hooks.js.map +1 -0
- package/dist/incremental-capture.d.ts +24 -0
- package/dist/incremental-capture.d.ts.map +1 -0
- package/dist/incremental-capture.js +81 -0
- package/dist/incremental-capture.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/migration.d.ts +29 -0
- package/dist/migration.d.ts.map +1 -0
- package/dist/migration.js +203 -0
- package/dist/migration.js.map +1 -0
- package/dist/service.d.ts +7 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +133 -0
- package/dist/service.js.map +1 -0
- package/dist/tools.d.ts +11 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +188 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +31 -0
- package/src/capture.ts +116 -0
- package/src/cli.ts +95 -0
- package/src/config.ts +43 -0
- package/src/context.ts +164 -0
- package/src/heartbeat-setup.ts +53 -0
- package/src/hooks.ts +175 -0
- package/src/incremental-capture.ts +88 -0
- package/src/index.ts +68 -0
- package/src/migration.ts +241 -0
- package/src/service.ts +145 -0
- package/src/tools.ts +239 -0
- package/src/types.ts +40 -0
- package/test/capture.test.ts +139 -0
- package/test/context.test.ts +273 -0
- package/test/hooks.test.ts +137 -0
- package/test/tools.test.ts +174 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { registerTools } from '../src/tools.js';
|
|
3
|
+
import type { PluginApi, AgentTool } from '../src/types.js';
|
|
4
|
+
|
|
5
|
+
// Mock KeyokuClient
|
|
6
|
+
function createMockClient() {
|
|
7
|
+
return {
|
|
8
|
+
search: vi.fn(),
|
|
9
|
+
remember: vi.fn(),
|
|
10
|
+
getMemory: vi.fn(),
|
|
11
|
+
deleteMemory: vi.fn(),
|
|
12
|
+
getStats: vi.fn(),
|
|
13
|
+
createSchedule: vi.fn(),
|
|
14
|
+
listSchedules: vi.fn(),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createMockApi() {
|
|
19
|
+
const tools: Record<string, AgentTool> = {};
|
|
20
|
+
return {
|
|
21
|
+
api: {
|
|
22
|
+
id: 'test',
|
|
23
|
+
name: 'test',
|
|
24
|
+
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
25
|
+
registerTool: vi.fn((tool: AgentTool, opts?: { name?: string }) => {
|
|
26
|
+
tools[opts?.name ?? tool.name] = tool;
|
|
27
|
+
}),
|
|
28
|
+
registerHook: vi.fn(),
|
|
29
|
+
registerCli: vi.fn(),
|
|
30
|
+
registerService: vi.fn(),
|
|
31
|
+
resolvePath: (p: string) => p,
|
|
32
|
+
on: vi.fn(),
|
|
33
|
+
} as unknown as PluginApi,
|
|
34
|
+
tools,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
describe('tools', () => {
|
|
39
|
+
let mockClient: ReturnType<typeof createMockClient>;
|
|
40
|
+
let mockApi: ReturnType<typeof createMockApi>;
|
|
41
|
+
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
mockClient = createMockClient();
|
|
44
|
+
mockApi = createMockApi();
|
|
45
|
+
registerTools(mockApi.api, mockClient as any, 'entity-1', 'agent-1');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('registers 7 tools', () => {
|
|
49
|
+
expect(mockApi.api.registerTool).toHaveBeenCalledTimes(7);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('memory_search', () => {
|
|
53
|
+
it('searches and formats results', async () => {
|
|
54
|
+
mockClient.search.mockResolvedValue([
|
|
55
|
+
{ memory: { id: 'm1', content: 'Likes TypeScript' }, similarity: 0.92, score: 0.85 },
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
const tool = mockApi.tools['memory_search'];
|
|
59
|
+
const result = await tool.execute('call-1', { query: 'preferences' });
|
|
60
|
+
|
|
61
|
+
expect(mockClient.search).toHaveBeenCalledWith('entity-1', 'preferences', { limit: 5, min_score: 0.1 });
|
|
62
|
+
const parsed = JSON.parse(result.content[0].text);
|
|
63
|
+
expect(parsed.results[0].snippet).toBe('Likes TypeScript');
|
|
64
|
+
expect(parsed.results[0].score).toBe(0.92);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('handles no results', async () => {
|
|
68
|
+
mockClient.search.mockResolvedValue([]);
|
|
69
|
+
|
|
70
|
+
const tool = mockApi.tools['memory_search'];
|
|
71
|
+
const result = await tool.execute('call-1', { query: 'nothing' });
|
|
72
|
+
|
|
73
|
+
const parsed = JSON.parse(result.content[0].text);
|
|
74
|
+
expect(parsed.results).toEqual([]);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('respects maxResults parameter', async () => {
|
|
78
|
+
mockClient.search.mockResolvedValue([]);
|
|
79
|
+
|
|
80
|
+
const tool = mockApi.tools['memory_search'];
|
|
81
|
+
await tool.execute('call-1', { query: 'test', maxResults: 10 });
|
|
82
|
+
|
|
83
|
+
expect(mockClient.search).toHaveBeenCalledWith('entity-1', 'test', { limit: 10, min_score: 0.1 });
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('memory_store', () => {
|
|
88
|
+
it('stores memory and returns confirmation', async () => {
|
|
89
|
+
mockClient.remember.mockResolvedValue({ memories_created: 1 });
|
|
90
|
+
|
|
91
|
+
const tool = mockApi.tools['memory_store'];
|
|
92
|
+
const result = await tool.execute('call-1', { text: 'User prefers dark mode' });
|
|
93
|
+
|
|
94
|
+
expect(mockClient.remember).toHaveBeenCalledWith(
|
|
95
|
+
'entity-1',
|
|
96
|
+
'User prefers dark mode',
|
|
97
|
+
{ agent_id: 'agent-1' },
|
|
98
|
+
);
|
|
99
|
+
expect(result.content[0].text).toContain('Stored');
|
|
100
|
+
expect(result.content[0].text).toContain('dark mode');
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('memory_forget', () => {
|
|
105
|
+
it('deletes memory by ID', async () => {
|
|
106
|
+
mockClient.deleteMemory.mockResolvedValue({ status: 'deleted' });
|
|
107
|
+
|
|
108
|
+
const tool = mockApi.tools['memory_forget'];
|
|
109
|
+
const result = await tool.execute('call-1', { memory_id: 'm1' });
|
|
110
|
+
|
|
111
|
+
expect(mockClient.deleteMemory).toHaveBeenCalledWith('m1');
|
|
112
|
+
expect(result.content[0].text).toContain('deleted');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('memory_stats', () => {
|
|
117
|
+
it('returns formatted stats', async () => {
|
|
118
|
+
mockClient.getStats.mockResolvedValue({
|
|
119
|
+
total_memories: 42,
|
|
120
|
+
active_memories: 30,
|
|
121
|
+
by_type: { fact: 20, preference: 10 },
|
|
122
|
+
by_state: { active: 30, archived: 12 },
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const tool = mockApi.tools['memory_stats'];
|
|
126
|
+
const result = await tool.execute('call-1', {});
|
|
127
|
+
|
|
128
|
+
expect(result.content[0].text).toContain('Total memories: 42');
|
|
129
|
+
expect(result.content[0].text).toContain('Active memories: 30');
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe('schedule_create', () => {
|
|
134
|
+
it('creates schedule with correct params', async () => {
|
|
135
|
+
mockClient.createSchedule.mockResolvedValue({ id: 's1' });
|
|
136
|
+
|
|
137
|
+
const tool = mockApi.tools['schedule_create'];
|
|
138
|
+
const result = await tool.execute('call-1', {
|
|
139
|
+
content: 'Daily standup',
|
|
140
|
+
cron_tag: 'daily',
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
expect(mockClient.createSchedule).toHaveBeenCalledWith(
|
|
144
|
+
'entity-1', 'agent-1', 'Daily standup', 'daily',
|
|
145
|
+
);
|
|
146
|
+
expect(result.content[0].text).toContain('Scheduled');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('schedule_list', () => {
|
|
151
|
+
it('lists schedules', async () => {
|
|
152
|
+
mockClient.listSchedules.mockResolvedValue([
|
|
153
|
+
{ id: 's1', content: 'Daily standup' },
|
|
154
|
+
{ id: 's2', content: 'Weekly review' },
|
|
155
|
+
]);
|
|
156
|
+
|
|
157
|
+
const tool = mockApi.tools['schedule_list'];
|
|
158
|
+
const result = await tool.execute('call-1', {});
|
|
159
|
+
|
|
160
|
+
expect(result.content[0].text).toContain('2 schedules');
|
|
161
|
+
expect(result.content[0].text).toContain('Daily standup');
|
|
162
|
+
expect(result.content[0].text).toContain('Weekly review');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('handles no schedules', async () => {
|
|
166
|
+
mockClient.listSchedules.mockResolvedValue([]);
|
|
167
|
+
|
|
168
|
+
const tool = mockApi.tools['schedule_list'];
|
|
169
|
+
const result = await tool.execute('call-1', {});
|
|
170
|
+
|
|
171
|
+
expect(result.content[0].text).toBe('No active schedules.');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
});
|