@batalabs/virlow-mcp-core 3.84.1 → 3.85.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/cjs/memories.d.ts +3 -0
- package/dist/cjs/memories.js +5 -0
- package/dist/cjs/memory-secrets.d.ts +7 -2
- package/dist/cjs/memory-secrets.js +52 -4
- package/dist/cjs/tool-annotations.d.ts +82 -0
- package/dist/cjs/tool-annotations.js +160 -0
- package/dist/cjs/widgets.d.ts +119 -0
- package/dist/cjs/widgets.js +425 -0
- package/dist/memories.d.ts +3 -0
- package/dist/memories.d.ts.map +1 -1
- package/dist/memories.js +5 -0
- package/dist/memories.js.map +1 -1
- package/dist/memory-secrets.d.ts +7 -2
- package/dist/memory-secrets.d.ts.map +1 -1
- package/dist/memory-secrets.js +52 -4
- package/dist/memory-secrets.js.map +1 -1
- package/dist/tool-annotations.d.ts +83 -0
- package/dist/tool-annotations.d.ts.map +1 -0
- package/dist/tool-annotations.js +156 -0
- package/dist/tool-annotations.js.map +1 -0
- package/dist/tools.d.ts +8 -2
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +186 -63
- package/dist/tools.js.map +1 -1
- package/dist/widgets.d.ts +120 -0
- package/dist/widgets.d.ts.map +1 -0
- package/dist/widgets.js +420 -0
- package/dist/widgets.js.map +1 -0
- package/package.json +3 -3
package/dist/memory-secrets.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Refuses memories that contain credentials,
|
|
2
|
+
* Refuses memories that contain credentials, payment card and bank account
|
|
3
|
+
* numbers, or government ID numbers, before anything is written.
|
|
3
4
|
*
|
|
4
5
|
* Memories are captured automatically, so the rule cannot depend on the AI
|
|
5
6
|
* remembering not to save a key: a memory is encrypted, but it is recalled
|
|
@@ -8,7 +9,11 @@
|
|
|
8
9
|
* left out instead of retrying with the secret reworded.
|
|
9
10
|
*
|
|
10
11
|
* Deliberately narrow: patterns that are credentials with near certainty,
|
|
11
|
-
* plus long high-entropy tokens
|
|
12
|
+
* plus long high-entropy tokens, plus the restricted data that has a shape
|
|
13
|
+
* to match (card numbers and security codes, IBANs and labelled account
|
|
14
|
+
* numbers, US Social Security numbers, labelled passport, licence and
|
|
15
|
+
* national ID numbers). Health information has no such shape; the server
|
|
16
|
+
* instructions tell the model not to save it. A false positive costs one memory; a false
|
|
12
17
|
* negative puts a live key into every future prompt that recalls it.
|
|
13
18
|
*/
|
|
14
19
|
const PATTERNS = [
|
|
@@ -26,7 +31,47 @@ const PATTERNS = [
|
|
|
26
31
|
test: /\b(password|passwd|pwd|passphrase|api[_ -]?key|secret|token)\s*[:=]\s*\S{6,}/i,
|
|
27
32
|
},
|
|
28
33
|
{ what: 'a connection string with a password', test: /\b[a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:[^\s@/]{3,}@/i },
|
|
34
|
+
{ what: 'a card security code', test: /\b(cvv2?|cvc2?|card security code)\s*[:#=]?\s*\d{3,4}\b/i },
|
|
35
|
+
{
|
|
36
|
+
// The issued format: no 000/666/9xx area, no 00 group, no 0000 serial.
|
|
37
|
+
// Phone numbers (3-3-4) and dates (4-2-2) do not take this shape.
|
|
38
|
+
what: 'a Social Security number',
|
|
39
|
+
test: /\b(?!000|666|9\d\d)\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b/,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
what: 'a Social Security number',
|
|
43
|
+
test: /\b(ssn|social security(\s+(number|no\.?|#))?)\b\D{0,20}\d{3}[ -]?\d{2}[ -]?\d{4}\b/i,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
what: 'a bank account number',
|
|
47
|
+
test: /\b((bank\s+)?account|acct|routing)\s*(number|num|no\.?|#)\s*[:#=]?\s*\d[\d -]{4,}\d\b/i,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
// A labelled ID followed by something with a digit in it, so "passport
|
|
51
|
+
// renewal is due in March" is a fact and "passport no. X1234567" is not.
|
|
52
|
+
what: 'a government ID number',
|
|
53
|
+
test: /\b(passport|driver'?s?\s+licen[cs]e|national\s+(id|insurance)|tax\s+(id|identification)|aadhaar|nino)(\s+(number|num|no\.?|#))?\s*[:#=]?\s*(?=[A-Z0-9-]*\d)[A-Z0-9][A-Z0-9-]{4,}\b/i,
|
|
54
|
+
},
|
|
29
55
|
];
|
|
56
|
+
/** An IBAN that passes its ISO 13616 mod-97 check: country code, two check
|
|
57
|
+
* digits, then 11 to 30 letters and digits, spaces allowed in groups of 4. */
|
|
58
|
+
function hasIban(text) {
|
|
59
|
+
for (const [match] of text.matchAll(/\b[A-Z]{2}\d{2}(?: ?[A-Z0-9]){11,30}\b/g)) {
|
|
60
|
+
const iban = match.replace(/ /g, '');
|
|
61
|
+
if (iban.length < 15 || iban.length > 34)
|
|
62
|
+
continue;
|
|
63
|
+
const rearranged = iban.slice(4) + iban.slice(0, 4);
|
|
64
|
+
let remainder = 0;
|
|
65
|
+
for (const ch of rearranged) {
|
|
66
|
+
const value = ch >= 'A' && ch <= 'Z' ? String(ch.charCodeAt(0) - 55) : ch;
|
|
67
|
+
for (const digit of value)
|
|
68
|
+
remainder = (remainder * 10 + Number(digit)) % 97;
|
|
69
|
+
}
|
|
70
|
+
if (remainder === 1)
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
30
75
|
/** Luhn-valid runs of 13 to 19 digits, spaces or dashes allowed. */
|
|
31
76
|
function hasCardNumber(text) {
|
|
32
77
|
for (const match of text.matchAll(/\b(?:\d[ -]?){13,19}\b/g)) {
|
|
@@ -82,14 +127,17 @@ export function findSecret(text) {
|
|
|
82
127
|
}
|
|
83
128
|
if (hasCardNumber(text))
|
|
84
129
|
return 'a card number';
|
|
130
|
+
if (hasIban(text))
|
|
131
|
+
return 'a bank account number';
|
|
85
132
|
if (hasHighEntropyToken(text))
|
|
86
133
|
return 'what looks like a key or token';
|
|
87
134
|
return null;
|
|
88
135
|
}
|
|
89
136
|
export class SecretInMemoryError extends Error {
|
|
90
137
|
constructor(what) {
|
|
91
|
-
super(`Not saved: this memory contains ${what}. Memories are recalled into prompts, so credentials
|
|
92
|
-
'stored. Save the fact without
|
|
138
|
+
super(`Not saved: this memory contains ${what}. Memories are recalled into prompts, so credentials, card and ` +
|
|
139
|
+
'account numbers and ID numbers are never stored. Save the fact without it (for example "the API key ' +
|
|
140
|
+
'is in 1Password"), not the value itself.');
|
|
93
141
|
this.name = 'SecretInMemoryError';
|
|
94
142
|
}
|
|
95
143
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-secrets.js","sourceRoot":"","sources":["../src/memory-secrets.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"memory-secrets.js","sourceRoot":"","sources":["../src/memory-secrets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/** The four fields every tool carries. Required, so a missing hint is a
|
|
2
|
+
* compile error rather than an omission a reviewer finds. */
|
|
3
|
+
export interface VirlowToolAnnotations {
|
|
4
|
+
title: string;
|
|
5
|
+
readOnlyHint: boolean;
|
|
6
|
+
destructiveHint: boolean;
|
|
7
|
+
openWorldHint: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const TOOL_ANNOTATIONS: {
|
|
10
|
+
readonly unlock: VirlowToolAnnotations;
|
|
11
|
+
readonly lock: VirlowToolAnnotations;
|
|
12
|
+
readonly status: VirlowToolAnnotations;
|
|
13
|
+
readonly add_memory: VirlowToolAnnotations;
|
|
14
|
+
readonly search_memory: VirlowToolAnnotations;
|
|
15
|
+
readonly list_memories: VirlowToolAnnotations;
|
|
16
|
+
readonly recall_entity: VirlowToolAnnotations;
|
|
17
|
+
readonly link_memory: VirlowToolAnnotations;
|
|
18
|
+
readonly merge_entities: VirlowToolAnnotations;
|
|
19
|
+
readonly memory_context: VirlowToolAnnotations;
|
|
20
|
+
readonly memory_health: VirlowToolAnnotations;
|
|
21
|
+
readonly describe_entity: VirlowToolAnnotations;
|
|
22
|
+
readonly untyped_entities: VirlowToolAnnotations;
|
|
23
|
+
readonly update_memory: VirlowToolAnnotations;
|
|
24
|
+
readonly delete_memory: VirlowToolAnnotations;
|
|
25
|
+
readonly search_notes: VirlowToolAnnotations;
|
|
26
|
+
readonly list_notes: VirlowToolAnnotations;
|
|
27
|
+
readonly list_folders: VirlowToolAnnotations;
|
|
28
|
+
readonly read_note: VirlowToolAnnotations;
|
|
29
|
+
readonly create_note: VirlowToolAnnotations;
|
|
30
|
+
readonly update_note: VirlowToolAnnotations;
|
|
31
|
+
readonly get_backlinks: VirlowToolAnnotations;
|
|
32
|
+
readonly list_folder_view: VirlowToolAnnotations;
|
|
33
|
+
readonly list_properties: VirlowToolAnnotations;
|
|
34
|
+
readonly define_property: VirlowToolAnnotations;
|
|
35
|
+
readonly read_dashboard: VirlowToolAnnotations;
|
|
36
|
+
readonly set_dashboard: VirlowToolAnnotations;
|
|
37
|
+
readonly set_properties: VirlowToolAnnotations;
|
|
38
|
+
readonly move_note: VirlowToolAnnotations;
|
|
39
|
+
readonly set_star: VirlowToolAnnotations;
|
|
40
|
+
readonly archive_note: VirlowToolAnnotations;
|
|
41
|
+
readonly trash_note: VirlowToolAnnotations;
|
|
42
|
+
readonly create_folder: VirlowToolAnnotations;
|
|
43
|
+
readonly list_attachments: VirlowToolAnnotations;
|
|
44
|
+
readonly add_attachment: VirlowToolAnnotations;
|
|
45
|
+
readonly read_attachment: VirlowToolAnnotations;
|
|
46
|
+
readonly rename_attachment: VirlowToolAnnotations;
|
|
47
|
+
readonly move_attachment: VirlowToolAnnotations;
|
|
48
|
+
readonly delete_attachment: VirlowToolAnnotations;
|
|
49
|
+
readonly restore_attachment: VirlowToolAnnotations;
|
|
50
|
+
};
|
|
51
|
+
export type ToolName = keyof typeof TOOL_ANNOTATIONS;
|
|
52
|
+
/**
|
|
53
|
+
* A tool's annotations for this host. Only read_attachment varies: with file
|
|
54
|
+
* access its `save_to` / `overwrite` can replace a file on the user's disk.
|
|
55
|
+
* A fresh object each call, so nothing downstream can mutate the table.
|
|
56
|
+
*/
|
|
57
|
+
export declare function toolAnnotations(name: ToolName, opts?: {
|
|
58
|
+
fileAccess?: boolean;
|
|
59
|
+
}): VirlowToolAnnotations;
|
|
60
|
+
/**
|
|
61
|
+
* Short status lines ChatGPT shows while a tool runs and once it returns
|
|
62
|
+
* (`openai/toolInvocation/invoking` and `.../invoked`, 64 characters at most).
|
|
63
|
+
* Other clients ignore `_meta`. Only the tools a user sees most often in a
|
|
64
|
+
* conversation carry them.
|
|
65
|
+
*/
|
|
66
|
+
export declare const INVOCATION_STATUS: Partial<Record<ToolName, {
|
|
67
|
+
invoking: string;
|
|
68
|
+
invoked: string;
|
|
69
|
+
}>>;
|
|
70
|
+
/**
|
|
71
|
+
* Everything registerTool takes besides the description, schema and handler:
|
|
72
|
+
* the display title, the annotations and, where there are any, the `_meta`
|
|
73
|
+
* keys: the status line, and the inline card for the tools that have one
|
|
74
|
+
* (see widgets.ts). Spread into each registerTool config.
|
|
75
|
+
*/
|
|
76
|
+
export declare function toolConfig(name: ToolName, opts?: {
|
|
77
|
+
fileAccess?: boolean;
|
|
78
|
+
}): {
|
|
79
|
+
title: string;
|
|
80
|
+
annotations: VirlowToolAnnotations;
|
|
81
|
+
_meta?: Record<string, unknown>;
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=tool-annotations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-annotations.d.ts","sourceRoot":"","sources":["../src/tool-annotations.ts"],"names":[],"mappings":"AA6CA;8DAC8D;AAC9D,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;CACxB;AAuBD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgD6B,CAAC;AAE3D,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,gBAAgB,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,qBAAqB,CAK1G;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAM9F,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,QAAQ,EACd,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAClC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,qBAAqB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAgBxF"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool annotations for every tool the server registers.
|
|
3
|
+
*
|
|
4
|
+
* Clients use these to decide when to ask the user before a call: ChatGPT,
|
|
5
|
+
* for one, confirms a write and asks again for anything marked destructive,
|
|
6
|
+
* and its plugin review requires all three hints to be explicit booleans on
|
|
7
|
+
* every tool. They live in one table, rather than inline at each
|
|
8
|
+
* registerTool call, so the whole surface can be read and reviewed at once
|
|
9
|
+
* and a test can hold every registered tool to it.
|
|
10
|
+
*
|
|
11
|
+
* The rules applied:
|
|
12
|
+
*
|
|
13
|
+
* - readOnlyHint: true only when the call changes nothing the user owns
|
|
14
|
+
* (retrieval, search, listings, status). Refreshing this process's own
|
|
15
|
+
* cache does not count as a change.
|
|
16
|
+
* - destructiveHint: true when the call can overwrite, remove, hide, move or
|
|
17
|
+
* rewrite something the user already has, even when the app can undo it
|
|
18
|
+
* (Trash, version history, a kept previous dashboard). false only for
|
|
19
|
+
* additive writes and for state changes that lose nothing.
|
|
20
|
+
* - openWorldHint: false everywhere. Every tool acts on the user's own
|
|
21
|
+
* private Virlow workspace; none searches the web or writes to an arbitrary
|
|
22
|
+
* destination.
|
|
23
|
+
*
|
|
24
|
+
* Judgment calls, so the next reader does not have to rediscover them:
|
|
25
|
+
*
|
|
26
|
+
* - add_memory and link_memory are not destructive. add_memory only folds
|
|
27
|
+
* into an existing memory when it is a near-identical restatement
|
|
28
|
+
* (similarity at or above DEDUPE_UPDATE_THRESHOLD) and never when the new
|
|
29
|
+
* fact contradicts the old one; superseded facts get an end date and are
|
|
30
|
+
* kept as history, never removed. link_memory only adds entities and
|
|
31
|
+
* relations, ending superseded facts the same way.
|
|
32
|
+
* - describe_entity is destructive: a kind or note given there replaces the
|
|
33
|
+
* one stored, and an empty note clears it.
|
|
34
|
+
* - set_star is not destructive: a star is a reversible marker with nothing
|
|
35
|
+
* behind it. archive_note is: it takes the note out of the user's lists.
|
|
36
|
+
* - unlock and lock change session state, not data, so neither is read-only
|
|
37
|
+
* and neither is destructive. lock only discards this session's in-memory
|
|
38
|
+
* key and caches; nothing stored is touched and unlock restores access.
|
|
39
|
+
* - read_attachment depends on the host. Without file access it only returns
|
|
40
|
+
* the file. With it (local CLI, desktop app) `save_to` writes to the user's
|
|
41
|
+
* disk and `overwrite: true` replaces an existing file, so it is a
|
|
42
|
+
* destructive write there.
|
|
43
|
+
*/
|
|
44
|
+
import { widgetToolMeta } from './widgets.js';
|
|
45
|
+
const read = (title) => ({
|
|
46
|
+
title,
|
|
47
|
+
readOnlyHint: true,
|
|
48
|
+
destructiveHint: false,
|
|
49
|
+
openWorldHint: false,
|
|
50
|
+
});
|
|
51
|
+
const additive = (title) => ({
|
|
52
|
+
title,
|
|
53
|
+
readOnlyHint: false,
|
|
54
|
+
destructiveHint: false,
|
|
55
|
+
openWorldHint: false,
|
|
56
|
+
});
|
|
57
|
+
const destructive = (title) => ({
|
|
58
|
+
title,
|
|
59
|
+
readOnlyHint: false,
|
|
60
|
+
destructiveHint: true,
|
|
61
|
+
openWorldHint: false,
|
|
62
|
+
});
|
|
63
|
+
export const TOOL_ANNOTATIONS = {
|
|
64
|
+
// vault lifecycle
|
|
65
|
+
unlock: additive('Unlock Virlow'),
|
|
66
|
+
lock: additive('Lock Virlow'),
|
|
67
|
+
status: read('Check Virlow status'),
|
|
68
|
+
// memories
|
|
69
|
+
add_memory: additive('Save a memory'),
|
|
70
|
+
search_memory: read('Search memories'),
|
|
71
|
+
list_memories: read('List memories'),
|
|
72
|
+
recall_entity: read('Recall a person or project'),
|
|
73
|
+
link_memory: additive('Link a memory to entities'),
|
|
74
|
+
merge_entities: destructive('Merge two entities'),
|
|
75
|
+
memory_context: read('Get memory briefing'),
|
|
76
|
+
memory_health: read('Check memory health'),
|
|
77
|
+
describe_entity: destructive('Describe an entity'),
|
|
78
|
+
untyped_entities: read('List entities without a kind'),
|
|
79
|
+
update_memory: destructive('Update a memory'),
|
|
80
|
+
delete_memory: destructive('Delete a memory'),
|
|
81
|
+
// notes
|
|
82
|
+
search_notes: read('Search notes'),
|
|
83
|
+
list_notes: read('List notes'),
|
|
84
|
+
list_folders: read('List folders'),
|
|
85
|
+
read_note: read('Read a note'),
|
|
86
|
+
create_note: additive('Create a note'),
|
|
87
|
+
update_note: destructive('Update a note'),
|
|
88
|
+
get_backlinks: read('Get backlinks'),
|
|
89
|
+
list_folder_view: read('Read folder table view'),
|
|
90
|
+
list_properties: read('List folder properties'),
|
|
91
|
+
define_property: additive('Define a folder property'),
|
|
92
|
+
read_dashboard: read('Read a dashboard'),
|
|
93
|
+
set_dashboard: destructive('Replace a dashboard'),
|
|
94
|
+
set_properties: destructive('Set note properties'),
|
|
95
|
+
move_note: destructive('Move a note'),
|
|
96
|
+
set_star: additive('Star or unstar a note'),
|
|
97
|
+
archive_note: destructive('Archive or unarchive a note'),
|
|
98
|
+
trash_note: destructive('Move a note to the trash'),
|
|
99
|
+
create_folder: additive('Create a folder'),
|
|
100
|
+
// attachments
|
|
101
|
+
list_attachments: read('List attachments'),
|
|
102
|
+
add_attachment: additive('Attach a file'),
|
|
103
|
+
read_attachment: read('Read an attachment'),
|
|
104
|
+
rename_attachment: destructive('Rename an attachment'),
|
|
105
|
+
move_attachment: destructive('Move an attachment'),
|
|
106
|
+
delete_attachment: destructive('Delete an attachment'),
|
|
107
|
+
restore_attachment: additive('Restore an attachment'),
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* A tool's annotations for this host. Only read_attachment varies: with file
|
|
111
|
+
* access its `save_to` / `overwrite` can replace a file on the user's disk.
|
|
112
|
+
* A fresh object each call, so nothing downstream can mutate the table.
|
|
113
|
+
*/
|
|
114
|
+
export function toolAnnotations(name, opts = {}) {
|
|
115
|
+
if (name === 'read_attachment' && opts.fileAccess === true) {
|
|
116
|
+
return destructive('Read or save an attachment');
|
|
117
|
+
}
|
|
118
|
+
return { ...TOOL_ANNOTATIONS[name] };
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Short status lines ChatGPT shows while a tool runs and once it returns
|
|
122
|
+
* (`openai/toolInvocation/invoking` and `.../invoked`, 64 characters at most).
|
|
123
|
+
* Other clients ignore `_meta`. Only the tools a user sees most often in a
|
|
124
|
+
* conversation carry them.
|
|
125
|
+
*/
|
|
126
|
+
export const INVOCATION_STATUS = {
|
|
127
|
+
add_memory: { invoking: 'Saving to Virlow…', invoked: 'Saved to Virlow' },
|
|
128
|
+
update_memory: { invoking: 'Updating Virlow…', invoked: 'Updated Virlow' },
|
|
129
|
+
search_memory: { invoking: 'Checking Virlow…', invoked: 'Checked Virlow' },
|
|
130
|
+
memory_context: { invoking: 'Checking Virlow…', invoked: 'Checked Virlow' },
|
|
131
|
+
recall_entity: { invoking: 'Checking Virlow…', invoked: 'Checked Virlow' },
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Everything registerTool takes besides the description, schema and handler:
|
|
135
|
+
* the display title, the annotations and, where there are any, the `_meta`
|
|
136
|
+
* keys: the status line, and the inline card for the tools that have one
|
|
137
|
+
* (see widgets.ts). Spread into each registerTool config.
|
|
138
|
+
*/
|
|
139
|
+
export function toolConfig(name, opts = {}) {
|
|
140
|
+
const annotations = toolAnnotations(name, opts);
|
|
141
|
+
const status = INVOCATION_STATUS[name];
|
|
142
|
+
const widget = widgetToolMeta(name);
|
|
143
|
+
const meta = {
|
|
144
|
+
...(status && {
|
|
145
|
+
'openai/toolInvocation/invoking': status.invoking,
|
|
146
|
+
'openai/toolInvocation/invoked': status.invoked,
|
|
147
|
+
}),
|
|
148
|
+
...widget,
|
|
149
|
+
};
|
|
150
|
+
return {
|
|
151
|
+
title: annotations.title,
|
|
152
|
+
annotations,
|
|
153
|
+
...(Object.keys(meta).length > 0 && { _meta: meta }),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=tool-annotations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-annotations.js","sourceRoot":"","sources":["../src/tool-annotations.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.d.ts
CHANGED
|
@@ -101,11 +101,17 @@ export interface ServerServices {
|
|
|
101
101
|
* client without the user configuring anything: Claude Code, Claude Desktop,
|
|
102
102
|
* claude.ai and the mobile apps all put it in the system prompt. Tool
|
|
103
103
|
* descriptions only help once the model has already decided to look at a tool;
|
|
104
|
-
* this is what makes it look.
|
|
105
|
-
* save memories on its own", so the memory paragraph is the point and the rest
|
|
104
|
+
* this is what makes it look. The memory paragraph is the point and the rest
|
|
106
105
|
* is kept short: this text is paid for in every conversation the server is
|
|
107
106
|
* attached to.
|
|
108
107
|
*
|
|
108
|
+
* The memory paragraph is written for a feature the user opted into and must
|
|
109
|
+
* stay that way (directory reviews check it): it says the user turned
|
|
110
|
+
* memories on, asks the model to tell the user whenever it saves or updates
|
|
111
|
+
* one, names the data that is never saved, honours "don't remember this",
|
|
112
|
+
* and says the user can read, edit and delete every memory. It does not tell
|
|
113
|
+
* the model to prefer Virlow over any other tool.
|
|
114
|
+
*
|
|
109
115
|
* The memory paragraph is left out when the memory tools are not registered.
|
|
110
116
|
* Telling a model to call a tool it cannot see produces a confident apology
|
|
111
117
|
* about a missing feature rather than silence.
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,EAAY,SAAS,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAe,KAAK,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAS1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,EAAY,SAAS,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAe,KAAK,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAS1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AA4B/D;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,KAAK,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,iEAAiE;IACjE,MAAM,EAAE,cAAc,CAAC;IACvB;;;;;;OAMG;IACH,oBAAoB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,CAAC;IAC7D,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;CACd;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,SAAS,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,YAAY,CAAC;CAC5B;AAgED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,CAAC,eAAe,EAAE,OAAO,GAAG,MAAM,CA2BnE;AAoTD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,cAAc,CAgCvE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,kBAAkB,GAAG;IAAE,QAAQ,CAAC,EAAE,cAAc,CAAA;CAAE,GACvD,WAAW,CA06Cb;AA2BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,kBAAkB,GAAG;IAAE,QAAQ,CAAC,EAAE,cAAc,CAAA;CAAE,GACvD,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CA+CzC"}
|