@batalabs/virlow-mcp-core 3.84.2 → 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/cjs/memories.d.ts
CHANGED
|
@@ -212,6 +212,9 @@ export declare class MemoryStore {
|
|
|
212
212
|
/** The namespace of a memory this session has seen, without a sync;
|
|
213
213
|
* undefined for a global memory or one not cached yet. */
|
|
214
214
|
namespaceOfCached(id: string): string | undefined;
|
|
215
|
+
/** One memory as this session has it, without a sync; undefined when it
|
|
216
|
+
* is not cached. */
|
|
217
|
+
cached(id: string): CachedMemory | undefined;
|
|
215
218
|
/** Requires a prior sync() in the same unlock to have populated the cache. */
|
|
216
219
|
list(namespace?: string): CachedMemory[];
|
|
217
220
|
update(id: string, changes: {
|
package/dist/cjs/memories.js
CHANGED
|
@@ -654,6 +654,11 @@ class MemoryStore {
|
|
|
654
654
|
namespaceOfCached(id) {
|
|
655
655
|
return this.cache.get(id)?.namespace;
|
|
656
656
|
}
|
|
657
|
+
/** One memory as this session has it, without a sync; undefined when it
|
|
658
|
+
* is not cached. */
|
|
659
|
+
cached(id) {
|
|
660
|
+
return this.cache.get(id);
|
|
661
|
+
}
|
|
657
662
|
/** Requires a prior sync() in the same unlock to have populated the cache. */
|
|
658
663
|
list(namespace) {
|
|
659
664
|
this.requireSession();
|
|
@@ -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
|
/** What secret the text holds, or null when it holds none. */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Refuses memories that contain credentials,
|
|
3
|
+
* Refuses memories that contain credentials, payment card and bank account
|
|
4
|
+
* numbers, or government ID numbers, before anything is written.
|
|
4
5
|
*
|
|
5
6
|
* Memories are captured automatically, so the rule cannot depend on the AI
|
|
6
7
|
* remembering not to save a key: a memory is encrypted, but it is recalled
|
|
@@ -9,7 +10,11 @@
|
|
|
9
10
|
* left out instead of retrying with the secret reworded.
|
|
10
11
|
*
|
|
11
12
|
* Deliberately narrow: patterns that are credentials with near certainty,
|
|
12
|
-
* plus long high-entropy tokens
|
|
13
|
+
* plus long high-entropy tokens, plus the restricted data that has a shape
|
|
14
|
+
* to match (card numbers and security codes, IBANs and labelled account
|
|
15
|
+
* numbers, US Social Security numbers, labelled passport, licence and
|
|
16
|
+
* national ID numbers). Health information has no such shape; the server
|
|
17
|
+
* instructions tell the model not to save it. A false positive costs one memory; a false
|
|
13
18
|
* negative puts a live key into every future prompt that recalls it.
|
|
14
19
|
*/
|
|
15
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -31,7 +36,47 @@ const PATTERNS = [
|
|
|
31
36
|
test: /\b(password|passwd|pwd|passphrase|api[_ -]?key|secret|token)\s*[:=]\s*\S{6,}/i,
|
|
32
37
|
},
|
|
33
38
|
{ what: 'a connection string with a password', test: /\b[a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:[^\s@/]{3,}@/i },
|
|
39
|
+
{ what: 'a card security code', test: /\b(cvv2?|cvc2?|card security code)\s*[:#=]?\s*\d{3,4}\b/i },
|
|
40
|
+
{
|
|
41
|
+
// The issued format: no 000/666/9xx area, no 00 group, no 0000 serial.
|
|
42
|
+
// Phone numbers (3-3-4) and dates (4-2-2) do not take this shape.
|
|
43
|
+
what: 'a Social Security number',
|
|
44
|
+
test: /\b(?!000|666|9\d\d)\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b/,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
what: 'a Social Security number',
|
|
48
|
+
test: /\b(ssn|social security(\s+(number|no\.?|#))?)\b\D{0,20}\d{3}[ -]?\d{2}[ -]?\d{4}\b/i,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
what: 'a bank account number',
|
|
52
|
+
test: /\b((bank\s+)?account|acct|routing)\s*(number|num|no\.?|#)\s*[:#=]?\s*\d[\d -]{4,}\d\b/i,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
// A labelled ID followed by something with a digit in it, so "passport
|
|
56
|
+
// renewal is due in March" is a fact and "passport no. X1234567" is not.
|
|
57
|
+
what: 'a government ID number',
|
|
58
|
+
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,
|
|
59
|
+
},
|
|
34
60
|
];
|
|
61
|
+
/** An IBAN that passes its ISO 13616 mod-97 check: country code, two check
|
|
62
|
+
* digits, then 11 to 30 letters and digits, spaces allowed in groups of 4. */
|
|
63
|
+
function hasIban(text) {
|
|
64
|
+
for (const [match] of text.matchAll(/\b[A-Z]{2}\d{2}(?: ?[A-Z0-9]){11,30}\b/g)) {
|
|
65
|
+
const iban = match.replace(/ /g, '');
|
|
66
|
+
if (iban.length < 15 || iban.length > 34)
|
|
67
|
+
continue;
|
|
68
|
+
const rearranged = iban.slice(4) + iban.slice(0, 4);
|
|
69
|
+
let remainder = 0;
|
|
70
|
+
for (const ch of rearranged) {
|
|
71
|
+
const value = ch >= 'A' && ch <= 'Z' ? String(ch.charCodeAt(0) - 55) : ch;
|
|
72
|
+
for (const digit of value)
|
|
73
|
+
remainder = (remainder * 10 + Number(digit)) % 97;
|
|
74
|
+
}
|
|
75
|
+
if (remainder === 1)
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
35
80
|
/** Luhn-valid runs of 13 to 19 digits, spaces or dashes allowed. */
|
|
36
81
|
function hasCardNumber(text) {
|
|
37
82
|
for (const match of text.matchAll(/\b(?:\d[ -]?){13,19}\b/g)) {
|
|
@@ -87,14 +132,17 @@ function findSecret(text) {
|
|
|
87
132
|
}
|
|
88
133
|
if (hasCardNumber(text))
|
|
89
134
|
return 'a card number';
|
|
135
|
+
if (hasIban(text))
|
|
136
|
+
return 'a bank account number';
|
|
90
137
|
if (hasHighEntropyToken(text))
|
|
91
138
|
return 'what looks like a key or token';
|
|
92
139
|
return null;
|
|
93
140
|
}
|
|
94
141
|
class SecretInMemoryError extends Error {
|
|
95
142
|
constructor(what) {
|
|
96
|
-
super(`Not saved: this memory contains ${what}. Memories are recalled into prompts, so credentials
|
|
97
|
-
'stored. Save the fact without
|
|
143
|
+
super(`Not saved: this memory contains ${what}. Memories are recalled into prompts, so credentials, card and ` +
|
|
144
|
+
'account numbers and ID numbers are never stored. Save the fact without it (for example "the API key ' +
|
|
145
|
+
'is in 1Password"), not the value itself.');
|
|
98
146
|
this.name = 'SecretInMemoryError';
|
|
99
147
|
}
|
|
100
148
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.INVOCATION_STATUS = exports.TOOL_ANNOTATIONS = void 0;
|
|
4
|
+
exports.toolAnnotations = toolAnnotations;
|
|
5
|
+
exports.toolConfig = toolConfig;
|
|
6
|
+
/**
|
|
7
|
+
* MCP tool annotations for every tool the server registers.
|
|
8
|
+
*
|
|
9
|
+
* Clients use these to decide when to ask the user before a call: ChatGPT,
|
|
10
|
+
* for one, confirms a write and asks again for anything marked destructive,
|
|
11
|
+
* and its plugin review requires all three hints to be explicit booleans on
|
|
12
|
+
* every tool. They live in one table, rather than inline at each
|
|
13
|
+
* registerTool call, so the whole surface can be read and reviewed at once
|
|
14
|
+
* and a test can hold every registered tool to it.
|
|
15
|
+
*
|
|
16
|
+
* The rules applied:
|
|
17
|
+
*
|
|
18
|
+
* - readOnlyHint: true only when the call changes nothing the user owns
|
|
19
|
+
* (retrieval, search, listings, status). Refreshing this process's own
|
|
20
|
+
* cache does not count as a change.
|
|
21
|
+
* - destructiveHint: true when the call can overwrite, remove, hide, move or
|
|
22
|
+
* rewrite something the user already has, even when the app can undo it
|
|
23
|
+
* (Trash, version history, a kept previous dashboard). false only for
|
|
24
|
+
* additive writes and for state changes that lose nothing.
|
|
25
|
+
* - openWorldHint: false everywhere. Every tool acts on the user's own
|
|
26
|
+
* private Virlow workspace; none searches the web or writes to an arbitrary
|
|
27
|
+
* destination.
|
|
28
|
+
*
|
|
29
|
+
* Judgment calls, so the next reader does not have to rediscover them:
|
|
30
|
+
*
|
|
31
|
+
* - add_memory and link_memory are not destructive. add_memory only folds
|
|
32
|
+
* into an existing memory when it is a near-identical restatement
|
|
33
|
+
* (similarity at or above DEDUPE_UPDATE_THRESHOLD) and never when the new
|
|
34
|
+
* fact contradicts the old one; superseded facts get an end date and are
|
|
35
|
+
* kept as history, never removed. link_memory only adds entities and
|
|
36
|
+
* relations, ending superseded facts the same way.
|
|
37
|
+
* - describe_entity is destructive: a kind or note given there replaces the
|
|
38
|
+
* one stored, and an empty note clears it.
|
|
39
|
+
* - set_star is not destructive: a star is a reversible marker with nothing
|
|
40
|
+
* behind it. archive_note is: it takes the note out of the user's lists.
|
|
41
|
+
* - unlock and lock change session state, not data, so neither is read-only
|
|
42
|
+
* and neither is destructive. lock only discards this session's in-memory
|
|
43
|
+
* key and caches; nothing stored is touched and unlock restores access.
|
|
44
|
+
* - read_attachment depends on the host. Without file access it only returns
|
|
45
|
+
* the file. With it (local CLI, desktop app) `save_to` writes to the user's
|
|
46
|
+
* disk and `overwrite: true` replaces an existing file, so it is a
|
|
47
|
+
* destructive write there.
|
|
48
|
+
*/
|
|
49
|
+
const widgets_js_1 = require("./widgets.js");
|
|
50
|
+
const read = (title) => ({
|
|
51
|
+
title,
|
|
52
|
+
readOnlyHint: true,
|
|
53
|
+
destructiveHint: false,
|
|
54
|
+
openWorldHint: false,
|
|
55
|
+
});
|
|
56
|
+
const additive = (title) => ({
|
|
57
|
+
title,
|
|
58
|
+
readOnlyHint: false,
|
|
59
|
+
destructiveHint: false,
|
|
60
|
+
openWorldHint: false,
|
|
61
|
+
});
|
|
62
|
+
const destructive = (title) => ({
|
|
63
|
+
title,
|
|
64
|
+
readOnlyHint: false,
|
|
65
|
+
destructiveHint: true,
|
|
66
|
+
openWorldHint: false,
|
|
67
|
+
});
|
|
68
|
+
exports.TOOL_ANNOTATIONS = {
|
|
69
|
+
// vault lifecycle
|
|
70
|
+
unlock: additive('Unlock Virlow'),
|
|
71
|
+
lock: additive('Lock Virlow'),
|
|
72
|
+
status: read('Check Virlow status'),
|
|
73
|
+
// memories
|
|
74
|
+
add_memory: additive('Save a memory'),
|
|
75
|
+
search_memory: read('Search memories'),
|
|
76
|
+
list_memories: read('List memories'),
|
|
77
|
+
recall_entity: read('Recall a person or project'),
|
|
78
|
+
link_memory: additive('Link a memory to entities'),
|
|
79
|
+
merge_entities: destructive('Merge two entities'),
|
|
80
|
+
memory_context: read('Get memory briefing'),
|
|
81
|
+
memory_health: read('Check memory health'),
|
|
82
|
+
describe_entity: destructive('Describe an entity'),
|
|
83
|
+
untyped_entities: read('List entities without a kind'),
|
|
84
|
+
update_memory: destructive('Update a memory'),
|
|
85
|
+
delete_memory: destructive('Delete a memory'),
|
|
86
|
+
// notes
|
|
87
|
+
search_notes: read('Search notes'),
|
|
88
|
+
list_notes: read('List notes'),
|
|
89
|
+
list_folders: read('List folders'),
|
|
90
|
+
read_note: read('Read a note'),
|
|
91
|
+
create_note: additive('Create a note'),
|
|
92
|
+
update_note: destructive('Update a note'),
|
|
93
|
+
get_backlinks: read('Get backlinks'),
|
|
94
|
+
list_folder_view: read('Read folder table view'),
|
|
95
|
+
list_properties: read('List folder properties'),
|
|
96
|
+
define_property: additive('Define a folder property'),
|
|
97
|
+
read_dashboard: read('Read a dashboard'),
|
|
98
|
+
set_dashboard: destructive('Replace a dashboard'),
|
|
99
|
+
set_properties: destructive('Set note properties'),
|
|
100
|
+
move_note: destructive('Move a note'),
|
|
101
|
+
set_star: additive('Star or unstar a note'),
|
|
102
|
+
archive_note: destructive('Archive or unarchive a note'),
|
|
103
|
+
trash_note: destructive('Move a note to the trash'),
|
|
104
|
+
create_folder: additive('Create a folder'),
|
|
105
|
+
// attachments
|
|
106
|
+
list_attachments: read('List attachments'),
|
|
107
|
+
add_attachment: additive('Attach a file'),
|
|
108
|
+
read_attachment: read('Read an attachment'),
|
|
109
|
+
rename_attachment: destructive('Rename an attachment'),
|
|
110
|
+
move_attachment: destructive('Move an attachment'),
|
|
111
|
+
delete_attachment: destructive('Delete an attachment'),
|
|
112
|
+
restore_attachment: additive('Restore an attachment'),
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* A tool's annotations for this host. Only read_attachment varies: with file
|
|
116
|
+
* access its `save_to` / `overwrite` can replace a file on the user's disk.
|
|
117
|
+
* A fresh object each call, so nothing downstream can mutate the table.
|
|
118
|
+
*/
|
|
119
|
+
function toolAnnotations(name, opts = {}) {
|
|
120
|
+
if (name === 'read_attachment' && opts.fileAccess === true) {
|
|
121
|
+
return destructive('Read or save an attachment');
|
|
122
|
+
}
|
|
123
|
+
return { ...exports.TOOL_ANNOTATIONS[name] };
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Short status lines ChatGPT shows while a tool runs and once it returns
|
|
127
|
+
* (`openai/toolInvocation/invoking` and `.../invoked`, 64 characters at most).
|
|
128
|
+
* Other clients ignore `_meta`. Only the tools a user sees most often in a
|
|
129
|
+
* conversation carry them.
|
|
130
|
+
*/
|
|
131
|
+
exports.INVOCATION_STATUS = {
|
|
132
|
+
add_memory: { invoking: 'Saving to Virlow…', invoked: 'Saved to Virlow' },
|
|
133
|
+
update_memory: { invoking: 'Updating Virlow…', invoked: 'Updated Virlow' },
|
|
134
|
+
search_memory: { invoking: 'Checking Virlow…', invoked: 'Checked Virlow' },
|
|
135
|
+
memory_context: { invoking: 'Checking Virlow…', invoked: 'Checked Virlow' },
|
|
136
|
+
recall_entity: { invoking: 'Checking Virlow…', invoked: 'Checked Virlow' },
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Everything registerTool takes besides the description, schema and handler:
|
|
140
|
+
* the display title, the annotations and, where there are any, the `_meta`
|
|
141
|
+
* keys: the status line, and the inline card for the tools that have one
|
|
142
|
+
* (see widgets.ts). Spread into each registerTool config.
|
|
143
|
+
*/
|
|
144
|
+
function toolConfig(name, opts = {}) {
|
|
145
|
+
const annotations = toolAnnotations(name, opts);
|
|
146
|
+
const status = exports.INVOCATION_STATUS[name];
|
|
147
|
+
const widget = (0, widgets_js_1.widgetToolMeta)(name);
|
|
148
|
+
const meta = {
|
|
149
|
+
...(status && {
|
|
150
|
+
'openai/toolInvocation/invoking': status.invoking,
|
|
151
|
+
'openai/toolInvocation/invoked': status.invoked,
|
|
152
|
+
}),
|
|
153
|
+
...widget,
|
|
154
|
+
};
|
|
155
|
+
return {
|
|
156
|
+
title: annotations.title,
|
|
157
|
+
annotations,
|
|
158
|
+
...(Object.keys(meta).length > 0 && { _meta: meta }),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline cards for hosts that render MCP Apps UI: ChatGPT (Apps SDK) and any
|
|
3
|
+
* other client that implements the MCP Apps extension.
|
|
4
|
+
*
|
|
5
|
+
* Two cards, each one self-contained HTML document served as a `ui://`
|
|
6
|
+
* resource:
|
|
7
|
+
*
|
|
8
|
+
* - saved-memory: shown after add_memory and update_memory. "Saved to
|
|
9
|
+
* Virlow" (or "Updated in Virlow"), the label, the fact, the entities as
|
|
10
|
+
* kind-coloured chips, and at most two actions: Undo (a fresh save only)
|
|
11
|
+
* and Open in Virlow.
|
|
12
|
+
* - memory-context: shown after memory_context. "What Virlow knows": a few
|
|
13
|
+
* recent facts and the people and projects they are about, with one
|
|
14
|
+
* action, Open in Virlow.
|
|
15
|
+
*
|
|
16
|
+
* Why it is registered for every deployment, not only the hosted connector:
|
|
17
|
+
*
|
|
18
|
+
* - Nothing changes for a client that does not render UI. The text `content`
|
|
19
|
+
* every tool returned before is returned unchanged; `structuredContent` and
|
|
20
|
+
* `_meta` are extra fields such a client ignores, and a client that never
|
|
21
|
+
* reads a `ui://` resource never sees the HTML.
|
|
22
|
+
* - "Hosted only" would not mean "ChatGPT only": the hosted connector also
|
|
23
|
+
* serves claude.ai, and Claude Desktop (the local CLI's main host) renders
|
|
24
|
+
* MCP Apps too. So the card has to be right in every host anyway, which is
|
|
25
|
+
* why it speaks both bridges (window.openai and the MCP Apps postMessage
|
|
26
|
+
* protocol) rather than ChatGPT's alone.
|
|
27
|
+
* - One tool surface for both deployments is the rule this package exists
|
|
28
|
+
* for (see tools.ts); a host-specific `_meta` would be the first exception.
|
|
29
|
+
*
|
|
30
|
+
* The page loads nothing from the network: inline CSS and script, system
|
|
31
|
+
* fonts, the brand mark as inline SVG. Its only way out is the host's own
|
|
32
|
+
* bridge (callTool, openExternal), so its CSP declares no domains at all.
|
|
33
|
+
* Data is written with textContent, never as markup: a memory's text is
|
|
34
|
+
* whatever a model or a person typed.
|
|
35
|
+
*/
|
|
36
|
+
import type { EntityKind } from './memory-graph.js';
|
|
37
|
+
/** The MCP Apps resource type. ChatGPT reads it too. */
|
|
38
|
+
export declare const WIDGET_MIME_TYPE = "text/html;profile=mcp-app";
|
|
39
|
+
export declare const SAVED_MEMORY_URI = "ui://widget/saved-memory.html";
|
|
40
|
+
export declare const MEMORY_CONTEXT_URI = "ui://widget/memory-context.html";
|
|
41
|
+
/** Where "Open in Virlow" goes. The web app has no per-memory route, so it
|
|
42
|
+
* opens the app itself. */
|
|
43
|
+
export declare const VIRLOW_APP_URL = "https://app.virlow.com";
|
|
44
|
+
/**
|
|
45
|
+
* The thirteen kind colours, light and dark. A copy of KIND_COLORS in the
|
|
46
|
+
* web app (src/lib/entityKinds.ts), which cannot be imported here: that
|
|
47
|
+
* module pulls in lucide-react. A test holds the two to the same values.
|
|
48
|
+
*/
|
|
49
|
+
export declare const KIND_COLORS: Record<EntityKind, {
|
|
50
|
+
light: string;
|
|
51
|
+
dark: string;
|
|
52
|
+
}>;
|
|
53
|
+
export interface CardEntity {
|
|
54
|
+
name: string;
|
|
55
|
+
kind: EntityKind;
|
|
56
|
+
}
|
|
57
|
+
/** structuredContent of add_memory and update_memory. */
|
|
58
|
+
export interface SavedMemoryContent {
|
|
59
|
+
id: string;
|
|
60
|
+
label: string;
|
|
61
|
+
text: string;
|
|
62
|
+
/** The project it was saved under; null for a memory that applies everywhere. */
|
|
63
|
+
namespace: string | null;
|
|
64
|
+
entities: CardEntity[];
|
|
65
|
+
/** True when an existing memory changed (update_memory, or add_memory
|
|
66
|
+
* folding a near-identical restatement into one), false for a new one. */
|
|
67
|
+
updated: boolean;
|
|
68
|
+
}
|
|
69
|
+
/** structuredContent of memory_context. */
|
|
70
|
+
export interface MemoryContextContent {
|
|
71
|
+
namespace: string | null;
|
|
72
|
+
/** Saving is paused for the account or this project (recall still works). */
|
|
73
|
+
paused: boolean;
|
|
74
|
+
/** The most recent current facts, newest first. */
|
|
75
|
+
facts: Array<{
|
|
76
|
+
id: string;
|
|
77
|
+
label: string;
|
|
78
|
+
text: string;
|
|
79
|
+
}>;
|
|
80
|
+
/** The entities these memories name most, most first. */
|
|
81
|
+
entities: Array<CardEntity & {
|
|
82
|
+
facts: number;
|
|
83
|
+
}>;
|
|
84
|
+
}
|
|
85
|
+
/** How many facts the context card shows; the text result keeps them all. */
|
|
86
|
+
export declare const CONTEXT_CARD_FACTS = 5;
|
|
87
|
+
type WidgetView = 'saved' | 'context';
|
|
88
|
+
/** Which tools show which card. Tools not named here have no UI. */
|
|
89
|
+
export declare const TOOL_WIDGETS: Partial<Record<string, WidgetView>>;
|
|
90
|
+
/** The tool-side `_meta` linking a tool to its card: the MCP Apps key and
|
|
91
|
+
* ChatGPT's alias for it. add_memory's card calls delete_memory (Undo), so
|
|
92
|
+
* it is marked as allowed to call tools. */
|
|
93
|
+
export declare function widgetToolMeta(tool: string): Record<string, unknown> | undefined;
|
|
94
|
+
/** Everything the server needs to list and serve the two resources. */
|
|
95
|
+
export declare const WIDGET_RESOURCES: Array<{
|
|
96
|
+
name: string;
|
|
97
|
+
uri: string;
|
|
98
|
+
title: string;
|
|
99
|
+
description: string;
|
|
100
|
+
view: WidgetView;
|
|
101
|
+
}>;
|
|
102
|
+
/** A `resources/read` result for one card. */
|
|
103
|
+
export declare function readWidget(view: WidgetView): {
|
|
104
|
+
contents: {
|
|
105
|
+
uri: string;
|
|
106
|
+
mimeType: string;
|
|
107
|
+
text: string;
|
|
108
|
+
_meta: Record<string, unknown>;
|
|
109
|
+
}[];
|
|
110
|
+
};
|
|
111
|
+
/** The whole page for one card. */
|
|
112
|
+
export declare function widgetHtml(view: WidgetView): string;
|
|
113
|
+
/** The pieces, for the widget tests: they run the script against the page
|
|
114
|
+
* body in jsdom without a host. */
|
|
115
|
+
export declare const WIDGET_PARTS: {
|
|
116
|
+
css: string;
|
|
117
|
+
script: string;
|
|
118
|
+
};
|
|
119
|
+
export {};
|