@introspection-ai/recipes 0.30.1 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,176 +1,48 @@
1
- import { Type } from "typebox";
1
+ import { createToolSearchExtension, } from "@earendil-works/pi-coding-agent";
2
2
  export const RECIPE_TOOL_SEARCH_NAME = "tool_search";
3
3
  export const LEGACY_MCP_TOOL_SEARCH_NAME = "mcp_search";
4
- function words(value) {
5
- return value
6
- .toLowerCase()
7
- .split(/[^a-z0-9]+/)
8
- .filter(Boolean);
9
- }
10
- function schemaSearchTerms(schema) {
11
- const propertyNames = [];
12
- const propertyDescriptions = [];
13
- const visited = new Set();
14
- const visit = (value) => {
15
- if (!value || typeof value !== "object" || visited.has(value))
16
- return;
17
- visited.add(value);
18
- const record = value;
19
- if (record.properties && typeof record.properties === "object") {
20
- for (const [name, property] of Object.entries(record.properties)) {
21
- propertyNames.push(name);
22
- if (property && typeof property === "object") {
23
- const description = property.description;
24
- if (typeof description === "string") {
25
- propertyDescriptions.push(description);
26
- }
27
- }
28
- visit(property);
29
- }
30
- }
31
- for (const keyword of [
32
- "allOf",
33
- "anyOf",
34
- "oneOf",
35
- "items",
36
- "additionalProperties",
37
- ]) {
38
- const nested = record[keyword];
39
- if (Array.isArray(nested)) {
40
- for (const entry of nested)
41
- visit(entry);
42
- }
43
- else {
44
- visit(nested);
45
- }
46
- }
47
- };
48
- visit(schema);
49
- return {
50
- propertyNames: propertyNames.join(" ").toLowerCase(),
51
- propertyDescriptions: propertyDescriptions.join(" ").toLowerCase(),
52
- };
53
- }
54
- function scoreTool(tool, query) {
55
- const normalizedQuery = query.trim().toLowerCase();
56
- if (!normalizedQuery)
57
- return 0;
58
- const name = tool.name.toLowerCase();
59
- const label = (tool.label ?? tool.name).toLowerCase();
60
- const description = tool.description.toLowerCase();
61
- const { propertyNames, propertyDescriptions } = schemaSearchTerms(tool.parameters);
62
- let score = 0;
63
- if (name === normalizedQuery)
64
- score += 500;
65
- if (label === normalizedQuery)
66
- score += 300;
67
- if (name.includes(normalizedQuery))
68
- score += 120;
69
- if (label.includes(normalizedQuery))
70
- score += 100;
71
- if (description.includes(normalizedQuery))
72
- score += 60;
73
- const nameTerms = new Set(words(name));
74
- const labelTerms = new Set(words(label));
75
- const propertyNameTerms = new Set(words(propertyNames));
76
- for (const term of words(normalizedQuery)) {
77
- if (nameTerms.has(term))
78
- score += 40;
79
- else if (name.includes(term))
80
- score += 20;
81
- if (labelTerms.has(term))
82
- score += 30;
83
- else if (label.includes(term))
84
- score += 15;
85
- if (description.includes(term))
86
- score += 16;
87
- if (propertyNameTerms.has(term))
88
- score += 12;
89
- else if (propertyNames.includes(term))
90
- score += 6;
91
- if (propertyDescriptions.includes(term))
92
- score += 6;
93
- }
94
- return score;
95
- }
96
- export function createRecipeToolSearch(options) {
97
- const toolsByName = new Map(options.tools.map((tool) => [tool.name, tool]));
98
- const deferred = [...new Set(options.deferredToolNames)].map((name) => {
99
- const tool = toolsByName.get(name);
100
- if (!tool) {
101
- throw new Error(`Recipe deferred tool '${name}' was not registered before tool search`);
102
- }
103
- return tool;
104
- });
105
- if (deferred.length === 0)
106
- return undefined;
107
- if (toolsByName.has(RECIPE_TOOL_SEARCH_NAME)) {
108
- throw new Error(`Recipe tool name '${RECIPE_TOOL_SEARCH_NAME}' is reserved by the session`);
109
- }
110
- return {
111
- name: RECIPE_TOOL_SEARCH_NAME,
112
- label: "Tool search",
113
- description: "Search inactive tools allowed for this Recipe and enable the best matches for the next model request.",
114
- parameters: Type.Object({
115
- query: Type.String({
116
- description: "Capability or task to find a tool for.",
117
- }),
118
- limit: Type.Optional(Type.Integer({ minimum: 1, maximum: 10, default: 3 })),
119
- }),
120
- executionMode: "sequential",
121
- async execute(_toolCallId, params) {
122
- const input = params;
123
- const query = typeof input.query === "string" ? input.query : "";
124
- const limit = typeof input.limit === "number" ? input.limit : 3;
125
- const active = new Set(options.activation.getActiveTools());
126
- const matches = deferred
127
- .filter((tool) => !active.has(tool.name))
128
- .map((tool) => ({ tool, score: scoreTool(tool, query) }))
129
- .filter((match) => match.score > 0)
130
- .sort((left, right) => right.score - left.score ||
131
- left.tool.name.localeCompare(right.tool.name))
132
- .slice(0, limit);
133
- const added = matches.map((match) => match.tool.name);
134
- if (added.length > 0) {
135
- options.activation.setActiveTools([...active, ...added]);
136
- }
137
- const details = {
138
- matches: matches.map(({ tool }) => ({
139
- name: tool.name,
140
- label: tool.label ?? tool.name,
141
- description: tool.description,
142
- })),
143
- added,
144
- };
145
- const text = matches.length === 0
146
- ? `No inactive Recipe tools matched "${query}".`
147
- : [
148
- `Enabled ${matches.length} Recipe tool(s) for the next model request:`,
149
- ...matches.map(({ tool }) => `- ${tool.name}${tool.description ? `: ${tool.description}` : ""}`),
150
- ].join("\n");
151
- return {
152
- content: [{ type: "text", text }],
153
- details,
154
- };
4
+ /**
5
+ * Pi's `tool_search`, plus `mcp_search` as an alias when MCP tools are
6
+ * deferred. It searches tools registered with `deferred` exposure and declares
7
+ * the matches for the next model request.
8
+ */
9
+ export function createRecipeToolSearchTools(tools, includeLegacyMcpAlias) {
10
+ let search;
11
+ createToolSearchExtension()({
12
+ ...tools,
13
+ registerTool: (definition) => {
14
+ search = definition;
155
15
  },
156
- };
157
- }
158
- export function createRecipeToolSearchTools(options, includeLegacyMcpAlias) {
159
- const search = createRecipeToolSearch(options);
16
+ });
160
17
  if (!search)
161
- return [];
162
- if (!includeLegacyMcpAlias)
163
- return [search];
164
- if (options.tools.some((tool) => tool.name === LEGACY_MCP_TOOL_SEARCH_NAME)) {
165
- throw new Error(`Recipe tool name '${LEGACY_MCP_TOOL_SEARCH_NAME}' is reserved by the session`);
166
- }
167
- return [
168
- search,
169
- {
170
- ...search,
171
- name: LEGACY_MCP_TOOL_SEARCH_NAME,
172
- label: "MCP search",
18
+ throw new Error("Pi did not provide tool_search");
19
+ const { defaultActive: _defaultActive, ...definition } = search;
20
+ return includeLegacyMcpAlias
21
+ ? [
22
+ definition,
23
+ {
24
+ ...definition,
25
+ name: LEGACY_MCP_TOOL_SEARCH_NAME,
26
+ label: LEGACY_MCP_TOOL_SEARCH_NAME,
27
+ },
28
+ ]
29
+ : [definition];
30
+ }
31
+ /** Register the named tools with `deferred` exposure, so tool search can load them. */
32
+ export function deferTools(factory, deferredToolNames) {
33
+ if (deferredToolNames.length === 0)
34
+ return factory;
35
+ const deferred = new Set(deferredToolNames);
36
+ return (pi) => factory(new Proxy(pi, {
37
+ get(target, property, receiver) {
38
+ const value = Reflect.get(target, property, receiver);
39
+ if (property !== "registerTool" || typeof value !== "function") {
40
+ return typeof value === "function" ? value.bind(target) : value;
41
+ }
42
+ return (definition) => value.call(target, deferred.has(definition.name)
43
+ ? { ...definition, exposure: "deferred" }
44
+ : definition);
173
45
  },
174
- ];
46
+ }));
175
47
  }
176
48
  //# sourceMappingURL=tool-search.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tool-search.js","sourceRoot":"","sources":["../src/tool-search.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tool-search.js","sourceRoot":"","sources":["../src/tool-search.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,GAI1B,MAAM,iCAAiC,CAAC;AAEzC,MAAM,CAAC,MAAM,uBAAuB,GAAG,aAAa,CAAC;AACrD,MAAM,CAAC,MAAM,2BAA2B,GAAG,YAAY,CAAC;AAOxD;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CACzC,KAA2B,EAC3B,qBAA8B;IAE9B,IAAI,MAAkC,CAAC;IACvC,yBAAyB,EAAE,CAAC;QAC1B,GAAG,KAAK;QACR,YAAY,EAAE,CAAC,UAA0B,EAAE,EAAE;YAC3C,MAAM,GAAG,UAAU,CAAC;QACtB,CAAC;KACyB,CAAC,CAAC;IAC9B,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAC/D,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,UAAU,EAAE,GAAG,MAAM,CAAC;IAChE,OAAO,qBAAqB;QAC1B,CAAC,CAAC;YACE,UAAU;YACV;gBACE,GAAG,UAAU;gBACb,IAAI,EAAE,2BAA2B;gBACjC,KAAK,EAAE,2BAA2B;aACnC;SACF;QACH,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;AACnB,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,UAAU,CACxB,OAAyB,EACzB,iBAAoC;IAEpC,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACnD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,EAAE,EAAE,CACZ,OAAO,CACL,IAAI,KAAK,CAAC,EAAE,EAAE;QACZ,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ;YAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACtD,IAAI,QAAQ,KAAK,cAAc,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;gBAC/D,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YAClE,CAAC;YACD,OAAO,CAAC,UAA0B,EAAE,EAAE,CACpC,KAAK,CAAC,IAAI,CACR,MAAM,EACN,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;gBAC3B,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE;gBACzC,CAAC,CAAC,UAAU,CACf,CAAC;QACN,CAAC;KACF,CAAC,CACH,CAAC;AACN,CAAC"}
@@ -91,11 +91,13 @@ to hide all authorized tools for a server, then optionally list exact tools in
91
91
  or a sole `"*"` selector. `eager` wins when a tool matches both fields, but
92
92
  neither field can authorize a tool excluded by `include`/`exclude`.
93
93
 
94
- Deferred tools remain authorized and discoverable. When at least one connector
95
- or MCP tool is deferred, Recipes registers `tool_search`. Calling it searches
96
- the inactive tools already allowed for the agent and adds the best matches to
97
- Pi's active tool set for the next model request. It never grants access beyond
98
- the Recipe manifest and agent policy. Recipes also registers `mcp_search` as a
94
+ Deferred tools remain authorized and discoverable. Recipes registers them with
95
+ Pi's `deferred` exposure and, when at least one connector or MCP tool is
96
+ deferred, activates Pi's `tool_search`. Calling it ranks the deferred tools by
97
+ the words in their names, descriptions and input schemas (BM25, default limit
98
+ 8) and declares the best matches for the next model request. Pi records the
99
+ change in the session, so loaded tools survive resume. It never grants access
100
+ beyond the Recipe manifest and agent policy. Recipes also registers `mcp_search` as a
99
101
  compatibility alias when MCP tools are deferred.
100
102
 
101
103
  `defer` and `eager` are invalid in CLI mode. An omitted agent `mcp` block
@@ -29,7 +29,7 @@ For direct Pi use:
29
29
  pi install npm:@introspection-ai/recipes
30
30
  ```
31
31
 
32
- Recipes currently requires Node.js 24 or later and Pi `>=0.86.1`.
32
+ Recipes currently requires Node.js 24 or later and Pi `>=1.1.0`.
33
33
 
34
34
  ## Selection
35
35
 
@@ -83,6 +83,45 @@ llm:
83
83
  Unknown fields are errors at every level. The obsolete top-level `model:`
84
84
  block is rejected.
85
85
 
86
+ ## Judge types
87
+
88
+ `type` says when a judge runs:
89
+
90
+ - `online`, the default: at the end of every runtime conversation.
91
+ - `offline`: at the end of each eval trial. It has the same shape as `online`.
92
+ - `mission`: on a request leaving the sandbox, which a route in the Recipe's
93
+ `policies/routes.yaml` names. Its answers reach the Recipe's Cedar policy
94
+ before the request is allowed.
95
+
96
+ A mission judge asks yes-or-no questions instead of grading against a rubric, and
97
+ the platform chooses the model:
98
+
99
+ ```yaml
100
+ name: booking
101
+ type: mission
102
+ description: Is this booking what the traveller asked for?
103
+ attrs: [city, check_in, check_out, total_cents]
104
+ questions:
105
+ requested:
106
+ instructions: >
107
+ Is the booking something the traveller asked for, or a natural part of
108
+ that trip?
109
+ criteria:
110
+ "true": The same destination and dates.
111
+ "false": Another place, other dates, or something they never asked for.
112
+ personal:
113
+ instructions: Did the traveller describe this part of the trip as personal?
114
+ ```
115
+
116
+ - `questions` maps between one and eight lowercase identifiers to questions;
117
+ each name is the field its answer is read as.
118
+ - `instructions` is non-empty text. `criteria` is optional and, when present,
119
+ describes both `true` and `false` in non-empty text.
120
+ - `attrs` lists the request attributes the judge sees, and is empty to show
121
+ them all.
122
+ - `on` and `llm` belong to `online` and `offline` judges and are rejected on a
123
+ mission judge; `questions` and `attrs` are rejected on the others.
124
+
86
125
  ### LLM settings
87
126
 
88
127
  - `provider` is a 1-64 byte lowercase slug containing ASCII letters, digits,
@@ -141,4 +180,5 @@ Invalid Recipe content is reported through the normal diagnostics model. Judge
141
180
  diagnostics use stable `judge.*` codes, Recipe-relative source paths, useful
142
181
  help text, and deterministic ordering. YAML syntax failures use
143
182
  `judge.yaml_malformed` and include a 1-based source span when the parser
144
- provides one.
183
+ provides one. An invalid mission judge reports `judge.mission_invalid`, and a
184
+ `type` outside `online`, `offline` and `mission` reports `judge.type_invalid`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@introspection-ai/recipes",
3
- "version": "0.30.1",
3
+ "version": "0.32.0",
4
4
  "description": "The open format for vertical agents, built on Pi.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -88,17 +88,17 @@
88
88
  "yaml": "^2.9.0"
89
89
  },
90
90
  "peerDependencies": {
91
- "@earendil-works/pi-agent-core": ">=0.86.1",
92
- "@earendil-works/pi-ai": ">=0.86.1",
93
- "@earendil-works/pi-coding-agent": ">=0.86.1",
94
- "@earendil-works/pi-tui": ">=0.86.1",
91
+ "@earendil-works/pi-agent-core": ">=1.1.0 <2.0.0",
92
+ "@earendil-works/pi-ai": ">=1.1.0 <2.0.0",
93
+ "@earendil-works/pi-coding-agent": ">=1.1.0 <2.0.0",
94
+ "@earendil-works/pi-tui": ">=1.1.0 <2.0.0",
95
95
  "typebox": "*"
96
96
  },
97
97
  "devDependencies": {
98
- "@earendil-works/pi-agent-core": "0.99.2",
99
- "@earendil-works/pi-ai": "0.99.2",
100
- "@earendil-works/pi-coding-agent": "0.99.2",
101
- "@earendil-works/pi-tui": "0.99.2",
98
+ "@earendil-works/pi-agent-core": "1.1.0",
99
+ "@earendil-works/pi-ai": "1.1.0",
100
+ "@earendil-works/pi-coding-agent": "1.1.0",
101
+ "@earendil-works/pi-tui": "1.1.0",
102
102
  "@types/node": "^26.1.2",
103
103
  "esbuild": "^0.28.1",
104
104
  "typebox": "^1.0.56",
@@ -106,10 +106,10 @@
106
106
  "vitest": "^5.0.1"
107
107
  },
108
108
  "optionalDependencies": {
109
- "@introspection-ai/mcp-client-linux-x64": "0.30.1",
110
- "@introspection-ai/mcp-client-linux-arm64": "0.30.1",
111
- "@introspection-ai/mcp-client-darwin-arm64": "0.30.1",
112
- "@introspection-ai/mcp-client-darwin-x64": "0.30.1"
109
+ "@introspection-ai/mcp-client-linux-x64": "0.32.0",
110
+ "@introspection-ai/mcp-client-linux-arm64": "0.32.0",
111
+ "@introspection-ai/mcp-client-darwin-arm64": "0.32.0",
112
+ "@introspection-ai/mcp-client-darwin-x64": "0.32.0"
113
113
  },
114
114
  "scripts": {
115
115
  "build": "pnpm build:ts && pnpm build:native",