@nyte-ai/plugin 0.0.24 → 0.0.25-nightly.20261025.2

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.
Files changed (52) hide show
  1. package/THIRD-PARTY-NOTICES.md +13 -5
  2. package/dist/chunks/bash-description-0ah30s12.js +33 -0
  3. package/dist/chunks/{bash-description-qnwggxq3.js → bash-description-1neewp76.js} +19 -8
  4. package/dist/chunks/bash-description-4cdbmar0.js +124 -0
  5. package/dist/chunks/bash-description-4h0hnsv4.js +68 -0
  6. package/dist/chunks/bash-description-5dpf5hpt.js +724 -0
  7. package/dist/chunks/bash-description-9gw9ets8.js +162 -0
  8. package/dist/chunks/bash-description-b78pre8c.js +147 -0
  9. package/dist/chunks/{bash-description-necnb2k7.js → bash-description-vg0xecwm.js} +17 -7
  10. package/dist/src/acp/connection.js +1 -1
  11. package/dist/src/acp/index.d.ts +3 -3
  12. package/dist/src/acp/index.js +1 -1
  13. package/dist/src/approvals/approvals.d.ts +16 -16
  14. package/dist/src/approvals/schema.d.ts +18 -18
  15. package/dist/src/bash-description.d.ts +1 -1
  16. package/dist/src/bash-description.js +3 -5
  17. package/dist/src/canvas/canvas-protocol.d.ts +12 -12
  18. package/dist/src/canvas/canvas.d.ts +12 -3
  19. package/dist/src/canvas/canvas.js +33 -11
  20. package/dist/src/canvas/schema.d.ts +48 -8
  21. package/dist/src/canvas/schema.js +5 -1
  22. package/dist/src/claude-code-sdk/index.d.ts +1 -1
  23. package/dist/src/claude-code-sdk/index.js +1 -0
  24. package/dist/src/client/notifications.d.ts +1 -1
  25. package/dist/src/client/presentation.d.ts +1 -27
  26. package/dist/src/client/presentation.js +1 -19
  27. package/dist/src/codemode.js +148 -41
  28. package/dist/src/core.d.ts +1 -1
  29. package/dist/src/question/question.d.ts +14 -14
  30. package/dist/src/question/schema.d.ts +23 -23
  31. package/dist/src/rename.d.ts +17 -32
  32. package/dist/src/rename.js +115 -48
  33. package/dist/src/subagents.d.ts +30 -0
  34. package/dist/src/subagents.js +323 -0
  35. package/dist/src/telemetry.d.ts +1 -1
  36. package/dist/src/tool-search.d.ts +49 -0
  37. package/dist/src/tool-search.js +14 -0
  38. package/dist/src/web/body.d.ts +3 -0
  39. package/dist/src/web/body.js +6 -0
  40. package/dist/src/web/fetch.d.ts +16 -0
  41. package/dist/src/web/fetch.js +8 -0
  42. package/dist/src/web/html-markdown.d.ts +9 -0
  43. package/dist/src/web/html-markdown.js +10 -0
  44. package/dist/src/web/index.d.ts +24 -0
  45. package/dist/src/web/index.js +93 -0
  46. package/dist/src/web/providers.d.ts +60 -0
  47. package/dist/src/web/providers.js +11 -0
  48. package/dist/src/web/search.d.ts +21 -0
  49. package/dist/src/web/search.js +6 -0
  50. package/package.json +17 -9
  51. package/dist/src/web-search.d.ts +0 -78
  52. package/dist/src/web-search.js +0 -219
