@matatbread/matbot-triggers 0.2.5 → 0.2.6
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/package.json +3 -3
- package/src/tools.ts +86 -20
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"node",
|
|
5
5
|
"browser"
|
|
6
6
|
],
|
|
7
|
-
"version": "0.2.
|
|
7
|
+
"version": "0.2.6",
|
|
8
8
|
"engines": {
|
|
9
9
|
"node": ">=24.0.0"
|
|
10
10
|
},
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@matatbread/matbot-plugin-api": "^0.2.
|
|
36
|
+
"@matatbread/matbot-plugin-api": "^0.2.6"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"typescript": "^5.8.0",
|
|
40
|
-
"@matatbread/matbot-plugin-api": "^0.2.
|
|
40
|
+
"@matatbread/matbot-plugin-api": "^0.2.6"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"typecheck": "tsc --noEmit"
|
package/src/tools.ts
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
import type { Tool, ToolExecutor,
|
|
1
|
+
import type { Tool, ToolExecutor, ToolResult, ToolResultOf, ToolContext, MatbotMachine } from '@matatbread/matbot-plugin-api';
|
|
2
2
|
import type { TriggerManager } from './manager.js';
|
|
3
|
-
import type { TriggerCondition, TriggerKind } from './types.js';
|
|
3
|
+
import type { TriggerCondition, TriggerKind, Trigger } from './types.js';
|
|
4
|
+
|
|
5
|
+
declare module '@matatbread/matbot-plugin-api' {
|
|
6
|
+
interface ToolResults {
|
|
7
|
+
// One arm per action: a caller of `invokeTool(machine, 'trigger_action', { action: '…' })` gets the
|
|
8
|
+
// matching result narrowed by the `action` it passed (see ToolResult / the multi-action note on ToolResults).
|
|
9
|
+
trigger_action:
|
|
10
|
+
| ToolResult<{ triggers: Trigger[] }, { action: 'list' }>
|
|
11
|
+
| ToolResult<{ triggers: Trigger[] }, { action: 'query' }>
|
|
12
|
+
| ToolResult<Trigger, { action: 'get' }>
|
|
13
|
+
| ToolResult<{ id: string }, { action: 'add' }>
|
|
14
|
+
| ToolResult<Trigger, { action: 'update' }>
|
|
15
|
+
| ToolResult<{ id: string }, { action: 'remove' }>
|
|
16
|
+
| ToolResult<{ triggers: Trigger[] }, { action: 'move' }>
|
|
17
|
+
| ToolResult<{ triggers: Trigger[] }, { action: 'copy' }>;
|
|
18
|
+
triggers_config:
|
|
19
|
+
| ToolResult<{ classifierProvider: string | null; available: string[] }, { action: 'get' }>
|
|
20
|
+
| ToolResult<{ classifierProvider: string }, { action: 'set' }>
|
|
21
|
+
| ToolResult<{ classifierProvider: null }, { action: 'clear' }>;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
4
24
|
|
|
5
25
|
const KINDS: readonly TriggerKind[] = ['ephemeral', 'contextual', 'retract', 'followup'];
|
|
6
26
|
const isKind = (x: unknown): x is TriggerKind => typeof x === 'string' && (KINDS as readonly string[]).includes(x);
|
|
@@ -39,7 +59,17 @@ type TriggerActionInput =
|
|
|
39
59
|
| { action: 'get'; id: string }
|
|
40
60
|
| { action: 'add'; conditions: TriggerCondition[]; tool: string; params?: unknown; enabled?: boolean }
|
|
41
61
|
| { action: 'update'; id: string; conditions?: TriggerCondition[]; tool?: string; params?: unknown; enabled?: boolean }
|
|
42
|
-
| { action: 'remove'; id: string }
|
|
62
|
+
| { action: 'remove'; id: string }
|
|
63
|
+
| { action: 'move'; tool?: string; params?: unknown; toTool: string; toParams?: unknown }
|
|
64
|
+
| { action: 'copy'; tool?: string; params?: unknown; toTool: string; toParams?: unknown };
|
|
65
|
+
|
|
66
|
+
// The query selector shared by query/move/copy: `tool`/`params` narrow the set by what a trigger invokes.
|
|
67
|
+
function queryFilter(a: { tool?: unknown; params?: unknown }): { tool?: string; params?: unknown } {
|
|
68
|
+
return {
|
|
69
|
+
...(typeof a.tool === 'string' ? { tool: a.tool } : {}),
|
|
70
|
+
...(a.params !== undefined ? { params: a.params } : {}),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
43
73
|
|
|
44
74
|
// A condition is valid if it has a recognised `kind` and a string `rule`.
|
|
45
75
|
function validConditions(x: unknown): x is TriggerCondition[] {
|
|
@@ -49,9 +79,9 @@ function validConditions(x: unknown): x is TriggerCondition[] {
|
|
|
49
79
|
typeof (c as { rule?: unknown }).rule === 'string');
|
|
50
80
|
}
|
|
51
81
|
|
|
52
|
-
export function createTriggerActionTool(manager: TriggerManager): Tool {
|
|
53
|
-
const executor: ToolExecutor = {
|
|
54
|
-
async *execute(input: unknown, _ctx: ToolContext)
|
|
82
|
+
export function createTriggerActionTool(manager: TriggerManager): Tool<ToolResultOf<'trigger_action'>> {
|
|
83
|
+
const executor: ToolExecutor<ToolResultOf<'trigger_action'>> = {
|
|
84
|
+
async *execute(input: unknown, _ctx: ToolContext) {
|
|
55
85
|
const args = input as Partial<TriggerActionInput> & { action?: string };
|
|
56
86
|
|
|
57
87
|
switch (args.action) {
|
|
@@ -62,10 +92,7 @@ export function createTriggerActionTool(manager: TriggerManager): Tool {
|
|
|
62
92
|
|
|
63
93
|
case 'query': {
|
|
64
94
|
const a = args as Extract<TriggerActionInput, { action: 'query' }>;
|
|
65
|
-
yield { type: 'result', value: { triggers: manager.query(
|
|
66
|
-
...(typeof a.tool === 'string' ? { tool: a.tool } : {}),
|
|
67
|
-
...(a.params !== undefined ? { params: a.params } : {}),
|
|
68
|
-
}) } };
|
|
95
|
+
yield { type: 'result', value: { triggers: manager.query(queryFilter(a)) } };
|
|
69
96
|
return;
|
|
70
97
|
}
|
|
71
98
|
|
|
@@ -118,8 +145,39 @@ export function createTriggerActionTool(manager: TriggerManager): Tool {
|
|
|
118
145
|
return;
|
|
119
146
|
}
|
|
120
147
|
|
|
148
|
+
case 'move': {
|
|
149
|
+
const a = args as Extract<TriggerActionInput, { action: 'move' }>;
|
|
150
|
+
if (typeof a.toTool !== 'string') { yield { type: 'error', message: 'action "move" requires a string "toTool" to re-target the selected triggers onto.' }; return; }
|
|
151
|
+
if (a.tool === undefined && a.params === undefined) { yield { type: 'error', message: 'action "move" requires a filter ("tool" and/or "params") selecting which triggers to re-target — refusing to move every trigger.' }; return; }
|
|
152
|
+
const invoke = { tool: a.toTool, ...(a.toParams !== undefined ? { params: a.toParams } : {}) };
|
|
153
|
+
const triggers: Trigger[] = [];
|
|
154
|
+
for (const t of manager.query(queryFilter(a))) {
|
|
155
|
+
const updated = await manager.update(t.id, { invoke });
|
|
156
|
+
if (updated !== undefined) triggers.push(updated);
|
|
157
|
+
}
|
|
158
|
+
yield { type: 'result', value: { triggers } };
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
case 'copy': {
|
|
163
|
+
const a = args as Extract<TriggerActionInput, { action: 'copy' }>;
|
|
164
|
+
if (typeof a.toTool !== 'string') { yield { type: 'error', message: 'action "copy" requires a string "toTool" to point the duplicates at.' }; return; }
|
|
165
|
+
if (a.tool === undefined && a.params === undefined) { yield { type: 'error', message: 'action "copy" requires a filter ("tool" and/or "params") selecting which triggers to duplicate — refusing to duplicate every trigger.' }; return; }
|
|
166
|
+
const invoke = { tool: a.toTool, ...(a.toParams !== undefined ? { params: a.toParams } : {}) };
|
|
167
|
+
const triggers: Trigger[] = [];
|
|
168
|
+
for (const t of manager.query(queryFilter(a))) {
|
|
169
|
+
triggers.push(await manager.add({
|
|
170
|
+
conditions: t.conditions,
|
|
171
|
+
invoke,
|
|
172
|
+
...(t.enabled !== undefined ? { enabled: t.enabled } : {}),
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
yield { type: 'result', value: { triggers } };
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
121
179
|
default:
|
|
122
|
-
yield { type: 'error', message: `Unknown action "${String(args.action)}". Expected one of: list, query, get, add, update, remove.` };
|
|
180
|
+
yield { type: 'error', message: `Unknown action "${String(args.action)}". Expected one of: list, query, get, add, update, remove, move, copy.` };
|
|
123
181
|
}
|
|
124
182
|
},
|
|
125
183
|
};
|
|
@@ -129,7 +187,8 @@ export function createTriggerActionTool(manager: TriggerManager): Tool {
|
|
|
129
187
|
description:
|
|
130
188
|
'Manage triggers — data-driven hooks that invoke a tool when an LLM classifier judges one of ' +
|
|
131
189
|
'their conditions matched against the current turn. Use this to list triggers, find the ones ' +
|
|
132
|
-
'that invoke a given tool (query), read one, create one, edit one by id, or
|
|
190
|
+
'that invoke a given tool (query), read one, create one, edit one by id, delete one, or bulk ' +
|
|
191
|
+
're-target a selected set onto a new tool — in place (move) or as duplicates (copy).\n\n' +
|
|
133
192
|
GUIDANCE + '\n\n' +
|
|
134
193
|
'A trigger has a stable `id` — address it by that, never by its conditions. To change one, ' +
|
|
135
194
|
'"get" or "list" first to read the id, then "update" by id.\n\n' +
|
|
@@ -143,18 +202,25 @@ export function createTriggerActionTool(manager: TriggerManager): Tool {
|
|
|
143
202
|
" | { action: 'get'; id: string } // -> the trigger\n" +
|
|
144
203
|
" | { action: 'add'; conditions: TriggerCondition[]; tool: string; params?: object; enabled?: boolean } // -> { id }\n" +
|
|
145
204
|
" | { action: 'update'; id: string; conditions?: TriggerCondition[]; tool?: string; params?: object; enabled?: boolean } // edit by id\n" +
|
|
146
|
-
" | { action: 'remove'; id: string }
|
|
147
|
-
'
|
|
205
|
+
" | { action: 'remove'; id: string } // -> { id }\n" +
|
|
206
|
+
" | { action: 'move'; tool?: string; params?: object; toTool: string; toParams?: object } // re-target the queried set's invoke to toTool/toParams in place -> { triggers: [...] }\n" +
|
|
207
|
+
" | { action: 'copy'; tool?: string; params?: object; toTool: string; toParams?: object }; // duplicate the queried set, the copies invoking toTool/toParams -> { triggers: [...] }\n" +
|
|
208
|
+
'```\n\n' +
|
|
209
|
+
'For `move`/`copy`, `tool`/`params` are the SAME selector as `query` (they pick which triggers ' +
|
|
210
|
+
'to act on); `toTool`/`toParams` are the new invocation. A filter is required — both refuse to ' +
|
|
211
|
+
'act on the entire trigger set.',
|
|
148
212
|
inputSchema: {
|
|
149
213
|
type: 'object',
|
|
150
214
|
required: ['action'],
|
|
151
215
|
properties: {
|
|
152
|
-
action: { type: 'string', enum: ['list', 'query', 'get', 'add', 'update', 'remove'], description: 'The operation to perform.' },
|
|
216
|
+
action: { type: 'string', enum: ['list', 'query', 'get', 'add', 'update', 'remove', 'move', 'copy'], description: 'The operation to perform.' },
|
|
153
217
|
id: { type: 'string', description: 'Trigger id. Required for get/update/remove.' },
|
|
154
218
|
conditions: { type: 'array', description: 'Conditions [{ kind: "ephemeral"|"contextual"|"retract"|"followup", rule: string }]. Required for add.',
|
|
155
219
|
items: { type: 'object', properties: { kind: { type: 'string', enum: ['ephemeral', 'contextual', 'retract', 'followup'] }, rule: { type: 'string' } } } },
|
|
156
|
-
tool: { type: 'string', description: '
|
|
157
|
-
params: { type: 'object', description: '
|
|
220
|
+
tool: { type: 'string', description: 'For add: the tool to invoke. For query/move/copy: the selector matching invoke.tool.' },
|
|
221
|
+
params: { type: 'object', description: 'For add: params passed verbatim as the invoked tool\'s input. For query/move/copy: the selector matching invoke.params.' },
|
|
222
|
+
toTool: { type: 'string', description: 'New tool the selected triggers should invoke. Required for move/copy.' },
|
|
223
|
+
toParams: { type: 'object', description: 'New params for the selected triggers\' invocation (move/copy).' },
|
|
158
224
|
enabled: { type: 'boolean', description: 'Set false to keep but disable the trigger.' },
|
|
159
225
|
},
|
|
160
226
|
},
|
|
@@ -168,10 +234,10 @@ export function createTriggerActionTool(manager: TriggerManager): Tool {
|
|
|
168
234
|
* own provider (so triggers work with zero config); set it to pin a small/fast model. Resolved per
|
|
169
235
|
* evaluation, so a change takes effect on the next turn without a restart.
|
|
170
236
|
*/
|
|
171
|
-
export function createTriggersConfigTool(services: MatbotMachine): Tool {
|
|
237
|
+
export function createTriggersConfigTool(services: MatbotMachine): Tool<ToolResultOf<'triggers_config'>> {
|
|
172
238
|
const KEY = 'classifierProvider';
|
|
173
|
-
const executor: ToolExecutor = {
|
|
174
|
-
async *execute(input: unknown, _ctx: ToolContext)
|
|
239
|
+
const executor: ToolExecutor<ToolResultOf<'triggers_config'>> = {
|
|
240
|
+
async *execute(input: unknown, _ctx: ToolContext) {
|
|
175
241
|
const args = input as { action?: string; provider?: string };
|
|
176
242
|
const settings = services.settings();
|
|
177
243
|
const available = [...services.providers.keys()];
|