@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
@@ -48,24 +48,24 @@ export declare const TINTS: readonly ["blue", "pink", "orange", "teal", "red", "
48
48
  * answers any other import of `nyte/canvas` with a positioned error.
49
49
  */
50
50
  export declare const KIT: {
51
- readonly Stack: "{ direction?: \"row\" | \"column\" = \"column\", gap?: 0 | 1 | 2 | 3 | 4 | 6 = 2 (×4 px), align?: \"start\" | \"center\" | \"end\" | \"stretch\", justify?: \"start\" | \"center\" | \"end\" | \"between\", wrap?: boolean, children }: flex layout";
52
- readonly Grid: "{ columns?: number | \"auto\" = \"auto\", minWidth?: number = 160 (px, with \"auto\"), gap?: 0 | 1 | 2 | 3 | 4 | 6 = 2, children }: equal columns";
51
+ readonly Stack: '{ direction?: "row" | "column" = "column", gap?: 0 | 1 | 2 | 3 | 4 | 6 = 2 (×4 px), align?: "start" | "center" | "end" | "stretch", justify?: "start" | "center" | "end" | "between", wrap?: boolean, children }: flex layout';
52
+ readonly Grid: '{ columns?: number | "auto" = "auto", minWidth?: number = 160 (px, with "auto"), gap?: 0 | 1 | 2 | 3 | 4 | 6 = 2, children }: equal columns';
53
53
  readonly Divider: "{}: a hairline";
54
54
  readonly Heading: "{ level?: 1 | 2 | 3 = 2, children }";
55
- readonly Text: "{ size?: \"xs\" | \"sm\" | \"base\" | \"lg\", tone?: \"primary\" | \"secondary\" | \"tertiary\", weight?: \"normal\" | \"medium\" | \"semibold\", mono?: boolean, truncate?: boolean, align?: \"start\" | \"center\" | \"end\", children }";
55
+ readonly Text: '{ size?: "xs" | "sm" | "base" | "lg", tone?: "primary" | "secondary" | "tertiary", weight?: "normal" | "medium" | "semibold", mono?: boolean, truncate?: boolean, align?: "start" | "center" | "end", children }';
56
56
  readonly Code: "{ block?: boolean, children: string }: monospace, inline or a block";
57
- readonly Stat: "{ label: string, value: ReactNode, detail?: ReactNode, tone?: \"neutral\" | \"success\" | \"warning\" | \"danger\" }: a labelled number";
58
- readonly Badge: "{ tone?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\", children }";
59
- readonly Meter: "{ value: number, max?: number = 100, label?: string, tone?: \"primary\" | \"success\" | \"warning\" | \"danger\" = \"primary\" }: a thin filled bar with the value beside the label";
60
- readonly Table: "{ columns: { key: string, label: ReactNode, align?: \"start\" | \"end\", width?: number | string }[], rows: Record<string, ReactNode>[], caption?: string }: rows are keyed by column key; a cell can hold a Sparkline or a Badge";
61
- readonly Callout: "{ tone?: \"info\" | \"success\" | \"warning\" | \"danger\", title?: string, children }";
57
+ readonly Stat: '{ label: string, value: ReactNode, detail?: ReactNode, tone?: "neutral" | "success" | "warning" | "danger" }: a labelled number';
58
+ readonly Badge: '{ tone?: "neutral" | "info" | "success" | "warning" | "danger", children }';
59
+ readonly Meter: '{ value: number, max?: number = 100, label?: string, tone?: "primary" | "success" | "warning" | "danger" = "primary" }: a thin filled bar with the value beside the label';
60
+ readonly Table: '{ columns: { key: string, label: ReactNode, align?: "start" | "end", width?: number | string }[], rows: Record<string, ReactNode>[], caption?: string }: rows are keyed by column key; a cell can hold a Sparkline or a Badge';
61
+ readonly Callout: '{ tone?: "info" | "success" | "warning" | "danger", title?: string, children }';
62
62
  readonly Card: "{ title?: ReactNode, actions?: ReactNode, padding?: 0 | 2 | 3 | 4 = 4, children }: an elevated bordered surface";
63
63
  readonly StackedBars: "{ label: string, series: { key: string, label: string, tint: Tint }[], buckets: { key: string, label: string, values: number[] }[], format: (value: number) => string, height?: number = 88, ticks?: number = 5 }: compact stacked bars without axes, a readout on pointer or arrow keys; the numbers live in the copy around it. Preferred beside a Stat or a heading figure";
64
64
  readonly Sparkline: "{ values: number[], tint?: Tint, label?: string, width?: number = 72, height?: number = 20 }: a row's trend scaled to its own peak, for a Table cell beside the row's number";
65
- readonly LineChart: "{ series: { id: string, data: { x: number | string, y: number }[], tint?: Tint }[], height?: number = 240, xFormat?: (x) => string, yFormat?: (y) => string, curve?: \"linear\" | \"monotone\" | \"step\", area?: boolean, legend?: boolean }: a full chart with axes and a readout";
66
- readonly BarChart: "{ data: Record<string, number | string>[], keys: (string | { key: string, label?: string, tint?: Tint })[], indexBy: string, height?: number = 240, layout?: \"vertical\" | \"horizontal\", mode?: \"grouped\" | \"stacked\" = \"stacked\", valueFormat?: (value: number) => string, legend?: boolean }: a full chart with axes and a readout with the total";
65
+ readonly LineChart: '{ series: { id: string, data: { x: number | string, y: number }[], tint?: Tint }[], height?: number = 240, xFormat?: (x) => string, yFormat?: (y) => string, curve?: "linear" | "monotone" | "step", area?: boolean, legend?: boolean }: a full chart with axes and a readout';
66
+ readonly BarChart: '{ data: Record<string, number | string>[], keys: (string | { key: string, label?: string, tint?: Tint })[], indexBy: string, height?: number = 240, layout?: "vertical" | "horizontal", mode?: "grouped" | "stacked" = "stacked", valueFormat?: (value: number) => string, legend?: boolean }: a full chart with axes and a readout with the total';
67
67
  readonly PieChart: "{ data: { id: string, value: number, label?: string, tint?: Tint }[], height?: number = 240, donut?: boolean, valueFormat?: (value: number) => string, legend?: boolean }";
68
- readonly Button: "{ variant?: \"solid\" | \"outline\" | \"ghost\", pill?: boolean, size?: \"2xs\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\", tone?: \"neutral\" | \"primary\" | \"success\" | \"warning\" | \"danger\", loading?: boolean, disabled?: boolean, onClick, children }";
68
+ readonly Button: '{ variant?: "solid" | "outline" | "ghost", pill?: boolean, size?: "2xs" | "xs" | "sm" | "md" | "lg" | "xl", tone?: "neutral" | "primary" | "success" | "warning" | "danger", loading?: boolean, disabled?: boolean, onClick, children }';
69
69
  readonly Tabs: "Tabs.Root { value?, defaultValue?, onValueChange? } > Tabs.List { children: Tabs.Tab { value, children }[] } + Tabs.Panel { value, children }";
70
70
  readonly Select: "Select { value?, defaultValue?, onValueChange? } > SelectTrigger { children: <SelectValue /> } + SelectContent { children: SelectItem[] }";
71
71
  readonly SelectTrigger: "see Select";
@@ -83,7 +83,7 @@ export declare const KIT: {
83
83
  readonly Collapsible: "Collapsible.Root { open?, defaultOpen?, onOpenChange? } > Collapsible.Trigger { children } + Collapsible.Panel { children }";
84
84
  readonly Kbd: "{ keys: string[] }";
85
85
  readonly Spinner: "{}";
86
- readonly useColorScheme: "(): \"light\" | \"dark\"";
86
+ readonly useColorScheme: '(): "light" | "dark"';
87
87
  };
88
88
  /** Every name `nyte/canvas` exports, in `KIT` order. */
89
89
  export declare const KIT_EXPORTS: readonly string[];
@@ -1,18 +1,27 @@
1
1
  import type { CanvasPreviewer } from "./canvas-preview.ts";
2
2
  import type { Plugin } from "@nyte-ai/plugin/core";
3
3
  export declare const canvas: import("@nyte-ai/core").PartDefinition<{
4
- code: string;
5
4
  runtime: number;
6
5
  title: string;
7
- error: string | null;
8
6
  height: number | null;
7
+ code: string;
8
+ error: string | null;
9
+ revisions?: {
10
+ runtime: number;
11
+ title: string;
12
+ height: number | null;
13
+ number: number;
14
+ blob: import("@nyte-ai/schema").Id<"blob">;
15
+ at: number;
16
+ }[] | undefined;
9
17
  }, {
10
18
  replace: {
11
19
  input: import("@nyte-ai/schema").Schema<{
12
- code: string;
13
20
  runtime: number;
14
21
  title: string;
15
22
  height: number | null;
23
+ code: string;
24
+ blob: import("@nyte-ai/schema").Id<"blob">;
16
25
  }>;
17
26
  };
18
27
  report: {
@@ -18,8 +18,10 @@ import {
18
18
  describeCanvasPreview2
19
19
  } from "../../chunks/bash-description-yyd9jznf.js";
20
20
  import {
21
+ CANVAS_RENDER_TOOL2,
22
+ CANVAS_REVISIONS_KEPT2,
21
23
  canvas2
22
- } from "../../chunks/bash-description-qnwggxq3.js";
24
+ } from "../../chunks/bash-description-1neewp76.js";
23
25
 
24
26
  // src/canvas/canvas.ts
25
27
  import { definePart, followedTrace, traced } from "@nyte-ai/core";
@@ -27,7 +29,24 @@ import { asId, standard } from "@nyte-ai/schema";
27
29
  import { Type } from "typebox";
28
30
  var handlers = {
29
31
  async replace(input, context) {
30
- const outcome = await context.part.update(() => ({ ...input, error: null }));
32
+ const outcome = await context.part.update((current) => ({
33
+ runtime: input.runtime,
34
+ title: input.title,
35
+ code: input.code,
36
+ height: input.height,
37
+ error: null,
38
+ revisions: [
39
+ ...current.revisions ?? [],
40
+ {
41
+ number: (current.revisions?.at(-1)?.number ?? 1) + 1,
42
+ blob: input.blob,
43
+ runtime: input.runtime,
44
+ title: input.title,
45
+ height: input.height,
46
+ at: Date.now()
47
+ }
48
+ ].slice(-CANVAS_REVISIONS_KEPT2)
49
+ }));
31
50
  if (outcome.kind !== "updated")
32
51
  throw new Error(`The canvas could not be replaced: ${outcome.kind}.`);
33
52
  },
@@ -99,7 +118,7 @@ ${describeErrors(compiled.errors)}`);
99
118
  var PREVIEW_FIRST = "Before rendering, call `canvas_preview` with the same `source` and `files`: it shows you the canvas and its errors, console and height without the user seeing it. Fix what it shows, then render once.";
100
119
  function renderTool(previewing) {
101
120
  return {
102
- name: "canvas_render",
121
+ name: CANVAS_RENDER_TOOL2,
103
122
  description: previewing ? `${PREVIEW_FIRST}
104
123
 
105
124
  ${CANVAS_DESCRIPTION}` : CANVAS_DESCRIPTION,
@@ -113,15 +132,18 @@ ${CANVAS_DESCRIPTION}` : CANVAS_DESCRIPTION,
113
132
  replay: "safe",
114
133
  async execute(args, invocation) {
115
134
  const compiled = await compile(args, invocation);
116
- const next = {
117
- runtime: compiled.runtime,
118
- title: args.title,
119
- code: compiled.code,
120
- height: args.height ?? null
121
- };
135
+ const drawn = { runtime: compiled.runtime, title: args.title, height: args.height ?? null };
136
+ const blob = await invocation.env.files.upload(async function* () {
137
+ yield encoder.encode(compiled.code);
138
+ }());
122
139
  if (args.canvas === undefined) {
123
140
  const part = await invocation.session.parts.create(canvas, {
124
- state: { ...next, error: null },
141
+ state: {
142
+ ...drawn,
143
+ code: compiled.code,
144
+ error: null,
145
+ revisions: [{ number: 1, blob, ...drawn, at: Date.now() }]
146
+ },
125
147
  placement: { kind: "transcript", role: "answer" }
126
148
  });
127
149
  return {
@@ -129,7 +151,7 @@ ${CANVAS_DESCRIPTION}` : CANVAS_DESCRIPTION,
129
151
  parts: [part.id]
130
152
  };
131
153
  }
132
- const outcome = await invocation.session.part(asId(args.canvas)).act("replace", next);
154
+ const outcome = await invocation.session.part(asId(args.canvas)).act("replace", { ...drawn, code: compiled.code, blob });
133
155
  if (outcome.kind !== "ok")
134
156
  throw new Error(`Canvas ${args.canvas} was not replaced: ${outcome.kind}.`);
135
157
  return {
@@ -1,41 +1,81 @@
1
1
  import type { Infer } from "@nyte-ai/schema";
2
+ /**
3
+ * The tool that renders a canvas and replaces one in place.
4
+ *
5
+ * @category plugins
6
+ * @since 0.1.0
7
+ */
8
+ export declare const CANVAS_RENDER_TOOL = "canvas_render";
9
+ /**
10
+ * How many revisions a canvas lists; a replace past it drops the oldest.
11
+ *
12
+ * @category plugins
13
+ * @since 0.1.0
14
+ */
15
+ export declare const CANVAS_REVISIONS_KEPT = 50;
2
16
  declare const state: import("@nyte-ai/schema").Schema<{
3
- code: string;
4
17
  runtime: number;
5
18
  title: string;
6
- error: string | null;
7
19
  height: number | null;
20
+ code: string;
21
+ error: string | null;
22
+ revisions?: {
23
+ runtime: number;
24
+ title: string;
25
+ height: number | null;
26
+ number: number;
27
+ blob: import("@nyte-ai/schema").Id<"blob">;
28
+ at: number;
29
+ }[] | undefined;
8
30
  }>;
9
31
  /**
10
32
  * Returns a canvas part's state: the compiled module, the runtime it needs,
11
- * its title, the agent's height hint and the last error a client reported.
33
+ * its title, the agent's height hint, the last error a client reported, and
34
+ * its revisions, oldest first, the last one being the module itself.
12
35
  *
13
36
  * @category plugins
14
37
  * @since 0.1.0
15
38
  */
16
39
  export type CanvasState = Infer<typeof state>;
40
+ /**
41
+ * One revision of a canvas: its compiled module stored as a blob, with what
42
+ * drawing it needs besides the code.
43
+ *
44
+ * @category plugins
45
+ * @since 0.1.0
46
+ */
47
+ export type CanvasRevision = NonNullable<CanvasState["revisions"]>[number];
17
48
  /**
18
49
  * A canvas part: a React module the agent wrote, compiled on the host and
19
50
  * drawn by a client inside the sandboxed runtime shell. `replace` swaps the
20
- * module in place; `report` records a load or render error a client saw,
21
- * which the model reads in the fallback.
51
+ * module in place and lists it as the next revision; `report` records a load
52
+ * or render error a client saw, which the model reads in the fallback.
22
53
  *
23
54
  * @category plugins
24
55
  * @since 0.1.0
25
56
  */
26
57
  export declare const canvas: import("@nyte-ai/core").PartDefinition<{
27
- code: string;
28
58
  runtime: number;
29
59
  title: string;
30
- error: string | null;
31
60
  height: number | null;
61
+ code: string;
62
+ error: string | null;
63
+ revisions?: {
64
+ runtime: number;
65
+ title: string;
66
+ height: number | null;
67
+ number: number;
68
+ blob: import("@nyte-ai/schema").Id<"blob">;
69
+ at: number;
70
+ }[] | undefined;
32
71
  }, {
33
72
  replace: {
34
73
  input: import("@nyte-ai/schema").Schema<{
35
- code: string;
36
74
  runtime: number;
37
75
  title: string;
38
76
  height: number | null;
77
+ code: string;
78
+ blob: import("@nyte-ai/schema").Id<"blob">;
39
79
  }>;
40
80
  };
41
81
  report: {
@@ -1,8 +1,12 @@
1
1
  import {
2
+ CANVAS_RENDER_TOOL2,
3
+ CANVAS_REVISIONS_KEPT2,
2
4
  canvas2
3
- } from "../../chunks/bash-description-qnwggxq3.js";
5
+ } from "../../chunks/bash-description-1neewp76.js";
4
6
  import"../../chunks/bash-description-dnvgk30y.js";
5
7
  import"../../chunks/bash-description-zfpm2rt0.js";
6
8
  export {
9
+ CANVAS_RENDER_TOOL2 as CANVAS_RENDER_TOOL,
10
+ CANVAS_REVISIONS_KEPT2 as CANVAS_REVISIONS_KEPT,
7
11
  canvas2 as canvas
8
12
  };
@@ -20,7 +20,7 @@ export declare function claudeCodeSdk(start?: StartQuery): {
20
20
  readonly contribute: import("@nyte-ai/core").Registries<"core">;
21
21
  readonly storage: import("@nyte-ai/core").PluginStorage;
22
22
  readonly signal: AbortSignal;
23
- 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;
23
+ hook<N extends import("@nyte-ai/core").HookName<"core">>(name: N, entry: import("@nyte-ai/core").HookEntry<"core", N>): import("@nyte-ai/schema").Disposer;
24
24
  report(issue: import("@nyte-ai/schema").ValidationIssue): void;
25
25
  reload(): void;
26
26
  } & {
@@ -54,6 +54,7 @@ var CLAUDE_CODE_HAS_ITS_OWN = new Set([
54
54
  "edit",
55
55
  "list",
56
56
  "web_search",
57
+ "web_fetch",
57
58
  "question"
58
59
  ]);
59
60
  var ultracodeSetting = {
@@ -22,7 +22,7 @@ declare const _default: {
22
22
  readonly contribute: import("@nyte-ai/core").Registries<"client">;
23
23
  readonly storage: import("@nyte-ai/core").PluginStorage;
24
24
  readonly signal: AbortSignal;
25
- hook<N extends "run_ended_anywhere" | "app_ready" | "session_opened" | "before_submit" | "session_closed" | "app_closing">(name: N, entry: import("@nyte-ai/core").HookEntry<"client", N>): import("@nyte-ai/schema").Disposer;
25
+ hook<N extends import("@nyte-ai/core").HookName<"client">>(name: N, entry: import("@nyte-ai/core").HookEntry<"client", N>): import("@nyte-ai/schema").Disposer;
26
26
  report(issue: import("@nyte-ai/schema").ValidationIssue): void;
27
27
  reload(): void;
28
28
  } & import("@nyte-ai/plugin/client").ClientApi;
@@ -1,6 +1,6 @@
1
1
  import { text, thinking } from "@nyte-ai/core";
2
2
  import type { PartState } from "@nyte-ai/core";
3
- import type { Execution, Failure, HeadInfo, Message, MessageSource, SessionInfo, ToolClass, ToolPartState, UserContent, UserStatus } from "@nyte-ai/schema";
3
+ import type { Execution, Failure, HeadInfo, Message, MessageSource, SessionInfo, ToolClass, ToolPartState, UserContent } from "@nyte-ai/schema";
4
4
  /**
5
5
  * A message the user sent, or one a child, job or action delivered for them.
6
6
  *
@@ -92,32 +92,6 @@ export declare function readRawPart(message: PartMessage): RawPart;
92
92
  * @category presentation
93
93
  */
94
94
  export declare function showsReport(message: UserMessage): message is ReportMessage;
95
- type PendingStatus = Extract<UserStatus, {
96
- readonly kind: "pending";
97
- }>;
98
- /**
99
- * A message that waits in the queue: unsent, or pending for a later turn. A pending steer sent
100
- * while idle or joining the live run is never one.
101
- *
102
- * @category presentation
103
- */
104
- export type QueuedMessage = UserMessage & {
105
- readonly status: Extract<UserStatus, {
106
- readonly kind: "unsent";
107
- }> | (PendingStatus & {
108
- readonly schedule: Exclude<PendingStatus["schedule"], {
109
- readonly kind: "joined";
110
- }>;
111
- });
112
- };
113
- /**
114
- * Whether a message waits in the queue rather than showing in the transcript. A retrying send
115
- * always waits. Reports, joined steers and steers sent while idle stay in the transcript.
116
- * Other messages wait only while a run is active.
117
- *
118
- * @category presentation
119
- */
120
- export declare function waitsInQueue(message: UserMessage, running: boolean): message is QueuedMessage;
121
95
  /**
122
96
  * What a user message shows: an action's label in place of the prompt it sent.
123
97
  *
@@ -21,23 +21,6 @@ function readRawPart(message) {
21
21
  function showsReport(message) {
22
22
  return message.source.kind === "child" || message.source.kind === "job";
23
23
  }
24
- function waitsInQueue(message, running) {
25
- const { status } = message;
26
- if (showsReport(message))
27
- return false;
28
- switch (status.kind) {
29
- case "landed":
30
- return false;
31
- case "unsent":
32
- return status.retrying !== null || running && message.delivery !== "steer";
33
- case "pending":
34
- return running && status.schedule.kind !== "joined" && !(message.delivery === "steer" && status.schedule.kind === "next-turn" && status.schedule.reason === "idle");
35
- default: {
36
- const _exhaustive = status;
37
- return _exhaustive;
38
- }
39
- }
40
- }
41
24
  function shownContent(message) {
42
25
  return message.source.kind === "action" ? message.source.label : message.content;
43
26
  }
@@ -386,6 +369,5 @@ export {
386
369
  toolStatus,
387
370
  toolSubject,
388
371
  toolTitle,
389
- toolVerbs,
390
- waitsInQueue
372
+ toolVerbs
391
373
  };
@@ -1,7 +1,14 @@
1
+ import {
2
+ DEFAULT_SEARCH_LIMIT2,
3
+ createToolSearchDocument2,
4
+ rankTools2
5
+ } from "../chunks/bash-description-b78pre8c.js";
6
+
1
7
  // src/codemode.ts
2
8
  import { CodemodeSandbox } from "@earendil-works/pi-codemode";
3
- import { renderToolSample } from "@earendil-works/pi-codemode/declarations";
9
+ import { renderToolSample, toCodemodeIdentifier } from "@earendil-works/pi-codemode/declarations";
4
10
  import { CODEMODE_SOURCE_GRAMMAR, parseCodemodeSource } from "@earendil-works/pi-codemode/source";
11
+ import { estimateTextTokens } from "@nyte-ai/ai/utils/estimate";
5
12
  import { dev } from "@nyte-ai/core";
6
13
  import { isJson, isJsonObject, SdkError, standard } from "@nyte-ai/schema";
7
14
  import { Type } from "typebox";
@@ -9,8 +16,8 @@ var DESCRIPTION = `Run JavaScript that calls other tools. The input is raw JavaS
9
16
  - \`await tools.<name>({ ...args })\` resolves to the tool's output, or its text, and rejects with an Error on failure.
10
17
  - Optional first line: \`// @options: {"timeout_ms": 60000}\`
11
18
  - \`text(value)\`, \`console.log(...)\` and \`return\` add output; \`store(key, value)\` and \`load(key)\` keep JSON values across codemode calls in this session.
12
- - \`ALL_TOOLS\`, \`searchTools(query, { limit?, namespace? })\` and \`describeTool(name)\` find tools and their declarations.`;
13
- var SUMMARY_CHARS = 160;
19
+ - \`ALL_TOOLS\`, \`await searchTools(query, { limit?, namespace? })\`, \`await describeTool(name)\` and \`await describeNamespace(name)\` find unlisted tools, such as MCP tools, and their declarations.`;
20
+ var LISTING_TOKENS = 3000;
14
21
  var parameters = standard(Type.Object({ code: Type.String({ description: "Raw JavaScript source." }) }));
15
22
  function codemodePlugin(runtime) {
16
23
  return {
@@ -18,32 +25,94 @@ function codemodePlugin(runtime) {
18
25
  activate(api) {
19
26
  api.contribute.tools.add(codemode(api, runtime));
20
27
  api.contribute.prompt.add((draft, siblings) => {
21
- const reachable = siblings.tools.list().flatMap((tool) => tool.exposure === "code" || tool.exposure === "deferred" ? [`- ${tool.name}: ${summarize(tool.description)}`] : []).toSorted();
22
- if (reachable.length === 0)
23
- return;
24
- draft.set("codemode", {
25
- id: "codemode",
26
- order: 96,
27
- text: [
28
- "Tools you reach only from a codemode script, as `await tools.<name>(args)`; `describeTool(name)` inside a script returns a tool's arguments:",
29
- ...reachable
30
- ].join(`
31
- `)
32
- });
28
+ const text = listTools(siblings.tools.list());
29
+ if (text !== null)
30
+ draft.set("codemode", { id: "codemode", order: 96, text });
33
31
  });
34
32
  }
35
33
  };
36
34
  }
37
- function summarize(description) {
38
- const [line = ""] = description.trim().split(`
35
+ function listTools(definitions) {
36
+ const sections = definitions.flatMap((definition) => {
37
+ if (definition.exposure !== "code")
38
+ return [];
39
+ const inputSchema = toJsonSchema(definition.parameters, "input");
40
+ const outputSchema = definition.output === undefined ? { type: "string" } : toJsonSchema(definition.output, "output");
41
+ if (inputSchema === null || outputSchema === null)
42
+ return [];
43
+ const id = toCodemodeIdentifier(definition.name);
44
+ const sample = renderToolSample({
45
+ name: definition.name,
46
+ description: definition.description,
47
+ inputSchema,
48
+ outputSchema
49
+ }).trim();
50
+ const section = `### \`${id}\`${id === definition.name ? "" : ` (\`${definition.name}\`)`}
51
+ ${sample}`;
52
+ return [
53
+ {
54
+ namespace: definition.namespace,
55
+ name: definition.name,
56
+ section,
57
+ cost: estimateTextTokens(section)
58
+ }
59
+ ];
60
+ });
61
+ if (sections.length === 0)
62
+ return null;
63
+ const groups = [
64
+ ...Map.groupBy(sections, (entry) => entry.namespace?.name ?? "").entries()
65
+ ].toSorted((left, right) => left[0].localeCompare(right[0])).map((pair) => ({ namespace: pair[1][0]?.namespace, entries: pair[1] }));
66
+ const shown = selectListed(groups, LISTING_TOKENS);
67
+ return [
68
+ "Tools you reach only from a codemode script, as `await tools.<name>(args)`:",
69
+ ...groups.flatMap((group) => {
70
+ const visible = group.entries.filter((entry) => shown.has(entry.name));
71
+ if (group.namespace === undefined)
72
+ return visible.map((entry) => entry.section);
73
+ const listing = visible.length === group.entries.length ? "" : visible.length === 0 ? " (tools not listed)" : " (some tools not listed)";
74
+ const description = group.namespace.description?.trim() ?? "";
75
+ return [
76
+ `## ${group.namespace.name}${listing}${description === "" ? "" : `
77
+ ${description}`}`,
78
+ ...visible.map((entry) => entry.section)
79
+ ];
80
+ })
81
+ ].join(`
82
+
39
83
  `);
40
- return line.length > SUMMARY_CHARS ? `${line.slice(0, SUMMARY_CHARS)}…` : line;
84
+ }
85
+ function selectListed(groups, budget) {
86
+ const queues = groups.map((group) => group.entries.toSorted((a, b) => a.cost - b.cost));
87
+ const shown = new Set;
88
+ let remaining = budget;
89
+ let active = queues.filter((queue) => queue.length > 0);
90
+ while (active.length > 0)
91
+ active = active.filter((queue) => {
92
+ const next = queue[0];
93
+ if (next === undefined || next.cost > remaining)
94
+ return false;
95
+ remaining -= next.cost;
96
+ shown.add(next.name);
97
+ queue.shift();
98
+ return queue.length > 0;
99
+ });
100
+ return shown;
101
+ }
102
+ function toJsonSchema(schema, direction) {
103
+ try {
104
+ const converted = schema["~standard"].jsonSchema[direction]({ target: "draft-2020-12" });
105
+ return isJson(converted) && isJsonObject(converted) ? converted : null;
106
+ } catch {
107
+ return null;
108
+ }
41
109
  }
42
110
  function codemode(api, runtime) {
43
111
  return {
44
112
  name: "codemode",
45
113
  description: DESCRIPTION,
46
114
  parameters,
115
+ exposure: "model-only",
47
116
  grammar: { kind: "lark", source: CODEMODE_SOURCE_GRAMMAR },
48
117
  class: () => ({ kind: "custom", label: "Running a script" }),
49
118
  effects: "none",
@@ -51,14 +120,24 @@ function codemode(api, runtime) {
51
120
  replay: "never",
52
121
  async execute(args, invocation) {
53
122
  const { code, options } = parseCodemodeSource(args.code);
54
- const callable = invocation.tools.list().filter((info) => info.name !== "codemode" && info.exposure !== "hidden");
123
+ const callable = invocation.tools.list().filter((info) => info.exposure !== "model-only" && info.exposure !== "hidden");
55
124
  const stored = await api.storage.get("store");
56
125
  if (stored !== undefined && !isJsonObject(stored))
57
126
  throw new SdkError("internal", "Codemode's stored values are not a JSON object.");
127
+ const namespaces = new Map(api.contribute.tools.list().flatMap((definition) => definition.namespace === undefined ? [] : [[definition.name, definition.namespace]]));
128
+ const samples = new Map(callable.map((info) => [
129
+ info.name,
130
+ renderToolSample({
131
+ name: info.name,
132
+ description: info.description,
133
+ inputSchema: info.parameters,
134
+ outputSchema: info.output ?? { type: "string" }
135
+ })
136
+ ]));
58
137
  const sandbox = new CodemodeSandbox({
59
138
  ...runtime,
60
- tools: callable.map((info) => bridge(info, invocation)),
61
- globals: discovery(callable),
139
+ tools: callable.map((info) => bridge(info, samples.get(info.name) ?? "", invocation)),
140
+ globals: discovery(callable, samples, namespaces),
62
141
  timeoutMs: options.timeoutMs ?? 300000,
63
142
  memoryLimitBytes: 256 * 1024 * 1024
64
143
  });
@@ -102,11 +181,11 @@ ${calls(result)}`);
102
181
  }
103
182
  };
104
183
  }
105
- function bridge(info, invocation) {
184
+ function bridge(info, sample, invocation) {
106
185
  let sequence = 0;
107
186
  return {
108
187
  name: info.name,
109
- description: info.description,
188
+ description: sample,
110
189
  inputSchema: info.parameters,
111
190
  outputSchema: info.output ?? { type: "string" },
112
191
  async execute(args, { signal }) {
@@ -121,42 +200,70 @@ function unwrapToolOutcome(outcome) {
121
200
  `);
122
201
  throw new Error(outcome.kind === "failed" ? outcome.message : outcome.kind === "rejected" ? `Rejected: ${outcome.reason}` : `The call was ${outcome.kind}.`);
123
202
  }
124
- function discovery(tools) {
203
+ function discovery(tools, samples, namespaces) {
125
204
  return [
126
205
  {
127
206
  name: "searchTools",
128
207
  spread: true,
129
208
  execute(args) {
130
209
  const [query, options] = Array.isArray(args) ? args : [];
131
- const words = new Set(String(query).toLowerCase().split(/[^a-z0-9]+/).filter((word) => word.length > 1));
132
- const limit = typeof options === "object" && options !== null && "limit" in options && typeof options.limit === "number" ? options.limit : 8;
133
- const namespace = typeof options === "object" && options !== null && "namespace" in options && typeof options.namespace === "string" ? options.namespace : null;
134
- return tools.filter((info) => namespace === null || info.namespace === namespace).map((info) => ({
135
- info,
136
- score: `${info.name} ${info.description}`.toLowerCase().split(/[^a-z0-9]+/).filter((word) => words.has(word)).length
137
- })).filter((entry) => entry.score > 0).toSorted((left, right) => right.score - left.score).slice(0, limit).map(({ info }) => ({
138
- name: info.name,
139
- namespace: info.namespace,
140
- description: info.description
210
+ if (typeof query !== "string")
211
+ throw new Error("searchTools() expects a query string");
212
+ const limit = isJsonObject(options) ? options.limit ?? null : null;
213
+ const namespace = isJsonObject(options) ? options.namespace ?? null : null;
214
+ if (limit !== null && (typeof limit !== "number" || !Number.isInteger(limit) || limit <= 0))
215
+ throw new Error("searchTools() limit must be a positive integer");
216
+ if (namespace !== null && typeof namespace !== "string")
217
+ throw new Error("searchTools() namespace must be a string");
218
+ const documents = tools.flatMap((info) => {
219
+ const found = namespaces.get(info.name);
220
+ if (namespace !== null && (found === undefined || !matchesNamespace(found, namespace)))
221
+ return [];
222
+ return [createToolSearchDocument2(info, found)];
223
+ });
224
+ return rankTools2(query, documents, limit ?? DEFAULT_SEARCH_LIMIT2).map((name) => ({
225
+ name: toCodemodeIdentifier(name),
226
+ description: samples.get(name) ?? ""
141
227
  }));
142
228
  }
143
229
  },
144
230
  {
145
231
  name: "describeTool",
146
232
  execute(name) {
147
- const info = tools.find((candidate) => candidate.name === name);
233
+ if (typeof name !== "string")
234
+ throw new Error("describeTool() expects a tool name");
235
+ const info = tools.find((candidate) => candidate.name === name || toCodemodeIdentifier(candidate.name) === name);
148
236
  if (info === undefined)
149
- throw new Error(`No tool is named ${String(name)}.`);
150
- return renderToolSample({
151
- name: info.name,
152
- description: info.description,
153
- inputSchema: info.parameters,
154
- outputSchema: info.output ?? { type: "string" }
237
+ throw new Error(`No tool is named ${name}.`);
238
+ return samples.get(info.name) ?? "";
239
+ }
240
+ },
241
+ {
242
+ name: "describeNamespace",
243
+ execute(name) {
244
+ if (typeof name !== "string")
245
+ throw new Error("describeNamespace() expects a namespace name");
246
+ const members = tools.filter((info) => {
247
+ const found = namespaces.get(info.name);
248
+ return found !== undefined && matchesNamespace(found, name);
155
249
  });
250
+ const namespace = members[0] === undefined ? undefined : namespaces.get(members[0].name);
251
+ if (namespace === undefined)
252
+ throw new Error(`No namespace is named ${name}.`);
253
+ return {
254
+ name: namespace.name,
255
+ ...namespace.description === undefined ? {} : { description: namespace.description },
256
+ ...namespace.instructions === undefined ? {} : { instructions: namespace.instructions },
257
+ tools: members.map((info) => toCodemodeIdentifier(info.name))
258
+ };
156
259
  }
157
260
  }
158
261
  ];
159
262
  }
263
+ function matchesNamespace(namespace, query) {
264
+ const id = toCodemodeIdentifier(query);
265
+ return [namespace.name, ...namespace.aliases ?? []].some((name) => name === query || toCodemodeIdentifier(name) === id);
266
+ }
160
267
  function calls(result) {
161
268
  return result.calls.length === 0 ? "No tool calls were made." : `Tool calls made before the failure (not undone): ${result.calls.map((call) => `${call.name} (${call.status})`).join(", ")}`;
162
269
  }
@@ -1,6 +1,6 @@
1
1
  import type { HookEntry as SideHookEntry, HookHandler as SideHookHandler, HookName as SideHookName, Plugin as CorePlugin, PluginApi as CorePluginApi } from "@nyte-ai/core";
2
2
  export { branchSummary, compaction, definePart, isPart, text, thinking, tool } from "@nyte-ai/core";
3
- export type { ActionContext, Agent, Command, Durable, HookTable, ModelContextPolicy, Part, PartDefinition, PartState, PromptSection, Setting, SettingDefinition, Skill, ToolDefinition, ToolInvocation, } from "@nyte-ai/core";
3
+ export type { ActionContext, Agent, Command, Durable, HookTable, ModelContextPolicy, Part, PartDefinition, PartState, PromptSection, SearchProvider, SearchResult, Setting, SettingDefinition, Skill, ToolDefinition, ToolInvocation, } from "@nyte-ai/core";
4
4
  export type { CompactionPlan, Decision, ModelRequest, Submission, ToolCall, Transcript, } from "@nyte-ai/schema";
5
5
  /**
6
6
  * A core plugin: per session on the host, with tools, prompt sections,