@koda-sl/baker-bridge 0.76.0-dev.9ce0abfe9 → 0.76.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 +8 -8
- package/dist/hono/agent-session.d.ts.map +1 -1
- package/dist/hono/agent-session.js +10 -2
- package/dist/hono/agent-session.js.map +1 -1
- package/dist/hono/agent-session.test.js +25 -0
- package/dist/hono/agent-session.test.js.map +1 -1
- package/dist/hono/agent.d.ts +0 -1
- package/dist/hono/agent.d.ts.map +1 -1
- package/dist/hono/agent.js +11 -16
- package/dist/hono/agent.js.map +1 -1
- package/dist/hono/agent.test.js +21 -5
- package/dist/hono/agent.test.js.map +1 -1
- package/dist/hono/bridge-job.d.ts +0 -7
- package/dist/hono/bridge-job.d.ts.map +1 -1
- package/dist/hono/bridge-job.js +0 -14
- package/dist/hono/bridge-job.js.map +1 -1
- package/dist/hono/bridge-job.test.js +0 -30
- package/dist/hono/bridge-job.test.js.map +1 -1
- package/dist/hono/convex.d.ts +11 -5
- package/dist/hono/convex.d.ts.map +1 -1
- package/dist/hono/convex.js +11 -15
- package/dist/hono/convex.js.map +1 -1
- package/dist/hono/convex.test.js +24 -5
- package/dist/hono/convex.test.js.map +1 -1
- package/dist/hono/relay.d.ts +1 -3
- package/dist/hono/relay.d.ts.map +1 -1
- package/dist/hono/relay.js +0 -6
- package/dist/hono/relay.js.map +1 -1
- package/dist/hono/session-continuity.integration.test.js +10 -2
- package/dist/hono/session-continuity.integration.test.js.map +1 -1
- package/dist/hono/tool-mentions.d.ts +36 -0
- package/dist/hono/tool-mentions.d.ts.map +1 -0
- package/dist/hono/tool-mentions.js +116 -0
- package/dist/hono/tool-mentions.js.map +1 -0
- package/dist/hono/tool-mentions.test.d.ts +2 -0
- package/dist/hono/tool-mentions.test.d.ts.map +1 -0
- package/dist/hono/tool-mentions.test.js +79 -0
- package/dist/hono/tool-mentions.test.js.map +1 -0
- package/package.json +1 -1
- package/dist/hono/mcp-mentions.d.ts +0 -23
- package/dist/hono/mcp-mentions.d.ts.map +0 -1
- package/dist/hono/mcp-mentions.js +0 -59
- package/dist/hono/mcp-mentions.js.map +0 -1
- package/dist/hono/mcp-mentions.test.d.ts +0 -2
- package/dist/hono/mcp-mentions.test.d.ts.map +0 -1
- package/dist/hono/mcp-mentions.test.js +0 -49
- package/dist/hono/mcp-mentions.test.js.map +0 -1
- package/dist/hono/tool-result-images.d.ts +0 -14
- package/dist/hono/tool-result-images.d.ts.map +0 -1
- package/dist/hono/tool-result-images.js +0 -44
- package/dist/hono/tool-result-images.js.map +0 -1
- package/dist/hono/tool-result-images.test.d.ts +0 -2
- package/dist/hono/tool-result-images.test.d.ts.map +0 -1
- package/dist/hono/tool-result-images.test.js +0 -46
- package/dist/hono/tool-result-images.test.js.map +0 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { applyToolMentions, parseToolMentions, stripToolMentions } from "./tool-mentions.js";
|
|
3
|
+
const CLARITY = "@[Microsoft Clarity](mcp:microsoft_clarity?slug=microsoft_clarity&title=Microsoft+Clarity)";
|
|
4
|
+
const LINEAR = "@[Linear](mcp:linear?slug=linear)";
|
|
5
|
+
const GA4 = "@[Google Analytics 4](integration:google-analytics?slug=google-analytics)";
|
|
6
|
+
const SEARCH_CONSOLE = "@[Google Search Console](integration:google-search-console)";
|
|
7
|
+
/** Written before integrations had their own mention type. Still in old messages. */
|
|
8
|
+
const LEGACY_DRIVE = "@[Google Drive](mcp:composio%3Agoogle_drive?slug=composio%3Agoogle_drive)";
|
|
9
|
+
describe("parseToolMentions", () => {
|
|
10
|
+
it("tells a Baker integration apart from a tool that arrives over MCP", () => {
|
|
11
|
+
expect(parseToolMentions(`Read ${GA4} and ${CLARITY}`)).toEqual([
|
|
12
|
+
{ kind: "integration", label: "Google Analytics 4", key: "google-analytics" },
|
|
13
|
+
{ kind: "mcp", label: "Microsoft Clarity", key: "microsoft_clarity" },
|
|
14
|
+
]);
|
|
15
|
+
});
|
|
16
|
+
it("still reads the older provider-prefixed spelling", () => {
|
|
17
|
+
expect(parseToolMentions(LEGACY_DRIVE)).toEqual([{ kind: "mcp", label: "Google Drive", key: "google_drive" }]);
|
|
18
|
+
});
|
|
19
|
+
it("returns every mention, deduped by label", () => {
|
|
20
|
+
expect(parseToolMentions(`${CLARITY} and ${LINEAR} and ${CLARITY}`)).toEqual([
|
|
21
|
+
{ kind: "mcp", label: "Microsoft Clarity", key: "microsoft_clarity" },
|
|
22
|
+
{ kind: "mcp", label: "Linear", key: "linear" },
|
|
23
|
+
]);
|
|
24
|
+
});
|
|
25
|
+
it("ignores /skill tokens and content references", () => {
|
|
26
|
+
expect(parseToolMentions("/plan then @[Spec](document:spec?slug=spec) go")).toEqual([]);
|
|
27
|
+
});
|
|
28
|
+
it("returns nothing for plain text", () => {
|
|
29
|
+
expect(parseToolMentions("just a normal message")).toEqual([]);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe("stripToolMentions", () => {
|
|
33
|
+
it("rewrites each tool token to its plain label", () => {
|
|
34
|
+
expect(stripToolMentions(`Pull last week from ${GA4}.`)).toBe("Pull last week from Google Analytics 4.");
|
|
35
|
+
});
|
|
36
|
+
it("leaves /skill tokens and content references untouched", () => {
|
|
37
|
+
const text = "/plan review @[Spec](document:spec?slug=spec)";
|
|
38
|
+
expect(stripToolMentions(text)).toBe(text);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe("applyToolMentions", () => {
|
|
42
|
+
it("returns the prompt unchanged when no tools are mentioned", () => {
|
|
43
|
+
expect(applyToolMentions("nothing to see here")).toBe("nothing to see here");
|
|
44
|
+
});
|
|
45
|
+
/**
|
|
46
|
+
* The failure this exists to stop: a scheduled task's brief says "read Google
|
|
47
|
+
* Search Console", the agent looks for an MCP tool by that name, finds none,
|
|
48
|
+
* and reports the platform as unavailable — while it is connected, answering,
|
|
49
|
+
* and one `baker gsc` away.
|
|
50
|
+
*/
|
|
51
|
+
it("tells the agent an integration is reached with a baker command, not an MCP tool", () => {
|
|
52
|
+
const result = applyToolMentions(`Review search performance using ${SEARCH_CONSOLE}`);
|
|
53
|
+
expect(result).toContain("Review search performance using Google Search Console");
|
|
54
|
+
expect(result).toContain("baker gsc");
|
|
55
|
+
expect(result).toContain("not through MCP");
|
|
56
|
+
});
|
|
57
|
+
it("names an integration it has no command for without inventing one", () => {
|
|
58
|
+
const result = applyToolMentions("Check @[Calendly](integration:calendly)");
|
|
59
|
+
expect(result).toContain("Calendly");
|
|
60
|
+
expect(result).not.toContain("`baker undefined`");
|
|
61
|
+
});
|
|
62
|
+
it("keeps the prefer-this-tool instruction for MCP tools", () => {
|
|
63
|
+
const result = applyToolMentions(`Grab the file from ${LINEAR}`);
|
|
64
|
+
expect(result).toContain("Grab the file from Linear");
|
|
65
|
+
expect(result).toContain("Prefer it");
|
|
66
|
+
});
|
|
67
|
+
/**
|
|
68
|
+
* A brief that names both — which every marketplace template does — has to say
|
|
69
|
+
* both things. Collapsing them into one instruction is how an integration ends
|
|
70
|
+
* up described as a tool to prefer.
|
|
71
|
+
*/
|
|
72
|
+
it("gives each kind its own instruction when a prompt names both", () => {
|
|
73
|
+
const result = applyToolMentions(`Read ${GA4} then ${CLARITY}`);
|
|
74
|
+
expect(result).toContain("baker ga4");
|
|
75
|
+
expect(result).toContain("Prefer it");
|
|
76
|
+
expect(result).toContain("Microsoft Clarity");
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=tool-mentions.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-mentions.test.js","sourceRoot":"","sources":["../../src/hono/tool-mentions.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE7F,MAAM,OAAO,GAAG,4FAA4F,CAAC;AAC7G,MAAM,MAAM,GAAG,mCAAmC,CAAC;AACnD,MAAM,GAAG,GAAG,2EAA2E,CAAC;AACxF,MAAM,cAAc,GAAG,6DAA6D,CAAC;AACrF,qFAAqF;AACrF,MAAM,YAAY,GAAG,2EAA2E,CAAC;AAEjG,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,CAAC,iBAAiB,CAAC,QAAQ,GAAG,QAAQ,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9D,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,oBAAoB,EAAE,GAAG,EAAE,kBAAkB,EAAE;YAC7E,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,mBAAmB,EAAE;SACtE,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;IACjH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,iBAAiB,CAAC,GAAG,OAAO,QAAQ,MAAM,QAAQ,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAC3E,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,mBAAmB,EAAE;YACrE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE;SAChD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,iBAAiB,CAAC,gDAAgD,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,iBAAiB,CAAC,uBAAuB,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,iBAAiB,CAAC,uBAAuB,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IAC3G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,IAAI,GAAG,+CAA+C,CAAC;QAC7D,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;IAEH;;;;;OAKG;IACH,EAAE,CAAC,iFAAiF,EAAE,GAAG,EAAE;QACzF,MAAM,MAAM,GAAG,iBAAiB,CAAC,mCAAmC,cAAc,EAAE,CAAC,CAAC;QAEtF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,uDAAuD,CAAC,CAAC;QAClF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,MAAM,GAAG,iBAAiB,CAAC,yCAAyC,CAAC,CAAC;QAE5E,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,MAAM,GAAG,iBAAiB,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAC;QAEjE,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC;QACtD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH;;;;OAIG;IACH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,GAAG,SAAS,OAAO,EAAE,CAAC,CAAC;QAEhE,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koda-sl/baker-bridge",
|
|
3
|
-
"version": "0.76.0
|
|
3
|
+
"version": "0.76.0",
|
|
4
4
|
"description": "HTTP server wrapping the Claude Agent SDK. Persists chat events to Convex; the dashboard subscribes via Convex realtime",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP tool mentions carried in a chat prompt. The dashboard serializes a green
|
|
3
|
-
* `@`-mention as `@[Label](mcp:<provider>:<key>?…metadata)`; the bridge strips
|
|
4
|
-
* those tokens back to their plain label and appends one explicit instruction so
|
|
5
|
-
* the agent prefers the requested tools this turn. Activation is a hint, not a
|
|
6
|
-
* restriction — every other tool stays available.
|
|
7
|
-
*/
|
|
8
|
-
export type McpMention = {
|
|
9
|
-
label: string;
|
|
10
|
-
provider: string;
|
|
11
|
-
key: string;
|
|
12
|
-
};
|
|
13
|
-
/** Every MCP tool the user `@`-mentioned in the prompt, in order, deduped by label. */
|
|
14
|
-
export declare function parseMcpMentions(content: string): McpMention[];
|
|
15
|
-
/** Rewrite each `@[Label](mcp:…)` token to its plain label, leaving all other text intact. */
|
|
16
|
-
export declare function stripMcpMentions(content: string): string;
|
|
17
|
-
/**
|
|
18
|
-
* Clean the prompt of MCP mention tokens and, when any were present, append the
|
|
19
|
-
* "prefer these tools" instruction. Returns the prompt unchanged when there are
|
|
20
|
-
* none, so non-mention turns are untouched.
|
|
21
|
-
*/
|
|
22
|
-
export declare function applyMcpMentions(content: string): string;
|
|
23
|
-
//# sourceMappingURL=mcp-mentions.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-mentions.d.ts","sourceRoot":"","sources":["../../src/hono/mcp-mentions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAqB1E,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CAY9D;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAUxD"}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP tool mentions carried in a chat prompt. The dashboard serializes a green
|
|
3
|
-
* `@`-mention as `@[Label](mcp:<provider>:<key>?…metadata)`; the bridge strips
|
|
4
|
-
* those tokens back to their plain label and appends one explicit instruction so
|
|
5
|
-
* the agent prefers the requested tools this turn. Activation is a hint, not a
|
|
6
|
-
* restriction — every other tool stays available.
|
|
7
|
-
*/
|
|
8
|
-
const MCP_MENTION_RE = /@\[([^\]]*)\]\(mcp:([^)]+)\)/g;
|
|
9
|
-
function decode(value) {
|
|
10
|
-
try {
|
|
11
|
-
return decodeURIComponent(value);
|
|
12
|
-
}
|
|
13
|
-
catch {
|
|
14
|
-
return value;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
/** Split the mention target (`composio%3Agoogle_drive?slug=…`) into provider + key. */
|
|
18
|
-
function parseTarget(rawTarget) {
|
|
19
|
-
const beforeQuery = rawTarget.split("?", 1)[0] ?? rawTarget;
|
|
20
|
-
const decoded = decode(beforeQuery);
|
|
21
|
-
const colon = decoded.indexOf(":");
|
|
22
|
-
if (colon === -1) {
|
|
23
|
-
return { provider: "", key: decoded };
|
|
24
|
-
}
|
|
25
|
-
return { provider: decoded.slice(0, colon), key: decoded.slice(colon + 1) };
|
|
26
|
-
}
|
|
27
|
-
/** Every MCP tool the user `@`-mentioned in the prompt, in order, deduped by label. */
|
|
28
|
-
export function parseMcpMentions(content) {
|
|
29
|
-
const seen = new Set();
|
|
30
|
-
const mentions = [];
|
|
31
|
-
for (const match of content.matchAll(MCP_MENTION_RE)) {
|
|
32
|
-
const label = (match[1] ?? "").trim();
|
|
33
|
-
if (!label || seen.has(label)) {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
seen.add(label);
|
|
37
|
-
mentions.push({ label, ...parseTarget(match[2] ?? "") });
|
|
38
|
-
}
|
|
39
|
-
return mentions;
|
|
40
|
-
}
|
|
41
|
-
/** Rewrite each `@[Label](mcp:…)` token to its plain label, leaving all other text intact. */
|
|
42
|
-
export function stripMcpMentions(content) {
|
|
43
|
-
return content.replace(MCP_MENTION_RE, (_full, label) => label.trim());
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Clean the prompt of MCP mention tokens and, when any were present, append the
|
|
47
|
-
* "prefer these tools" instruction. Returns the prompt unchanged when there are
|
|
48
|
-
* none, so non-mention turns are untouched.
|
|
49
|
-
*/
|
|
50
|
-
export function applyMcpMentions(content) {
|
|
51
|
-
const mentions = parseMcpMentions(content);
|
|
52
|
-
const stripped = stripMcpMentions(content);
|
|
53
|
-
if (mentions.length === 0) {
|
|
54
|
-
return stripped;
|
|
55
|
-
}
|
|
56
|
-
const labels = mentions.map((m) => m.label).join(", ");
|
|
57
|
-
return `${stripped}\n\n[Tool request: the user explicitly asked to use ${labels} for this turn. Prefer ${mentions.length === 1 ? "it" : "them"} to fulfill the request; other tools remain available.]`;
|
|
58
|
-
}
|
|
59
|
-
//# sourceMappingURL=mcp-mentions.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-mentions.js","sourceRoot":"","sources":["../../src/hono/mcp-mentions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,cAAc,GAAG,+BAA+B,CAAC;AAIvD,SAAS,MAAM,CAAC,KAAa;IAC3B,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,SAAS,WAAW,CAAC,SAAiB;IACpC,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;IAC5D,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QACjB,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;IACxC,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;AAC9E,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,QAAQ,GAAiB,EAAE,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,SAAS;QACX,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChB,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO,OAAO,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACjF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvD,OAAO,GAAG,QAAQ,uDAAuD,MAAM,0BAC7E,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MACjC,yDAAyD,CAAC;AAC5D,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-mentions.test.d.ts","sourceRoot":"","sources":["../../src/hono/mcp-mentions.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { applyMcpMentions, parseMcpMentions, stripMcpMentions } from "./mcp-mentions.js";
|
|
3
|
-
const DRIVE = "@[Google Drive](mcp:composio%3Agoogle_drive?slug=composio%3Agoogle_drive&title=Google+Drive)";
|
|
4
|
-
const LINEAR = "@[Linear](mcp:custom%3Alinear?slug=custom%3Alinear)";
|
|
5
|
-
describe("parseMcpMentions", () => {
|
|
6
|
-
it("extracts label, provider, and key from a serialized mention", () => {
|
|
7
|
-
expect(parseMcpMentions(`Use ${DRIVE} please`)).toEqual([
|
|
8
|
-
{ label: "Google Drive", provider: "composio", key: "google_drive" },
|
|
9
|
-
]);
|
|
10
|
-
});
|
|
11
|
-
it("returns every mention, deduped by label", () => {
|
|
12
|
-
expect(parseMcpMentions(`${DRIVE} and ${LINEAR} and ${DRIVE}`)).toEqual([
|
|
13
|
-
{ label: "Google Drive", provider: "composio", key: "google_drive" },
|
|
14
|
-
{ label: "Linear", provider: "custom", key: "linear" },
|
|
15
|
-
]);
|
|
16
|
-
});
|
|
17
|
-
it("ignores /skill tokens and non-mcp references", () => {
|
|
18
|
-
expect(parseMcpMentions("/plan then @[Spec](document:spec?slug=spec) go")).toEqual([]);
|
|
19
|
-
});
|
|
20
|
-
it("returns nothing for plain text", () => {
|
|
21
|
-
expect(parseMcpMentions("just a normal message")).toEqual([]);
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
describe("stripMcpMentions", () => {
|
|
25
|
-
it("rewrites each mcp token to its plain label", () => {
|
|
26
|
-
expect(stripMcpMentions(`Pull the deck from ${DRIVE}.`)).toBe("Pull the deck from Google Drive.");
|
|
27
|
-
});
|
|
28
|
-
it("leaves /skill tokens and content references untouched", () => {
|
|
29
|
-
const text = "/plan review @[Spec](document:spec?slug=spec)";
|
|
30
|
-
expect(stripMcpMentions(text)).toBe(text);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
describe("applyMcpMentions", () => {
|
|
34
|
-
it("returns the prompt unchanged when no mcp tools are mentioned", () => {
|
|
35
|
-
expect(applyMcpMentions("nothing to see here")).toBe("nothing to see here");
|
|
36
|
-
});
|
|
37
|
-
it("strips tokens and appends a singular prefer-this-tool instruction", () => {
|
|
38
|
-
const result = applyMcpMentions(`Grab the file from ${DRIVE}`);
|
|
39
|
-
expect(result).toContain("Grab the file from Google Drive");
|
|
40
|
-
expect(result).toContain("Prefer it");
|
|
41
|
-
expect(result).toContain("Google Drive");
|
|
42
|
-
});
|
|
43
|
-
it("names every requested tool in the appended instruction", () => {
|
|
44
|
-
const result = applyMcpMentions(`${DRIVE} ${LINEAR}`);
|
|
45
|
-
expect(result).toContain("Google Drive, Linear");
|
|
46
|
-
expect(result).toContain("Prefer them");
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
//# sourceMappingURL=mcp-mentions.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-mentions.test.js","sourceRoot":"","sources":["../../src/hono/mcp-mentions.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* When the agent reads an image — a screenshot it just took, a crop it made —
|
|
3
|
-
* the SDK returns the bytes inline on the tool result. Those results are never
|
|
4
|
-
* relayed (they are huge and mostly text), so the chat can only show the file
|
|
5
|
-
* path. This picks out just the image bytes so the dashboard can show the
|
|
6
|
-
* picture the agent actually looked at.
|
|
7
|
-
*/
|
|
8
|
-
export type ToolResultImage = {
|
|
9
|
-
toolUseId: string;
|
|
10
|
-
mediaType: string;
|
|
11
|
-
data: string;
|
|
12
|
-
};
|
|
13
|
-
export declare function extractToolResultImages(message: unknown): ToolResultImage[];
|
|
14
|
-
//# sourceMappingURL=tool-result-images.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-result-images.d.ts","sourceRoot":"","sources":["../../src/hono/tool-result-images.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AA6BF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe,EAAE,CAkB3E"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/** A screenshot is well under this; anything bigger is not worth a chat thumbnail. */
|
|
2
|
-
const MAX_BASE64_LENGTH = 4_000_000;
|
|
3
|
-
const MAX_IMAGES_PER_MESSAGE = 3;
|
|
4
|
-
function asBlocks(value) {
|
|
5
|
-
return Array.isArray(value) ? value.filter((b) => b && typeof b === "object") : [];
|
|
6
|
-
}
|
|
7
|
-
function imageFromBlock(block) {
|
|
8
|
-
if (block.type !== "image") {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
const source = block.source;
|
|
12
|
-
if (!source || source.type !== "base64") {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
const mediaType = source.media_type;
|
|
16
|
-
const data = source.data;
|
|
17
|
-
if (typeof mediaType !== "string" || !mediaType.startsWith("image/") || typeof data !== "string") {
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
if (data.length === 0 || data.length > MAX_BASE64_LENGTH) {
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
return { mediaType, data };
|
|
24
|
-
}
|
|
25
|
-
export function extractToolResultImages(message) {
|
|
26
|
-
const content = message?.message?.content;
|
|
27
|
-
const images = [];
|
|
28
|
-
for (const block of asBlocks(content)) {
|
|
29
|
-
if (block.type !== "tool_result" || typeof block.tool_use_id !== "string") {
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
for (const inner of asBlocks(block.content)) {
|
|
33
|
-
const image = imageFromBlock(inner);
|
|
34
|
-
if (image) {
|
|
35
|
-
images.push({ toolUseId: block.tool_use_id, ...image });
|
|
36
|
-
}
|
|
37
|
-
if (images.length >= MAX_IMAGES_PER_MESSAGE) {
|
|
38
|
-
return images;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return images;
|
|
43
|
-
}
|
|
44
|
-
//# sourceMappingURL=tool-result-images.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-result-images.js","sourceRoot":"","sources":["../../src/hono/tool-result-images.ts"],"names":[],"mappings":"AAaA,sFAAsF;AACtF,MAAM,iBAAiB,GAAG,SAAS,CAAC;AACpC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAEjC,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,CAA+B,CAAC,CAAC,CAAC,EAAE,CAAC;AACpH,CAAC;AAED,SAAS,cAAc,CAAC,KAA8B;IACpD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,MAA6C,CAAC;IACnE,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC;IACpC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACjG,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,iBAAiB,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,MAAM,OAAO,GAAI,OAA2D,EAAE,OAAO,EAAE,OAAO,CAAC;IAC/F,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;YAC1E,SAAS;QACX,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5C,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;YACpC,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,WAAW,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;YAC1D,CAAC;YACD,IAAI,MAAM,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC;gBAC5C,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-result-images.test.d.ts","sourceRoot":"","sources":["../../src/hono/tool-result-images.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { extractToolResultImages } from "./tool-result-images.js";
|
|
3
|
-
function userMessage(content) {
|
|
4
|
-
return { type: "user", message: { role: "user", content } };
|
|
5
|
-
}
|
|
6
|
-
describe("extractToolResultImages", () => {
|
|
7
|
-
it("returns the image bytes of a tool result that read a screenshot", () => {
|
|
8
|
-
const message = userMessage([
|
|
9
|
-
{
|
|
10
|
-
type: "tool_result",
|
|
11
|
-
tool_use_id: "toolu_1",
|
|
12
|
-
content: [
|
|
13
|
-
{ type: "text", text: "Read image" },
|
|
14
|
-
{ type: "image", source: { type: "base64", media_type: "image/png", data: "AAAA" } },
|
|
15
|
-
],
|
|
16
|
-
},
|
|
17
|
-
]);
|
|
18
|
-
expect(extractToolResultImages(message)).toEqual([{ toolUseId: "toolu_1", mediaType: "image/png", data: "AAAA" }]);
|
|
19
|
-
});
|
|
20
|
-
it("ignores text-only tool results", () => {
|
|
21
|
-
const message = userMessage([{ type: "tool_result", tool_use_id: "toolu_1", content: "file contents" }]);
|
|
22
|
-
expect(extractToolResultImages(message)).toEqual([]);
|
|
23
|
-
});
|
|
24
|
-
it("skips images too large to be worth a chat thumbnail", () => {
|
|
25
|
-
const message = userMessage([
|
|
26
|
-
{
|
|
27
|
-
type: "tool_result",
|
|
28
|
-
tool_use_id: "toolu_1",
|
|
29
|
-
content: [{ type: "image", source: { type: "base64", media_type: "image/png", data: "A".repeat(4_000_001) } }],
|
|
30
|
-
},
|
|
31
|
-
]);
|
|
32
|
-
expect(extractToolResultImages(message)).toEqual([]);
|
|
33
|
-
});
|
|
34
|
-
it("stops after three images so one tool result can't flood the chat", () => {
|
|
35
|
-
const image = { type: "image", source: { type: "base64", media_type: "image/png", data: "AAAA" } };
|
|
36
|
-
const message = userMessage([
|
|
37
|
-
{ type: "tool_result", tool_use_id: "toolu_1", content: [image, image, image, image] },
|
|
38
|
-
]);
|
|
39
|
-
expect(extractToolResultImages(message)).toHaveLength(3);
|
|
40
|
-
});
|
|
41
|
-
it("returns nothing for a message with no content blocks", () => {
|
|
42
|
-
expect(extractToolResultImages({ type: "user" })).toEqual([]);
|
|
43
|
-
expect(extractToolResultImages(undefined)).toEqual([]);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
//# sourceMappingURL=tool-result-images.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-result-images.test.js","sourceRoot":"","sources":["../../src/hono/tool-result-images.test.ts"],"names":[],"mappings":"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"}
|