@animalabs/agent-framework 0.28.0 → 0.30.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/README.md +88 -25
- package/dist/src/admission/admit.d.ts +90 -0
- package/dist/src/admission/admit.d.ts.map +1 -0
- package/dist/src/admission/admit.js +43 -0
- package/dist/src/admission/admit.js.map +1 -0
- package/dist/src/agent.d.ts +21 -0
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +47 -7
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/mcp-server-core.d.ts.map +1 -1
- package/dist/src/api/mcp-server-core.js +3 -12
- package/dist/src/api/mcp-server-core.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +7 -3
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/author-presentation.d.ts +50 -0
- package/dist/src/author-presentation.d.ts.map +1 -0
- package/dist/src/author-presentation.js +58 -0
- package/dist/src/author-presentation.js.map +1 -0
- package/dist/src/auto-continue.d.ts +2 -0
- package/dist/src/auto-continue.d.ts.map +1 -1
- package/dist/src/auto-continue.js +5 -2
- package/dist/src/auto-continue.js.map +1 -1
- package/dist/src/code-execution/isolate/runner.d.ts +7 -5
- package/dist/src/code-execution/isolate/runner.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/runner.js +7 -5
- package/dist/src/code-execution/isolate/runner.js.map +1 -1
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/scripts.js +3 -2
- package/dist/src/code-execution/isolate/scripts.js.map +1 -1
- package/dist/src/dendrite/index.d.ts +6 -0
- package/dist/src/dendrite/index.d.ts.map +1 -0
- package/dist/src/dendrite/index.js +3 -0
- package/dist/src/dendrite/index.js.map +1 -0
- package/dist/src/dendrite/presets.d.ts +60 -0
- package/dist/src/dendrite/presets.d.ts.map +1 -0
- package/dist/src/dendrite/presets.js +117 -0
- package/dist/src/dendrite/presets.js.map +1 -0
- package/dist/src/dendrite/registry.d.ts +260 -0
- package/dist/src/dendrite/registry.d.ts.map +1 -0
- package/dist/src/dendrite/registry.js +742 -0
- package/dist/src/dendrite/registry.js.map +1 -0
- package/dist/src/dendrite/types.d.ts +392 -0
- package/dist/src/dendrite/types.d.ts.map +1 -0
- package/dist/src/dendrite/types.js +24 -0
- package/dist/src/dendrite/types.js.map +1 -0
- package/dist/src/framework.d.ts +846 -67
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +4213 -924
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +46 -14
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +143 -53
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/gate/index.d.ts +1 -1
- package/dist/src/gate/index.d.ts.map +1 -1
- package/dist/src/gate/index.js +1 -1
- package/dist/src/gate/index.js.map +1 -1
- package/dist/src/gate/types.d.ts +12 -2
- package/dist/src/gate/types.d.ts.map +1 -1
- package/dist/src/heartbeat/heartbeat.d.ts +18 -0
- package/dist/src/heartbeat/heartbeat.d.ts.map +1 -1
- package/dist/src/heartbeat/heartbeat.js +34 -8
- package/dist/src/heartbeat/heartbeat.js.map +1 -1
- package/dist/src/held-writes.d.ts +3 -3
- package/dist/src/held-writes.js +3 -3
- package/dist/src/host-presentation.d.ts +174 -0
- package/dist/src/host-presentation.d.ts.map +1 -0
- package/dist/src/host-presentation.js +565 -0
- package/dist/src/host-presentation.js.map +1 -0
- package/dist/src/index.d.ts +7 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +7 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/line-reader.d.ts +4 -0
- package/dist/src/line-reader.d.ts.map +1 -0
- package/dist/src/line-reader.js +59 -0
- package/dist/src/line-reader.js.map +1 -0
- package/dist/src/mcpl/channel-registry.d.ts +118 -15
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +266 -110
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +2 -1
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts +1 -0
- package/dist/src/mcpl/convert-block.d.ts.map +1 -1
- package/dist/src/mcpl/convert-block.js +16 -4
- package/dist/src/mcpl/convert-block.js.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.js +4 -3
- package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +3 -1
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +3 -1
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
- package/dist/src/mcpl/modern-connection.js +11 -7
- package/dist/src/mcpl/modern-connection.js.map +1 -1
- package/dist/src/mcpl/protocol-family.d.ts +3 -2
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
- package/dist/src/mcpl/protocol-family.js +25 -3
- package/dist/src/mcpl/protocol-family.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +9 -0
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +21 -0
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.js +2 -2
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/references.d.ts +12 -40
- package/dist/src/mcpl/references.d.ts.map +1 -1
- package/dist/src/mcpl/references.js +29 -23
- package/dist/src/mcpl/references.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +20 -20
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/skip-reply-wake.d.ts +25 -0
- package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -1
- package/dist/src/mcpl/skip-reply-wake.js +25 -0
- package/dist/src/mcpl/skip-reply-wake.js.map +1 -1
- package/dist/src/mcpl/tool-presence.d.ts.map +1 -1
- package/dist/src/mcpl/tool-presence.js +18 -17
- package/dist/src/mcpl/tool-presence.js.map +1 -1
- package/dist/src/mcpl/tool-signature.d.ts.map +1 -1
- package/dist/src/mcpl/tool-signature.js +17 -16
- package/dist/src/mcpl/tool-signature.js.map +1 -1
- package/dist/src/mcpl/toolset-host.d.ts +8 -26
- package/dist/src/mcpl/toolset-host.d.ts.map +1 -1
- package/dist/src/mcpl/toolset-host.js +16 -6
- package/dist/src/mcpl/toolset-host.js.map +1 -1
- package/dist/src/mcpl/toolsets-module.d.ts +14 -25
- package/dist/src/mcpl/toolsets-module.d.ts.map +1 -1
- package/dist/src/mcpl/toolsets-module.js +187 -50
- package/dist/src/mcpl/toolsets-module.js.map +1 -1
- package/dist/src/mcpl/transport.d.ts +1 -1
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +16 -16
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +28 -12
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/module-registry.d.ts +6 -7
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +6 -7
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/api/index.d.ts.map +1 -1
- package/dist/src/modules/api/index.js +4 -2
- package/dist/src/modules/api/index.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +33 -25
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/history/index.js +8 -6
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/sender-name.d.ts +7 -0
- package/dist/src/modules/sender-name.d.ts.map +1 -0
- package/dist/src/modules/sender-name.js +10 -0
- package/dist/src/modules/sender-name.js.map +1 -0
- package/dist/src/modules/workspace/answers.d.ts +5 -1
- package/dist/src/modules/workspace/answers.d.ts.map +1 -1
- package/dist/src/modules/workspace/answers.js +16 -1
- package/dist/src/modules/workspace/answers.js.map +1 -1
- package/dist/src/modules/workspace/direct-write.d.ts.map +1 -1
- package/dist/src/modules/workspace/direct-write.js +6 -4
- package/dist/src/modules/workspace/direct-write.js.map +1 -1
- package/dist/src/modules/workspace/effects.d.ts +4 -2
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +50 -40
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +1 -0
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +66 -36
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +51 -20
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +120 -82
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/reconcile.d.ts +7 -1
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +133 -37
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/notice-tags.d.ts +81 -0
- package/dist/src/notice-tags.d.ts.map +1 -0
- package/dist/src/notice-tags.js +85 -0
- package/dist/src/notice-tags.js.map +1 -0
- package/dist/src/reasoning-loss-notice.d.ts.map +1 -1
- package/dist/src/reasoning-loss-notice.js +5 -3
- package/dist/src/reasoning-loss-notice.js.map +1 -1
- package/dist/src/silent-heartbeat.d.ts +5 -55
- package/dist/src/silent-heartbeat.d.ts.map +1 -1
- package/dist/src/silent-heartbeat.js +63 -7
- package/dist/src/silent-heartbeat.js.map +1 -1
- package/dist/src/stored-injections.d.ts +4 -0
- package/dist/src/stored-injections.d.ts.map +1 -1
- package/dist/src/stored-injections.js +6 -0
- package/dist/src/stored-injections.js.map +1 -1
- package/dist/src/supplied-text.d.ts +35 -0
- package/dist/src/supplied-text.d.ts.map +1 -0
- package/dist/src/supplied-text.js +141 -0
- package/dist/src/supplied-text.js.map +1 -0
- package/dist/src/tool-args.d.ts.map +1 -1
- package/dist/src/tool-args.js +9 -8
- package/dist/src/tool-args.js.map +1 -1
- package/dist/src/tool-image-ledger.d.ts.map +1 -1
- package/dist/src/tool-image-ledger.js +2 -1
- package/dist/src/tool-image-ledger.js.map +1 -1
- package/dist/src/tool-presentation.d.ts.map +1 -1
- package/dist/src/tool-presentation.js +5 -4
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +382 -11
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +1100 -119
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/tune-out/tools.d.ts +101 -5
- package/dist/src/tune-out/tools.d.ts.map +1 -1
- package/dist/src/tune-out/tools.js +55 -18
- package/dist/src/tune-out/tools.js.map +1 -1
- package/dist/src/types/agent.d.ts +48 -9
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +142 -0
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +22 -11
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +136 -0
- package/dist/src/types/trace.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/admission/admit.ts +113 -0
- package/src/agent.ts +52 -7
- package/src/api/mcp-server-core.ts +3 -14
- package/src/api/server.ts +7 -3
- package/src/author-presentation.ts +81 -0
- package/src/auto-continue.ts +8 -2
- package/src/code-execution/isolate/runner.ts +7 -5
- package/src/code-execution/isolate/scripts.ts +3 -2
- package/src/dendrite/index.ts +32 -0
- package/src/dendrite/presets.ts +149 -0
- package/src/dendrite/registry.ts +808 -0
- package/src/dendrite/types.ts +397 -0
- package/src/framework.ts +4362 -852
- package/src/gate/event-gate.ts +159 -52
- package/src/gate/index.ts +1 -1
- package/src/gate/types.ts +12 -2
- package/src/heartbeat/heartbeat.ts +48 -9
- package/src/held-writes.ts +3 -3
- package/src/host-presentation.ts +612 -0
- package/src/index.ts +17 -4
- package/src/line-reader.ts +58 -0
- package/src/mcpl/channel-registry.ts +306 -111
- package/src/mcpl/conversation-router.ts +2 -1
- package/src/mcpl/convert-block.ts +17 -4
- package/src/mcpl/hook-orchestrator.ts +4 -3
- package/src/mcpl/inbound-source.ts +3 -1
- package/src/mcpl/modern-connection.ts +11 -7
- package/src/mcpl/protocol-family.ts +24 -3
- package/src/mcpl/push-coalescer.ts +19 -0
- package/src/mcpl/push-handler.ts +2 -2
- package/src/mcpl/references.ts +31 -23
- package/src/mcpl/server-connection.ts +20 -18
- package/src/mcpl/skip-reply-wake.ts +35 -0
- package/src/mcpl/tool-presence.ts +18 -17
- package/src/mcpl/tool-signature.ts +17 -16
- package/src/mcpl/toolset-host.ts +18 -6
- package/src/mcpl/toolsets-module.ts +149 -50
- package/src/mcpl/transport.ts +18 -14
- package/src/mcpl/types.ts +29 -12
- package/src/module-registry.ts +6 -7
- package/src/modules/api/index.ts +4 -2
- package/src/modules/discord/index.ts +37 -25
- package/src/modules/history/index.ts +8 -6
- package/src/modules/sender-name.ts +9 -0
- package/src/modules/workspace/answers.ts +20 -2
- package/src/modules/workspace/direct-write.ts +4 -3
- package/src/modules/workspace/effects.ts +50 -40
- package/src/modules/workspace/index.ts +58 -34
- package/src/modules/workspace/observe.ts +139 -88
- package/src/modules/workspace/reconcile.ts +159 -36
- package/src/notice-tags.ts +86 -0
- package/src/reasoning-loss-notice.ts +5 -3
- package/src/silent-heartbeat.ts +11 -7
- package/src/stored-injections.ts +7 -0
- package/src/supplied-text.ts +154 -0
- package/src/tool-args.ts +9 -8
- package/src/tool-image-ledger.ts +2 -1
- package/src/tool-presentation.ts +5 -4
- package/src/tune-out/coordinator.ts +1252 -123
- package/src/tune-out/tools.ts +152 -11
- package/src/types/agent.ts +51 -9
- package/src/types/framework.ts +146 -0
- package/src/types/module.ts +23 -11
- package/src/types/trace.ts +150 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text the framework didn't write (what a participant or a server supplied),
|
|
3
|
+
* put beside structure of the framework's own: the reply judge's document,
|
|
4
|
+
* and notices the framework writes. A value that can end its line can start
|
|
5
|
+
* a line that reads as the framework's own.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { CONTEXT_MANAGER_TAGS, MEMBRANE_TAGS, NOTICE_TAG } from './notice-tags.js';
|
|
9
|
+
|
|
10
|
+
/** Every form of line break a reader might take for one: CR LF, CR, LF,
|
|
11
|
+
* vertical tab, form feed, NEL, and the Unicode line and paragraph separators. */
|
|
12
|
+
const LINE_BREAK = /\r\n|[\r\n\u000b\u000c\u0085\u2028\u2029]/g;
|
|
13
|
+
|
|
14
|
+
/** Text with each line break, in whatever form, as `\n`. */
|
|
15
|
+
export function normalizeLineBreaks(text: string): string {
|
|
16
|
+
return text.replace(LINE_BREAK, '\n');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** A value kept to one line: each run of line breaks, in whatever form, as one
|
|
20
|
+
* space, so it can't end the line it's put in or start one of its own. */
|
|
21
|
+
export function oneLine(text: string): string {
|
|
22
|
+
return normalizeLineBreaks(text).replace(/\n+/g, ' ');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const INVISIBLE = '\\p{Cf}\\p{Default_Ignorable_Code_Point}';
|
|
26
|
+
const SKIPPED = `[\\s\\p{Cc}${INVISIBLE}]`;
|
|
27
|
+
const tagWord = (word: string): string =>
|
|
28
|
+
[...word].map((c) => (/[\\^$.*+?()[\]{}|/]/.test(c) ? `\\${c}` : c)).join(`${SKIPPED}*`);
|
|
29
|
+
const NOTICE_OPENING = new RegExp(
|
|
30
|
+
`\\[(?=${SKIPPED}*(?:${[...Object.values(NOTICE_TAG), ...CONTEXT_MANAGER_TAGS, ...MEMBRANE_TAGS].map((tag) => tag.split(' ').map(tagWord).join(`${SKIPPED}+`)).join('|')})(?![\\p{L}\\p{N}]))`,
|
|
31
|
+
'giu',
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Texts read as one string, joined by line breaks, with a backslash put
|
|
36
|
+
* before the bracket of each opening of a listed tag (NOTICE_TAG,
|
|
37
|
+
* CONTEXT_MANAGER_TAGS, MEMBRANE_TAGS) that hasn't one before it in its own
|
|
38
|
+
* text. A text `marks` says false of is read and never changed.
|
|
39
|
+
*
|
|
40
|
+
* Every opening, not only one that starts a line: membrane's XML formatter
|
|
41
|
+
* writes `participant: ` before each message, so the framework's own
|
|
42
|
+
* openings stand mid-line there too. It joins a message's text blocks with
|
|
43
|
+
* line breaks and sets its images apart from that text, while the native
|
|
44
|
+
* formatter sends each block on its own, so an opening split across a
|
|
45
|
+
* message's text blocks is one either way. In any case, by Unicode's case folding, and
|
|
46
|
+
* through whitespace, control and invisible characters anywhere inside the
|
|
47
|
+
* bracket, which a model reads past.
|
|
48
|
+
*/
|
|
49
|
+
export function markedTexts(texts: readonly string[], marks: readonly boolean[] = []): string[] {
|
|
50
|
+
const starts: number[] = [];
|
|
51
|
+
let at = 0;
|
|
52
|
+
for (const text of texts) {
|
|
53
|
+
starts.push(at);
|
|
54
|
+
at += text.length + 1;
|
|
55
|
+
}
|
|
56
|
+
const offsets: number[][] = texts.map(() => []);
|
|
57
|
+
for (const match of texts.join('\n').matchAll(NOTICE_OPENING)) {
|
|
58
|
+
let holder = texts.length - 1;
|
|
59
|
+
while (starts[holder]! > match.index) holder--;
|
|
60
|
+
const offset = match.index - starts[holder]!;
|
|
61
|
+
if (marks[holder] !== false && texts[holder]![offset - 1] !== '\\') offsets[holder]!.push(offset);
|
|
62
|
+
}
|
|
63
|
+
return texts.map((text, i) => withMarks(text, offsets[i]!));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function withMarks(text: string, offsets: readonly number[]): string {
|
|
67
|
+
let marked = '';
|
|
68
|
+
let from = 0;
|
|
69
|
+
for (const offset of offsets) {
|
|
70
|
+
marked += `${text.slice(from, offset)}\\`;
|
|
71
|
+
from = offset;
|
|
72
|
+
}
|
|
73
|
+
return marked + text.slice(from);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function closedWithin(text: string, at: number): boolean {
|
|
77
|
+
let depth = 0;
|
|
78
|
+
for (let i = at; i < text.length; i++) {
|
|
79
|
+
if (text[i] === '[') depth++;
|
|
80
|
+
else if (text[i] === ']' && --depth === 0) return true;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function unmarkedOpenings(text: string): number[] {
|
|
86
|
+
return [...text.matchAll(NOTICE_OPENING)].map((match) => match.index).filter((at) => text[at - 1] !== '\\');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function markedText(text: string): string {
|
|
90
|
+
return markedTexts([text])[0]!;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function markNoticeOpenings<T extends object>(blocks: readonly T[], marks: (index: number) => boolean = () => true): T[] {
|
|
94
|
+
const at: number[] = [];
|
|
95
|
+
blocks.forEach((block, index) => {
|
|
96
|
+
const { type, text } = (block ?? {}) as { type?: unknown; text?: unknown };
|
|
97
|
+
if (type === 'text' && typeof text === 'string') at.push(index);
|
|
98
|
+
});
|
|
99
|
+
const textOf = (index: number): string => (blocks[index] as unknown as { text: string }).text;
|
|
100
|
+
const marked = markedTexts(at.map(textOf), at.map(marks));
|
|
101
|
+
const out = [...blocks];
|
|
102
|
+
at.forEach((index, i) => {
|
|
103
|
+
if (marked[i] !== textOf(index)) out[index] = { ...blocks[index]!, text: marked[i] };
|
|
104
|
+
});
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function suppliedValue(value: unknown): string {
|
|
109
|
+
return markedText(oneLine(String(value)));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function cutToFit(text: string, length: number): string {
|
|
113
|
+
let end = Math.max(0, Math.floor(length));
|
|
114
|
+
if (end >= text.length) return text;
|
|
115
|
+
for (;;) {
|
|
116
|
+
const last = text.charCodeAt(end - 1);
|
|
117
|
+
if (end < text.length && last >= 0xd800 && last <= 0xdbff) end--;
|
|
118
|
+
else if (text[end - 1] === '\\' && text[end] === '[') end--;
|
|
119
|
+
else {
|
|
120
|
+
const cut = text.slice(0, end);
|
|
121
|
+
const open = unmarkedOpenings(cut).find((at) => !closedWithin(cut, at));
|
|
122
|
+
if (open === undefined) return cut;
|
|
123
|
+
end = open;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function showsAsItself(value: string): boolean {
|
|
129
|
+
return value !== '' && suppliedValue(value) === value && value.isWellFormed() && !EDGE_OR_QUOTE.test(value);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const EDGE_OR_QUOTE = /^\s|\s$|["\\]/;
|
|
133
|
+
|
|
134
|
+
export function quotedValue(value: unknown, space?: number): string {
|
|
135
|
+
return (JSON.stringify(value, null, space) ?? 'null').replace(/"(?:[^"\\]|\\.)*"/g, (literal) => quotedString(JSON.parse(literal)));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function quotedString(text: string): string {
|
|
139
|
+
let quoted = '';
|
|
140
|
+
let from = 0;
|
|
141
|
+
for (const match of text.matchAll(NOTICE_OPENING)) {
|
|
142
|
+
quoted += `${jsonText(text.slice(from, match.index))}\\u005b`;
|
|
143
|
+
from = match.index + 1;
|
|
144
|
+
}
|
|
145
|
+
return `"${quoted}${jsonText(text.slice(from))}"`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// JSON.stringify leaves NEL, U+2028 and U+2029 as they are.
|
|
149
|
+
const jsonText = (text: string): string =>
|
|
150
|
+
JSON.stringify(text).slice(1, -1).replace(/[\u0085\u2028\u2029]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`);
|
|
151
|
+
|
|
152
|
+
export function nameToTypeBack(name: string): string {
|
|
153
|
+
return showsAsItself(name) ? name : quotedValue(name);
|
|
154
|
+
}
|
package/src/tool-args.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nameToTypeBack, quotedValue } from './supplied-text.js';
|
|
1
2
|
import type { ToolDefinition } from './types/index.js';
|
|
2
3
|
|
|
3
4
|
/** A run of 16 or more digits, which membrane's XML parser passes as text for
|
|
@@ -79,20 +80,20 @@ export function markedInputRefusal(call: { name: string; unparseableInput?: stri
|
|
|
79
80
|
// object. A block still open when a stream breaks the API's block order
|
|
80
81
|
// is marked the same way, and one that had stopped with its object's JSON,
|
|
81
82
|
// so the arguments may be another call's (ToolUseContent.unparseableInput).
|
|
82
|
-
if (/^[ \t\n\r]*$/.test(text)) return `Nothing was done: ${call.name} its arguments never arrived; call it again with them whole.`;
|
|
83
|
+
if (/^[ \t\n\r]*$/.test(text)) return `Nothing was done: ${nameToTypeBack(call.name)} its arguments never arrived; call it again with them whole.`;
|
|
83
84
|
let parsed: unknown;
|
|
84
85
|
try {
|
|
85
86
|
parsed = JSON.parse(text);
|
|
86
87
|
} catch {
|
|
87
|
-
return `Nothing was done: ${call.name} its arguments must be one JSON object, and this call gave text that isn't JSON, which may have been cut off: ${shown(text)}; call it again with one JSON object.`;
|
|
88
|
+
return `Nothing was done: ${nameToTypeBack(call.name)} its arguments must be one JSON object, and this call gave text that isn't JSON, which may have been cut off: ${shown(text)}; call it again with one JSON object.`;
|
|
88
89
|
}
|
|
89
90
|
if (parsed === null) return undefined;
|
|
90
|
-
if (typeof parsed !== 'object' || Array.isArray(parsed)) return `Nothing was done: ${call.name} ${notAnObject(parsed)}.`;
|
|
91
|
-
return `Nothing was done: ${call.name} its arguments came in a response that didn't arrive whole and in order, so they can't be taken as this call's; call it again.`;
|
|
91
|
+
if (typeof parsed !== 'object' || Array.isArray(parsed)) return `Nothing was done: ${nameToTypeBack(call.name)} ${notAnObject(parsed)}.`;
|
|
92
|
+
return `Nothing was done: ${nameToTypeBack(call.name)} its arguments came in a response that didn't arrive whole and in order, so they can't be taken as this call's; call it again.`;
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
export function cutOffRefusal(call: { name: string }): string {
|
|
95
|
-
return `Nothing was done: ${call.name} didn't run, because the response it was in was cut off at the output limit. ` +
|
|
96
|
+
return `Nothing was done: ${nameToTypeBack(call.name)} didn't run, because the response it was in was cut off at the output limit. ` +
|
|
96
97
|
'To make the call, send less in one response: shorter text before it, shorter arguments, or fewer calls at once.';
|
|
97
98
|
}
|
|
98
99
|
|
|
@@ -216,7 +217,7 @@ export function toolArgsProblems(
|
|
|
216
217
|
const kinds = admittedKinds(declared(key));
|
|
217
218
|
if (value !== undefined && (value !== null || takesNull(declared(key)))) continue;
|
|
218
219
|
missing.add(key);
|
|
219
|
-
const wanted = kinds.length > 0 ?
|
|
220
|
+
const wanted = kinds.length > 0 ? `${quotedValue(key)} (${oneOf(kinds.map(withArticle))})` : quotedValue(key);
|
|
220
221
|
problems.push(`needs ${wanted}, and this call gave ${value === null ? 'null' : 'none'}`);
|
|
221
222
|
}
|
|
222
223
|
if (missing.size > 0 && declaresKeysPlainly(schema as Record<string, unknown>)) {
|
|
@@ -235,11 +236,11 @@ export function toolArgsProblems(
|
|
|
235
236
|
const kind = kindOf(value);
|
|
236
237
|
const largeInteger = kind === 'string' && kinds.includes('number') && LARGE_INTEGER_TEXT.test(value as string);
|
|
237
238
|
if (kinds.length > 0 && !kinds.includes(kind) && !largeInteger) {
|
|
238
|
-
problems.push(
|
|
239
|
+
problems.push(`${quotedValue(key)} must be ${oneOf(kinds.map(withArticle))}, and this call gave ${withArticle(kind)}`);
|
|
239
240
|
continue;
|
|
240
241
|
}
|
|
241
242
|
if (Array.isArray(param.enum) && !param.enum.includes(value)) {
|
|
242
|
-
problems.push(
|
|
243
|
+
problems.push(`${quotedValue(key)} must be one of ${oneOf(param.enum.map((e) => quotedValue(e)))}, and this call gave ${shown(value)}`);
|
|
243
244
|
}
|
|
244
245
|
}
|
|
245
246
|
return problems;
|
package/src/tool-image-ledger.ts
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
* of bytes from another surface is the failure this exists to end.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
+
import { NOTICE_TAG } from './notice-tags.js';
|
|
29
30
|
import { createHash, randomBytes } from 'node:crypto';
|
|
30
31
|
import { REFERENCE_STUB_MAX_CHARS, referenceTypeLabel } from './mcpl/references.js';
|
|
31
32
|
import { safeSlice } from './safe-slice.js';
|
|
@@ -256,7 +257,7 @@ export type ParsedImagePlaceholder =
|
|
|
256
257
|
const PLACEHOLDER_RE = /\[image: ([a-z0-9!#$&^_.+-]{1,127}\/[a-z0-9!#$&^_.+-]{1,127}), (~?[\d.]{1,16}(?:B|KB|MB))(?:, ref (img_[0-9a-z]{1,16}_\d{1,16}))?\]/g;
|
|
257
258
|
/** `[ref_1_ab3d] cam.png — image/png, 1.2MB claimed — from tool result — …`
|
|
258
259
|
* (one line, at most REFERENCE_STUB_MAX_CHARS long: see parseImagePlaceholders). */
|
|
259
|
-
const REFERENCE_STUB_RE =
|
|
260
|
+
const REFERENCE_STUB_RE = new RegExp(`^\\[(${NOTICE_TAG.referenceId}_[0-9a-z]+_[0-9a-z]+)\\] ([^\\n]*)$`, 'gm');
|
|
260
261
|
const IMAGE_MIME_RE = /\bimage\/[a-z0-9!#$&^_.+-]+/i;
|
|
261
262
|
|
|
262
263
|
/**
|
package/src/tool-presentation.ts
CHANGED
|
@@ -32,7 +32,8 @@ const MAX_BYTES = 256 * 1024;
|
|
|
32
32
|
*/
|
|
33
33
|
const NONBLOCK = typeof constants.O_NONBLOCK === 'number' ? constants.O_NONBLOCK : 0;
|
|
34
34
|
const MAX_DESCRIPTION_CHARS = 32768;
|
|
35
|
-
|
|
35
|
+
// The toolsets meta-tools are how a hidden tool is reached again, so they stay.
|
|
36
|
+
const protectedNames = new Set(['set_tool_visibility', 'set_tool_description', 'workspace--read', 'toolsets--open', 'toolsets--act', 'toolsets--look', 'toolsets--close']);
|
|
36
37
|
export const isPresentationTool = (name: string): boolean => name === 'set_tool_visibility' || name === 'set_tool_description';
|
|
37
38
|
const hash = (value: string): string => createHash('sha256').update(value).digest('hex');
|
|
38
39
|
|
|
@@ -175,7 +176,7 @@ function lockLeftBehind(error: unknown): string {
|
|
|
175
176
|
}
|
|
176
177
|
|
|
177
178
|
export function presentationTools(path: string): ToolDefinition[] {
|
|
178
|
-
const signpost = ` Read the generated catalogue with workspace--read {"path":${JSON.stringify(path)},"limit":140}.
|
|
179
|
+
const signpost = ` Read the generated catalogue with workspace--read {"path":${JSON.stringify(path)},"limit":140}. A hidden tool moves out of your tool list into the host's "settings" toolset (an MCPL server's tool, into that server's tab): toolsets--look lists it there, and toolsets--act calls it once that toolset is open. Changes affect the next newly compiled request, not an in-flight stream.`;
|
|
179
180
|
return [
|
|
180
181
|
{name:'set_tool_visibility', description:'Show or hide a tool definition. Hiding does not revoke permission.' + signpost,
|
|
181
182
|
inputSchema:{type:'object',properties:{name:{type:'string'},visible:{type:'boolean'}},required:['name','visible'],additionalProperties:false}},
|
|
@@ -341,7 +342,7 @@ export class ToolPresentation {
|
|
|
341
342
|
if (field === 'description' && typeof args.description === 'string' && characters(args.description) > MAX_DESCRIPTION_CHARS)
|
|
342
343
|
throw new PresentationRefusal(`Nothing was changed: the description is ${count(characters(args.description))} characters, over the ${count(MAX_DESCRIPTION_CHARS)} allowed. Shorten it and call set_tool_description again.`);
|
|
343
344
|
if (field === 'visible' && args.visible === false && protectedNames.has(name))
|
|
344
|
-
throw new PresentationRefusal(`Nothing was changed: ${name} can't be hidden, since workspace--read, set_tool_visibility and
|
|
345
|
+
throw new PresentationRefusal(`Nothing was changed: ${name} can't be hidden, since workspace--read, set_tool_visibility, set_tool_description and the toolsets-- tools are how you read the catalogue, reach hidden tools and undo these changes. Calling this again won't change that.`);
|
|
345
346
|
return name;
|
|
346
347
|
}
|
|
347
348
|
}
|
|
@@ -356,7 +357,7 @@ export function renderCatalogue(snapshot: PresentationSnapshot): string {
|
|
|
356
357
|
'# Tool catalogue — generated from currently available tools', '',
|
|
357
358
|
`Revision: ${snapshot.revision}`, '',
|
|
358
359
|
`${snapshot.entries.length} tools: ${visible} visible, ${snapshot.entries.length-visible} hidden.`,
|
|
359
|
-
'Visible =
|
|
360
|
+
'Visible = not hidden by you: in your tool list, unless the host keeps it in its "settings" toolset or a server\'s tab (toolsets--look shows those). Hidden = moved into the "settings" toolset, or its MCPL server\'s tab: toolsets--look shows it, toolsets--act calls it once that toolset is open.',
|
|
360
361
|
'These are your visibility choices, not fixed primary/secondary rankings.',
|
|
361
362
|
'Copy exact names from the index; similar-sounding names may not exist.',
|
|
362
363
|
'Show a hidden tool: set_tool_visibility {"name":"EXACT_NAME","visible":true}.',
|