@kenkaiiii/ggcoder 5.48.0 → 5.49.1
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/app-sidecar-auth-broadcast.test.js +1 -1
- package/dist/app-sidecar-auth-broadcast.test.js.map +1 -1
- package/dist/app-sidecar.js +253 -2
- package/dist/app-sidecar.js.map +1 -1
- package/dist/cli/shared.d.ts.map +1 -1
- package/dist/cli/shared.js +2 -0
- package/dist/cli/shared.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-compaction.test.js +1 -0
- package/dist/core/agent-session-compaction.test.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +15 -8
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-providers.d.ts.map +1 -1
- package/dist/core/auth-providers.js +21 -21
- package/dist/core/auth-providers.js.map +1 -1
- package/dist/core/context-limits.d.ts +35 -0
- package/dist/core/context-limits.d.ts.map +1 -0
- package/dist/core/context-limits.js +35 -0
- package/dist/core/context-limits.js.map +1 -0
- package/dist/core/context-limits.test.d.ts +2 -0
- package/dist/core/context-limits.test.d.ts.map +1 -0
- package/dist/core/context-limits.test.js +55 -0
- package/dist/core/context-limits.test.js.map +1 -0
- package/dist/core/local-endpoint-store.test.js +1 -9
- package/dist/core/local-endpoint-store.test.js.map +1 -1
- package/dist/core/mcp/deferred-catalog.d.ts +9 -0
- package/dist/core/mcp/deferred-catalog.d.ts.map +1 -1
- package/dist/core/mcp/deferred-catalog.js +15 -1
- package/dist/core/mcp/deferred-catalog.js.map +1 -1
- package/dist/core/process-manager-notifications.test.js +31 -13
- package/dist/core/process-manager-notifications.test.js.map +1 -1
- package/dist/core/process-manager-wake.test.js +8 -4
- package/dist/core/process-manager-wake.test.js.map +1 -1
- package/dist/core/process-manager.d.ts +11 -0
- package/dist/core/process-manager.d.ts.map +1 -1
- package/dist/core/process-manager.js +9 -2
- package/dist/core/process-manager.js.map +1 -1
- package/dist/core/sandbox.d.ts.map +1 -1
- package/dist/core/sandbox.js +66 -1
- package/dist/core/sandbox.js.map +1 -1
- package/dist/core/sandbox.test.js +64 -0
- package/dist/core/sandbox.test.js.map +1 -1
- package/dist/core/settings-manager.d.ts +9 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +18 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills-routing.test.js +42 -0
- package/dist/core/skills-routing.test.js.map +1 -1
- package/dist/core/skills.d.ts +16 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +37 -5
- package/dist/core/skills.js.map +1 -1
- package/dist/core/subagent-manager.d.ts +17 -0
- package/dist/core/subagent-manager.d.ts.map +1 -1
- package/dist/core/subagent-manager.js +92 -1
- package/dist/core/subagent-manager.js.map +1 -1
- package/dist/core/subagent-manager.test.js +161 -0
- package/dist/core/subagent-manager.test.js.map +1 -1
- package/dist/core/subagent-turn-record.d.ts +17 -0
- package/dist/core/subagent-turn-record.d.ts.map +1 -0
- package/dist/core/subagent-turn-record.js +82 -0
- package/dist/core/subagent-turn-record.js.map +1 -0
- package/dist/core/subagent-turn-record.test.d.ts +2 -0
- package/dist/core/subagent-turn-record.test.d.ts.map +1 -0
- package/dist/core/subagent-turn-record.test.js +70 -0
- package/dist/core/subagent-turn-record.test.js.map +1 -0
- package/dist/hf-pull.d.ts +66 -0
- package/dist/hf-pull.d.ts.map +1 -0
- package/dist/hf-pull.js +109 -0
- package/dist/hf-pull.js.map +1 -0
- package/dist/hf-pull.test.d.ts +2 -0
- package/dist/hf-pull.test.d.ts.map +1 -0
- package/dist/hf-pull.test.js +112 -0
- package/dist/hf-pull.test.js.map +1 -0
- package/dist/modes/subagent-worker-mode.d.ts.map +1 -1
- package/dist/modes/subagent-worker-mode.js +66 -8
- package/dist/modes/subagent-worker-mode.js.map +1 -1
- package/dist/system-prompt.d.ts +7 -2
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +26 -9
- package/dist/system-prompt.js.map +1 -1
- package/dist/system-prompt.test.js +26 -0
- package/dist/system-prompt.test.js.map +1 -1
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/path-utils.d.ts +28 -1
- package/dist/tools/path-utils.d.ts.map +1 -1
- package/dist/tools/path-utils.js +44 -2
- package/dist/tools/path-utils.js.map +1 -1
- package/dist/tools/path-utils.test.js +57 -1
- package/dist/tools/path-utils.test.js.map +1 -1
- package/dist/tools/skill.d.ts +3 -2
- package/dist/tools/skill.d.ts.map +1 -1
- package/dist/tools/skill.js +10 -7
- package/dist/tools/skill.js.map +1 -1
- package/dist/tools/tool-search.d.ts +2 -1
- package/dist/tools/tool-search.d.ts.map +1 -1
- package/dist/tools/tool-search.js +28 -3
- package/dist/tools/tool-search.js.map +1 -1
- package/dist/tools/tool-search.test.js +58 -0
- package/dist/tools/tool-search.test.js.map +1 -1
- package/dist/tools/web-fetch.d.ts +7 -0
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +284 -20
- package/dist/tools/web-fetch.js.map +1 -1
- package/dist/tools/web-fetch.test.js +137 -0
- package/dist/tools/web-fetch.test.js.map +1 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/ModelSelector.d.ts.map +1 -1
- package/dist/ui/components/ModelSelector.js +1 -0
- package/dist/ui/components/ModelSelector.js.map +1 -1
- package/dist/ui/login.d.ts.map +1 -1
- package/dist/ui/login.js +7 -2
- package/dist/ui/login.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { resolveToolSchema } from "@kenkaiiii/gg-ai";
|
|
3
|
+
import { CONTEXT_LIMITS } from "../core/context-limits.js";
|
|
2
4
|
const ToolSearchParams = z.object({
|
|
3
5
|
query: z
|
|
4
6
|
.string()
|
|
@@ -15,7 +17,7 @@ const ToolSearchParams = z.object({
|
|
|
15
17
|
* learns *now* whether the capability really exists, instead of promoting a
|
|
16
18
|
* tool that will fail on first call. Returns undefined for already-live tools.
|
|
17
19
|
*/
|
|
18
|
-
export function createToolSearchTool(catalog, onPromote, resolveCached) {
|
|
20
|
+
export function createToolSearchTool(catalog, onPromote, resolveCached, limits = CONTEXT_LIMITS) {
|
|
19
21
|
return {
|
|
20
22
|
name: "tool_search",
|
|
21
23
|
description: "Load a tool that is listed as available on demand. Searches the catalog of " +
|
|
@@ -31,7 +33,26 @@ export function createToolSearchTool(catalog, onPromote, resolveCached) {
|
|
|
31
33
|
? "No tools matched and the catalog is empty — every catalog tool is already available."
|
|
32
34
|
: `No tools matched "${query}". Still in the catalog: ${remaining.join(", ")}`;
|
|
33
35
|
}
|
|
34
|
-
|
|
36
|
+
// Schema budget, fail closed: a tool whose serialized input schema exceeds
|
|
37
|
+
// the budget is NOT promoted — promoting it would bill those bytes on every
|
|
38
|
+
// subsequent request. The user can raise contextLimits.mcpToolSchemaBytes.
|
|
39
|
+
const oversized = [];
|
|
40
|
+
const promotable = [];
|
|
41
|
+
for (const tool of matches) {
|
|
42
|
+
const bytes = Buffer.byteLength(JSON.stringify(resolveToolSchema(tool)), "utf8");
|
|
43
|
+
if (bytes > limits.mcpToolSchemaBytes)
|
|
44
|
+
oversized.push({ name: tool.name, bytes });
|
|
45
|
+
else
|
|
46
|
+
promotable.push(tool);
|
|
47
|
+
}
|
|
48
|
+
if (promotable.length === 0) {
|
|
49
|
+
const details = oversized
|
|
50
|
+
.map((t) => `- ${t.name}: schema is ${Math.round(t.bytes / 1024)}KB (budget ${Math.round(limits.mcpToolSchemaBytes / 1024)}KB)`)
|
|
51
|
+
.join("\n");
|
|
52
|
+
return (`No tools promoted — every match exceeds the schema byte budget.\n${details}\n` +
|
|
53
|
+
`Raise the contextLimits.mcpToolSchemaBytes setting if this tool is trusted.`);
|
|
54
|
+
}
|
|
55
|
+
const promoted = catalog.promote(promotable.map((t) => t.name));
|
|
35
56
|
onPromote(promoted);
|
|
36
57
|
const unavailable = new Map();
|
|
37
58
|
if (resolveCached) {
|
|
@@ -48,7 +69,11 @@ export function createToolSearchTool(catalog, onPromote, resolveCached) {
|
|
|
48
69
|
}
|
|
49
70
|
const lines = available.map((t) => `- ${t.name}: ${t.description.split("\n")[0].slice(0, 200)}`);
|
|
50
71
|
const body = `${available.length} tool(s) now available:\n${lines.join("\n")}`;
|
|
51
|
-
|
|
72
|
+
const refused = oversized.length > 0
|
|
73
|
+
? `\n\nRefused (schema byte budget):\n${oversized.map((t) => `- ${t.name} (${Math.round(t.bytes / 1024)}KB schema)`).join("\n")}\nRaise the contextLimits.mcpToolSchemaBytes setting if a refused tool is trusted.`
|
|
74
|
+
: "";
|
|
75
|
+
const unreachable = failures.length > 0 ? `\n\nUnreachable:\n${failures.join("\n")}` : "";
|
|
76
|
+
return `${body}${refused}${unreachable}`;
|
|
52
77
|
},
|
|
53
78
|
};
|
|
54
79
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-search.js","sourceRoot":"","sources":["../../src/tools/tool-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-search.js","sourceRoot":"","sources":["../../src/tools/tool-search.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { resolveContextLimits } from "../core/context-limits.js";
|
|
3
4
|
import { DeferredToolCatalog } from "../core/mcp/deferred-catalog.js";
|
|
4
5
|
import { createToolSearchTool } from "./tool-search.js";
|
|
5
6
|
const CONTEXT = {};
|
|
@@ -65,5 +66,62 @@ describe("tool_search", () => {
|
|
|
65
66
|
const tool = createToolSearchTool(catalog, () => { });
|
|
66
67
|
expect(await search(tool, "design screenshots")).toContain("1 tool(s) now available");
|
|
67
68
|
});
|
|
69
|
+
it("refuses promotion of a tool whose schema exceeds the byte budget", async () => {
|
|
70
|
+
const catalog = new DeferredToolCatalog();
|
|
71
|
+
const huge = z.object({
|
|
72
|
+
blob: z.string().describe("x".repeat(200 * 1024)), // 200KB serialized schema
|
|
73
|
+
});
|
|
74
|
+
catalog.add([
|
|
75
|
+
{
|
|
76
|
+
name: "mcp__big__blob",
|
|
77
|
+
description: "fetch design screenshots",
|
|
78
|
+
parameters: huge,
|
|
79
|
+
execute: async () => "ok",
|
|
80
|
+
},
|
|
81
|
+
stub("mcp__figma__get_screens", "fetch design screenshots"),
|
|
82
|
+
]);
|
|
83
|
+
const promotedNames = [];
|
|
84
|
+
const tool = createToolSearchTool(catalog, (tools) => promotedNames.push(...tools.map((t) => t.name)));
|
|
85
|
+
const result = await search(tool, "design screenshots");
|
|
86
|
+
// The fit tool promoted; the oversized one was refused and named.
|
|
87
|
+
expect(result).toContain("1 tool(s) now available");
|
|
88
|
+
expect(result).toContain("mcp__figma__get_screens");
|
|
89
|
+
expect(result).toContain("Refused (schema byte budget)");
|
|
90
|
+
expect(result).toContain("mcp__big__blob");
|
|
91
|
+
expect(result).toContain("contextLimits.mcpToolSchemaBytes");
|
|
92
|
+
expect(promotedNames).toEqual(["mcp__figma__get_screens"]);
|
|
93
|
+
// Refused tool stays in the catalog, not the live toolset.
|
|
94
|
+
expect(catalog.names()).toContain("mcp__big__blob");
|
|
95
|
+
});
|
|
96
|
+
it("fails closed when EVERY match exceeds the schema budget", async () => {
|
|
97
|
+
const catalog = new DeferredToolCatalog();
|
|
98
|
+
catalog.add([
|
|
99
|
+
{
|
|
100
|
+
name: "mcp__big__blob",
|
|
101
|
+
description: "fetch design screenshots",
|
|
102
|
+
parameters: z.object({ blob: z.string().describe("x".repeat(200 * 1024)) }),
|
|
103
|
+
execute: async () => "ok",
|
|
104
|
+
},
|
|
105
|
+
]);
|
|
106
|
+
const promotedNames = [];
|
|
107
|
+
const tool = createToolSearchTool(catalog, (tools) => promotedNames.push(...tools.map((t) => t.name)));
|
|
108
|
+
const result = await search(tool, "design screenshots");
|
|
109
|
+
expect(result).toContain("No tools promoted");
|
|
110
|
+
expect(result).toContain("mcp__big__blob");
|
|
111
|
+
expect(promotedNames).toEqual([]);
|
|
112
|
+
});
|
|
113
|
+
it("honors a raised schema budget from limits", async () => {
|
|
114
|
+
const catalog = new DeferredToolCatalog();
|
|
115
|
+
catalog.add([
|
|
116
|
+
{
|
|
117
|
+
name: "mcp__big__blob",
|
|
118
|
+
description: "fetch design screenshots",
|
|
119
|
+
parameters: z.object({ blob: z.string().describe("x".repeat(8 * 1024)) }), // ~8KB
|
|
120
|
+
execute: async () => "ok",
|
|
121
|
+
},
|
|
122
|
+
]);
|
|
123
|
+
const tool = createToolSearchTool(catalog, () => { }, undefined, resolveContextLimits({ mcpToolSchemaBytes: 16 * 1024 }));
|
|
124
|
+
expect(await search(tool, "design screenshots")).toContain("1 tool(s) now available");
|
|
125
|
+
});
|
|
68
126
|
});
|
|
69
127
|
//# sourceMappingURL=tool-search.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-search.test.js","sourceRoot":"","sources":["../../src/tools/tool-search.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tool-search.test.js","sourceRoot":"","sources":["../../src/tools/tool-search.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,11 @@ import { type GetNetworkPolicy } from "../core/network-guard.js";
|
|
|
7
7
|
*/
|
|
8
8
|
export declare function isBlockedUrl(urlString: string): boolean;
|
|
9
9
|
export declare function htmlToCleanText(html: string): string;
|
|
10
|
+
/** A hyperlink shown in an outline render as `anchor text [number]`. */
|
|
11
|
+
export interface OutlineLink {
|
|
12
|
+
number: number;
|
|
13
|
+
url: string;
|
|
14
|
+
}
|
|
10
15
|
type LlmsCandidateKind = "llms" | "llms-full" | "llms-ctx" | "page-md";
|
|
11
16
|
interface LlmsCandidate {
|
|
12
17
|
url: string;
|
|
@@ -20,11 +25,13 @@ export declare function createWebFetchTool(getNetworkPolicy?: GetNetworkPolicy):
|
|
|
20
25
|
declare const parameters: z.ZodObject<{
|
|
21
26
|
url: z.ZodOptional<z.ZodString>;
|
|
22
27
|
urls: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
28
|
+
follow: z.ZodOptional<z.ZodNumber>;
|
|
23
29
|
max_length: z.ZodOptional<z.ZodNumber>;
|
|
24
30
|
format: z.ZodOptional<z.ZodEnum<{
|
|
25
31
|
text: "text";
|
|
26
32
|
html: "html";
|
|
27
33
|
markdown: "markdown";
|
|
34
|
+
outline: "outline";
|
|
28
35
|
}>>;
|
|
29
36
|
prefer_llms_txt: z.ZodOptional<z.ZodBoolean>;
|
|
30
37
|
}, z.core.$strip>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../src/tools/web-fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,qBAAqB,CAAC;AAIlE,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CA0CvD;AAmGD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYpD;
|
|
1
|
+
{"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../src/tools/web-fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,qBAAqB,CAAC;AAIlE,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CA0CvD;AAmGD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYpD;AAcD,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AA6MD,KAAK,iBAAiB,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AAEvE,UAAU,aAAa;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAkID,wBAAsB,eAAe,CACnC,QAAQ,EAAE,QAAQ,EAClB,QAAQ,SAAqB,GAC5B,OAAO,CAAC,UAAU,CAAC,CA2BrB;AAwLD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa,EAAE,CAuCnF;AA2HD,wBAAgB,kBAAkB,CAChC,gBAAgB,CAAC,EAAE,gBAAgB,GAClC,SAAS,CAAC,OAAO,UAAU,CAAC,CA8E9B;AA0BD,QAAA,MAAM,UAAU;;;;;;;;;;;;iBAyCb,CAAC"}
|
package/dist/tools/web-fetch.js
CHANGED
|
@@ -142,6 +142,184 @@ export function htmlToCleanText(html) {
|
|
|
142
142
|
.replace(/\n{3,}/g, "\n\n")
|
|
143
143
|
.trim();
|
|
144
144
|
}
|
|
145
|
+
// ── Outline rendering (compact numbered view) ────────────────
|
|
146
|
+
/** Hard cap on how many links one tool call will number. */
|
|
147
|
+
const MAX_OUTLINE_LINKS = 100;
|
|
148
|
+
/** ~500 tokens of body: the whole point of the outline format. */
|
|
149
|
+
const OUTLINE_DEFAULT_MAX_LENGTH = 2000;
|
|
150
|
+
/** Per-session render cache size (pages, not bytes). */
|
|
151
|
+
const MAX_CACHED_PAGES = 32;
|
|
152
|
+
const OUTLINE_INDEX_HEADER = "Links (fetch one with `follow`):";
|
|
153
|
+
const BLOCKED_URL_MESSAGE = "Error: URL blocked — requests to private/internal network addresses are not allowed.";
|
|
154
|
+
/**
|
|
155
|
+
* Allocates the small stable numbers that replace hyperlinks in an outline
|
|
156
|
+
* render. Scoped to a single tool call, deduped by absolute URL, and capped at
|
|
157
|
+
* {@link MAX_OUTLINE_LINKS} so a link-farm page cannot grow the index (or the
|
|
158
|
+
* session's follow map) without bound.
|
|
159
|
+
*/
|
|
160
|
+
class LinkNumbers {
|
|
161
|
+
byUrl = new Map();
|
|
162
|
+
used = new Set();
|
|
163
|
+
ordered = [];
|
|
164
|
+
next = 1;
|
|
165
|
+
get size() {
|
|
166
|
+
return this.byUrl.size;
|
|
167
|
+
}
|
|
168
|
+
/** Adopt the numbers baked into a cached render so they stay resolvable. */
|
|
169
|
+
reserve(links) {
|
|
170
|
+
for (const link of links) {
|
|
171
|
+
if (this.used.has(link.number))
|
|
172
|
+
continue;
|
|
173
|
+
this.used.add(link.number);
|
|
174
|
+
this.byUrl.set(link.url, link.number);
|
|
175
|
+
this.ordered.push(link);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/** Number for `url`, or null once the per-call cap is reached. */
|
|
179
|
+
numberFor(url) {
|
|
180
|
+
const existing = this.byUrl.get(url);
|
|
181
|
+
if (existing !== undefined)
|
|
182
|
+
return existing;
|
|
183
|
+
if (this.byUrl.size >= MAX_OUTLINE_LINKS)
|
|
184
|
+
return null;
|
|
185
|
+
while (this.used.has(this.next))
|
|
186
|
+
this.next++;
|
|
187
|
+
const number = this.next++;
|
|
188
|
+
this.used.add(number);
|
|
189
|
+
this.byUrl.set(url, number);
|
|
190
|
+
this.ordered.push({ number, url });
|
|
191
|
+
return number;
|
|
192
|
+
}
|
|
193
|
+
all() {
|
|
194
|
+
return this.ordered;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/** Absolute http(s) form of `href` relative to `base`, or null if unusable. */
|
|
198
|
+
function absoluteHttpUrl(href, base) {
|
|
199
|
+
const trimmed = href.trim();
|
|
200
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
201
|
+
return null;
|
|
202
|
+
let resolved;
|
|
203
|
+
try {
|
|
204
|
+
resolved = new URL(trimmed, base);
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
if (resolved.protocol !== "http:" && resolved.protocol !== "https:")
|
|
210
|
+
return null;
|
|
211
|
+
// Fragments only move within a page we already have: drop them so anchors
|
|
212
|
+
// into the same document collapse onto one number, and spend no number at
|
|
213
|
+
// all on links back into the page being rendered.
|
|
214
|
+
resolved.hash = "";
|
|
215
|
+
let self;
|
|
216
|
+
try {
|
|
217
|
+
self = new URL(base);
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
return resolved.toString();
|
|
221
|
+
}
|
|
222
|
+
self.hash = "";
|
|
223
|
+
if (resolved.href === self.href)
|
|
224
|
+
return null;
|
|
225
|
+
return resolved.href;
|
|
226
|
+
}
|
|
227
|
+
const MARKDOWN_LINK = /(!?)\[([^\]]*)\]\(\s*<?([^)<>\s]*)>?(?:\s+"[^"]*")?\s*\)/g;
|
|
228
|
+
const HTML_ANCHOR = /<a\b[^>]*\bhref\s*=\s*["']([^"']*)["'][^>]*>([\s\S]*?)<\/a>/gi;
|
|
229
|
+
/** Rewrite markdown links to `text [n]`; drop images, which carry no text. */
|
|
230
|
+
function numberMarkdownLinks(markdown, base, numbers) {
|
|
231
|
+
return markdown.replace(MARKDOWN_LINK, (_match, image, text, href) => {
|
|
232
|
+
if (image)
|
|
233
|
+
return "";
|
|
234
|
+
const url = absoluteHttpUrl(href, base);
|
|
235
|
+
if (!url)
|
|
236
|
+
return text;
|
|
237
|
+
const number = numbers.numberFor(url);
|
|
238
|
+
return number === null ? text : `${text} [${number}]`;
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
/** Same rewrite for raw HTML, used when the markdown extractor is unavailable. */
|
|
242
|
+
function numberHtmlAnchors(html, base, numbers) {
|
|
243
|
+
return html.replace(HTML_ANCHOR, (_match, href, inner) => {
|
|
244
|
+
const url = absoluteHttpUrl(decodeHTMLEntities(href), base);
|
|
245
|
+
if (!url)
|
|
246
|
+
return inner;
|
|
247
|
+
const number = numbers.numberFor(url);
|
|
248
|
+
return number === null ? inner : `${inner} [${number}]`;
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
function compactBlankLines(text) {
|
|
252
|
+
return text
|
|
253
|
+
.split("\n")
|
|
254
|
+
.map((line) => line.replace(/[ \t]+$/, ""))
|
|
255
|
+
.join("\n")
|
|
256
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
257
|
+
.trim();
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Render a fetched document as main content with every hyperlink replaced by a
|
|
261
|
+
* number, followed by a compact number → absolute URL index. The body reuses
|
|
262
|
+
* the existing `max_length` budget; only links still visible in the (possibly
|
|
263
|
+
* truncated) body are indexed.
|
|
264
|
+
*/
|
|
265
|
+
async function renderOutline(text, isHtml, finalUrl, opts) {
|
|
266
|
+
const numbers = opts.numbers ?? new LinkNumbers();
|
|
267
|
+
let heading = "";
|
|
268
|
+
let body;
|
|
269
|
+
if (!isHtml) {
|
|
270
|
+
body = numberMarkdownLinks(text, finalUrl, numbers);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
let extracted;
|
|
274
|
+
try {
|
|
275
|
+
extracted = await extractToMarkdown(text, finalUrl);
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
extracted = null;
|
|
279
|
+
}
|
|
280
|
+
if (extracted) {
|
|
281
|
+
heading = extracted.title ? `# ${extracted.title}\n\n` : "";
|
|
282
|
+
body = numberMarkdownLinks(extracted.markdown, finalUrl, numbers);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
body = htmlToCleanText(numberHtmlAnchors(removeBoilerplateElements(text), finalUrl, numbers));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const rendered = truncate(compactBlankLines(heading + body), opts.maxLength);
|
|
289
|
+
const shown = numbers.all().filter((link) => rendered.includes(`[${link.number}]`));
|
|
290
|
+
let output = rendered;
|
|
291
|
+
if (shown.length > 0) {
|
|
292
|
+
const index = shown.map((link) => `[${link.number}] ${link.url}`).join("\n");
|
|
293
|
+
output += `\n\n${OUTLINE_INDEX_HEADER}\n${index}`;
|
|
294
|
+
if (numbers.size >= MAX_OUTLINE_LINKS) {
|
|
295
|
+
output += `\n[link index truncated at ${MAX_OUTLINE_LINKS}; further links left as plain text]`;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
opts.onRender?.(finalUrl, output, [...shown]);
|
|
299
|
+
return output;
|
|
300
|
+
}
|
|
301
|
+
function cacheKey(url, maxLength) {
|
|
302
|
+
return `${maxLength}\u0000${url}`;
|
|
303
|
+
}
|
|
304
|
+
function cacheGet(cache, key) {
|
|
305
|
+
const hit = cache.get(key);
|
|
306
|
+
if (!hit)
|
|
307
|
+
return undefined;
|
|
308
|
+
// Re-insert so Map iteration order stays least-recently-used first.
|
|
309
|
+
cache.delete(key);
|
|
310
|
+
cache.set(key, hit);
|
|
311
|
+
return hit;
|
|
312
|
+
}
|
|
313
|
+
function cacheSet(cache, key, entry) {
|
|
314
|
+
cache.delete(key);
|
|
315
|
+
cache.set(key, entry);
|
|
316
|
+
while (cache.size > MAX_CACHED_PAGES) {
|
|
317
|
+
const oldest = cache.keys().next();
|
|
318
|
+
if (oldest.done)
|
|
319
|
+
break;
|
|
320
|
+
cache.delete(oldest.value);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
145
323
|
// ── Fetch configuration ──────────────────────────────────────
|
|
146
324
|
const MAX_REDIRECTS = 5;
|
|
147
325
|
const MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
|
|
@@ -165,7 +343,7 @@ const DEFAULT_LLMS_CANDIDATE_LIMIT = 6;
|
|
|
165
343
|
* error string describing why the fetch could not complete.
|
|
166
344
|
*/
|
|
167
345
|
function headersForFormat(format, honestUserAgent = false) {
|
|
168
|
-
const accept = format === "html"
|
|
346
|
+
const accept = format === "html" || format === "outline"
|
|
169
347
|
? "text/html,application/xhtml+xml;q=0.9,*/*;q=0.5"
|
|
170
348
|
: format === "markdown"
|
|
171
349
|
? "text/markdown,text/plain;q=0.9,text/html;q=0.8,*/*;q=0.5"
|
|
@@ -324,6 +502,9 @@ async function processHtmlOrText(response, text, opts) {
|
|
|
324
502
|
/application\/octet-stream|binary\/octet-stream|text\/plain/i.test(response.contentType);
|
|
325
503
|
const isHtml = response.contentType.includes("html") ||
|
|
326
504
|
(genericContentType && /^(?:<!doctype\s+html|<html\b|<head\b|<body\b)/i.test(prefix));
|
|
505
|
+
if (opts.format === "outline") {
|
|
506
|
+
return await renderOutline(text, isHtml, response.finalUrl, opts);
|
|
507
|
+
}
|
|
327
508
|
if (opts.format === "html") {
|
|
328
509
|
return truncate(text, opts.maxLength);
|
|
329
510
|
}
|
|
@@ -352,7 +533,7 @@ async function processHtmlOrText(response, text, opts) {
|
|
|
352
533
|
*/
|
|
353
534
|
async function fetchAndProcess(url, opts, signal) {
|
|
354
535
|
if (isBlockedUrl(url)) {
|
|
355
|
-
return
|
|
536
|
+
return BLOCKED_URL_MESSAGE;
|
|
356
537
|
}
|
|
357
538
|
try {
|
|
358
539
|
const result = await fetchOne(url, signal, opts.format, opts.getNetworkPolicy);
|
|
@@ -519,27 +700,98 @@ async function tryLlmsResource(url, opts, signal) {
|
|
|
519
700
|
return probes.find((probe) => probe !== null) ?? null;
|
|
520
701
|
}
|
|
521
702
|
async function fetchWithPreferredDocs(url, opts, signal) {
|
|
522
|
-
if (opts.format !== "html" &&
|
|
703
|
+
if (opts.format !== "html" &&
|
|
704
|
+
opts.format !== "outline" &&
|
|
705
|
+
opts.preferLlmsTxt &&
|
|
706
|
+
!isBlockedUrl(url) &&
|
|
707
|
+
isDocish(url)) {
|
|
523
708
|
const llms = await tryLlmsResource(url, opts, signal);
|
|
524
709
|
if (llms)
|
|
525
710
|
return llms;
|
|
526
711
|
}
|
|
527
712
|
return await fetchAndProcess(url, opts, signal);
|
|
528
713
|
}
|
|
714
|
+
/**
|
|
715
|
+
* Outline-mode wrapper around {@link fetchWithPreferredDocs} that serves
|
|
716
|
+
* repeat views of a page from the per-session cache. The URL is re-validated
|
|
717
|
+
* *before* the cache is consulted, so a cached render can never resurrect a
|
|
718
|
+
* host the current SSRF/allowlist policy forbids.
|
|
719
|
+
*/
|
|
720
|
+
async function fetchPage(url, opts, signal, cache) {
|
|
721
|
+
if (opts.format !== "outline")
|
|
722
|
+
return await fetchWithPreferredDocs(url, opts, signal);
|
|
723
|
+
if (isBlockedUrl(url))
|
|
724
|
+
return BLOCKED_URL_MESSAGE;
|
|
725
|
+
const policyError = checkUrlPolicy(url, opts.getNetworkPolicy);
|
|
726
|
+
if (policyError)
|
|
727
|
+
return `Error: ${policyError}`;
|
|
728
|
+
const requestKey = cacheKey(url, opts.maxLength);
|
|
729
|
+
const hit = cacheGet(cache, requestKey);
|
|
730
|
+
if (hit) {
|
|
731
|
+
opts.numbers?.reserve(hit.links);
|
|
732
|
+
return hit.text;
|
|
733
|
+
}
|
|
734
|
+
let rendered;
|
|
735
|
+
const result = await fetchWithPreferredDocs(url, {
|
|
736
|
+
...opts,
|
|
737
|
+
onRender: (finalUrl, text, links) => {
|
|
738
|
+
rendered = { text, links };
|
|
739
|
+
// Keyed by the post-redirect URL, plus the requested URL below.
|
|
740
|
+
cacheSet(cache, cacheKey(finalUrl, opts.maxLength), rendered);
|
|
741
|
+
},
|
|
742
|
+
}, signal);
|
|
743
|
+
if (rendered)
|
|
744
|
+
cacheSet(cache, requestKey, rendered);
|
|
745
|
+
return result;
|
|
746
|
+
}
|
|
529
747
|
export function createWebFetchTool(getNetworkPolicy) {
|
|
748
|
+
// Per-session state, both bounded: the render cache evicts least-recently
|
|
749
|
+
// used pages past MAX_CACHED_PAGES, and the follow map is replaced (not
|
|
750
|
+
// grown) by each outline call, itself capped at MAX_OUTLINE_LINKS entries.
|
|
751
|
+
const pageCache = new Map();
|
|
752
|
+
let followTargets = new Map();
|
|
530
753
|
return {
|
|
531
754
|
name: "web_fetch",
|
|
532
755
|
description: "Fetch and read web page content. Accepts a single `url` or a `urls` array (up to 10, " +
|
|
533
|
-
"fetched concurrently). Returns clean Markdown by default (`format`: markdown|text|html)
|
|
534
|
-
"main-content extraction. Extracts text from PDFs, follows safe redirects automatically, and " +
|
|
535
|
-
"prefers a site's curated /llms.txt for docs pages when available
|
|
756
|
+
"fetched concurrently). Returns clean Markdown by default (`format`: markdown|text|html|outline) " +
|
|
757
|
+
"via main-content extraction. Extracts text from PDFs, follows safe redirects automatically, and " +
|
|
758
|
+
"prefers a site's curated /llms.txt for docs pages when available.\n" +
|
|
759
|
+
'`format: "outline"` is the cheap mode: main content only, every hyperlink replaced by a ' +
|
|
760
|
+
"number (`anchor text [12]`) with a numbered URL index at the end, and a small default " +
|
|
761
|
+
"`max_length`. Use it when hunting for the right page; then pass `follow: 12` " +
|
|
762
|
+
"(instead of `url`) to fetch link 12 from the last outline. Repeat views of a page in the " +
|
|
763
|
+
"same session are served from cache. Outline mode skips the /llms.txt probe.",
|
|
536
764
|
parameters,
|
|
537
765
|
async execute(args, context) {
|
|
538
|
-
const maxLength = args.max_length ?? 10000;
|
|
539
766
|
const format = args.format ?? "markdown";
|
|
767
|
+
const maxLength = args.max_length ?? (format === "outline" ? OUTLINE_DEFAULT_MAX_LENGTH : 10000);
|
|
540
768
|
const preferLlmsTxt = args.prefer_llms_txt !== false;
|
|
769
|
+
const numbers = format === "outline" ? new LinkNumbers() : undefined;
|
|
770
|
+
// A followed link is attacker-controlled page content: it resolves to a
|
|
771
|
+
// plain URL here and then travels the exact same validation path as a
|
|
772
|
+
// user-supplied one (isBlockedUrl + allowlist + per-redirect-hop checks).
|
|
773
|
+
let followUrl;
|
|
774
|
+
if (args.follow !== undefined) {
|
|
775
|
+
followUrl = followTargets.get(args.follow);
|
|
776
|
+
if (!followUrl) {
|
|
777
|
+
return followTargets.size === 0
|
|
778
|
+
? 'Error: no numbered links available — fetch a page with format: "outline" first.'
|
|
779
|
+
: `Error: link [${args.follow}] is not in the last outline (known: ${[...followTargets.keys()].join(", ")}).`;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
// Every outline render replaces the follow map, even when the page had no
|
|
783
|
+
// links: keeping the previous page's numbers would make `follow: 3` fetch
|
|
784
|
+
// from a page the user already moved past, while the error text and the
|
|
785
|
+
// tool description both promise "the last outline". Non-outline fetches
|
|
786
|
+
// leave the map alone, so a markdown read does not discard usable numbers.
|
|
787
|
+
const remember = (output) => {
|
|
788
|
+
if (numbers) {
|
|
789
|
+
followTargets = new Map(numbers.all().map((link) => [link.number, link.url]));
|
|
790
|
+
}
|
|
791
|
+
return output;
|
|
792
|
+
};
|
|
541
793
|
// Multi-URL path: bounded-concurrency pool, per-URL budget, ordered output.
|
|
542
|
-
if (args.urls && args.urls.length > 0) {
|
|
794
|
+
if (!followUrl && args.urls && args.urls.length > 0) {
|
|
543
795
|
const urls = args.urls;
|
|
544
796
|
const perUrlBudget = Math.max(PER_URL_MIN_BUDGET, Math.floor(maxLength / urls.length));
|
|
545
797
|
const opts = {
|
|
@@ -547,16 +799,17 @@ export function createWebFetchTool(getNetworkPolicy) {
|
|
|
547
799
|
format,
|
|
548
800
|
preferLlmsTxt,
|
|
549
801
|
getNetworkPolicy,
|
|
802
|
+
numbers,
|
|
550
803
|
};
|
|
551
|
-
const sections = await runPool(urls, MAX_CONCURRENCY, (u) =>
|
|
552
|
-
return urls.map((u, i) => `## ${u}\n${sections[i]}`).join("\n\n");
|
|
804
|
+
const sections = await runPool(urls, MAX_CONCURRENCY, (u) => fetchPage(u, opts, context.signal, pageCache));
|
|
805
|
+
return remember(urls.map((u, i) => `## ${u}\n${sections[i]}`).join("\n\n"));
|
|
553
806
|
}
|
|
554
|
-
const url = args.url;
|
|
807
|
+
const url = followUrl ?? args.url;
|
|
555
808
|
if (!url) {
|
|
556
|
-
return "Error: provide either `url` or `
|
|
809
|
+
return "Error: provide either `url`, `urls`, or `follow`.";
|
|
557
810
|
}
|
|
558
|
-
const opts = { maxLength, format, preferLlmsTxt, getNetworkPolicy };
|
|
559
|
-
return await
|
|
811
|
+
const opts = { maxLength, format, preferLlmsTxt, getNetworkPolicy, numbers };
|
|
812
|
+
return remember(await fetchPage(url, opts, context.signal, pageCache));
|
|
560
813
|
},
|
|
561
814
|
};
|
|
562
815
|
}
|
|
@@ -585,17 +838,28 @@ const parameters = z
|
|
|
585
838
|
.max(MAX_URLS)
|
|
586
839
|
.optional()
|
|
587
840
|
.describe(`Fetch multiple URLs concurrently (up to ${MAX_URLS}); returns a sectioned digest`),
|
|
588
|
-
|
|
841
|
+
follow: z
|
|
842
|
+
.number()
|
|
843
|
+
.int()
|
|
844
|
+
.positive()
|
|
845
|
+
.optional()
|
|
846
|
+
.describe("Fetch link N from the most recent outline render, instead of `url`. " +
|
|
847
|
+
"Followed links are SSRF/allowlist-checked exactly like a supplied URL."),
|
|
848
|
+
max_length: z
|
|
849
|
+
.number()
|
|
850
|
+
.optional()
|
|
851
|
+
.describe(`Maximum characters to return (default: 10000; ${OUTLINE_DEFAULT_MAX_LENGTH} for outline)`),
|
|
589
852
|
format: z
|
|
590
|
-
.enum(["markdown", "text", "html"])
|
|
853
|
+
.enum(["markdown", "text", "html", "outline"])
|
|
591
854
|
.optional()
|
|
592
|
-
.describe("Output format: markdown (default, main-content extraction), text, or
|
|
855
|
+
.describe("Output format: markdown (default, main-content extraction), text, html, or outline " +
|
|
856
|
+
`(compact main content with each link replaced by a number plus a numbered URL index, ` +
|
|
857
|
+
`capped at ${MAX_OUTLINE_LINKS} links — cheapest; follow links with \`follow\`)`),
|
|
593
858
|
prefer_llms_txt: z
|
|
594
859
|
.boolean()
|
|
595
860
|
.optional()
|
|
596
861
|
.describe("Prefer a site's curated /llms.txt for documentation pages (default: true)"),
|
|
597
862
|
})
|
|
598
|
-
.refine((v) => Boolean(v.url)
|
|
599
|
-
message: "Provide exactly one of `url` or `
|
|
600
|
-
});
|
|
863
|
+
.refine((v) => [Boolean(v.url), Boolean(v.urls && v.urls.length > 0), v.follow !== undefined].filter(Boolean)
|
|
864
|
+
.length === 1, { message: "Provide exactly one of `url`, `urls`, or `follow`." });
|
|
601
865
|
//# sourceMappingURL=web-fetch.js.map
|