@mojoaar/opencode-mimir 0.19.0 → 0.21.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/index.js +2 -1
- package/dist/tools.js +60 -1
- package/package.json +1 -1
- package/src/index.ts +2 -1
- package/src/tools.ts +69 -1
package/dist/index.js
CHANGED
|
@@ -12,7 +12,8 @@ export const NUDGE_HEADER = '## Memory check (Mimir)\n\n';
|
|
|
12
12
|
*/
|
|
13
13
|
const NUDGE_EVERY = 20;
|
|
14
14
|
const NUDGE = 'If this session settled a decision, a convention or a gotcha that is not in Mimir yet, ' +
|
|
15
|
-
'call memory_write now at one clear path,
|
|
15
|
+
'call memory_write now at one clear path, or hand the conversation over with mimir_learn, ' +
|
|
16
|
+
'before the detail is compacted away.';
|
|
16
17
|
/**
|
|
17
18
|
* One injection point and two tools. The hook is what puts the project's
|
|
18
19
|
* digest in front of the model before the first turn, so a session starts
|
package/dist/tools.js
CHANGED
|
@@ -12,6 +12,8 @@ export async function registerTools(ctx, config, repo) {
|
|
|
12
12
|
return ctx.tool.transform((editor) => {
|
|
13
13
|
editor.add(digestTool(repo));
|
|
14
14
|
editor.add(rememberTool(repo));
|
|
15
|
+
editor.add(searchTool(repo));
|
|
16
|
+
editor.add(learnTool(repo));
|
|
15
17
|
});
|
|
16
18
|
}
|
|
17
19
|
const IDLE = { dispose: async () => { } };
|
|
@@ -70,7 +72,10 @@ function rememberTool(repo) {
|
|
|
70
72
|
properties: {
|
|
71
73
|
path: { type: 'string', description: 'Slash-separated memory path, e.g. deploy/rollback' },
|
|
72
74
|
body: { type: 'string', description: 'What to remember, written so it reads without the conversation' },
|
|
73
|
-
kind: {
|
|
75
|
+
kind: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
enum: ['note', 'fact', 'decision', 'gotcha', 'procedure', 'snippet', 'import'],
|
|
78
|
+
},
|
|
74
79
|
},
|
|
75
80
|
required: ['path', 'body'],
|
|
76
81
|
additionalProperties: false,
|
|
@@ -84,3 +89,57 @@ function rememberTool(repo) {
|
|
|
84
89
|
},
|
|
85
90
|
};
|
|
86
91
|
}
|
|
92
|
+
function searchTool(repo) {
|
|
93
|
+
return {
|
|
94
|
+
name: 'mimir_search',
|
|
95
|
+
description: 'Search what this project has already settled in Mimir. Returns paths, titles and summaries; read a path with the MCP server if you need the body.',
|
|
96
|
+
input: {
|
|
97
|
+
type: 'object',
|
|
98
|
+
properties: {
|
|
99
|
+
query: { type: 'string', description: 'What to look for, in plain words' },
|
|
100
|
+
path_prefix: { type: 'string', description: 'Scope to a directory, e.g. auth' },
|
|
101
|
+
},
|
|
102
|
+
required: ['query'],
|
|
103
|
+
additionalProperties: false,
|
|
104
|
+
},
|
|
105
|
+
async execute(input) {
|
|
106
|
+
const result = await callTool('memory_search', { query: input?.query, path_prefix: input?.path_prefix, repo: repo ?? undefined }, { timeoutMs: 8000 });
|
|
107
|
+
if (!result.ok)
|
|
108
|
+
return { content: `Mimir is unavailable (${result.error}). Carry on without it.` };
|
|
109
|
+
const hits = result.result;
|
|
110
|
+
if (!Array.isArray(hits) || hits.length === 0)
|
|
111
|
+
return { content: 'Nothing matches that in Mimir.' };
|
|
112
|
+
return {
|
|
113
|
+
content: hits
|
|
114
|
+
.map((hit) => `${hit.path}\n${hit.summary ?? hit.title}`)
|
|
115
|
+
.join('\n\n'),
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function learnTool(repo) {
|
|
121
|
+
return {
|
|
122
|
+
name: 'mimir_learn',
|
|
123
|
+
description: 'Hand the part of this conversation worth keeping to Mimir. The project model writes at most three memories, in the background, so this answers at once.',
|
|
124
|
+
input: {
|
|
125
|
+
type: 'object',
|
|
126
|
+
properties: {
|
|
127
|
+
transcript: { type: 'string', description: 'The conversation excerpt, verbatim. Up to 32 KB.' },
|
|
128
|
+
hint: { type: 'string', description: 'What to look for, e.g. "the deploy rollback"' },
|
|
129
|
+
},
|
|
130
|
+
required: ['transcript'],
|
|
131
|
+
additionalProperties: false,
|
|
132
|
+
},
|
|
133
|
+
async execute(input) {
|
|
134
|
+
const result = await callTool('memory_learn', { transcript: input?.transcript, hint: input?.hint, repo: repo ?? undefined }, { timeoutMs: 8000 });
|
|
135
|
+
if (!result.ok)
|
|
136
|
+
return { content: `Could not hand that over (${result.error}).` };
|
|
137
|
+
const queued = result.result;
|
|
138
|
+
return {
|
|
139
|
+
content: queued.queued
|
|
140
|
+
? 'Queued. The model writes the memories in the background.'
|
|
141
|
+
: 'Mimir took no job: its queue is not running.',
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -15,7 +15,8 @@ export const NUDGE_HEADER = '## Memory check (Mimir)\n\n'
|
|
|
15
15
|
const NUDGE_EVERY = 20
|
|
16
16
|
const NUDGE =
|
|
17
17
|
'If this session settled a decision, a convention or a gotcha that is not in Mimir yet, ' +
|
|
18
|
-
'call memory_write now at one clear path,
|
|
18
|
+
'call memory_write now at one clear path, or hand the conversation over with mimir_learn, ' +
|
|
19
|
+
'before the detail is compacted away.'
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* One injection point and two tools. The hook is what puts the project's
|
package/src/tools.ts
CHANGED
|
@@ -36,6 +36,8 @@ export async function registerTools(
|
|
|
36
36
|
return ctx.tool.transform((editor) => {
|
|
37
37
|
editor.add(digestTool(repo))
|
|
38
38
|
editor.add(rememberTool(repo))
|
|
39
|
+
editor.add(searchTool(repo))
|
|
40
|
+
editor.add(learnTool(repo))
|
|
39
41
|
})
|
|
40
42
|
}
|
|
41
43
|
|
|
@@ -104,7 +106,10 @@ function rememberTool(repo: string | null): ToolDefinition {
|
|
|
104
106
|
properties: {
|
|
105
107
|
path: { type: 'string', description: 'Slash-separated memory path, e.g. deploy/rollback' },
|
|
106
108
|
body: { type: 'string', description: 'What to remember, written so it reads without the conversation' },
|
|
107
|
-
kind: {
|
|
109
|
+
kind: {
|
|
110
|
+
type: 'string',
|
|
111
|
+
enum: ['note', 'fact', 'decision', 'gotcha', 'procedure', 'snippet', 'import'],
|
|
112
|
+
},
|
|
108
113
|
},
|
|
109
114
|
required: ['path', 'body'],
|
|
110
115
|
additionalProperties: false,
|
|
@@ -121,3 +126,66 @@ function rememberTool(repo: string | null): ToolDefinition {
|
|
|
121
126
|
},
|
|
122
127
|
}
|
|
123
128
|
}
|
|
129
|
+
|
|
130
|
+
function searchTool(repo: string | null): ToolDefinition {
|
|
131
|
+
return {
|
|
132
|
+
name: 'mimir_search',
|
|
133
|
+
description:
|
|
134
|
+
'Search what this project has already settled in Mimir. Returns paths, titles and summaries; read a path with the MCP server if you need the body.',
|
|
135
|
+
input: {
|
|
136
|
+
type: 'object',
|
|
137
|
+
properties: {
|
|
138
|
+
query: { type: 'string', description: 'What to look for, in plain words' },
|
|
139
|
+
path_prefix: { type: 'string', description: 'Scope to a directory, e.g. auth' },
|
|
140
|
+
},
|
|
141
|
+
required: ['query'],
|
|
142
|
+
additionalProperties: false,
|
|
143
|
+
},
|
|
144
|
+
async execute(input) {
|
|
145
|
+
const result = await callTool(
|
|
146
|
+
'memory_search',
|
|
147
|
+
{ query: input?.query, path_prefix: input?.path_prefix, repo: repo ?? undefined },
|
|
148
|
+
{ timeoutMs: 8000 },
|
|
149
|
+
)
|
|
150
|
+
if (!result.ok) return { content: `Mimir is unavailable (${result.error}). Carry on without it.` }
|
|
151
|
+
const hits = result.result as { path: string; title: string; summary: string | null }[]
|
|
152
|
+
if (!Array.isArray(hits) || hits.length === 0) return { content: 'Nothing matches that in Mimir.' }
|
|
153
|
+
return {
|
|
154
|
+
content: hits
|
|
155
|
+
.map((hit) => `${hit.path}\n${hit.summary ?? hit.title}`)
|
|
156
|
+
.join('\n\n'),
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function learnTool(repo: string | null): ToolDefinition {
|
|
163
|
+
return {
|
|
164
|
+
name: 'mimir_learn',
|
|
165
|
+
description:
|
|
166
|
+
'Hand the part of this conversation worth keeping to Mimir. The project model writes at most three memories, in the background, so this answers at once.',
|
|
167
|
+
input: {
|
|
168
|
+
type: 'object',
|
|
169
|
+
properties: {
|
|
170
|
+
transcript: { type: 'string', description: 'The conversation excerpt, verbatim. Up to 32 KB.' },
|
|
171
|
+
hint: { type: 'string', description: 'What to look for, e.g. "the deploy rollback"' },
|
|
172
|
+
},
|
|
173
|
+
required: ['transcript'],
|
|
174
|
+
additionalProperties: false,
|
|
175
|
+
},
|
|
176
|
+
async execute(input) {
|
|
177
|
+
const result = await callTool(
|
|
178
|
+
'memory_learn',
|
|
179
|
+
{ transcript: input?.transcript, hint: input?.hint, repo: repo ?? undefined },
|
|
180
|
+
{ timeoutMs: 8000 },
|
|
181
|
+
)
|
|
182
|
+
if (!result.ok) return { content: `Could not hand that over (${result.error}).` }
|
|
183
|
+
const queued = result.result as { queued?: boolean }
|
|
184
|
+
return {
|
|
185
|
+
content: queued.queued
|
|
186
|
+
? 'Queued. The model writes the memories in the background.'
|
|
187
|
+
: 'Mimir took no job: its queue is not running.',
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
}
|
|
191
|
+
}
|