@introspection-ai/recipes 0.21.0 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/channels/index.d.ts +7 -0
- package/dist/channels/index.d.ts.map +1 -0
- package/dist/channels/index.js +4 -0
- package/dist/channels/index.js.map +1 -0
- package/dist/channels/module.d.ts +43 -0
- package/dist/channels/module.d.ts.map +1 -0
- package/dist/channels/module.js +61 -0
- package/dist/channels/module.js.map +1 -0
- package/dist/channels/refs.d.ts +28 -0
- package/dist/channels/refs.d.ts.map +1 -0
- package/dist/channels/refs.js +91 -0
- package/dist/channels/refs.js.map +1 -0
- package/dist/channels/tools.d.ts +56 -0
- package/dist/channels/tools.d.ts.map +1 -0
- package/dist/channels/tools.js +325 -0
- package/dist/channels/tools.js.map +1 -0
- package/dist/channels/types.d.ts +209 -0
- package/dist/channels/types.d.ts.map +1 -0
- package/dist/channels/types.js +23 -0
- package/dist/channels/types.js.map +1 -0
- package/dist/connector-tools.d.ts +37 -0
- package/dist/connector-tools.d.ts.map +1 -0
- package/dist/connector-tools.js +88 -0
- package/dist/connector-tools.js.map +1 -0
- package/dist/mcp-chunks/{chunk-XK3LRH3Q.js → chunk-JZDXKYQM.js} +1 -1
- package/dist/mcp-daemon.js +1 -1
- package/dist/mcp-run-worker.js +1 -1
- package/dist/mcp-tools.d.ts +1 -6
- package/dist/mcp-tools.d.ts.map +1 -1
- package/dist/mcp-tools.js +5 -73
- package/dist/mcp-tools.js.map +1 -1
- package/dist/pi-extension.d.ts.map +1 -1
- package/dist/pi-extension.js +63 -13
- package/dist/pi-extension.js.map +1 -1
- package/dist/recipe-agent.d.ts.map +1 -1
- package/dist/recipe-agent.js +3 -2
- package/dist/recipe-agent.js.map +1 -1
- package/dist/recipe-extensions.d.ts +1 -0
- package/dist/recipe-extensions.d.ts.map +1 -1
- package/dist/recipe-extensions.js +32 -11
- package/dist/recipe-extensions.js.map +1 -1
- package/dist/recipe-package.d.ts +5 -0
- package/dist/recipe-package.d.ts.map +1 -1
- package/dist/recipe-package.js +68 -3
- package/dist/recipe-package.js.map +1 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +71 -16
- package/dist/session.js.map +1 -1
- package/dist/test-utils.d.ts +1 -0
- package/dist/test-utils.d.ts.map +1 -1
- package/dist/test-utils.js +1 -0
- package/dist/test-utils.js.map +1 -1
- package/dist/tool-search.d.ts +21 -0
- package/dist/tool-search.d.ts.map +1 -0
- package/dist/tool-search.js +176 -0
- package/dist/tool-search.js.map +1 -0
- package/docs/channels.md +167 -0
- package/docs/index.md +2 -0
- package/docs/mcp-configuration.md +6 -4
- package/docs/pi-extension.md +4 -3
- package/docs/recipe-format.md +37 -0
- package/docs/slack.md +135 -0
- package/package.json +17 -12
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
export const RECIPE_TOOL_SEARCH_NAME = "tool_search";
|
|
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
|
+
};
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
export function createRecipeToolSearchTools(options, includeLegacyMcpAlias) {
|
|
159
|
+
const search = createRecipeToolSearch(options);
|
|
160
|
+
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",
|
|
173
|
+
},
|
|
174
|
+
];
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=tool-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-search.js","sourceRoot":"","sources":["../src/tool-search.ts"],"names":[],"mappings":"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"}
|
package/docs/channels.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Channel tools
|
|
2
|
+
|
|
3
|
+
A Recipe that answers a chat message declares a **channel connector**. The host
|
|
4
|
+
then registers a fixed set of `channel_*` tools, named and shaped identically
|
|
5
|
+
for every provider, and bound to the one conversation the task came from.
|
|
6
|
+
|
|
7
|
+
Two properties follow from that, and both are structural rather than
|
|
8
|
+
conventional:
|
|
9
|
+
|
|
10
|
+
- **The agent cannot address anything else.** No `channel_*` tool takes a
|
|
11
|
+
channel, thread, workspace, or user argument. The conversation is closed over
|
|
12
|
+
by the host from the task origin, so a compromised prompt has no vocabulary
|
|
13
|
+
for "post this somewhere else". The invariant is asserted by a test that
|
|
14
|
+
walks every registered tool's input schema.
|
|
15
|
+
- **A tool that the provider cannot support is absent, not failing.** Each
|
|
16
|
+
adapter declares a capability descriptor, and registration filters on it.
|
|
17
|
+
For example, an adapter with no history API has no `channel_read` tool.
|
|
18
|
+
|
|
19
|
+
Before the first model call, the channel extension adds origin metadata to the
|
|
20
|
+
system prompt. The metadata contains the provider, the conversation name and
|
|
21
|
+
permalink when the adapter can resolve them, whether the origin is a thread,
|
|
22
|
+
and the available channel tools. It contains no provider conversation IDs and
|
|
23
|
+
no messages. The injected guidance tells the agent to deliver its user-facing
|
|
24
|
+
response with `channel_reply`, because a normal final assistant response is not
|
|
25
|
+
delivered to the originating channel. `channel_read` remains the only way to
|
|
26
|
+
fetch earlier messages when the provider supports it.
|
|
27
|
+
|
|
28
|
+
## The tools
|
|
29
|
+
|
|
30
|
+
| Tool | Model arguments | Requires |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| `channel_reply` | `text` (Markdown) | always |
|
|
33
|
+
| `channel_read` | `limit?`, `cursor?` | `read` |
|
|
34
|
+
| `channel_react` | `message`, `emoji`, `action?` (`add` or `remove`) | `react` |
|
|
35
|
+
| `channel_edit` | `message`, `text` | `edit` |
|
|
36
|
+
| `channel_retract` | `message` | `retract` |
|
|
37
|
+
| `channel_attach` | `path`, `title?`, `comment?` | `attach` |
|
|
38
|
+
| `channel_fetch_file` | `file` (a `file_…` handle), `variant?` | `fetch_file` |
|
|
39
|
+
| `channel_post_document` | `title`, `markdown` | `documents` |
|
|
40
|
+
|
|
41
|
+
`channel_reply`, `channel_read`, and `channel_react` are active by default when
|
|
42
|
+
the provider supports them. The other selected tools start inactive, and the
|
|
43
|
+
model can find them through `tool_search`.
|
|
44
|
+
|
|
45
|
+
Reply content is **Markdown**. Each adapter renders it in the provider's own
|
|
46
|
+
format. There is no raw provider payload because the same tool contract must
|
|
47
|
+
work with every adapter.
|
|
48
|
+
|
|
49
|
+
### Message and file references
|
|
50
|
+
|
|
51
|
+
`channel_react`, `channel_edit`, and `channel_retract` take a `message`, which is
|
|
52
|
+
an opaque handle minted by the host for the current session. It is not a Slack
|
|
53
|
+
timestamp or another provider message ID. Handles come back from
|
|
54
|
+
`channel_reply` and `channel_read`, so the model can only act on a message that
|
|
55
|
+
a channel tool returned.
|
|
56
|
+
|
|
57
|
+
`channel_react` adds a reaction when `action` is omitted. Set `action` to
|
|
58
|
+
`remove` to remove the agent's reaction with the same emoji.
|
|
59
|
+
|
|
60
|
+
Edit and retract have an extra check. They accept only a handle for a message
|
|
61
|
+
that this agent posted. Reading the same message again keeps its original
|
|
62
|
+
handle and authorship record.
|
|
63
|
+
|
|
64
|
+
`channel_fetch_file` works the same way. Attachments returned by `channel_read`
|
|
65
|
+
carry a `file_…` handle, and that is the only value the tool accepts. A bot can
|
|
66
|
+
usually read files from every conversation it belongs to, so accepting a raw
|
|
67
|
+
provider file ID would let the model reach files outside the bound conversation.
|
|
68
|
+
|
|
69
|
+
### Enrichment, not lookup tools
|
|
70
|
+
|
|
71
|
+
Author names and permalinks are resolved by the adapter in trusted code and
|
|
72
|
+
attached to what the agent is already reading: `channel_read` rows carry
|
|
73
|
+
`author.display_name`, and `channel_reply` returns a `permalink` where the
|
|
74
|
+
provider has one. There is no `resolve_user` or `get_permalink` tool, because
|
|
75
|
+
each would require another model turn. Each lookup would also take an
|
|
76
|
+
addressing argument.
|
|
77
|
+
|
|
78
|
+
### Unsupported operations
|
|
79
|
+
|
|
80
|
+
Workspace search, channel listing and joining, directory lookup, and posting to
|
|
81
|
+
another conversation are unsupported. The proposal does not choose an API or
|
|
82
|
+
access model for those operations. A separate proposal can define them when a
|
|
83
|
+
concrete use case requires them.
|
|
84
|
+
|
|
85
|
+
Typing indicators and presence are runtime effects rather than model decisions.
|
|
86
|
+
Streaming controls how a reply is delivered. The runtime derives idempotency
|
|
87
|
+
keys, and the webhook already removes duplicate inbound events.
|
|
88
|
+
|
|
89
|
+
## Declare a channel connector
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"dependencies": {
|
|
94
|
+
"@introspection-ai/recipe-channel-slack": "^0.1.0"
|
|
95
|
+
},
|
|
96
|
+
"pi": {
|
|
97
|
+
"connectors": [
|
|
98
|
+
{
|
|
99
|
+
"provider": "slack"
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The connector declaration enables the provider package and its supported tool
|
|
107
|
+
catalog. The agent YAML file is the only place that narrows the catalog:
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
tools: [channel_reply, channel_read, channel_react, channel_edit, channel_retract, channel_fetch_file]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The host fails when an agent selects a tool that the provider does not support.
|
|
114
|
+
|
|
115
|
+
Because the vocabulary is neutral, the same declaration and the same agent
|
|
116
|
+
prompt work against another provider by changing the dependency and `provider`.
|
|
117
|
+
Each provider package declares the capabilities that it can support.
|
|
118
|
+
|
|
119
|
+
## Write an adapter
|
|
120
|
+
|
|
121
|
+
An adapter supplies transport and a capability descriptor. It writes no tool
|
|
122
|
+
schemas. The shared schema keeps providers from defining different forms of
|
|
123
|
+
the same operation, and it prevents a provider from adding an addressing
|
|
124
|
+
argument.
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import {
|
|
128
|
+
createChannelConnectorModule,
|
|
129
|
+
type ChannelAdapter,
|
|
130
|
+
} from "@introspection-ai/recipes/channels";
|
|
131
|
+
|
|
132
|
+
const capabilities = {
|
|
133
|
+
react: false, edit: true, retract: true, read: false,
|
|
134
|
+
attach: false, fetchFile: false,
|
|
135
|
+
documents: false, resolveAuthors: true, permalinks: false,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
class MyAdapter implements ChannelAdapter {
|
|
139
|
+
readonly provider = "my-channel";
|
|
140
|
+
readonly capabilities = capabilities;
|
|
141
|
+
async reply(ctx, { text }) { /* post into ctx.target */ }
|
|
142
|
+
async edit(ctx, { ref, text }) { /* edit an agent-authored message */ }
|
|
143
|
+
async retract(ctx, { ref }) { /* retract an agent-authored message */ }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export default createChannelConnectorModule({
|
|
147
|
+
provider: "my-channel",
|
|
148
|
+
capabilities,
|
|
149
|
+
createSession: ({ env }) => ({
|
|
150
|
+
adapter: new MyAdapter(/* client from env */),
|
|
151
|
+
// A function, so a task with no channel origin still starts: the tools
|
|
152
|
+
// fail when called, the session does not fail to open.
|
|
153
|
+
target: () => resolveTargetFrom(env),
|
|
154
|
+
}),
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Registration checks that the adapter implements every method its capabilities
|
|
159
|
+
claim, so a descriptor cannot promise a tool the adapter does not have.
|
|
160
|
+
|
|
161
|
+
The result is an ordinary `RecipeConnectorModule`. Manifest validation, agent
|
|
162
|
+
tool selection, and `tool_search` work without provider-specific code in the
|
|
163
|
+
Recipe.
|
|
164
|
+
|
|
165
|
+
## Provider pages
|
|
166
|
+
|
|
167
|
+
- [Slack](slack.md)
|
package/docs/index.md
CHANGED
|
@@ -17,6 +17,8 @@ task lifecycle, protocols, and deployment.
|
|
|
17
17
|
| Compose agents and subagents | [Agent composition](agent-composition.md) |
|
|
18
18
|
| Ask for user input across hosts | [Interactions](interactions.md) |
|
|
19
19
|
| Declare capability policy and bindings | [MCP configuration](mcp-configuration.md) |
|
|
20
|
+
| Answer a chat message from a Recipe | [Channel tools](channels.md) |
|
|
21
|
+
| Add Slack tools to a Recipe | [Slack channel connector](slack.md) |
|
|
20
22
|
| Define portable evaluation judges | [Recipe judges](recipe-judges.md) |
|
|
21
23
|
|
|
22
24
|
## Boundary
|
|
@@ -91,10 +91,12 @@ 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
|
|
95
|
-
Recipes registers `
|
|
96
|
-
|
|
97
|
-
model request. It never grants access beyond
|
|
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
|
|
99
|
+
compatibility alias when MCP tools are deferred.
|
|
98
100
|
|
|
99
101
|
`defer` and `eager` are invalid in CLI mode. An omitted agent `mcp` block
|
|
100
102
|
inherits its base policy. Once a child declares `mcp`, the complete block
|
package/docs/pi-extension.md
CHANGED
|
@@ -53,9 +53,10 @@ For the selected agent, the extension:
|
|
|
53
53
|
1. reads the root `package.json#pi` resource declarations;
|
|
54
54
|
2. resolves the agent YAML, including `from:` inheritance;
|
|
55
55
|
3. selects the model, thinking level, and tool allowlist;
|
|
56
|
-
4. loads
|
|
57
|
-
5.
|
|
58
|
-
6.
|
|
56
|
+
4. loads providers from `pi.connectors` and registers the tools selected by the agent;
|
|
57
|
+
5. loads selected skills, package prompts, and the complete Recipe extension closure;
|
|
58
|
+
6. materializes declared MCP bindings from host or local configuration;
|
|
59
|
+
7. exposes only the declared subagents through the shared `agent` tool.
|
|
59
60
|
|
|
60
61
|
See [Recipe Format](recipe-format.md) for the authored contract and
|
|
61
62
|
[Agent composition](agent-composition.md) for inheritance and selection.
|
package/docs/recipe-format.md
CHANGED
|
@@ -81,6 +81,43 @@ MUST commit one supported dependency lockfile: `package-lock.json`,
|
|
|
81
81
|
`npm-shrinkwrap.json`, `pnpm-lock.yaml`, or `yarn.lock`. npm lockfiles MUST
|
|
82
82
|
carry the same package name and version as `package.json`.
|
|
83
83
|
|
|
84
|
+
## Connector tools
|
|
85
|
+
|
|
86
|
+
`pi.connectors` declares official provider tools that the host may register for
|
|
87
|
+
the Recipe. The declaration does not contain a connector ID, workspace ID, or
|
|
88
|
+
credential. A host binds those values when it starts a task.
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"dependencies": {
|
|
93
|
+
"@introspection-ai/recipe-channel-slack": "^0.1.0"
|
|
94
|
+
},
|
|
95
|
+
"pi": {
|
|
96
|
+
"connectors": [
|
|
97
|
+
{
|
|
98
|
+
"provider": "slack"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Each provider may appear once. The host derives the package name from the
|
|
106
|
+
provider. For example, `slack` resolves to
|
|
107
|
+
`@introspection-ai/recipe-channel-slack`. The package owns its tool catalog
|
|
108
|
+
and marks which tools are active by default.
|
|
109
|
+
|
|
110
|
+
The provider package must be in the Recipe's production dependencies and
|
|
111
|
+
lockfile. The host imports the package only when the Recipe declares the
|
|
112
|
+
provider. The agent YAML file is the only place that narrows the package tool
|
|
113
|
+
catalog. An agent lists each allowed tool by its full name, such as
|
|
114
|
+
`channel_reply`, in its `tools` list. The host fails when the agent names a
|
|
115
|
+
tool that the connector does not register.
|
|
116
|
+
|
|
117
|
+
Chat providers share one connector shape. A channel connector registers the
|
|
118
|
+
provider-neutral `channel_*` tools that its capabilities support. See
|
|
119
|
+
[Channel tools](channels.md).
|
|
120
|
+
|
|
84
121
|
## Agents
|
|
85
122
|
|
|
86
123
|
`pi.agents` may declare YAML agent definitions explicitly. When omitted,
|
package/docs/slack.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Slack channel connector
|
|
2
|
+
|
|
3
|
+
`@introspection-ai/recipe-channel-slack` is the Slack adapter for the
|
|
4
|
+
[channel tools](channels.md). It supplies Slack Web API transport and a
|
|
5
|
+
capability descriptor; the tool names and schemas are the neutral `channel_*`
|
|
6
|
+
set, so a Recipe written against it is not written against Slack.
|
|
7
|
+
|
|
8
|
+
Slack sends inbound events to the existing Events API webhook. The tools make
|
|
9
|
+
ordinary HTTP requests to the Slack Web API with the bot that received the
|
|
10
|
+
task. The package does not use Socket Mode, WebSockets, or a streamed tool
|
|
11
|
+
protocol.
|
|
12
|
+
|
|
13
|
+
## Declare it
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@introspection-ai/recipe-channel-slack": "^0.1.0"
|
|
19
|
+
},
|
|
20
|
+
"pi": {
|
|
21
|
+
"connectors": [
|
|
22
|
+
{
|
|
23
|
+
"provider": "slack"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Commit the package manager lockfile. The host loads the package only for a
|
|
31
|
+
Recipe that declares the connector.
|
|
32
|
+
|
|
33
|
+
The connector package provides the complete Slack tool catalog. Each agent
|
|
34
|
+
lists the exact `channel_*` tools it may call in its YAML file. `channel_reply`,
|
|
35
|
+
`channel_read`, and `channel_react` are active from the start. Other selected
|
|
36
|
+
tools are available through `tool_search`.
|
|
37
|
+
|
|
38
|
+
## What Slack registers
|
|
39
|
+
|
|
40
|
+
| Tool | Slack operation |
|
|
41
|
+
| --- | --- |
|
|
42
|
+
| `channel_reply` | `chat.postMessage` into the origin channel and thread |
|
|
43
|
+
| `channel_read` | `conversations.replies` in a thread, else `conversations.history` |
|
|
44
|
+
| `channel_react` | `reactions.add` or `reactions.remove` |
|
|
45
|
+
| `channel_edit` | `chat.update` for a message the agent posted |
|
|
46
|
+
| `channel_retract` | `chat.delete` for a message the agent posted |
|
|
47
|
+
| `channel_fetch_file` | `files.info` plus a private file download |
|
|
48
|
+
|
|
49
|
+
Slack history returns at most 15 messages to the agent per call. For a thread,
|
|
50
|
+
the first call reads the thread and returns the newest messages. The adapter
|
|
51
|
+
keeps older messages in the current session, and the returned opaque cursor
|
|
52
|
+
pages backward through that cache without another `conversations.replies`
|
|
53
|
+
request.
|
|
54
|
+
|
|
55
|
+
The connector uses a customer owned internal Slack app. Slack gives internal
|
|
56
|
+
apps the larger `conversations.replies` page and rate limits needed to read a
|
|
57
|
+
thread before selecting its newest messages. The connector does not support a
|
|
58
|
+
commercially distributed Slack app outside the Slack Marketplace, because
|
|
59
|
+
Slack restricts those installations to 15 replies and one request per minute.
|
|
60
|
+
|
|
61
|
+
`channel_attach` and `channel_post_document` are not registered: `files.uploadV2`
|
|
62
|
+
and canvases are not implemented in this package yet, and the capability
|
|
63
|
+
descriptor says so rather than registering tools that fail.
|
|
64
|
+
|
|
65
|
+
None of these take a channel or thread argument. Every tool acts on the
|
|
66
|
+
conversation the task came from. Author display names (`users.info`) and
|
|
67
|
+
permalinks (`chat.getPermalink`) are resolved inside the adapter and attached to
|
|
68
|
+
message rows and reply results, so there is no user lookup or permalink tool.
|
|
69
|
+
Edit and retract also require an opaque reference for a message posted by this
|
|
70
|
+
agent. They cannot act on another author's message.
|
|
71
|
+
|
|
72
|
+
Workspace search, channel listing and joining, directory lookup, and
|
|
73
|
+
cross-channel posting are unsupported. Their contract and access model are
|
|
74
|
+
deferred to a separate proposal.
|
|
75
|
+
|
|
76
|
+
## Cloud access
|
|
77
|
+
|
|
78
|
+
The Recipe never receives the Slack bot token. The adapter sends the task
|
|
79
|
+
locator to `INTROSPECTION_EGRESS_URL`, the provider proxy inside the
|
|
80
|
+
Introspection environment, with the Slack host as the proxy route. The proxy
|
|
81
|
+
verifies and removes the locator, checks the connector's granted scope and
|
|
82
|
+
allowed path, and adds the bot token before the request leaves for Slack.
|
|
83
|
+
|
|
84
|
+
The adapter refuses to send a task locator when the provider proxy URL is
|
|
85
|
+
missing. It never falls back to sending the locator to Slack.
|
|
86
|
+
|
|
87
|
+
After `channel_reply` succeeds in cloud, the adapter posts the `connector_posted`
|
|
88
|
+
task event to the Data Plane, which checks the agent session, current run,
|
|
89
|
+
provider, and origin channel before recording the new thread root. A later Slack
|
|
90
|
+
reply then resumes the same task.
|
|
91
|
+
|
|
92
|
+
Slack writes are attempted once. The adapter does not retry `chat.postMessage`,
|
|
93
|
+
because Slack accepts no idempotency key for it. If Slack accepts the post but
|
|
94
|
+
event recording fails, the tool returns the message reference and a
|
|
95
|
+
`bridge_error`. It does not post again.
|
|
96
|
+
|
|
97
|
+
## Test with introspection dev
|
|
98
|
+
|
|
99
|
+
Run `introspection dev` from the Recipe repository. A Slack event sent to the
|
|
100
|
+
development runtime starts a cloud sandbox with the local Recipe overlay, so the
|
|
101
|
+
adapter uses the cloud task origin and provider proxy and needs no local Slack
|
|
102
|
+
credential. Use `introspection dev --logs` for sandbox logs.
|
|
103
|
+
|
|
104
|
+
## Test with introspection local
|
|
105
|
+
|
|
106
|
+
An `introspection local` run has no inbound Slack event, cloud task origin, or
|
|
107
|
+
credential proxy. Install dependencies, then set a bot token and a conversation:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pnpm install --frozen-lockfile
|
|
111
|
+
export SLACK_BOT_TOKEN='xoxb-...'
|
|
112
|
+
export SLACK_CHANNEL_ID='C0123456789'
|
|
113
|
+
export SLACK_THREAD_TS='1234567890.123456' # optional
|
|
114
|
+
introspection local -p 'Summarise this thread and reply.'
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Local tools call Slack directly with `SLACK_BOT_TOKEN`. Local posts create no
|
|
118
|
+
inbound task or reply bridge, because no Data Plane task exists.
|
|
119
|
+
|
|
120
|
+
## File downloads
|
|
121
|
+
|
|
122
|
+
`channel_fetch_file` writes a file under the task files directory and returns its
|
|
123
|
+
path, media type, size, and SHA-256 digest. The bytes land in the workspace and
|
|
124
|
+
not in model context. It accepts only a `file_…` handle from a `channel_read`
|
|
125
|
+
attachment, so the bot's cross-channel file read is not reachable from model
|
|
126
|
+
input. On the wire it accepts only `files.slack.com` download URLs, rejects
|
|
127
|
+
redirects, caps the body at 100 MiB, checks the declared size, and removes
|
|
128
|
+
partial files after a failure. The `video_low` variant uses Slack's smaller MP4
|
|
129
|
+
rendition when one exists.
|
|
130
|
+
|
|
131
|
+
## Direct host use
|
|
132
|
+
|
|
133
|
+
The package exports `SlackChannelAdapter`, `createSlackChannelSession` and
|
|
134
|
+
`slackChannelTarget` for custom hosts and tests, alongside the default
|
|
135
|
+
`slackRecipeConnectorModule`. A normal Recipe uses `pi.connectors` instead.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@introspection-ai/recipes",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.1",
|
|
4
4
|
"description": "The open format for vertical agents, built on Pi.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -58,6 +58,10 @@
|
|
|
58
58
|
"types": "./dist/api/session.d.ts",
|
|
59
59
|
"import": "./dist/api/session.js"
|
|
60
60
|
},
|
|
61
|
+
"./channels": {
|
|
62
|
+
"types": "./dist/channels/index.d.ts",
|
|
63
|
+
"import": "./dist/channels/index.js"
|
|
64
|
+
},
|
|
61
65
|
"./test-utils": {
|
|
62
66
|
"types": "./dist/test-utils.d.ts",
|
|
63
67
|
"import": "./dist/test-utils.js"
|
|
@@ -87,10 +91,10 @@
|
|
|
87
91
|
"typebox": "*"
|
|
88
92
|
},
|
|
89
93
|
"devDependencies": {
|
|
90
|
-
"@earendil-works/pi-agent-core": "0.84.
|
|
91
|
-
"@earendil-works/pi-ai": "0.84.
|
|
92
|
-
"@earendil-works/pi-coding-agent": "0.84.
|
|
93
|
-
"@earendil-works/pi-tui": "0.84.
|
|
94
|
+
"@earendil-works/pi-agent-core": "0.84.3",
|
|
95
|
+
"@earendil-works/pi-ai": "0.84.3",
|
|
96
|
+
"@earendil-works/pi-coding-agent": "0.84.3",
|
|
97
|
+
"@earendil-works/pi-tui": "0.84.3",
|
|
94
98
|
"@types/node": "^26.1.2",
|
|
95
99
|
"esbuild": "^0.28.1",
|
|
96
100
|
"typebox": "^1.0.56",
|
|
@@ -98,19 +102,20 @@
|
|
|
98
102
|
"vitest": "^4.0.18"
|
|
99
103
|
},
|
|
100
104
|
"optionalDependencies": {
|
|
101
|
-
"@introspection-ai/mcp-client-linux-x64": "0.
|
|
102
|
-
"@introspection-ai/mcp-client-linux-arm64": "0.
|
|
103
|
-
"@introspection-ai/mcp-client-darwin-arm64": "0.
|
|
104
|
-
"@introspection-ai/mcp-client-darwin-x64": "0.
|
|
105
|
+
"@introspection-ai/mcp-client-linux-x64": "0.22.1",
|
|
106
|
+
"@introspection-ai/mcp-client-linux-arm64": "0.22.1",
|
|
107
|
+
"@introspection-ai/mcp-client-darwin-arm64": "0.22.1",
|
|
108
|
+
"@introspection-ai/mcp-client-darwin-x64": "0.22.1"
|
|
105
109
|
},
|
|
106
110
|
"scripts": {
|
|
107
111
|
"build": "pnpm build:ts && pnpm build:native",
|
|
108
|
-
"build:
|
|
112
|
+
"build:workspace-packages": "pnpm --filter './packages/**' build",
|
|
113
|
+
"build:ts": "rm -rf dist && tsc && node scripts/build-mcp-daemon.mjs && pnpm build:workspace-packages",
|
|
109
114
|
"build:native": "cargo build --release -p pi-mcp-client && node scripts/package-mcp-client.mjs",
|
|
110
115
|
"bench:mcp-client": "pnpm build:ts && cargo build --release -p pi-mcp-client && node scripts/benchmark-mcp-client.mjs",
|
|
111
|
-
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
|
|
116
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json && pnpm --filter './packages/**' typecheck",
|
|
112
117
|
"test": "pnpm build:ts && cargo test -p pi-mcp-client -p introspection-recipe-check && cargo build -p pi-mcp-client && MCP_CLIENT_BIN=target/debug/mcp-client node scripts/package-mcp-client.mjs && vitest run",
|
|
113
|
-
"pack:check": "pnpm pack --dry-run --json | node scripts/check-npm-pack.mjs",
|
|
118
|
+
"pack:check": "pnpm pack --dry-run --json | node scripts/check-npm-pack.mjs && pnpm --filter './packages/**' pack:check",
|
|
114
119
|
"clean": "rm -rf dist .turbo node_modules target vendor/mcp-client"
|
|
115
120
|
}
|
|
116
121
|
}
|