@yolk-sdk/codemode 0.1.0-canary.107 → 0.1.0-canary.108
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -2
- package/dist/catalog.d.mts +69 -9
- package/dist/catalog.d.mts.map +1 -1
- package/dist/catalog.mjs +168 -19
- package/dist/catalog.mjs.map +1 -1
- package/dist/classifier-tool.mjs +1 -1
- package/dist/executor.d.mts +10 -1
- package/dist/executor.d.mts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/node.d.mts.map +1 -1
- package/dist/node.mjs +12 -5
- package/dist/node.mjs.map +1 -1
- package/dist/search.d.mts +11 -6
- package/dist/search.d.mts.map +1 -1
- package/dist/search.mjs +23 -45
- package/dist/search.mjs.map +1 -1
- package/dist/tool.d.mts +9 -0
- package/dist/tool.d.mts.map +1 -1
- package/dist/tool.mjs +72 -21
- package/dist/tool.mjs.map +1 -1
- package/package.json +2 -2
- package/src/catalog.ts +241 -22
- package/src/executor.ts +6 -0
- package/src/index.ts +8 -1
- package/src/node.ts +22 -9
- package/src/search.ts +31 -85
- package/src/tool.ts +112 -16
package/README.md
CHANGED
|
@@ -78,7 +78,9 @@ const program = Effect.gen(function* () {
|
|
|
78
78
|
declarations within `inlineBudget` (default 3,000 estimated tokens, filled fairly across
|
|
79
79
|
namespaces); `callableBy: 'all'` tools get one line each outside the budget; `codemode` +
|
|
80
80
|
`search` tools contribute nothing (no headings or hints), so the description stays
|
|
81
|
-
byte-identical when they, or whole namespaces of them, change.
|
|
81
|
+
byte-identical when they, or whole namespaces of them, change. `codemode` + `pinned` tools are
|
|
82
|
+
always declared, outside the budget, and deferred (`loading: 'deferred'`) `all` tools count as
|
|
83
|
+
`search` tools. One fixed line tells scripts to
|
|
82
84
|
find unlisted tools with `searchTools(query, { limit?, namespace? })` (BM25 over names,
|
|
83
85
|
descriptions, namespaces, and module descriptions), `describeTool(name)`, and
|
|
84
86
|
`describeNamespace(name)`.
|
|
@@ -140,12 +142,28 @@ the plan once and its result tells the model to call `review_plan({ planId, plan
|
|
|
140
142
|
stay fail-closed for `tools.<name>()`. Pass `staging: false` to turn it off or `staging: { maxCalls }`
|
|
141
143
|
to lower the cap.
|
|
142
144
|
|
|
145
|
+
A stageable tool may be **stage-only** (`callableBy: 'codemode'`, usually with `discovery: 'search'`):
|
|
146
|
+
it is never declared to the model, scripts find it with `searchTools()` (hits marked
|
|
147
|
+
`stageOnly: true`) and read it with `describeTool()`, and the only thing they can do with it is
|
|
148
|
+
`stage()` it. See [ADR 0007](https://github.com/magoz/yolk-sdk/blob/main/docs/adr/0007-tool-exposure-and-catalog.md).
|
|
149
|
+
|
|
143
150
|
Applied plan calls run inside the review action: they bypass `beforeNestedCall` and `ToolExecutor`
|
|
144
151
|
decorators. Wire the same per-call check as `makePlanReviewTool({ beforeCall })`. Review screens
|
|
145
152
|
show each staged call with the tool's `changePreview` from `@yolk-sdk/agent/tools`. See
|
|
146
153
|
[ADR 0005](https://github.com/magoz/yolk-sdk/blob/main/docs/adr/0005-staged-tool-plans.md) and
|
|
147
154
|
[ADR 0006](https://github.com/magoz/yolk-sdk/blob/main/docs/adr/0006-tool-change-previews.md).
|
|
148
155
|
|
|
156
|
+
## Catalog as instructions
|
|
157
|
+
|
|
158
|
+
`makeCodeModeTool({ executor, catalog: 'instructions' })` keeps the `codemode` description
|
|
159
|
+
invariant and delivers the catalog (every namespace with its tool count, listed tools within
|
|
160
|
+
`inlineBudget`, `pinned` tools always) as a host instruction: pass `toolSet.instructions` to
|
|
161
|
+
`RunConfig.instructions`, or, for durable hosts driving `runModelTurn`, append and persist
|
|
162
|
+
`instructionMessages(transcript, toolSet.instructions)` from `@yolk-sdk/agent/loop` before each
|
|
163
|
+
model step. A changed catalog is appended to the conversation, whole, instead of rewriting the
|
|
164
|
+
cached request prefix. Hosts with their own compaction keep `latestInstructionMessages(...)` from
|
|
165
|
+
`@yolk-sdk/agent/protocol` after their summary, as window compaction does.
|
|
166
|
+
|
|
149
167
|
## Limits
|
|
150
168
|
|
|
151
169
|
| Limit | Default | Notes |
|
|
@@ -170,7 +188,7 @@ permits. Nested-call records carry token usage; cost stays in the result's
|
|
|
170
188
|
|
|
171
189
|
## Host responsibilities
|
|
172
190
|
|
|
173
|
-
- Which tools are callable from scripts (`callableBy`, `discovery`), approvals, and policy.
|
|
191
|
+
- Which tools are callable from scripts (`callableBy`, `discovery`, `loading`), approvals, and policy.
|
|
174
192
|
- Run authority for nested calls: decorators around the `ToolExecutor` (outside
|
|
175
193
|
`ResolvedToolSet.execute`) do not see nested calls. Use `beforeNestedCall` or registration-level
|
|
176
194
|
wrappers for per-call checks.
|
package/dist/catalog.d.mts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { CodeModeJsonSchema } from "./executor.mjs";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
2
3
|
import { NestedTool } from "@yolk-sdk/agent/tools";
|
|
4
|
+
import { RunInstruction } from "@yolk-sdk/agent/loop";
|
|
3
5
|
|
|
4
6
|
//#region src/catalog.d.ts
|
|
5
7
|
/** How a nested tool reaches scripts: `all` tools are also direct model tools; `listed` and
|
|
6
|
-
* `search` are the two discovery modes of `codemode`-only tools
|
|
8
|
+
* `search` are the two discovery modes of `codemode`-only tools; `stage` marks a stage-only tool
|
|
9
|
+
* (ADR 0007): found by search, never callable, only passed to `stage()`.
|
|
7
10
|
*/
|
|
8
|
-
type CodeModeToolExposure = 'all' | 'listed' | 'search';
|
|
11
|
+
type CodeModeToolExposure = 'all' | 'listed' | 'search' | 'pinned' | 'stage';
|
|
9
12
|
/** One nested tool as scripts see it. */
|
|
10
13
|
type CodeModeCatalogTool = {
|
|
11
14
|
/** Raw tool name; scripts may call `tools["<name>"](args)`. */readonly name: string; /** Identifier for `tools.<identifier>(args)` (invalid identifier characters become `_`). */
|
|
@@ -34,6 +37,12 @@ type CodeModeCatalogTool = {
|
|
|
34
37
|
declare const codeModeCallLabels: (names: ReadonlyArray<string>) => ReadonlyArray<string>;
|
|
35
38
|
/** Catalog of nested tools in resolution order. */
|
|
36
39
|
declare const codeModeCatalog: (tools: ReadonlyArray<NestedTool>) => ReadonlyArray<CodeModeCatalogTool>;
|
|
40
|
+
/**
|
|
41
|
+
* Catalog entries of the stage-only tools among the stageable ones (`callableBy: 'codemode'`,
|
|
42
|
+
* ADR 0007): searchable and describable, never callable (no `tools` binding), so their call label
|
|
43
|
+
* is the `stage()` call that records them.
|
|
44
|
+
*/
|
|
45
|
+
declare const codeModeStageOnlyCatalog: (stageable: ReadonlyArray<NestedTool>) => ReadonlyArray<CodeModeCatalogTool>;
|
|
37
46
|
/** Default inline budget of the nested tool listing, in estimated tokens. */
|
|
38
47
|
declare const defaultCodeModeInlineBudget = 3000;
|
|
39
48
|
/** Estimated tokens of a text: four characters per token, rounded up. */
|
|
@@ -47,9 +56,10 @@ type CodeModeListing = {
|
|
|
47
56
|
};
|
|
48
57
|
/**
|
|
49
58
|
* Chooses the tools the description lists. `all` tools are always placed, outside the budget
|
|
50
|
-
* (the model already has their declarations)
|
|
51
|
-
* across namespaces: each round, every namespace still in play
|
|
52
|
-
* a namespace whose next tool does not fit drops out. `search`
|
|
59
|
+
* (the model already has their declarations), and so are `pinned` tools. `listed` tools fill
|
|
60
|
+
* `budget` estimated tokens fairly across namespaces: each round, every namespace still in play
|
|
61
|
+
* places its cheapest remaining tool; a namespace whose next tool does not fit drops out. `search`
|
|
62
|
+
* tools are never candidates.
|
|
53
63
|
*/
|
|
54
64
|
declare const selectCodeModeListing: (catalog: ReadonlyArray<CodeModeCatalogTool>, budget: number) => CodeModeListing;
|
|
55
65
|
/** Staged tool plans as the description shows them (`NestedToolStagingDescription`). */
|
|
@@ -60,7 +70,7 @@ type CodeModeStagingDescription = {
|
|
|
60
70
|
type CodeModeDescriptionInput = {
|
|
61
71
|
readonly tools: ReadonlyArray<NestedTool>;
|
|
62
72
|
readonly inlineBudget?: number; /** Mention `store()`/`load()` persistence. */
|
|
63
|
-
readonly store?: boolean; /** Document `stage()` and list the stageable tools
|
|
73
|
+
readonly store?: boolean; /** Document `stage()` and list the stageable tools that are not stage-only `search` tools. */
|
|
64
74
|
readonly staging?: CodeModeStagingDescription;
|
|
65
75
|
};
|
|
66
76
|
/**
|
|
@@ -69,13 +79,63 @@ type CodeModeDescriptionInput = {
|
|
|
69
79
|
* `all` tools get one line each outside the budget; `listed` tools are declared within the inline
|
|
70
80
|
* budget; `search` tools never contribute, so adding or removing them (even whole namespaces of
|
|
71
81
|
* them) leaves the text byte-identical. With `staging` (and stageable tools), `stage()` is listed
|
|
72
|
-
* with the globals and the stageable tool names follow the nested tools
|
|
82
|
+
* with the globals and the stageable tool names follow the nested tools; stage-only `search` tools
|
|
83
|
+
* are never named, so they leave the text byte-identical too once any stageable tool exists.
|
|
73
84
|
*/
|
|
74
85
|
declare const renderCodeModeDescription: (input: CodeModeDescriptionInput) => string;
|
|
75
|
-
/**
|
|
86
|
+
/**
|
|
87
|
+
* `describeTool` text: the description and TypeScript declaration of one tool. A stage-only tool
|
|
88
|
+
* has no `tools` binding, so it is described as the `stage()` call that records it.
|
|
89
|
+
*/
|
|
76
90
|
declare const describeCodeModeTool: (tool: CodeModeCatalogTool) => string;
|
|
77
91
|
/** Finds a tool by identifier or raw name. */
|
|
78
92
|
declare const findCodeModeTool: (catalog: ReadonlyArray<CodeModeCatalogTool>, name: string) => CodeModeCatalogTool | undefined;
|
|
93
|
+
/** The instruction key of the code mode catalog (`catalog: 'instructions'`, ADR 0007). */
|
|
94
|
+
declare const codeModeCatalogInstructionKey = "yolk.codemode.catalog";
|
|
95
|
+
/** The catalog an instruction message records as its state (JSON, never model-visible). */
|
|
96
|
+
declare const CodeModeCatalogSummary: Schema.Struct<{
|
|
97
|
+
readonly namespaces: Schema.$Array<Schema.Struct<{
|
|
98
|
+
readonly name: Schema.String;
|
|
99
|
+
readonly description: Schema.optional<Schema.String>; /** Every tool scripts reach in the namespace: callable and stage-only. */
|
|
100
|
+
readonly count: Schema.Number; /** Tools the listing shows. */
|
|
101
|
+
readonly shown: Schema.Number; /** The rendered declarations and direct tool lines of the shown tools. */
|
|
102
|
+
readonly listing: Schema.String;
|
|
103
|
+
}>>; /** Stageable tool names the catalog lists: `pinned` ones, then `listed` ones (never `search`). */
|
|
104
|
+
readonly stageable: Schema.Struct<{
|
|
105
|
+
readonly pinned: Schema.$Array<Schema.String>;
|
|
106
|
+
readonly listed: Schema.$Array<Schema.String>;
|
|
107
|
+
}>;
|
|
108
|
+
}>;
|
|
109
|
+
type CodeModeCatalogSummary = typeof CodeModeCatalogSummary.Type;
|
|
110
|
+
/**
|
|
111
|
+
* The catalog of one resolution: every namespace with its tool count and description, and the
|
|
112
|
+
* listing of the tools the inline budget (or `pinned`) places. `search` and stage-only tools are
|
|
113
|
+
* counted, never listed.
|
|
114
|
+
*/
|
|
115
|
+
declare const summarizeCodeModeCatalog: (input: {
|
|
116
|
+
readonly tools: ReadonlyArray<NestedTool>;
|
|
117
|
+
readonly staging?: CodeModeStagingDescription;
|
|
118
|
+
readonly inlineBudget?: number;
|
|
119
|
+
}) => CodeModeCatalogSummary;
|
|
120
|
+
/** The full catalog text of an instruction message. */
|
|
121
|
+
declare const renderCodeModeCatalog: (summary: CodeModeCatalogSummary) => string;
|
|
122
|
+
/**
|
|
123
|
+
* The host instruction of the code mode catalog: its state is the encoded summary, and its render
|
|
124
|
+
* the full catalog (every change renders it whole, see `RunInstruction.render`) or a removal notice.
|
|
125
|
+
*/
|
|
126
|
+
declare const codeModeCatalogInstruction: (input: {
|
|
127
|
+
readonly tools: ReadonlyArray<NestedTool>;
|
|
128
|
+
readonly staging?: CodeModeStagingDescription;
|
|
129
|
+
readonly inlineBudget?: number;
|
|
130
|
+
}) => RunInstruction;
|
|
131
|
+
/**
|
|
132
|
+
* The code mode description when the catalog is delivered as an instruction: invariant across
|
|
133
|
+
* catalog changes (only staging availability adds the `stage()` line).
|
|
134
|
+
*/
|
|
135
|
+
declare const renderCodeModeInstructedDescription: (input: {
|
|
136
|
+
readonly store?: boolean;
|
|
137
|
+
readonly staging?: CodeModeStagingDescription;
|
|
138
|
+
}) => string;
|
|
79
139
|
//#endregion
|
|
80
|
-
export { CodeModeCatalogTool, CodeModeDescriptionInput, CodeModeListing, CodeModeStagingDescription, CodeModeToolExposure, codeModeCallLabels, codeModeCatalog, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, renderCodeModeDescription, selectCodeModeListing };
|
|
140
|
+
export { CodeModeCatalogSummary, CodeModeCatalogTool, CodeModeDescriptionInput, CodeModeListing, CodeModeStagingDescription, CodeModeToolExposure, codeModeCallLabels, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeStageOnlyCatalog, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, selectCodeModeListing, summarizeCodeModeCatalog };
|
|
81
141
|
//# sourceMappingURL=catalog.d.mts.map
|
package/dist/catalog.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.mts","names":[],"sources":["../src/catalog.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"catalog.d.mts","names":[],"sources":["../src/catalog.ts"],"mappings":";;;;;;;;AAkBA;;KAAY,oBAAA;;KAGA,mBAAA;EAAA,wEAED,IAAA;WAEA,UAAA;EAcc;;;;;EAAA,SARd,SAAA;EAAA,SAEA,SAAA,UAEA;EAAA,SAAA,oBAAA;EAAA,SACA,WAAA;EAAA,SACA,WAAA,EAAa,kBAAA,EAEb;EAAA,SAAA,YAAA,EAAc,kBAAA,EAEd;EAAA,SAAA,UAAA;EAAA,SACA,QAAA,EAAU,oBAAA;AAAA;AAAoB;AAYzC;;;;;;AAZyC,cAY5B,kBAAA,GAAsB,KAAA,EAAO,aAAA,aAAwB,aAAa;;cAelE,eAAA,GACX,KAAA,EAAO,aAAA,CAAc,UAAA,MACpB,aAAA,CAAc,mBAAA;AAFjB;;;;;AAAA,cA+Ba,wBAAA,GACX,SAAA,EAAW,aAAA,CAAc,UAAA,MACxB,aAAA,CAAc,mBAAA;;cAsBJ,2BAAA;;cAGA,sBAAA,GAA0B,IAAY;AAAA,KA4DvC,eAAA;EArHV;;;EAAA,SAyHS,MAAA,EAAQ,aAAA,CAAc,mBAAA,GAxHG;EAAA,SA0HzB,kBAAA,EAAoB,aAAA;AAAA;;;;;;;;cAUlB,qBAAA,GACX,OAAA,EAAS,aAAA,CAAc,mBAAA,GACvB,MAAA,aACC,eAAA;;KAiIS,0BAAA;EAAA,SACD,KAAA,EAAO,aAAa,CAAC,UAAA;EAAA,SACrB,cAAA;AAAA;AAAA,KAGC,wBAAA;EAAA,SACD,KAAA,EAAO,aAAA,CAAc,UAAA;EAAA,SACrB,YAAA;WAEA,KAAA,YA5N6B;EAAA,SA8N7B,OAAA,GAAU,0BAAA;AAAA;;;AA3N8B;AA4DnD;;;;;;cA2Ka,yBAAA,GAA6B,KAA+B,EAAxB,wBAAwB;;;;;cAsC5D,oBAAA,GAAwB,IAAyB,EAAnB,mBAAmB;;cAUjD,gBAAA,GACX,OAAA,EAAS,aAAA,CAAc,mBAAA,GACvB,IAAA,aACC,mBAAA;AAxNyC;AAAA,cA4N/B,6BAAA;;cAcA,sBAAA,EAAsB,MAAA,CAAA,MAAA;EAAA;;0DA9KlC;IAAA,+BAjDU;IAAA,+BAAT;IAAA;OAiDD;EAAA;;;;;KAuLW,sBAAA,UAAgC,sBAAA,CAAuB,IAAI;;;;;AAnG9C;cAwHZ,wBAAA,GAA4B,KAAA;EAAA,SAC9B,KAAA,EAAO,aAAA,CAAc,UAAA;EAAA,SACrB,OAAA,GAAU,0BAAA;EAAA,SACV,YAAA;AAAA,MACP,sBAAA;;cA6CS,qBAAA,GAAyB,OAA+B,EAAtB,sBAAsB;;;;;cAexD,0BAAA,GAA8B,KAAA;EAAA,SAChC,KAAA,EAAO,aAAA,CAAc,UAAA;EAAA,SACrB,OAAA,GAAU,0BAAA;EAAA,SACV,YAAA;AAAA,MACP,cAAA;AAnL2C;AAY/C;;;AAZ+C,cA0MlC,mCAAA,GAAuC,KAAA;EAAA,SACzC,KAAA;EAAA,SACA,OAAA,GAAU,0BAA0B;AAAA"}
|
package/dist/catalog.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Predicate } from "effect";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import { Option, Predicate } from "effect";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
import { renderDeclarations, renderToolOutputType, renderToolSample, schemaToType, toCodemodeIdentifier } from "@earendil-works/pi-codemode/declarations";
|
|
4
|
+
import { isDeferredTool, toolDiscovery } from "@yolk-sdk/agent/protocol";
|
|
4
5
|
//#region src/catalog.ts
|
|
5
6
|
const textOutputSchema = { type: "string" };
|
|
6
7
|
/**
|
|
@@ -33,7 +34,7 @@ const codeModeCatalog = (tools) => {
|
|
|
33
34
|
inputSchema: def.parameters,
|
|
34
35
|
outputSchema: def.outputSchema ?? textOutputSchema,
|
|
35
36
|
structured: def.outputSchema !== void 0,
|
|
36
|
-
exposure: toolDiscovery(def) ?? "all"
|
|
37
|
+
exposure: toolDiscovery(def) ?? (isDeferredTool(def) ? "search" : "all")
|
|
37
38
|
};
|
|
38
39
|
return moduleDescription === void 0 ? tool : {
|
|
39
40
|
...tool,
|
|
@@ -41,6 +42,29 @@ const codeModeCatalog = (tools) => {
|
|
|
41
42
|
};
|
|
42
43
|
});
|
|
43
44
|
};
|
|
45
|
+
/**
|
|
46
|
+
* Catalog entries of the stage-only tools among the stageable ones (`callableBy: 'codemode'`,
|
|
47
|
+
* ADR 0007): searchable and describable, never callable (no `tools` binding), so their call label
|
|
48
|
+
* is the `stage()` call that records them.
|
|
49
|
+
*/
|
|
50
|
+
const codeModeStageOnlyCatalog = (stageable) => stageable.flatMap(({ def, moduleId, moduleDescription }) => {
|
|
51
|
+
if (def.callableBy !== "codemode") return [];
|
|
52
|
+
const tool = {
|
|
53
|
+
name: def.name,
|
|
54
|
+
identifier: toCodemodeIdentifier(def.name),
|
|
55
|
+
callLabel: `stage(${JSON.stringify(def.name)})`,
|
|
56
|
+
namespace: moduleId,
|
|
57
|
+
description: def.description,
|
|
58
|
+
inputSchema: def.parameters,
|
|
59
|
+
outputSchema: def.outputSchema ?? textOutputSchema,
|
|
60
|
+
structured: def.outputSchema !== void 0,
|
|
61
|
+
exposure: "stage"
|
|
62
|
+
};
|
|
63
|
+
return [moduleDescription === void 0 ? tool : {
|
|
64
|
+
...tool,
|
|
65
|
+
namespaceDescription: moduleDescription
|
|
66
|
+
}];
|
|
67
|
+
});
|
|
44
68
|
/** Default inline budget of the nested tool listing, in estimated tokens. */
|
|
45
69
|
const defaultCodeModeInlineBudget = 3e3;
|
|
46
70
|
/** Estimated tokens of a text: four characters per token, rounded up. */
|
|
@@ -76,9 +100,10 @@ const groupByNamespace = (items) => {
|
|
|
76
100
|
};
|
|
77
101
|
/**
|
|
78
102
|
* Chooses the tools the description lists. `all` tools are always placed, outside the budget
|
|
79
|
-
* (the model already has their declarations)
|
|
80
|
-
* across namespaces: each round, every namespace still in play
|
|
81
|
-
* a namespace whose next tool does not fit drops out. `search`
|
|
103
|
+
* (the model already has their declarations), and so are `pinned` tools. `listed` tools fill
|
|
104
|
+
* `budget` estimated tokens fairly across namespaces: each round, every namespace still in play
|
|
105
|
+
* places its cheapest remaining tool; a namespace whose next tool does not fit drops out. `search`
|
|
106
|
+
* tools are never candidates.
|
|
82
107
|
*/
|
|
83
108
|
const selectCodeModeListing = (catalog, budget) => {
|
|
84
109
|
const candidates = catalog.flatMap((tool, index) => tool.exposure === "listed" ? [{
|
|
@@ -87,7 +112,7 @@ const selectCodeModeListing = (catalog, budget) => {
|
|
|
87
112
|
cost: candidateCost(tool)
|
|
88
113
|
}] : []);
|
|
89
114
|
const queues = new Map([...groupByNamespace(candidates)].map(([namespace, group]) => [namespace, [...group].sort((left, right) => left.cost - right.cost || left.index - right.index)]));
|
|
90
|
-
const placed = new Set(catalog.flatMap((tool, index) => tool.exposure === "all" ? [index] : []));
|
|
115
|
+
const placed = new Set(catalog.flatMap((tool, index) => tool.exposure === "all" || tool.exposure === "pinned" ? [index] : []));
|
|
91
116
|
const inPlay = new Set(queues.keys());
|
|
92
117
|
let remaining = budget;
|
|
93
118
|
while (inPlay.size > 0) for (const [namespace, queue] of queues) {
|
|
@@ -112,17 +137,26 @@ const intro = [
|
|
|
112
137
|
"Call tools as `await tools.<id>(args)`. Arguments must be plain JSON (no `NaN`, `undefined` array items, `Map`, or functions). A call resolves to the declared result type and rejects with an Error whose message starts with `tools.<id>:` when the tool fails. Calls still running when the script ends are cancelled, so await every call (use `Promise.all` for parallel calls).",
|
|
113
138
|
"Only the script output and its return value come back to you: filter and aggregate inside the script and return a small JSON value."
|
|
114
139
|
].join("\n");
|
|
115
|
-
const stageLine = (reviewToolName) => `- \`await stage(name, args)\`: record a call of a stageable tool for review instead of running it; resolves to \`{ staged: true, key, index }\`. Nothing runs until a person approves the plan through the \`${reviewToolName}\` tool, which the result tells you how to call. Once a script stages, it may only run read tools; a script that already ran a write tool cannot stage.`;
|
|
140
|
+
const stageLine = (reviewToolName) => `- \`await stage(name, args)\`: record a call of a stageable tool for review instead of running it; resolves to \`{ staged: true, key, index }\`. Nothing runs until a person approves the plan through the \`${reviewToolName}\` tool, which the result tells you how to call. Once a script stages, it may only run read tools; a script that already ran a write tool cannot stage. \`searchTools\` marks approval-gated tools \`stageOnly: true\`: they have no \`tools\` binding, only \`stage()\` them.`;
|
|
116
141
|
/** Stageable tool names listed in the description; the rest are summarized with a count. */
|
|
117
142
|
const maxListedStageableTools = 20;
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
143
|
+
const listedStageableNames = (staging) => ({
|
|
144
|
+
pinned: staging.tools.flatMap(({ def }) => toolDiscovery(def) === "pinned" ? [def.name] : []),
|
|
145
|
+
listed: staging.tools.flatMap(({ def }) => {
|
|
146
|
+
const discovery = toolDiscovery(def);
|
|
147
|
+
return discovery === "search" || discovery === "pinned" ? [] : [def.name];
|
|
148
|
+
})
|
|
149
|
+
});
|
|
150
|
+
const hasStageableNames = (names) => names.pinned.length > 0 || names.listed.length > 0;
|
|
151
|
+
/** `pinned` names are always shown; the cap applies to the others. */
|
|
152
|
+
const stageableSection = (names) => {
|
|
153
|
+
const room = Math.max(0, maxListedStageableTools - names.pinned.length);
|
|
154
|
+
const hidden = names.listed.length - room;
|
|
121
155
|
return [
|
|
122
156
|
"## Stageable tools",
|
|
123
157
|
"Approval-gated tools a script cannot call through `tools`, only stage with `await stage(\"<name>\", args)` (arguments as for the tool of the same name):",
|
|
124
|
-
...names.slice(0,
|
|
125
|
-
...hidden > 0 ? [`- … and ${hidden} more (
|
|
158
|
+
...[...names.pinned, ...names.listed.slice(0, room)].map((name) => `- \`${name}\``),
|
|
159
|
+
...hidden > 0 ? [`- … and ${hidden} more (find them with \`searchTools\`).`] : []
|
|
126
160
|
].join("\n");
|
|
127
161
|
};
|
|
128
162
|
const globalLines = (store) => [
|
|
@@ -157,11 +191,16 @@ const unlistedToolsLine = "More tools may be callable than are listed here: find
|
|
|
157
191
|
* `all` tools get one line each outside the budget; `listed` tools are declared within the inline
|
|
158
192
|
* budget; `search` tools never contribute, so adding or removing them (even whole namespaces of
|
|
159
193
|
* them) leaves the text byte-identical. With `staging` (and stageable tools), `stage()` is listed
|
|
160
|
-
* with the globals and the stageable tool names follow the nested tools
|
|
194
|
+
* with the globals and the stageable tool names follow the nested tools; stage-only `search` tools
|
|
195
|
+
* are never named, so they leave the text byte-identical too once any stageable tool exists.
|
|
161
196
|
*/
|
|
162
197
|
const renderCodeModeDescription = (input) => {
|
|
163
198
|
const sections = [...groupByNamespace(selectCodeModeListing(codeModeCatalog(input.tools), input.inlineBudget ?? 3e3).listed.map((tool) => ({ tool })))].map(([namespace, items]) => namespaceSection(namespace, items.map((item) => item.tool)));
|
|
164
199
|
const staging = input.staging !== void 0 && input.staging.tools.length > 0 ? input.staging : void 0;
|
|
200
|
+
const stageableNames = staging === void 0 ? {
|
|
201
|
+
pinned: [],
|
|
202
|
+
listed: []
|
|
203
|
+
} : listedStageableNames(staging);
|
|
165
204
|
return [
|
|
166
205
|
intro,
|
|
167
206
|
[
|
|
@@ -170,15 +209,125 @@ const renderCodeModeDescription = (input) => {
|
|
|
170
209
|
...staging === void 0 ? [] : [stageLine(staging.reviewToolName)]
|
|
171
210
|
].join("\n"),
|
|
172
211
|
sections.length === 0 ? "Nested tools: none are listed here." : ["## Nested tools by namespace", ...sections].join("\n\n"),
|
|
173
|
-
...
|
|
212
|
+
...hasStageableNames(stageableNames) ? [stageableSection(stageableNames)] : [],
|
|
174
213
|
unlistedToolsLine
|
|
175
214
|
].join("\n\n");
|
|
176
215
|
};
|
|
177
|
-
/**
|
|
178
|
-
|
|
216
|
+
/**
|
|
217
|
+
* `describeTool` text: the description and TypeScript declaration of one tool. A stage-only tool
|
|
218
|
+
* has no `tools` binding, so it is described as the `stage()` call that records it.
|
|
219
|
+
*/
|
|
220
|
+
const describeCodeModeTool = (tool) => tool.exposure === "stage" ? [
|
|
221
|
+
tool.description,
|
|
222
|
+
`Stage-only (approval-gated): record a call with \`await stage(${JSON.stringify(tool.name)}, args)\`; it runs only after a person approves the plan.`,
|
|
223
|
+
`args: ${schemaToType(tool.inputSchema)}`
|
|
224
|
+
].join("\n\n") : renderToolSample(declarationTool(tool));
|
|
179
225
|
/** Finds a tool by identifier or raw name. */
|
|
180
226
|
const findCodeModeTool = (catalog, name) => catalog.find((tool) => tool.identifier === name) ?? catalog.find((tool) => tool.name === name);
|
|
227
|
+
/** The instruction key of the code mode catalog (`catalog: 'instructions'`, ADR 0007). */
|
|
228
|
+
const codeModeCatalogInstructionKey = "yolk.codemode.catalog";
|
|
229
|
+
const CodeModeCatalogNamespace = Schema.Struct({
|
|
230
|
+
name: Schema.String,
|
|
231
|
+
description: Schema.optional(Schema.String),
|
|
232
|
+
/** Every tool scripts reach in the namespace: callable and stage-only. */
|
|
233
|
+
count: Schema.Number,
|
|
234
|
+
/** Tools the listing shows. */
|
|
235
|
+
shown: Schema.Number,
|
|
236
|
+
/** The rendered declarations and direct tool lines of the shown tools. */
|
|
237
|
+
listing: Schema.String
|
|
238
|
+
});
|
|
239
|
+
/** The catalog an instruction message records as its state (JSON, never model-visible). */
|
|
240
|
+
const CodeModeCatalogSummary = Schema.Struct({
|
|
241
|
+
namespaces: Schema.Array(CodeModeCatalogNamespace),
|
|
242
|
+
/** Stageable tool names the catalog lists: `pinned` ones, then `listed` ones (never `search`). */
|
|
243
|
+
stageable: Schema.Struct({
|
|
244
|
+
pinned: Schema.Array(Schema.String),
|
|
245
|
+
listed: Schema.Array(Schema.String)
|
|
246
|
+
})
|
|
247
|
+
});
|
|
248
|
+
const decodeCatalogSummary = Schema.decodeUnknownOption(CodeModeCatalogSummary);
|
|
249
|
+
const encodeCatalogSummary = Schema.encodeOption(CodeModeCatalogSummary);
|
|
250
|
+
const namespaceListing = (tools) => {
|
|
251
|
+
const declared = tools.filter((tool) => tool.exposure !== "all");
|
|
252
|
+
const direct = tools.filter((tool) => tool.exposure === "all");
|
|
253
|
+
return [...declared.length > 0 ? [
|
|
254
|
+
"```ts",
|
|
255
|
+
declarationMembers(declared),
|
|
256
|
+
"```"
|
|
257
|
+
] : [], ...direct.map(directToolLine)].join("\n");
|
|
258
|
+
};
|
|
259
|
+
/**
|
|
260
|
+
* The catalog of one resolution: every namespace with its tool count and description, and the
|
|
261
|
+
* listing of the tools the inline budget (or `pinned`) places. `search` and stage-only tools are
|
|
262
|
+
* counted, never listed.
|
|
263
|
+
*/
|
|
264
|
+
const summarizeCodeModeCatalog = (input) => {
|
|
265
|
+
const catalog = codeModeCatalog(input.tools);
|
|
266
|
+
const stageOnly = input.staging === void 0 ? [] : codeModeStageOnlyCatalog(input.staging.tools);
|
|
267
|
+
const listedByNamespace = groupByNamespace(selectCodeModeListing(catalog, input.inlineBudget ?? 3e3).listed.map((tool) => ({ tool })));
|
|
268
|
+
return {
|
|
269
|
+
namespaces: [...groupByNamespace([...catalog, ...stageOnly].map((tool) => ({ tool })))].map(([name, items]) => {
|
|
270
|
+
const shown = (listedByNamespace.get(name) ?? []).map((item) => item.tool);
|
|
271
|
+
const description = items.find((item) => item.tool.namespaceDescription !== void 0)?.tool.namespaceDescription;
|
|
272
|
+
const namespace = {
|
|
273
|
+
name,
|
|
274
|
+
count: items.length,
|
|
275
|
+
shown: shown.length,
|
|
276
|
+
listing: namespaceListing(shown)
|
|
277
|
+
};
|
|
278
|
+
return description === void 0 ? namespace : {
|
|
279
|
+
...namespace,
|
|
280
|
+
description
|
|
281
|
+
};
|
|
282
|
+
}),
|
|
283
|
+
stageable: input.staging === void 0 ? {
|
|
284
|
+
pinned: [],
|
|
285
|
+
listed: []
|
|
286
|
+
} : listedStageableNames(input.staging)
|
|
287
|
+
};
|
|
288
|
+
};
|
|
289
|
+
const namespaceLine = (namespace) => {
|
|
290
|
+
const count = namespace.count === 1 ? "1 tool" : `${namespace.count} tools`;
|
|
291
|
+
const label = namespace.shown === namespace.count ? count : namespace.shown === 0 ? `${count}, none listed` : `${count}, ${namespace.shown} listed`;
|
|
292
|
+
return `- \`${namespace.name}\` (${label})${namespace.description === void 0 ? "" : `: ${namespace.description}`}`;
|
|
293
|
+
};
|
|
294
|
+
/** The full catalog text of an instruction message. */
|
|
295
|
+
const renderCodeModeCatalog = (summary) => [
|
|
296
|
+
"# Code mode catalog",
|
|
297
|
+
"Tools `codemode` scripts can call, by namespace; the latest catalog in the conversation replaces any earlier one. Call a listed tool as `await tools.<id>(args)`; find the others with `await searchTools(query, { namespace })` and read one with `await describeTool(name)` before calling it.",
|
|
298
|
+
["## Namespaces", ...summary.namespaces.map(namespaceLine)].join("\n"),
|
|
299
|
+
...summary.namespaces.flatMap((namespace) => namespace.listing.length === 0 ? [] : [`### ${namespace.name}\n${namespace.listing}`]),
|
|
300
|
+
...hasStageableNames(summary.stageable) ? [stageableSection(summary.stageable)] : []
|
|
301
|
+
].join("\n\n");
|
|
302
|
+
/**
|
|
303
|
+
* The host instruction of the code mode catalog: its state is the encoded summary, and its render
|
|
304
|
+
* the full catalog (every change renders it whole, see `RunInstruction.render`) or a removal notice.
|
|
305
|
+
*/
|
|
306
|
+
const codeModeCatalogInstruction = (input) => {
|
|
307
|
+
const summary = summarizeCodeModeCatalog(input);
|
|
308
|
+
return {
|
|
309
|
+
key: codeModeCatalogInstructionKey,
|
|
310
|
+
state: summary.namespaces.length === 0 ? void 0 : Option.getOrUndefined(encodeCatalogSummary(summary)),
|
|
311
|
+
render: (current) => {
|
|
312
|
+
const decoded = current === void 0 ? Option.none() : decodeCatalogSummary(current);
|
|
313
|
+
return Option.isNone(decoded) ? "Code mode tools are no longer available: do not call previously listed code mode tools." : renderCodeModeCatalog(decoded.value);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* The code mode description when the catalog is delivered as an instruction: invariant across
|
|
319
|
+
* catalog changes (only staging availability adds the `stage()` line).
|
|
320
|
+
*/
|
|
321
|
+
const renderCodeModeInstructedDescription = (input) => [
|
|
322
|
+
intro,
|
|
323
|
+
[
|
|
324
|
+
"Globals:",
|
|
325
|
+
...globalLines(input.store === true),
|
|
326
|
+
...input.staging === void 0 ? [] : [stageLine(input.staging.reviewToolName)]
|
|
327
|
+
].join("\n"),
|
|
328
|
+
"The tools scripts can call are in the \"Code mode catalog\" (namespaces, tool counts and listed tools; the latest one applies). Find the others with `await searchTools(query, { namespace? })` and read one with `await describeTool(name)` before calling it."
|
|
329
|
+
].join("\n\n");
|
|
181
330
|
//#endregion
|
|
182
|
-
export { codeModeCallLabels, codeModeCatalog, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, renderCodeModeDescription, selectCodeModeListing };
|
|
331
|
+
export { CodeModeCatalogSummary, codeModeCallLabels, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeStageOnlyCatalog, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, selectCodeModeListing, summarizeCodeModeCatalog };
|
|
183
332
|
|
|
184
333
|
//# sourceMappingURL=catalog.mjs.map
|
package/dist/catalog.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.mjs","names":[],"sources":["../src/catalog.ts"],"sourcesContent":["import { Predicate } from 'effect'\nimport {\n renderDeclarations,\n renderToolOutputType,\n renderToolSample,\n toCodemodeIdentifier\n} from '@earendil-works/pi-codemode/declarations'\nimport { toolDiscovery } from '@yolk-sdk/agent/protocol'\nimport type { NestedTool } from '@yolk-sdk/agent/tools'\nimport type { CodeModeJsonSchema } from './executor.ts'\n\n/** How a nested tool reaches scripts: `all` tools are also direct model tools; `listed` and\n * `search` are the two discovery modes of `codemode`-only tools.\n */\nexport type CodeModeToolExposure = 'all' | 'listed' | 'search'\n\n/** One nested tool as scripts see it. */\nexport type CodeModeCatalogTool = {\n /** Raw tool name; scripts may call `tools[\"<name>\"](args)`. */\n readonly name: string\n /** Identifier for `tools.<identifier>(args)` (invalid identifier characters become `_`). */\n readonly identifier: string\n /**\n * How scripts call this tool, used to prefix its rejections: `tools.<identifier>`, or\n * `tools[\"<name>\"]` when an earlier tool already has the identifier (see `codeModeCallLabels`;\n * when the name is taken too, the tool is unreachable and the label only names it).\n */\n readonly callLabel: string\n /** The tool's `ToolModule.id`. */\n readonly namespace: string\n /** The module's `ToolModule.description`, when set. */\n readonly namespaceDescription?: string\n readonly description: string\n readonly inputSchema: CodeModeJsonSchema\n /** The declared output schema, or `{ type: 'string' }` for text results. */\n readonly outputSchema: CodeModeJsonSchema\n /** True when the tool declares an output schema (calls resolve to `structuredContent`). */\n readonly structured: boolean\n readonly exposure: CodeModeToolExposure\n}\n\nconst textOutputSchema: CodeModeJsonSchema = { type: 'string' }\n\n/**\n * The call label of each tool name, in order, as pi binds `tools`: each tool takes\n * `tools[<identifier>]` unless an earlier tool holds that key (first tool wins), then\n * `tools[<name>]` if still free. The label is `tools.<identifier>` for the tool that holds its\n * identifier, otherwise `tools[\"<name>\"]`. The executor guard and the host rejection prefix share\n * it, so both name a call the same way.\n */\nexport const codeModeCallLabels = (names: ReadonlyArray<string>): ReadonlyArray<string> => {\n const bound = new Set<string>()\n\n return names.map(name => {\n const identifier = toCodemodeIdentifier(name)\n const ownsIdentifier = !bound.has(identifier)\n\n bound.add(identifier)\n bound.add(name)\n\n return ownsIdentifier ? `tools.${identifier}` : `tools[${JSON.stringify(name)}]`\n })\n}\n\n/** Catalog of nested tools in resolution order. */\nexport const codeModeCatalog = (\n tools: ReadonlyArray<NestedTool>\n): ReadonlyArray<CodeModeCatalogTool> => {\n const labels = codeModeCallLabels(tools.map(({ def }) => def.name))\n\n return tools.map(({ def, moduleId, moduleDescription }, index) => {\n const tool: CodeModeCatalogTool = {\n name: def.name,\n identifier: toCodemodeIdentifier(def.name),\n callLabel: labels[index] ?? `tools[${JSON.stringify(def.name)}]`,\n namespace: moduleId,\n description: def.description,\n inputSchema: def.parameters,\n outputSchema: def.outputSchema ?? textOutputSchema,\n structured: def.outputSchema !== undefined,\n exposure: toolDiscovery(def) ?? 'all'\n }\n\n return moduleDescription === undefined\n ? tool\n : { ...tool, namespaceDescription: moduleDescription }\n })\n}\n\n/** Default inline budget of the nested tool listing, in estimated tokens. */\nexport const defaultCodeModeInlineBudget = 3000\n\n/** Estimated tokens of a text: four characters per token, rounded up. */\nexport const estimateCodeModeTokens = (text: string): number => Math.ceil(text.length / 4)\n\nconst maxShortTypeChars = 60\n\nconst shortType = (schema: CodeModeJsonSchema): string => {\n const rendered = renderToolOutputType(schema)\n\n if (rendered.length <= maxShortTypeChars) return rendered\n\n if (!Predicate.isBoolean(schema)) {\n if (schema.type === 'array') return 'Array<unknown>'\n\n if (schema.type === 'object') return 'object'\n }\n\n return 'unknown'\n}\n\n// Declarations only read names, descriptions, and schemas; `execute` is never called.\nconst declarationTool = (tool: CodeModeCatalogTool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n execute: () => undefined\n})\n\nconst directToolLine = (tool: CodeModeCatalogTool) =>\n `- \\`tools.${tool.identifier}(args)\\` takes the arguments of the \\`${tool.name}\\` tool and resolves to \\`${shortType(tool.outputSchema)}\\`.`\n\nconst declarationMembers = (tools: ReadonlyArray<CodeModeCatalogTool>) =>\n renderDeclarations({ tools: tools.map(declarationTool) })\n\ntype Candidate = {\n readonly tool: CodeModeCatalogTool\n readonly index: number\n readonly cost: number\n}\n\nconst candidateCost = (tool: CodeModeCatalogTool) =>\n estimateCodeModeTokens(declarationMembers([tool]))\n\nconst groupByNamespace = <A extends { readonly tool: CodeModeCatalogTool }>(\n items: ReadonlyArray<A>\n): ReadonlyMap<string, ReadonlyArray<A>> => {\n const groups = new Map<string, Array<A>>()\n\n for (const item of items) {\n const group = groups.get(item.tool.namespace)\n\n if (group === undefined) {\n groups.set(item.tool.namespace, [item])\n } else {\n group.push(item)\n }\n }\n\n return groups\n}\n\nexport type CodeModeListing = {\n /** Tools placed in the description, in catalog order: every `all` tool, and the `listed` tools\n * that fit the budget.\n */\n readonly listed: ReadonlyArray<CodeModeCatalogTool>\n /** Namespaces (catalog order) with callable tools the description does not list. */\n readonly unlistedNamespaces: ReadonlyArray<string>\n}\n\n/**\n * Chooses the tools the description lists. `all` tools are always placed, outside the budget\n * (the model already has their declarations). `listed` tools fill `budget` estimated tokens fairly\n * across namespaces: each round, every namespace still in play places its cheapest remaining tool;\n * a namespace whose next tool does not fit drops out. `search` tools are never candidates.\n */\nexport const selectCodeModeListing = (\n catalog: ReadonlyArray<CodeModeCatalogTool>,\n budget: number\n): CodeModeListing => {\n const candidates = catalog.flatMap((tool, index): ReadonlyArray<Candidate> =>\n tool.exposure === 'listed' ? [{ tool, index, cost: candidateCost(tool) }] : []\n )\n\n const queues = new Map(\n [...groupByNamespace(candidates)].map(([namespace, group]) => [\n namespace,\n [...group].sort((left, right) => left.cost - right.cost || left.index - right.index)\n ])\n )\n\n const placed = new Set(catalog.flatMap((tool, index) => (tool.exposure === 'all' ? [index] : [])))\n\n const inPlay = new Set(queues.keys())\n let remaining = budget\n\n while (inPlay.size > 0) {\n for (const [namespace, queue] of queues) {\n if (!inPlay.has(namespace)) continue\n\n const next = queue.shift()\n\n if (next === undefined || next.cost > remaining) {\n inPlay.delete(namespace)\n continue\n }\n\n placed.add(next.index)\n remaining -= next.cost\n }\n }\n\n const unlisted = new Set(\n catalog.flatMap((tool, index) => (placed.has(index) ? [] : [tool.namespace]))\n )\n\n return {\n listed: catalog.filter((_, index) => placed.has(index)),\n unlistedNamespaces: [...new Set(catalog.map(tool => tool.namespace))].filter(namespace =>\n unlisted.has(namespace)\n )\n }\n}\n\nconst intro = [\n 'Run a JavaScript script that calls tools and returns only what matters.',\n '`code` is the body of an async function: top-level `await` and `return` work. Write plain JavaScript; simple TypeScript annotations are stripped. There is no Node.js, network, filesystem, `require`, `fetch`, or timers.',\n 'Call tools as `await tools.<id>(args)`. Arguments must be plain JSON (no `NaN`, `undefined` array items, `Map`, or functions). A call resolves to the declared result type and rejects with an Error whose message starts with `tools.<id>:` when the tool fails. Calls still running when the script ends are cancelled, so await every call (use `Promise.all` for parallel calls).',\n 'Only the script output and its return value come back to you: filter and aggregate inside the script and return a small JSON value.'\n].join('\\n')\n\nconst stageLine = (reviewToolName: string) =>\n `- \\`await stage(name, args)\\`: record a call of a stageable tool for review instead of running it; resolves to \\`{ staged: true, key, index }\\`. Nothing runs until a person approves the plan through the \\`${reviewToolName}\\` tool, which the result tells you how to call. Once a script stages, it may only run read tools; a script that already ran a write tool cannot stage.`\n\n/** Stageable tool names listed in the description; the rest are summarized with a count. */\nconst maxListedStageableTools = 20\n\nconst stageableSection = (staging: CodeModeStagingDescription) => {\n const names = staging.tools.map(tool => tool.def.name)\n const hidden = names.length - maxListedStageableTools\n\n return [\n '## Stageable tools',\n 'Approval-gated tools a script cannot call through `tools`, only stage with `await stage(\"<name>\", args)` (arguments as for the tool of the same name):',\n ...names.slice(0, maxListedStageableTools).map(name => `- \\`${name}\\``),\n ...(hidden > 0\n ? [`- … and ${hidden} more (an unknown name rejects with the stageable tools).`]\n : [])\n ].join('\\n')\n}\n\nconst globalLines = (store: boolean) => [\n '- `text(value)` and `console.log(...values)`: append text to the output.',\n '- `image(dataUrl)`: append a base64 image (a `data:` URL or `{ type: \"image\", data, mimeType }`).',\n '- `exit()`: end the script successfully.',\n '- `ALL_TOOLS`: `{ name, description }` of every callable tool.',\n '- `await searchTools(query, { limit?, namespace? })`: find tools by topic; resolves to `Array<{ name: string; description: string }>` (default limit 8).',\n '- `await describeTool(name)`: the description and TypeScript declaration of a tool, or `undefined`.',\n '- `await describeNamespace(name)`: `{ name, description?, tools: Array<{ name, description }> }` for a namespace, or `undefined`.',\n ...(store\n ? [\n '- `store(key, value)` and `load(key)`: keep small JSON values for later scripts; writes are saved only when the script succeeds.'\n ]\n : [])\n]\n\nconst namespaceSection = (namespace: string, tools: ReadonlyArray<CodeModeCatalogTool>) => {\n const declared = tools.filter(tool => tool.exposure !== 'all')\n const direct = tools.filter(tool => tool.exposure === 'all')\n\n const description = tools.find(\n tool => tool.namespaceDescription !== undefined\n )?.namespaceDescription\n\n return [\n `### ${namespace}`,\n ...(description === undefined ? [] : [description]),\n ...(declared.length > 0 ? ['```ts', declarationMembers(declared), '```'] : []),\n ...direct.map(directToolLine)\n ].join('\\n')\n}\n\n// Fixed text: never derived from `search` tools or from which tools did not fit the budget.\nconst unlistedToolsLine =\n 'More tools may be callable than are listed here: find them with `await searchTools(query, { namespace? })` and read one with `await describeTool(name)` or `await describeNamespace(name)` before calling it.'\n\n/** Staged tool plans as the description shows them (`NestedToolStagingDescription`). */\nexport type CodeModeStagingDescription = {\n readonly tools: ReadonlyArray<NestedTool>\n readonly reviewToolName: string\n}\n\nexport type CodeModeDescriptionInput = {\n readonly tools: ReadonlyArray<NestedTool>\n readonly inlineBudget?: number\n /** Mention `store()`/`load()` persistence. */\n readonly store?: boolean\n /** Document `stage()` and list the stageable tools (only when some exist). */\n readonly staging?: CodeModeStagingDescription\n}\n\n/**\n * The code mode tool description: intro, globals one per line, then nested tools grouped by\n * namespace, then one fixed line pointing to `searchTools`/`describeTool`/`describeNamespace`.\n * `all` tools get one line each outside the budget; `listed` tools are declared within the inline\n * budget; `search` tools never contribute, so adding or removing them (even whole namespaces of\n * them) leaves the text byte-identical. With `staging` (and stageable tools), `stage()` is listed\n * with the globals and the stageable tool names follow the nested tools.\n */\nexport const renderCodeModeDescription = (input: CodeModeDescriptionInput): string => {\n const catalog = codeModeCatalog(input.tools)\n\n const listing = selectCodeModeListing(catalog, input.inlineBudget ?? defaultCodeModeInlineBudget)\n\n const sections = [...groupByNamespace(listing.listed.map(tool => ({ tool })))].map(\n ([namespace, items]) =>\n namespaceSection(\n namespace,\n items.map(item => item.tool)\n )\n )\n\n const staging =\n input.staging !== undefined && input.staging.tools.length > 0 ? input.staging : undefined\n\n return [\n intro,\n [\n 'Globals:',\n ...globalLines(input.store === true),\n ...(staging === undefined ? [] : [stageLine(staging.reviewToolName)])\n ].join('\\n'),\n sections.length === 0\n ? 'Nested tools: none are listed here.'\n : ['## Nested tools by namespace', ...sections].join('\\n\\n'),\n ...(staging === undefined ? [] : [stageableSection(staging)]),\n unlistedToolsLine\n ].join('\\n\\n')\n}\n\n/** `describeTool` text: the description and TypeScript declaration of one tool. */\nexport const describeCodeModeTool = (tool: CodeModeCatalogTool): string =>\n renderToolSample(declarationTool(tool))\n\n/** Finds a tool by identifier or raw name. */\nexport const findCodeModeTool = (\n catalog: ReadonlyArray<CodeModeCatalogTool>,\n name: string\n): CodeModeCatalogTool | undefined =>\n catalog.find(tool => tool.identifier === name) ?? catalog.find(tool => tool.name === name)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"catalog.mjs","names":[],"sources":["../src/catalog.ts"],"sourcesContent":["import { Option, Predicate } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport {\n renderDeclarations,\n renderToolOutputType,\n renderToolSample,\n schemaToType,\n toCodemodeIdentifier\n} from '@earendil-works/pi-codemode/declarations'\nimport { isDeferredTool, toolDiscovery } from '@yolk-sdk/agent/protocol'\nimport type { RunInstruction } from '@yolk-sdk/agent/loop'\nimport type { NestedTool } from '@yolk-sdk/agent/tools'\nimport type { CodeModeJsonSchema } from './executor.ts'\n\n/** How a nested tool reaches scripts: `all` tools are also direct model tools; `listed` and\n * `search` are the two discovery modes of `codemode`-only tools; `stage` marks a stage-only tool\n * (ADR 0007): found by search, never callable, only passed to `stage()`.\n */\nexport type CodeModeToolExposure = 'all' | 'listed' | 'search' | 'pinned' | 'stage'\n\n/** One nested tool as scripts see it. */\nexport type CodeModeCatalogTool = {\n /** Raw tool name; scripts may call `tools[\"<name>\"](args)`. */\n readonly name: string\n /** Identifier for `tools.<identifier>(args)` (invalid identifier characters become `_`). */\n readonly identifier: string\n /**\n * How scripts call this tool, used to prefix its rejections: `tools.<identifier>`, or\n * `tools[\"<name>\"]` when an earlier tool already has the identifier (see `codeModeCallLabels`;\n * when the name is taken too, the tool is unreachable and the label only names it).\n */\n readonly callLabel: string\n /** The tool's `ToolModule.id`. */\n readonly namespace: string\n /** The module's `ToolModule.description`, when set. */\n readonly namespaceDescription?: string\n readonly description: string\n readonly inputSchema: CodeModeJsonSchema\n /** The declared output schema, or `{ type: 'string' }` for text results. */\n readonly outputSchema: CodeModeJsonSchema\n /** True when the tool declares an output schema (calls resolve to `structuredContent`). */\n readonly structured: boolean\n readonly exposure: CodeModeToolExposure\n}\n\nconst textOutputSchema: CodeModeJsonSchema = { type: 'string' }\n\n/**\n * The call label of each tool name, in order, as pi binds `tools`: each tool takes\n * `tools[<identifier>]` unless an earlier tool holds that key (first tool wins), then\n * `tools[<name>]` if still free. The label is `tools.<identifier>` for the tool that holds its\n * identifier, otherwise `tools[\"<name>\"]`. The executor guard and the host rejection prefix share\n * it, so both name a call the same way.\n */\nexport const codeModeCallLabels = (names: ReadonlyArray<string>): ReadonlyArray<string> => {\n const bound = new Set<string>()\n\n return names.map(name => {\n const identifier = toCodemodeIdentifier(name)\n const ownsIdentifier = !bound.has(identifier)\n\n bound.add(identifier)\n bound.add(name)\n\n return ownsIdentifier ? `tools.${identifier}` : `tools[${JSON.stringify(name)}]`\n })\n}\n\n/** Catalog of nested tools in resolution order. */\nexport const codeModeCatalog = (\n tools: ReadonlyArray<NestedTool>\n): ReadonlyArray<CodeModeCatalogTool> => {\n const labels = codeModeCallLabels(tools.map(({ def }) => def.name))\n\n return tools.map(({ def, moduleId, moduleDescription }, index) => {\n const tool: CodeModeCatalogTool = {\n name: def.name,\n identifier: toCodemodeIdentifier(def.name),\n callLabel: labels[index] ?? `tools[${JSON.stringify(def.name)}]`,\n namespace: moduleId,\n description: def.description,\n inputSchema: def.parameters,\n outputSchema: def.outputSchema ?? textOutputSchema,\n structured: def.outputSchema !== undefined,\n // A deferred tool's declaration is not in model context until activated: scripts find it\n // by search like a codemode-only `search` tool (ADR 0007).\n exposure: toolDiscovery(def) ?? (isDeferredTool(def) ? 'search' : 'all')\n }\n\n return moduleDescription === undefined\n ? tool\n : { ...tool, namespaceDescription: moduleDescription }\n })\n}\n\n/**\n * Catalog entries of the stage-only tools among the stageable ones (`callableBy: 'codemode'`,\n * ADR 0007): searchable and describable, never callable (no `tools` binding), so their call label\n * is the `stage()` call that records them.\n */\nexport const codeModeStageOnlyCatalog = (\n stageable: ReadonlyArray<NestedTool>\n): ReadonlyArray<CodeModeCatalogTool> =>\n stageable.flatMap(({ def, moduleId, moduleDescription }) => {\n if (def.callableBy !== 'codemode') return []\n\n const tool: CodeModeCatalogTool = {\n name: def.name,\n identifier: toCodemodeIdentifier(def.name),\n callLabel: `stage(${JSON.stringify(def.name)})`,\n namespace: moduleId,\n description: def.description,\n inputSchema: def.parameters,\n outputSchema: def.outputSchema ?? textOutputSchema,\n structured: def.outputSchema !== undefined,\n exposure: 'stage'\n }\n\n return [\n moduleDescription === undefined ? tool : { ...tool, namespaceDescription: moduleDescription }\n ]\n })\n\n/** Default inline budget of the nested tool listing, in estimated tokens. */\nexport const defaultCodeModeInlineBudget = 3000\n\n/** Estimated tokens of a text: four characters per token, rounded up. */\nexport const estimateCodeModeTokens = (text: string): number => Math.ceil(text.length / 4)\n\nconst maxShortTypeChars = 60\n\nconst shortType = (schema: CodeModeJsonSchema): string => {\n const rendered = renderToolOutputType(schema)\n\n if (rendered.length <= maxShortTypeChars) return rendered\n\n if (!Predicate.isBoolean(schema)) {\n if (schema.type === 'array') return 'Array<unknown>'\n\n if (schema.type === 'object') return 'object'\n }\n\n return 'unknown'\n}\n\n// Declarations only read names, descriptions, and schemas; `execute` is never called.\nconst declarationTool = (tool: CodeModeCatalogTool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n execute: () => undefined\n})\n\nconst directToolLine = (tool: CodeModeCatalogTool) =>\n `- \\`tools.${tool.identifier}(args)\\` takes the arguments of the \\`${tool.name}\\` tool and resolves to \\`${shortType(tool.outputSchema)}\\`.`\n\nconst declarationMembers = (tools: ReadonlyArray<CodeModeCatalogTool>) =>\n renderDeclarations({ tools: tools.map(declarationTool) })\n\ntype Candidate = {\n readonly tool: CodeModeCatalogTool\n readonly index: number\n readonly cost: number\n}\n\nconst candidateCost = (tool: CodeModeCatalogTool) =>\n estimateCodeModeTokens(declarationMembers([tool]))\n\nconst groupByNamespace = <A extends { readonly tool: CodeModeCatalogTool }>(\n items: ReadonlyArray<A>\n): ReadonlyMap<string, ReadonlyArray<A>> => {\n const groups = new Map<string, Array<A>>()\n\n for (const item of items) {\n const group = groups.get(item.tool.namespace)\n\n if (group === undefined) {\n groups.set(item.tool.namespace, [item])\n } else {\n group.push(item)\n }\n }\n\n return groups\n}\n\nexport type CodeModeListing = {\n /** Tools placed in the description, in catalog order: every `all` tool, and the `listed` tools\n * that fit the budget.\n */\n readonly listed: ReadonlyArray<CodeModeCatalogTool>\n /** Namespaces (catalog order) with callable tools the description does not list. */\n readonly unlistedNamespaces: ReadonlyArray<string>\n}\n\n/**\n * Chooses the tools the description lists. `all` tools are always placed, outside the budget\n * (the model already has their declarations), and so are `pinned` tools. `listed` tools fill\n * `budget` estimated tokens fairly across namespaces: each round, every namespace still in play\n * places its cheapest remaining tool; a namespace whose next tool does not fit drops out. `search`\n * tools are never candidates.\n */\nexport const selectCodeModeListing = (\n catalog: ReadonlyArray<CodeModeCatalogTool>,\n budget: number\n): CodeModeListing => {\n const candidates = catalog.flatMap((tool, index): ReadonlyArray<Candidate> =>\n tool.exposure === 'listed' ? [{ tool, index, cost: candidateCost(tool) }] : []\n )\n\n const queues = new Map(\n [...groupByNamespace(candidates)].map(([namespace, group]) => [\n namespace,\n [...group].sort((left, right) => left.cost - right.cost || left.index - right.index)\n ])\n )\n\n const placed = new Set(\n catalog.flatMap((tool, index) =>\n tool.exposure === 'all' || tool.exposure === 'pinned' ? [index] : []\n )\n )\n\n const inPlay = new Set(queues.keys())\n let remaining = budget\n\n while (inPlay.size > 0) {\n for (const [namespace, queue] of queues) {\n if (!inPlay.has(namespace)) continue\n\n const next = queue.shift()\n\n if (next === undefined || next.cost > remaining) {\n inPlay.delete(namespace)\n continue\n }\n\n placed.add(next.index)\n remaining -= next.cost\n }\n }\n\n const unlisted = new Set(\n catalog.flatMap((tool, index) => (placed.has(index) ? [] : [tool.namespace]))\n )\n\n return {\n listed: catalog.filter((_, index) => placed.has(index)),\n unlistedNamespaces: [...new Set(catalog.map(tool => tool.namespace))].filter(namespace =>\n unlisted.has(namespace)\n )\n }\n}\n\nconst intro = [\n 'Run a JavaScript script that calls tools and returns only what matters.',\n '`code` is the body of an async function: top-level `await` and `return` work. Write plain JavaScript; simple TypeScript annotations are stripped. There is no Node.js, network, filesystem, `require`, `fetch`, or timers.',\n 'Call tools as `await tools.<id>(args)`. Arguments must be plain JSON (no `NaN`, `undefined` array items, `Map`, or functions). A call resolves to the declared result type and rejects with an Error whose message starts with `tools.<id>:` when the tool fails. Calls still running when the script ends are cancelled, so await every call (use `Promise.all` for parallel calls).',\n 'Only the script output and its return value come back to you: filter and aggregate inside the script and return a small JSON value.'\n].join('\\n')\n\nconst stageLine = (reviewToolName: string) =>\n `- \\`await stage(name, args)\\`: record a call of a stageable tool for review instead of running it; resolves to \\`{ staged: true, key, index }\\`. Nothing runs until a person approves the plan through the \\`${reviewToolName}\\` tool, which the result tells you how to call. Once a script stages, it may only run read tools; a script that already ran a write tool cannot stage. \\`searchTools\\` marks approval-gated tools \\`stageOnly: true\\`: they have no \\`tools\\` binding, only \\`stage()\\` them.`\n\n/** Stageable tool names listed in the description; the rest are summarized with a count. */\nconst maxListedStageableTools = 20\n\n/** Stageable tools the description names: `pinned` ones first, never stage-only `search` ones. */\ntype StageableNames = {\n readonly pinned: ReadonlyArray<string>\n readonly listed: ReadonlyArray<string>\n}\n\nconst listedStageableNames = (staging: CodeModeStagingDescription): StageableNames => ({\n pinned: staging.tools.flatMap(({ def }) => (toolDiscovery(def) === 'pinned' ? [def.name] : [])),\n listed: staging.tools.flatMap(({ def }) => {\n const discovery = toolDiscovery(def)\n\n return discovery === 'search' || discovery === 'pinned' ? [] : [def.name]\n })\n})\n\nconst hasStageableNames = (names: StageableNames) =>\n names.pinned.length > 0 || names.listed.length > 0\n\n/** `pinned` names are always shown; the cap applies to the others. */\nconst stageableSection = (names: StageableNames) => {\n const room = Math.max(0, maxListedStageableTools - names.pinned.length)\n const hidden = names.listed.length - room\n\n return [\n '## Stageable tools',\n 'Approval-gated tools a script cannot call through `tools`, only stage with `await stage(\"<name>\", args)` (arguments as for the tool of the same name):',\n ...[...names.pinned, ...names.listed.slice(0, room)].map(name => `- \\`${name}\\``),\n ...(hidden > 0 ? [`- … and ${hidden} more (find them with \\`searchTools\\`).`] : [])\n ].join('\\n')\n}\n\nconst globalLines = (store: boolean) => [\n '- `text(value)` and `console.log(...values)`: append text to the output.',\n '- `image(dataUrl)`: append a base64 image (a `data:` URL or `{ type: \"image\", data, mimeType }`).',\n '- `exit()`: end the script successfully.',\n '- `ALL_TOOLS`: `{ name, description }` of every callable tool.',\n '- `await searchTools(query, { limit?, namespace? })`: find tools by topic; resolves to `Array<{ name: string; description: string }>` (default limit 8).',\n '- `await describeTool(name)`: the description and TypeScript declaration of a tool, or `undefined`.',\n '- `await describeNamespace(name)`: `{ name, description?, tools: Array<{ name, description }> }` for a namespace, or `undefined`.',\n ...(store\n ? [\n '- `store(key, value)` and `load(key)`: keep small JSON values for later scripts; writes are saved only when the script succeeds.'\n ]\n : [])\n]\n\nconst namespaceSection = (namespace: string, tools: ReadonlyArray<CodeModeCatalogTool>) => {\n const declared = tools.filter(tool => tool.exposure !== 'all')\n const direct = tools.filter(tool => tool.exposure === 'all')\n\n const description = tools.find(\n tool => tool.namespaceDescription !== undefined\n )?.namespaceDescription\n\n return [\n `### ${namespace}`,\n ...(description === undefined ? [] : [description]),\n ...(declared.length > 0 ? ['```ts', declarationMembers(declared), '```'] : []),\n ...direct.map(directToolLine)\n ].join('\\n')\n}\n\n// Fixed text: never derived from `search` tools or from which tools did not fit the budget.\nconst unlistedToolsLine =\n 'More tools may be callable than are listed here: find them with `await searchTools(query, { namespace? })` and read one with `await describeTool(name)` or `await describeNamespace(name)` before calling it.'\n\n/** Staged tool plans as the description shows them (`NestedToolStagingDescription`). */\nexport type CodeModeStagingDescription = {\n readonly tools: ReadonlyArray<NestedTool>\n readonly reviewToolName: string\n}\n\nexport type CodeModeDescriptionInput = {\n readonly tools: ReadonlyArray<NestedTool>\n readonly inlineBudget?: number\n /** Mention `store()`/`load()` persistence. */\n readonly store?: boolean\n /** Document `stage()` and list the stageable tools that are not stage-only `search` tools. */\n readonly staging?: CodeModeStagingDescription\n}\n\n/**\n * The code mode tool description: intro, globals one per line, then nested tools grouped by\n * namespace, then one fixed line pointing to `searchTools`/`describeTool`/`describeNamespace`.\n * `all` tools get one line each outside the budget; `listed` tools are declared within the inline\n * budget; `search` tools never contribute, so adding or removing them (even whole namespaces of\n * them) leaves the text byte-identical. With `staging` (and stageable tools), `stage()` is listed\n * with the globals and the stageable tool names follow the nested tools; stage-only `search` tools\n * are never named, so they leave the text byte-identical too once any stageable tool exists.\n */\nexport const renderCodeModeDescription = (input: CodeModeDescriptionInput): string => {\n const catalog = codeModeCatalog(input.tools)\n\n const listing = selectCodeModeListing(catalog, input.inlineBudget ?? defaultCodeModeInlineBudget)\n\n const sections = [...groupByNamespace(listing.listed.map(tool => ({ tool })))].map(\n ([namespace, items]) =>\n namespaceSection(\n namespace,\n items.map(item => item.tool)\n )\n )\n\n const staging =\n input.staging !== undefined && input.staging.tools.length > 0 ? input.staging : undefined\n\n const stageableNames =\n staging === undefined ? { pinned: [], listed: [] } : listedStageableNames(staging)\n\n return [\n intro,\n [\n 'Globals:',\n ...globalLines(input.store === true),\n ...(staging === undefined ? [] : [stageLine(staging.reviewToolName)])\n ].join('\\n'),\n sections.length === 0\n ? 'Nested tools: none are listed here.'\n : ['## Nested tools by namespace', ...sections].join('\\n\\n'),\n ...(hasStageableNames(stageableNames) ? [stageableSection(stageableNames)] : []),\n unlistedToolsLine\n ].join('\\n\\n')\n}\n\n/**\n * `describeTool` text: the description and TypeScript declaration of one tool. A stage-only tool\n * has no `tools` binding, so it is described as the `stage()` call that records it.\n */\nexport const describeCodeModeTool = (tool: CodeModeCatalogTool): string =>\n tool.exposure === 'stage'\n ? [\n tool.description,\n `Stage-only (approval-gated): record a call with \\`await stage(${JSON.stringify(tool.name)}, args)\\`; it runs only after a person approves the plan.`,\n `args: ${schemaToType(tool.inputSchema)}`\n ].join('\\n\\n')\n : renderToolSample(declarationTool(tool))\n\n/** Finds a tool by identifier or raw name. */\nexport const findCodeModeTool = (\n catalog: ReadonlyArray<CodeModeCatalogTool>,\n name: string\n): CodeModeCatalogTool | undefined =>\n catalog.find(tool => tool.identifier === name) ?? catalog.find(tool => tool.name === name)\n\n/** The instruction key of the code mode catalog (`catalog: 'instructions'`, ADR 0007). */\nexport const codeModeCatalogInstructionKey = 'yolk.codemode.catalog'\n\nconst CodeModeCatalogNamespace = Schema.Struct({\n name: Schema.String,\n description: Schema.optional(Schema.String),\n /** Every tool scripts reach in the namespace: callable and stage-only. */\n count: Schema.Number,\n /** Tools the listing shows. */\n shown: Schema.Number,\n /** The rendered declarations and direct tool lines of the shown tools. */\n listing: Schema.String\n})\n\n/** The catalog an instruction message records as its state (JSON, never model-visible). */\nexport const CodeModeCatalogSummary = Schema.Struct({\n namespaces: Schema.Array(CodeModeCatalogNamespace),\n /** Stageable tool names the catalog lists: `pinned` ones, then `listed` ones (never `search`). */\n stageable: Schema.Struct({\n pinned: Schema.Array(Schema.String),\n listed: Schema.Array(Schema.String)\n })\n})\n\nexport type CodeModeCatalogSummary = typeof CodeModeCatalogSummary.Type\n\nconst decodeCatalogSummary = Schema.decodeUnknownOption(CodeModeCatalogSummary)\n\nconst encodeCatalogSummary = Schema.encodeOption(CodeModeCatalogSummary)\n\nconst namespaceListing = (tools: ReadonlyArray<CodeModeCatalogTool>) => {\n const declared = tools.filter(tool => tool.exposure !== 'all')\n const direct = tools.filter(tool => tool.exposure === 'all')\n\n return [\n ...(declared.length > 0 ? ['```ts', declarationMembers(declared), '```'] : []),\n ...direct.map(directToolLine)\n ].join('\\n')\n}\n\n/**\n * The catalog of one resolution: every namespace with its tool count and description, and the\n * listing of the tools the inline budget (or `pinned`) places. `search` and stage-only tools are\n * counted, never listed.\n */\nexport const summarizeCodeModeCatalog = (input: {\n readonly tools: ReadonlyArray<NestedTool>\n readonly staging?: CodeModeStagingDescription\n readonly inlineBudget?: number\n}): CodeModeCatalogSummary => {\n const catalog = codeModeCatalog(input.tools)\n const stageOnly = input.staging === undefined ? [] : codeModeStageOnlyCatalog(input.staging.tools)\n const listing = selectCodeModeListing(catalog, input.inlineBudget ?? defaultCodeModeInlineBudget)\n const listedByNamespace = groupByNamespace(listing.listed.map(tool => ({ tool })))\n\n const namespaces = [...groupByNamespace([...catalog, ...stageOnly].map(tool => ({ tool })))].map(\n ([name, items]) => {\n const shown = (listedByNamespace.get(name) ?? []).map(item => item.tool)\n\n const description = items.find(item => item.tool.namespaceDescription !== undefined)?.tool\n .namespaceDescription\n\n const namespace = {\n name,\n count: items.length,\n shown: shown.length,\n listing: namespaceListing(shown)\n }\n\n return description === undefined ? namespace : { ...namespace, description }\n }\n )\n\n return {\n namespaces,\n stageable:\n input.staging === undefined ? { pinned: [], listed: [] } : listedStageableNames(input.staging)\n }\n}\n\nconst namespaceLine = (namespace: CodeModeCatalogSummary['namespaces'][number]) => {\n const count = namespace.count === 1 ? '1 tool' : `${namespace.count} tools`\n\n const label =\n namespace.shown === namespace.count\n ? count\n : namespace.shown === 0\n ? `${count}, none listed`\n : `${count}, ${namespace.shown} listed`\n\n return `- \\`${namespace.name}\\` (${label})${namespace.description === undefined ? '' : `: ${namespace.description}`}`\n}\n\n/** The full catalog text of an instruction message. */\nexport const renderCodeModeCatalog = (summary: CodeModeCatalogSummary): string =>\n [\n '# Code mode catalog',\n 'Tools `codemode` scripts can call, by namespace; the latest catalog in the conversation replaces any earlier one. Call a listed tool as `await tools.<id>(args)`; find the others with `await searchTools(query, { namespace })` and read one with `await describeTool(name)` before calling it.',\n ['## Namespaces', ...summary.namespaces.map(namespaceLine)].join('\\n'),\n ...summary.namespaces.flatMap(namespace =>\n namespace.listing.length === 0 ? [] : [`### ${namespace.name}\\n${namespace.listing}`]\n ),\n ...(hasStageableNames(summary.stageable) ? [stageableSection(summary.stageable)] : [])\n ].join('\\n\\n')\n\n/**\n * The host instruction of the code mode catalog: its state is the encoded summary, and its render\n * the full catalog (every change renders it whole, see `RunInstruction.render`) or a removal notice.\n */\nexport const codeModeCatalogInstruction = (input: {\n readonly tools: ReadonlyArray<NestedTool>\n readonly staging?: CodeModeStagingDescription\n readonly inlineBudget?: number\n}): RunInstruction => {\n const summary = summarizeCodeModeCatalog(input)\n\n return {\n key: codeModeCatalogInstructionKey,\n state:\n summary.namespaces.length === 0\n ? undefined\n : Option.getOrUndefined(encodeCatalogSummary(summary)),\n render: current => {\n const decoded = current === undefined ? Option.none() : decodeCatalogSummary(current)\n\n return Option.isNone(decoded)\n ? 'Code mode tools are no longer available: do not call previously listed code mode tools.'\n : renderCodeModeCatalog(decoded.value)\n }\n }\n}\n\n/**\n * The code mode description when the catalog is delivered as an instruction: invariant across\n * catalog changes (only staging availability adds the `stage()` line).\n */\nexport const renderCodeModeInstructedDescription = (input: {\n readonly store?: boolean\n readonly staging?: CodeModeStagingDescription\n}): string =>\n [\n intro,\n [\n 'Globals:',\n ...globalLines(input.store === true),\n ...(input.staging === undefined ? [] : [stageLine(input.staging.reviewToolName)])\n ].join('\\n'),\n 'The tools scripts can call are in the \"Code mode catalog\" (namespaces, tool counts and listed tools; the latest one applies). Find the others with `await searchTools(query, { namespace? })` and read one with `await describeTool(name)` before calling it.'\n ].join('\\n\\n')\n"],"mappings":"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"}
|
package/dist/classifier-tool.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect, Predicate, Semaphore } from "effect";
|
|
2
|
-
import { AgentInputUsage, AgentOutputUsage, AgentUsage, ToolResult } from "@yolk-sdk/agent/protocol";
|
|
3
2
|
import * as Schema from "effect/Schema";
|
|
3
|
+
import { AgentInputUsage, AgentOutputUsage, AgentUsage, ToolResult } from "@yolk-sdk/agent/protocol";
|
|
4
4
|
import { ClassificationResult, ClassifierQuestions, ClassifierState } from "@yolk-sdk/agent/classification";
|
|
5
5
|
import { makeTool, modelVisibleToolError, modelVisibleToolErrorStructuredContent } from "@yolk-sdk/agent/tools";
|
|
6
6
|
//#region src/classifier-tool.ts
|
package/dist/executor.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ToolJsonSchema } from "@yolk-sdk/agent/protocol";
|
|
2
1
|
import * as Schema from "effect/Schema";
|
|
2
|
+
import { ToolJsonSchema } from "@yolk-sdk/agent/protocol";
|
|
3
3
|
|
|
4
4
|
//#region src/executor.d.ts
|
|
5
5
|
/** A JSON Schema document. Only shapes declarations; values are never validated against it. */
|
|
@@ -88,6 +88,15 @@ type CodeModeExecuteOptions = {
|
|
|
88
88
|
readonly memoryLimitBytes: number; /** Values the script reads with `load(key)`. */
|
|
89
89
|
readonly store: CodeModeStore;
|
|
90
90
|
readonly signal: AbortSignal;
|
|
91
|
+
/**
|
|
92
|
+
* Keys of `tools` a script may reach for that have no binding (stage-only tools, ADR 0007), with
|
|
93
|
+
* the message their call rejects with, for example a hint to use `stage()`. Absent keys keep the
|
|
94
|
+
* engine's own behavior.
|
|
95
|
+
*/
|
|
96
|
+
readonly unbound?: ReadonlyArray<{
|
|
97
|
+
readonly key: string;
|
|
98
|
+
readonly message: string;
|
|
99
|
+
}>;
|
|
91
100
|
};
|
|
92
101
|
/**
|
|
93
102
|
* Runs one script. `code` is the body of an async function (top-level `await` and `return`) and
|
package/dist/executor.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.mts","names":[],"sources":["../src/executor.ts"],"mappings":";;;;;KAIY,kBAAA,GAAqB,cAAc;AAA/C;AAAA,KAGY,aAAA,GAAgB,QAAA,CAAS,MAAA,SAAe,MAAA,CAAO,IAAA;AAAA,KAE/C,mBAAA;EALmC,uGAOpC,MAAA,EAAQ,WAAW;AAAA;;;;;;;;;;;;;AAJiC;AAE/D;;;;AAE8B;AAsB9B;KAAY,oBAAA;EAAA,SACD,IAAA;EAAA,SACA,WAAA;EAAA,SACA,WAAA,GAAc,kBAAA;EAAA,SACd,YAAA,GAAe,kBAAA;EAM2C;;;;EAAA,SAD1D,SAAA;EAAA,SACA,OAAA,GAAU,IAAA,WAAe,OAAA,EAAS,mBAAA,KAAwB,OAAA;AAAA;;;;;KAOzD,sBAAA,GAAyB,IAAI,CAAC,oBAAA;EAPG,4FASlC,MAAA,YAT0D;EAAA,SAW1D,SAAA;AAAA;AAJX;AAAA,KAQY,kBAAA;EAAA,SACG,IAAA;EAAA,SAAuB,IAAA;AAAA;EAAA,SACvB,IAAA;EAAA,SAAwB,IAAA;EAAA,SAAuB,QAAA;AAAA;AAN1C;AAIpB;;;;;AAJoB,KAcR,iBAAA;AAAA,KAEA,aAAA;EAAA,SACD,IAAA,EAAM,iBAAiB;EAAA,SACvB,OAAA;EAAA,SACA,KAAA;AAAA;AALX;AAAA,KASY,mBAAA;EAAA,SACD,GAAA,EAAK,aAAA;EAAA,SACL,MAAA,EAAQ,aAAa;AAAA;AAAA,KAGpB,uBAAA;EAAA,SACD,EAAA;WAEA,KAAA;EAAA,SACA,KAAA,GAAQ,aAAA,EAfF;EAAA,SAiBN,MAAA,EAAQ,aAAA,CAAc,kBAAA,GAftB;EAAA,SAiBA,WAAA,GAAc,mBAAA;AAAA;AAAA,KAGb,sBAAA;EAAA,SACD,KAAA,EAAO,aAAA,CAAc,oBAAA;EAAA,SACrB,OAAA,EAAS,aAAA,CAAc,sBAAA,GAhBF;EAAA,SAkBrB,SAAA,UAnBK;EAAA,SAqBL,gBAAA,UApBQ;EAAA,SAsBR,KAAA,EAAO,aAAA;EAAA,SACP,MAAA,EAAQ,WAAA;AAAA
|
|
1
|
+
{"version":3,"file":"executor.d.mts","names":[],"sources":["../src/executor.ts"],"mappings":";;;;;KAIY,kBAAA,GAAqB,cAAc;AAA/C;AAAA,KAGY,aAAA,GAAgB,QAAA,CAAS,MAAA,SAAe,MAAA,CAAO,IAAA;AAAA,KAE/C,mBAAA;EALmC,uGAOpC,MAAA,EAAQ,WAAW;AAAA;;;;;;;;;;;;;AAJiC;AAE/D;;;;AAE8B;AAsB9B;KAAY,oBAAA;EAAA,SACD,IAAA;EAAA,SACA,WAAA;EAAA,SACA,WAAA,GAAc,kBAAA;EAAA,SACd,YAAA,GAAe,kBAAA;EAM2C;;;;EAAA,SAD1D,SAAA;EAAA,SACA,OAAA,GAAU,IAAA,WAAe,OAAA,EAAS,mBAAA,KAAwB,OAAA;AAAA;;;;;KAOzD,sBAAA,GAAyB,IAAI,CAAC,oBAAA;EAPG,4FASlC,MAAA,YAT0D;EAAA,SAW1D,SAAA;AAAA;AAJX;AAAA,KAQY,kBAAA;EAAA,SACG,IAAA;EAAA,SAAuB,IAAA;AAAA;EAAA,SACvB,IAAA;EAAA,SAAwB,IAAA;EAAA,SAAuB,QAAA;AAAA;AAN1C;AAIpB;;;;;AAJoB,KAcR,iBAAA;AAAA,KAEA,aAAA;EAAA,SACD,IAAA,EAAM,iBAAiB;EAAA,SACvB,OAAA;EAAA,SACA,KAAA;AAAA;AALX;AAAA,KASY,mBAAA;EAAA,SACD,GAAA,EAAK,aAAA;EAAA,SACL,MAAA,EAAQ,aAAa;AAAA;AAAA,KAGpB,uBAAA;EAAA,SACD,EAAA;WAEA,KAAA;EAAA,SACA,KAAA,GAAQ,aAAA,EAfF;EAAA,SAiBN,MAAA,EAAQ,aAAA,CAAc,kBAAA,GAftB;EAAA,SAiBA,WAAA,GAAc,mBAAA;AAAA;AAAA,KAGb,sBAAA;EAAA,SACD,KAAA,EAAO,aAAA,CAAc,oBAAA;EAAA,SACrB,OAAA,EAAS,aAAA,CAAc,sBAAA,GAhBF;EAAA,SAkBrB,SAAA,UAnBK;EAAA,SAqBL,gBAAA,UApBQ;EAAA,SAsBR,KAAA,EAAO,aAAA;EAAA,SACP,MAAA,EAAQ,WAAA;EApBP;;;;;EAAA,SA0BD,OAAA,GAAU,aAAA;IAAA,SAAyB,GAAA;IAAA,SAAsB,OAAA;EAAA;AAAA;;;;;;;;;;AAlBxB;AAG5C;KA6BY,gBAAA;EAAA,SACD,OAAA,GACP,IAAA,UACA,OAAA,EAAS,sBAAA,KACN,OAAA,CAAQ,uBAAA;AAAA"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CodeModeError, CodeModeErrorKind, CodeModeExecuteOptions, CodeModeExecutionResult, CodeModeExecutor, CodeModeExecutorGlobal, CodeModeExecutorTool, CodeModeJsonSchema, CodeModeOutputItem, CodeModeStore, CodeModeStoreWrites, CodeModeToolContext } from "./executor.mjs";
|
|
2
|
-
import { CodeModeCatalogTool, CodeModeDescriptionInput, CodeModeListing, CodeModeStagingDescription, CodeModeToolExposure, codeModeCatalog, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, renderCodeModeDescription, selectCodeModeListing } from "./catalog.mjs";
|
|
2
|
+
import { CodeModeCatalogSummary, CodeModeCatalogTool, CodeModeDescriptionInput, CodeModeListing, CodeModeStagingDescription, CodeModeToolExposure, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeStageOnlyCatalog, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, selectCodeModeListing, summarizeCodeModeCatalog } from "./catalog.mjs";
|
|
3
3
|
import { ClassifierConcurrencyLimiter, ClassifierToolParams, MakeClassifierToolOptions, classifierToolName, defaultClassifierProcessLimiter, defaultClassifierProcessMaxConcurrency, defaultClassifierToolMaxConcurrency, makeClassifierConcurrencyLimiter, makeClassifierTool } from "./classifier-tool.mjs";
|
|
4
4
|
import { CodeModeSearchHit, CodeModeSearchOptions, codeModeSearchTokens, defaultCodeModeSearchLimit, searchCodeModeTools } from "./search.mjs";
|
|
5
5
|
import { CodeModeCallSummary, CodeModeResultSegment, boundCodeModeSegments, codeModeResultSegments, codeModeSegmentsContent, defaultCodeModeMaxImageBytes, defaultCodeModeMaxImages, summarizeCodeModeCalls } from "./output.mjs";
|
|
6
6
|
import { CodeModeInterruptedCall, CodeModeInterruptedCallStatus, CodeModeInterruptedCalls, CodeModeStagedPlan, CodeModeStructuredContent, CodeModeToolResultEntry, codeModeStoreFromToolResults, maxCodeModeStoreTotalChars, maxCodeModeStoreValueChars } from "./store.mjs";
|
|
7
7
|
import { CodeModeAfterNestedCallInput, CodeModeLimits, CodeModeNestedCallOutcome, CodeModeStagingOptions, MakeCodeModeToolOptions, codeModeDeadlineMarginMs, codeModeMinimumTimeoutMs, codeModeToolName, defaultCodeModeLimits, makeCodeModeTool } from "./tool.mjs";
|
|
8
|
-
export { type ClassifierConcurrencyLimiter, ClassifierToolParams, type CodeModeAfterNestedCallInput, type CodeModeCallSummary, type CodeModeCatalogTool, type CodeModeDescriptionInput, type CodeModeError, type CodeModeErrorKind, type CodeModeExecuteOptions, type CodeModeExecutionResult, type CodeModeExecutor, type CodeModeExecutorGlobal, type CodeModeExecutorTool, type CodeModeInterruptedCall, type CodeModeInterruptedCallStatus, type CodeModeInterruptedCalls, type CodeModeJsonSchema, type CodeModeLimits, type CodeModeListing, type CodeModeNestedCallOutcome, type CodeModeOutputItem, type CodeModeResultSegment, type CodeModeSearchHit, type CodeModeSearchOptions, type CodeModeStagedPlan, type CodeModeStagingDescription, type CodeModeStagingOptions, type CodeModeStore, type CodeModeStoreWrites, type CodeModeStructuredContent, type CodeModeToolContext, type CodeModeToolExposure, type CodeModeToolResultEntry, type MakeClassifierToolOptions, type MakeCodeModeToolOptions, boundCodeModeSegments, classifierToolName, codeModeCatalog, codeModeDeadlineMarginMs, codeModeMinimumTimeoutMs, codeModeResultSegments, codeModeSearchTokens, codeModeSegmentsContent, codeModeStoreFromToolResults, codeModeToolName, defaultClassifierProcessLimiter, defaultClassifierProcessMaxConcurrency, defaultClassifierToolMaxConcurrency, defaultCodeModeInlineBudget, defaultCodeModeLimits, defaultCodeModeMaxImageBytes, defaultCodeModeMaxImages, defaultCodeModeSearchLimit, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, makeClassifierConcurrencyLimiter, makeClassifierTool, makeCodeModeTool, maxCodeModeStoreTotalChars, maxCodeModeStoreValueChars, renderCodeModeDescription, searchCodeModeTools, selectCodeModeListing, summarizeCodeModeCalls };
|
|
8
|
+
export { type ClassifierConcurrencyLimiter, ClassifierToolParams, type CodeModeAfterNestedCallInput, type CodeModeCallSummary, CodeModeCatalogSummary, type CodeModeCatalogTool, type CodeModeDescriptionInput, type CodeModeError, type CodeModeErrorKind, type CodeModeExecuteOptions, type CodeModeExecutionResult, type CodeModeExecutor, type CodeModeExecutorGlobal, type CodeModeExecutorTool, type CodeModeInterruptedCall, type CodeModeInterruptedCallStatus, type CodeModeInterruptedCalls, type CodeModeJsonSchema, type CodeModeLimits, type CodeModeListing, type CodeModeNestedCallOutcome, type CodeModeOutputItem, type CodeModeResultSegment, type CodeModeSearchHit, type CodeModeSearchOptions, type CodeModeStagedPlan, type CodeModeStagingDescription, type CodeModeStagingOptions, type CodeModeStore, type CodeModeStoreWrites, type CodeModeStructuredContent, type CodeModeToolContext, type CodeModeToolExposure, type CodeModeToolResultEntry, type MakeClassifierToolOptions, type MakeCodeModeToolOptions, boundCodeModeSegments, classifierToolName, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeDeadlineMarginMs, codeModeMinimumTimeoutMs, codeModeResultSegments, codeModeSearchTokens, codeModeSegmentsContent, codeModeStageOnlyCatalog, codeModeStoreFromToolResults, codeModeToolName, defaultClassifierProcessLimiter, defaultClassifierProcessMaxConcurrency, defaultClassifierToolMaxConcurrency, defaultCodeModeInlineBudget, defaultCodeModeLimits, defaultCodeModeMaxImageBytes, defaultCodeModeMaxImages, defaultCodeModeSearchLimit, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, makeClassifierConcurrencyLimiter, makeClassifierTool, makeCodeModeTool, maxCodeModeStoreTotalChars, maxCodeModeStoreValueChars, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, searchCodeModeTools, selectCodeModeListing, summarizeCodeModeCalls, summarizeCodeModeCatalog };
|