@@ -0,0 +1,323 @@
1
+ // src/subagents.ts
2
+ import { Type } from "typebox";
3
+ import { asId, standard } from "@nyte-ai/schema";
4
+ import { isPart, text, tool } from "@nyte-ai/core";
5
+ var ANSWER_LIMIT = 16000;
6
+ var TRANSCRIPT_LIMIT = 16000;
7
+ var SCHEDULED = {
8
+ joined: "it joins the work in progress",
9
+ "next-turn": "it runs once its current work ends",
10
+ attached: "it rides with its next turn",
11
+ deciding: "its plugins are deciding it"
12
+ };
13
+ var selectionParameters = {
14
+ agent: Type.Optional(Type.String({ description: "A registered agent to run as; the default agent otherwise." })),
15
+ model: Type.Optional(Type.String({
16
+ description: "A model from /model, as provider/id or its id alone; a fast variant is its own id. The default model otherwise."
17
+ })),
18
+ thinking: Type.Optional(Type.Enum(["off", "minimal", "low", "medium", "high", "xhigh", "max"], {
19
+ description: "A thinking level the model accepts; its default otherwise."
20
+ }))
21
+ };
22
+ var isolationParameter = {
23
+ isolation: Type.Optional(Type.Literal("worktree", {
24
+ description: "Run the subagent in a git worktree on a new branch from HEAD, with your uncommitted changes copied in, so its edits stay out of this workspace. The reply names the folder and branch. Without it, the subagent works in this workspace."
25
+ }))
26
+ };
27
+ var taskParameters = standard(Type.Object({
28
+ prompt: Type.String({
29
+ description: "The task for the subagent, with everything it needs to know."
30
+ }),
31
+ title: Type.Optional(Type.String({ description: "A short name for the subagent's session." })),
32
+ ...selectionParameters,
33
+ ...isolationParameter
34
+ }));
35
+ var createParameters = standard(Type.Object({
36
+ prompt: Type.String({
37
+ description: "The subagent's first message; it starts working on it at once."
38
+ }),
39
+ title: Type.Optional(Type.String({ description: "A short name for the subagent's session." })),
40
+ ...selectionParameters,
41
+ ...isolationParameter,
42
+ role: Type.Optional(Type.String({
43
+ description: "Instructions the subagent keeps for every message, added to its prompt."
44
+ }))
45
+ }));
46
+ var sendParameters = standard(Type.Object({
47
+ session: Type.String({ description: "The subagent's session id, from task or create." }),
48
+ prompt: Type.String({ description: "The message for the subagent." })
49
+ }));
50
+ var awaitParameters = standard(Type.Object({
51
+ session: Type.String({ description: "The subagent's session id, from task or create." }),
52
+ timeout: Type.Optional(Type.Integer({
53
+ minimum: 1,
54
+ description: "Seconds to wait before returning while it still works."
55
+ }))
56
+ }));
57
+ var readParameters = standard(Type.Object({
58
+ session: Type.String({ description: "The subagent's session id, from task or create." })
59
+ }));
60
+ var stopParameters = standard(Type.Object({
61
+ session: Type.String({ description: "The subagent's session id, from task or create." })
62
+ }));
63
+ var task = {
64
+ name: "task",
65
+ description: "Run a subagent on a task and wait for its answer. Give it everything it needs; it does not see this conversation.",
66
+ parameters: taskParameters,
67
+ class: (args) => ({ kind: "delegate", child: null, role: "task", title: args.title ?? null }),
68
+ replay: "safe",
69
+ async execute(args, invocation) {
70
+ const { session: child, receipt } = await invocation.sdk.sessions.start({
71
+ parent: invocation.session.id,
72
+ name: args.title,
73
+ configuration: await childConfiguration(invocation, args),
74
+ isolation: args.isolation,
75
+ content: args.prompt
76
+ });
77
+ const run = await invocation.memo("run", async () => {
78
+ const landing = await receipt.landed();
79
+ return landing.kind === "landed" ? landing.run : null;
80
+ });
81
+ if (run === null)
82
+ return reply(`Subagent ${child.id} did not start the task.`);
83
+ const outcome = await invocation.wait({
84
+ kind: "any",
85
+ targets: [{ kind: "run", session: child.id, run }],
86
+ untilInput: true
87
+ });
88
+ const answer = await readSubagentReply(child, run, outcome);
89
+ const worktree = await describeWorktree(invocation, child);
90
+ return reply(worktree === null ? answer : `${worktree}
91
+
92
+ ${answer}`);
93
+ }
94
+ };
95
+ var create = {
96
+ name: "create",
97
+ description: "Start a subagent on a first message and return its id, to send it more messages and await it later.",
98
+ parameters: createParameters,
99
+ class: (args) => ({ kind: "delegate", child: null, role: "create", title: args.title ?? null }),
100
+ effects: "none",
101
+ replay: "safe",
102
+ async execute(args, invocation) {
103
+ const { session: child } = await invocation.sdk.sessions.start({
104
+ parent: invocation.session.id,
105
+ name: args.title,
106
+ configuration: await childConfiguration(invocation, args),
107
+ prompt: args.role === undefined ? undefined : { kind: "layer", text: args.role },
108
+ isolation: args.isolation,
109
+ content: args.prompt
110
+ });
111
+ const worktree = await describeWorktree(invocation, child);
112
+ return reply(worktree === null ? `Started subagent ${child.id}.` : `Started subagent ${child.id}. ${worktree}`);
113
+ }
114
+ };
115
+ var send = {
116
+ name: "send",
117
+ description: "Send a message to a subagent; it works in the background. Use await for its answer.",
118
+ parameters: sendParameters,
119
+ class: (args) => ({
120
+ kind: "delegate",
121
+ child: asId(args.session),
122
+ role: "send",
123
+ title: null
124
+ }),
125
+ effects: "none",
126
+ replay: "safe",
127
+ async execute(args, invocation) {
128
+ const child = await requireChildSession(invocation, args.session);
129
+ const receipt = await child.send(args.prompt, {
130
+ id: asId(`${invocation.call}:${child.id}`)
131
+ });
132
+ const view = await child.view();
133
+ const message = [...view.messages, ...view.queue].find((entry) => entry.id === receipt.message);
134
+ return reply(`Sent to subagent ${child.id}; ${scheduled(message)}.`);
135
+ }
136
+ };
137
+ var awaitChild = {
138
+ name: "await",
139
+ description: "Wait for a subagent to finish its current work and return its answer.",
140
+ parameters: awaitParameters,
141
+ class: (args) => ({
142
+ kind: "delegate",
143
+ child: asId(args.session),
144
+ role: "await",
145
+ title: null
146
+ }),
147
+ replay: "safe",
148
+ async execute(args, invocation) {
149
+ const child = await requireChildSession(invocation, args.session);
150
+ const run = await invocation.memo("run", async () => {
151
+ const { execution } = await child.view();
152
+ return execution.kind === "idle" ? null : execution.run.id;
153
+ });
154
+ if (run === null) {
155
+ const execution = (await child.view()).execution;
156
+ const last = execution.kind === "idle" ? execution.lastRun : null;
157
+ if (last === null)
158
+ return reply(`Subagent ${child.id} has not worked on anything yet.`);
159
+ return reply(await readSubagentReply(child, last.id, {
160
+ kind: "run",
161
+ session: child.id,
162
+ run: last.id,
163
+ end: last.end
164
+ }));
165
+ }
166
+ const targets = [{ kind: "run", session: child.id, run }];
167
+ const outcome = await invocation.wait(args.timeout === undefined ? { kind: "any", targets, untilInput: true } : {
168
+ kind: "any",
169
+ targets,
170
+ untilInput: true,
171
+ deadline: invocation.now() + args.timeout * 1000
172
+ });
173
+ return reply(await readSubagentReply(child, run, outcome));
174
+ }
175
+ };
176
+ var readAgent = {
177
+ name: "read_agent",
178
+ description: "Read a subagent's conversation so far, newest last.",
179
+ parameters: readParameters,
180
+ class: (args) => ({
181
+ kind: "delegate",
182
+ child: asId(args.session),
183
+ role: "read",
184
+ title: null
185
+ }),
186
+ effects: "none",
187
+ replay: "safe",
188
+ async execute(args, invocation) {
189
+ const child = await requireChildSession(invocation, args.session);
190
+ const view = await child.view();
191
+ const execution = view.execution.kind;
192
+ const state = execution === "idle" ? "idle" : execution === "waiting" ? "waiting" : "working";
193
+ const transcript = fromEnd([...view.messages, ...view.queue].flatMap(renderTranscriptMessage).join(`
194
+
195
+ `), TRANSCRIPT_LIMIT);
196
+ return reply(transcript === "" ? `Subagent ${child.id} is ${state} and has no messages yet.` : `Subagent ${child.id} is ${state}.
197
+
198
+ ${transcript}`);
199
+ }
200
+ };
201
+ var stop = {
202
+ name: "stop",
203
+ description: "Stop a subagent's current work.",
204
+ parameters: stopParameters,
205
+ class: (args) => ({
206
+ kind: "delegate",
207
+ child: asId(args.session),
208
+ role: "stop",
209
+ title: null
210
+ }),
211
+ effects: "none",
212
+ replay: "safe",
213
+ async execute(args, invocation) {
214
+ const child = await requireChildSession(invocation, args.session);
215
+ const { stopped, withdrawn } = await child.stop();
216
+ return reply(`Stopped ${stopped.length} run${stopped.length === 1 ? "" : "s"} of subagent ${child.id} and withdrew ${withdrawn.length} pending message${withdrawn.length === 1 ? "" : "s"}.`);
217
+ }
218
+ };
219
+ var subagents_default = {
220
+ id: "subagents",
221
+ async activate(api) {
222
+ if ((await api.session.info()).parent !== null)
223
+ return;
224
+ for (const definition of [task, create, send, awaitChild, readAgent, stop])
225
+ api.contribute.tools.add(definition);
226
+ }
227
+ };
228
+ async function childConfiguration(invocation, { agent, model, thinking }) {
229
+ if (agent === undefined && model === undefined && thinking === undefined)
230
+ return;
231
+ return {
232
+ agent,
233
+ model: model === undefined ? undefined : await findModel(invocation, model),
234
+ thinking
235
+ };
236
+ }
237
+ async function findModel(invocation, name) {
238
+ const models = (await invocation.sdk.models.list()).providers.flatMap((provider) => provider.credential === "unknown" || provider.credential === "configured" || provider.credential === "verified" ? provider.models : []);
239
+ const refs = models.flatMap((info) => info.fast === null ? [info.ref] : [info.ref, info.fast]);
240
+ const exact = refs.filter((ref) => `${ref.provider}/${ref.id}` === name);
241
+ const matches = exact.length > 0 ? exact : refs.filter((ref) => ref.id === name);
242
+ const [only, ...others] = matches;
243
+ if (only !== undefined && others.length === 0)
244
+ return only;
245
+ if (only !== undefined)
246
+ throw new Error(`${name} names more than one model; pass one of ${matches.map((ref) => `${ref.provider}/${ref.id}`).join(", ")}.`);
247
+ if (models.length === 0)
248
+ throw new Error("No model is available; sign in to a provider first.");
249
+ throw new Error(`/model has no ${name}. Choose one of:
250
+ ${models.map((info) => `- ${info.ref.provider}/${info.ref.id} (thinking: ${info.thinking.join(", ")})${info.fast === null ? "" : `, fast: ${info.fast.provider}/${info.fast.id}`}`).join(`
251
+ `)}`);
252
+ }
253
+ async function describeWorktree(invocation, child) {
254
+ const workspace = await invocation.sdk.workspace((await child.info()).workspace).info();
255
+ if (workspace.isolation === null)
256
+ return null;
257
+ const folder = "path" in workspace.target ? workspace.target.path : workspace.id;
258
+ return `It works in the worktree ${folder} on branch ${workspace.isolation.branch}.`;
259
+ }
260
+ function reply(content) {
261
+ return { content: [{ kind: "text", text: content }] };
262
+ }
263
+ async function requireChildSession(invocation, id) {
264
+ const child = invocation.sdk.session(asId(id));
265
+ if ((await child.info()).parent !== invocation.session.id)
266
+ throw new Error(`Session ${id} is not a subagent of this session.`);
267
+ return child;
268
+ }
269
+ async function readSubagentReply(child, run, outcome) {
270
+ const header = `Subagent ${child.id} ${describeSubagentOutcome(outcome)}.`;
271
+ const view = await child.view();
272
+ const turn = view.turns.find((entry) => entry.run === run)?.id;
273
+ const answer = view.messages.flatMap((message) => message.turn === turn && isPart(message, text) && message.state.markdown !== "" ? [message.state.markdown] : []).at(-1) ?? "";
274
+ return answer === "" ? header : `${header}
275
+
276
+ ${fromStart(answer, ANSWER_LIMIT)}`;
277
+ }
278
+ function describeSubagentOutcome(outcome) {
279
+ if (outcome.kind === "run")
280
+ return endedAs(outcome.end);
281
+ return outcome.kind === "stopped" ? "is still working; this call was stopped before it ended" : "is still working";
282
+ }
283
+ function endedAs(end) {
284
+ if (end.kind === "failed")
285
+ return `failed: ${end.failure.message}`;
286
+ return end.kind === "completed" ? "finished" : "was stopped";
287
+ }
288
+ function scheduled(message) {
289
+ if (message?.kind !== "user")
290
+ return "it was admitted";
291
+ if (message.status.kind === "landed")
292
+ return "it started working on it";
293
+ if (message.status.kind !== "pending")
294
+ return "it was admitted";
295
+ return SCHEDULED[message.status.schedule.kind];
296
+ }
297
+ function renderTranscriptMessage(message) {
298
+ if (message.kind === "user")
299
+ return [
300
+ `User: ${typeof message.content === "string" ? message.content : message.content.flatMap((item) => item.kind === "text" ? [item.text] : []).join(" ")}`
301
+ ];
302
+ if (isPart(message, text))
303
+ return message.state.markdown === "" ? [] : [`Assistant: ${message.state.markdown}`];
304
+ if (isPart(message, tool)) {
305
+ const state = message.state;
306
+ const status = state.phase === "settled" ? state.outcome.kind : state.phase;
307
+ return [`Tool ${state.name}(${JSON.stringify(state.args)}): ${status}`];
308
+ }
309
+ return [];
310
+ }
311
+ function fromStart(content, limit) {
312
+ return content.length > limit ? `${content.slice(0, limit)}
313
+
314
+ [… cut at ${limit} characters]` : content;
315
+ }
316
+ function fromEnd(content, limit) {
317
+ return content.length > limit ? `[… earlier messages cut]
318
+
319
+ ${content.slice(-limit)}` : content;
320
+ }
321
+ export {
322
+ subagents_default as default
323
+ };
@@ -21,7 +21,7 @@ declare const _default: {
21
21
  readonly contribute: import("@nyte-ai/core").Registries<"core">;
22
22
  readonly storage: import("@nyte-ai/core").PluginStorage;
23
23
  readonly signal: AbortSignal;
24
- hook<N extends "session_activated" | "before_send" | "run_started" | "transform_transcript" | "before_compaction" | "before_request" | "before_tool" | "after_tool" | "after_request" | "run_ended">(name: N, entry: import("@nyte-ai/core").HookEntry<"core", N>): import("@nyte-ai/schema").Disposer;
24
+ hook<N extends import("@nyte-ai/core").HookName<"core">>(name: N, entry: import("@nyte-ai/core").HookEntry<"core", N>): import("@nyte-ai/schema").Disposer;
25
25
  report(issue: import("@nyte-ai/schema").ValidationIssue): void;
26
26
  reload(): void;
27
27
  } & {
@@ -0,0 +1,49 @@
1
+ import type { ToolNamespace } from "@nyte-ai/core";
2
+ import type { ToolInfo } from "@nyte-ai/schema";
3
+ export declare const DEFAULT_SEARCH_LIMIT = 8;
4
+ /** A tool as the ranker sees it: its name and the text {@link createToolSearchDocument} builds. */
5
+ export type ToolSearchDocument = {
6
+ readonly name: string;
7
+ readonly text: string;
8
+ };
9
+ /**
10
+ * The `tool_search` tool: ranks the `code` and `deferred` tools the head
11
+ * has not loaded yet and loads the matches, so the model sees them declared
12
+ * from its next request on. Loads live in the call's output, so they follow
13
+ * the head's history through restarts, branches and compaction. The tool is
14
+ * declared only while some `deferred` tool is not.
15
+ *
16
+ * @category plugins
17
+ * @since 0.1.0
18
+ */
19
+ declare const _default: {
20
+ id: string;
21
+ activate(api: {
22
+ readonly side: "core";
23
+ readonly sdk: import("@nyte-ai/core").Connection;
24
+ readonly contribute: import("@nyte-ai/core").Registries<"core">;
25
+ readonly storage: import("@nyte-ai/core").PluginStorage;
26
+ readonly signal: AbortSignal;
27
+ hook<N extends import("@nyte-ai/core").HookName<"core">>(name: N, entry: import("@nyte-ai/core").HookEntry<"core", N>): import("@nyte-ai/schema").Disposer;
28
+ report(issue: import("@nyte-ai/schema").ValidationIssue): void;
29
+ reload(): void;
30
+ } & {
31
+ readonly session: import("@nyte-ai/core").Session;
32
+ readonly env: import("@nyte-ai/core").ExecutionEnv;
33
+ wrapEnv(wrap: import("@nyte-ai/core").EnvironmentWrap): import("@nyte-ai/schema").Disposer;
34
+ readonly inputs: import("@nyte-ai/core").Resources;
35
+ request<T = string>(input: import("@nyte-ai/schema").ModelRequestInput<T>): Promise<import("@nyte-ai/schema").ModelRequestOutcome<T>>;
36
+ approve(call: import("@nyte-ai/core").RuntimeCall, signal: AbortSignal): Promise<import("@nyte-ai/core").RuntimeVerdict>;
37
+ }): void;
38
+ };
39
+ export default _default;
40
+ /** Lowercase terms split at camelCase boundaries and non-alphanumerics, without stop words, naively singular. */
41
+ export declare function tokenize(text: string): readonly string[];
42
+ /**
43
+ * A tool's search text: its name, the name with `_` as spaces, its
44
+ * description, every parameter's name and description, and its namespace's
45
+ * name, description and instructions.
46
+ */
47
+ export declare function createToolSearchDocument(tool: Pick<ToolInfo, "name" | "description" | "parameters">, namespace: ToolNamespace | undefined): ToolSearchDocument;
48
+ /** The names of the `limit` best documents for `query` by Okapi BM25; ties keep document order. */
49
+ export declare function rankTools(query: string, documents: readonly ToolSearchDocument[], limit: number): readonly string[];
@@ -0,0 +1,14 @@
1
+ import {
2
+ DEFAULT_SEARCH_LIMIT2,
3
+ tool_search_default,
4
+ tokenize2,
5
+ createToolSearchDocument2,
6
+ rankTools2
7
+ } from "../chunks/bash-description-b78pre8c.js";
8
+ export {
9
+ DEFAULT_SEARCH_LIMIT2 as DEFAULT_SEARCH_LIMIT,
10
+ createToolSearchDocument2 as createToolSearchDocument,
11
+ tool_search_default as default,
12
+ rankTools2 as rankTools,
13
+ tokenize2 as tokenize
14
+ };
@@ -0,0 +1,3 @@
1
+ export type Fetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
2
+ /** Reads a response body, throwing once its declared or streamed size passes `limit` bytes. */
3
+ export declare function readCapped(response: Response, limit: number): Promise<Uint8Array>;
@@ -0,0 +1,6 @@
1
+ import {
2
+ readCapped2
3
+ } from "../../chunks/bash-description-0ah30s12.js";
4
+ export {
5
+ readCapped2 as readCapped
6
+ };
@@ -0,0 +1,16 @@
1
+ import { Type } from "typebox";
2
+ import type { Static } from "typebox";
3
+ import type { ToolDefinition } from "@nyte-ai/plugin/core";
4
+ import type { Fetch } from "./body.ts";
5
+ declare const fetchParameters: Type.TObject<{
6
+ url: Type.TString;
7
+ format: Type.TOptional<Type.TUnion<[Type.TLiteral<"markdown">, Type.TLiteral<"text">, Type.TLiteral<"html">]>>;
8
+ timeout: Type.TOptional<Type.TNumber>;
9
+ }>;
10
+ /**
11
+ * The `web_fetch` tool: GETs an http(s) URL through `fetch`, following at most ten
12
+ * redirects that stay on http(s), and returns HTML as markdown, text or itself, other
13
+ * text as is, and an image as a file. Bodies stop at 5 MiB; text shown inline at 50 KiB.
14
+ */
15
+ export declare function webFetch(fetch: Fetch): ToolDefinition<Static<typeof fetchParameters>>;
16
+ export {};
@@ -0,0 +1,8 @@
1
+ import {
2
+ webFetch2
3
+ } from "../../chunks/bash-description-4cdbmar0.js";
4
+ import"../../chunks/bash-description-5dpf5hpt.js";
5
+ import"../../chunks/bash-description-0ah30s12.js";
6
+ export {
7
+ webFetch2 as webFetch
8
+ };
@@ -0,0 +1,9 @@
1
+ export declare const MAX_MARKDOWN_BYTES: number;
2
+ /**
3
+ * Converts HTML to Markdown in one streaming pass: drops scripts, styles, the head and
4
+ * hidden elements; keeps headings, lists, GFM tables, fenced code, links and images;
5
+ * stops nesting past 10,000 levels and caps the result at `MAX_MARKDOWN_BYTES`.
6
+ */
7
+ export declare function htmlToMarkdown(html: string): string;
8
+ /** Returns an HTML document's text outside scripts, styles and embeds, trimmed. */
9
+ export declare function htmlToText(html: string): string;
@@ -0,0 +1,10 @@
1
+ import {
2
+ MAX_MARKDOWN_BYTES2,
3
+ htmlToMarkdown2,
4
+ htmlToText2
5
+ } from "../../chunks/bash-description-5dpf5hpt.js";
6
+ export {
7
+ MAX_MARKDOWN_BYTES2 as MAX_MARKDOWN_BYTES,
8
+ htmlToMarkdown2 as htmlToMarkdown,
9
+ htmlToText2 as htmlToText
10
+ };
@@ -0,0 +1,24 @@
1
+ import type { Plugin } from "@nyte-ai/plugin/core";
2
+ import type { Fetch } from "./body.ts";
3
+ export { adapters, PROVIDERS } from "./providers.ts";
4
+ export type { SearchInput, ShippedProvider } from "./providers.ts";
5
+ /**
6
+ * Returns the web plugin sending through `fetch`: `web_fetch`, and `web_search`
7
+ * routed by the host setting `web_search.provider` to any provider in the
8
+ * search registry. It adds Exa, Tavily, Firecrawl and Parallel there, each
9
+ * keyed from the plugin's secrets under its id (set with `/websearch-key`) or
10
+ * on its keyless route without one. The setting `off`, or an empty registry,
11
+ * drops `web_search`.
12
+ *
13
+ * @category plugins
14
+ * @since 0.1.0
15
+ */
16
+ export declare function webPlugin(fetch: Fetch): Plugin;
17
+ /**
18
+ * The web plugin over the global `fetch`.
19
+ *
20
+ * @category plugins
21
+ * @since 0.1.0
22
+ */
23
+ declare const _default: Plugin;
24
+ export default _default;
@@ -0,0 +1,93 @@
1
+ import"../../chunks/bash-description-0ah30s12.js";
2
+ import"../../chunks/bash-description-5dpf5hpt.js";
3
+ import {
4
+ webFetch2
5
+ } from "../../chunks/bash-description-4cdbmar0.js";
6
+ import {
7
+ PROVIDERS2,
8
+ adapters2,
9
+ shippedProviders2
10
+ } from "../../chunks/bash-description-9gw9ets8.js";
11
+ import {
12
+ webSearch2
13
+ } from "../../chunks/bash-description-4h0hnsv4.js";
14
+
15
+ // src/web/index.ts
16
+ import { standard } from "@nyte-ai/schema";
17
+ import { Type } from "typebox";
18
+ var OFF = { value: "off", label: "Off" };
19
+ var provider = {
20
+ id: "web_search.provider",
21
+ label: "Web search provider",
22
+ schema: standard(Type.String({ minLength: 1 })),
23
+ choices: [...PROVIDERS2.map((known) => ({ value: known.id, label: known.name })), OFF],
24
+ default: "exa",
25
+ scope: "host"
26
+ };
27
+ var keyCommand = {
28
+ name: "websearch-key",
29
+ title: "Set a web search key",
30
+ description: "Store a web search provider's API key: <provider> <key>; no key removes it.",
31
+ complete(prefix) {
32
+ const typed = prefix.trimStart();
33
+ if (/\s/u.test(typed))
34
+ return [];
35
+ return PROVIDERS2.filter((known) => known.id.startsWith(typed.toLowerCase())).map((known) => ({
36
+ value: `${known.id} `,
37
+ label: known.id
38
+ }));
39
+ },
40
+ async run(text, { api }) {
41
+ const [named = "", key = ""] = text.split(/\s+(.*)/su);
42
+ const chosen = PROVIDERS2.find((known) => known.id === named.toLowerCase());
43
+ if (chosen === undefined)
44
+ throw new Error(`Name a provider first: ${PROVIDERS2.map((known) => known.id).join(", ")}.`);
45
+ if (key === "")
46
+ await api.storage.secrets.delete(chosen.id);
47
+ else
48
+ await api.storage.secrets.set(chosen.id, key);
49
+ return `Key for ${chosen.id} ${key === "" ? "removed" : "saved"}.`;
50
+ }
51
+ };
52
+ function webPlugin(fetch) {
53
+ return {
54
+ id: "web",
55
+ contribute: {
56
+ settings: [provider],
57
+ commands: [keyCommand],
58
+ tools: [webFetch2(fetch)]
59
+ },
60
+ async activate(api) {
61
+ for (const shipped of shippedProviders2(fetch, (id) => api.storage.secrets.get(id)))
62
+ api.contribute.searchProviders.add(shipped);
63
+ let selected = await api.contribute.settings.value(provider.id);
64
+ (async () => {
65
+ for await (const value of api.contribute.settings.watch(provider.id)) {
66
+ if (value === selected)
67
+ continue;
68
+ selected = value;
69
+ api.reload();
70
+ }
71
+ })();
72
+ api.contribute.settings.add((draft, siblings) => draft.wrap(provider.id, (inner) => ({
73
+ ...inner,
74
+ choices: [
75
+ ...siblings.searchProviders.list().map((known) => ({ value: known.id, label: known.name })),
76
+ OFF
77
+ ]
78
+ })));
79
+ api.contribute.tools.add((draft, siblings) => {
80
+ if (selected === OFF.value || siblings.searchProviders.list().length === 0)
81
+ return;
82
+ draft.set("web_search", webSearch2(api, provider.id));
83
+ });
84
+ }
85
+ };
86
+ }
87
+ var web_default = webPlugin((input, init) => globalThis.fetch(input, init));
88
+ export {
89
+ PROVIDERS2 as PROVIDERS,
90
+ adapters2 as adapters,
91
+ web_default as default,
92
+ webPlugin
93
+ };
@@ -0,0 +1,60 @@
1
+ import type { SearchProvider, SearchResult } from "@nyte-ai/plugin/core";
2
+ import type { Fetch } from "./body.ts";
3
+ /**
4
+ * The search providers the web plugin ships, by id and display name.
5
+ *
6
+ * @category plugins
7
+ * @since 0.1.0
8
+ */
9
+ export declare const PROVIDERS: readonly [{
10
+ readonly id: "exa";
11
+ readonly name: "Exa";
12
+ }, {
13
+ readonly id: "tavily";
14
+ readonly name: "Tavily";
15
+ }, {
16
+ readonly id: "firecrawl";
17
+ readonly name: "Firecrawl";
18
+ }, {
19
+ readonly id: "parallel";
20
+ readonly name: "Parallel";
21
+ }];
22
+ /**
23
+ * Names a search provider the web plugin ships.
24
+ *
25
+ * @category plugins
26
+ * @since 0.1.0
27
+ */
28
+ export type ShippedProvider = (typeof PROVIDERS)[number]["id"];
29
+ /**
30
+ * Returns what one adapter call needs: the query, the provider's key or
31
+ * undefined for its keyless route, the fetch to send with, and a signal.
32
+ *
33
+ * @category plugins
34
+ * @since 0.1.0
35
+ */
36
+ export interface SearchInput {
37
+ readonly query: string;
38
+ readonly key: string | undefined;
39
+ readonly fetch: Fetch;
40
+ readonly signal: AbortSignal;
41
+ }
42
+ /**
43
+ * One adapter per provider: Tavily over its REST endpoint, the others over
44
+ * one stateless MCP `tools/call` to their public route. Each sends through
45
+ * the given fetch only, reads at most 256 KiB, and returns the hits it recognised.
46
+ *
47
+ * @category plugins
48
+ * @since 0.1.0
49
+ */
50
+ export declare const adapters: {
51
+ readonly [P in ShippedProvider]: (input: SearchInput) => Promise<readonly SearchResult[]>;
52
+ };
53
+ /**
54
+ * Returns the shipped providers for the search registry, each reading its key
55
+ * through `key` on every search and sending through `fetch`.
56
+ *
57
+ * @category plugins
58
+ * @since 0.1.0
59
+ */
60
+ export declare function shippedProviders(fetch: Fetch, key: (provider: ShippedProvider) => Promise<string | undefined>): readonly SearchProvider[];
@@ -0,0 +1,11 @@
1
+ import {
2
+ PROVIDERS2,
3
+ adapters2,
4
+ shippedProviders2
5
+ } from "../../chunks/bash-description-9gw9ets8.js";
6
+ import"../../chunks/bash-description-0ah30s12.js";
7
+ export {
8
+ PROVIDERS2 as PROVIDERS,
9
+ adapters2 as adapters,
10
+ shippedProviders2 as shippedProviders
11
+ };
@@ -0,0 +1,21 @@
1
+ import { Type } from "typebox";
2
+ import type { Static } from "typebox";
3
+ import type { PluginApi, ToolDefinition } from "@nyte-ai/plugin/core";
4
+ declare const searchOutput: Type.TObject<{
5
+ provider: Type.TString;
6
+ results: Type.TArray<Type.TObject<{
7
+ url: Type.TString;
8
+ title: Type.TOptional<Type.TString>;
9
+ content: Type.TOptional<Type.TString>;
10
+ published: Type.TOptional<Type.TNumber>;
11
+ }>>;
12
+ }>;
13
+ type SearchOutput = Static<typeof searchOutput>;
14
+ /**
15
+ * The `web_search` tool: asks the registered provider the setting `setting` names,
16
+ * falling back to Exa and then to the first one registered.
17
+ */
18
+ export declare function webSearch(api: PluginApi, setting: string): ToolDefinition<{
19
+ query: string;
20
+ }, SearchOutput>;
21
+ export {};