@introspection-ai/recipes 0.22.1 → 0.24.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.
- package/README.md +1 -1
- package/dist/api/memory.d.ts +3 -0
- package/dist/api/memory.d.ts.map +1 -0
- package/dist/api/memory.js +2 -0
- package/dist/api/memory.js.map +1 -0
- package/dist/api/session.d.ts +1 -0
- package/dist/api/session.d.ts.map +1 -1
- package/dist/channels/config.d.ts +10 -0
- package/dist/channels/config.d.ts.map +1 -0
- package/dist/channels/config.js +13 -0
- package/dist/channels/config.js.map +1 -0
- package/dist/channels/index.d.ts +4 -2
- package/dist/channels/index.d.ts.map +1 -1
- package/dist/channels/index.js +2 -1
- package/dist/channels/index.js.map +1 -1
- package/dist/channels/module.d.ts +11 -6
- package/dist/channels/module.d.ts.map +1 -1
- package/dist/channels/module.js +22 -10
- package/dist/channels/module.js.map +1 -1
- package/dist/channels/refs.d.ts +3 -3
- package/dist/channels/refs.d.ts.map +1 -1
- package/dist/channels/refs.js +11 -8
- package/dist/channels/refs.js.map +1 -1
- package/dist/channels/tools.d.ts +15 -22
- package/dist/channels/tools.d.ts.map +1 -1
- package/dist/channels/tools.js +279 -114
- package/dist/channels/tools.js.map +1 -1
- package/dist/channels/types.d.ts +34 -29
- package/dist/channels/types.d.ts.map +1 -1
- package/dist/channels/types.js +4 -17
- package/dist/channels/types.js.map +1 -1
- package/dist/child-session.d.ts +3 -0
- package/dist/child-session.d.ts.map +1 -1
- package/dist/child-session.js +4 -0
- package/dist/child-session.js.map +1 -1
- package/dist/connector-tools.d.ts +2 -0
- package/dist/connector-tools.d.ts.map +1 -1
- package/dist/connector-tools.js +17 -15
- package/dist/connector-tools.js.map +1 -1
- package/dist/mcp-chunks/{chunk-JZDXKYQM.js → chunk-PLSS6TQZ.js} +6 -1
- package/dist/mcp-daemon.js +1 -1
- package/dist/mcp-run-worker.js +1 -1
- package/dist/memory.d.ts +40 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +146 -0
- package/dist/memory.js.map +1 -0
- package/dist/recipe-package.d.ts +4 -2
- package/dist/recipe-package.d.ts.map +1 -1
- package/dist/recipe-package.js +31 -18
- package/dist/recipe-package.js.map +1 -1
- package/dist/run-controller.d.ts +3 -0
- package/dist/run-controller.d.ts.map +1 -1
- package/dist/run-controller.js +4 -0
- package/dist/run-controller.js.map +1 -1
- package/dist/session.d.ts +5 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +26 -4
- package/dist/session.js.map +1 -1
- package/docs/channels.md +171 -58
- package/docs/host-api.md +21 -0
- package/docs/pi-extension.md +1 -1
- package/docs/recipe-format.md +9 -7
- package/docs/slack.md +46 -53
- package/package.json +9 -5
package/docs/channels.md
CHANGED
|
@@ -1,90 +1,186 @@
|
|
|
1
1
|
# Channel tools
|
|
2
2
|
|
|
3
3
|
A Recipe that answers a chat message declares a **channel connector**. The host
|
|
4
|
-
then registers
|
|
5
|
-
for every provider
|
|
4
|
+
then registers one `channels` tool with a `command` discriminator, shaped identically
|
|
5
|
+
for every provider. Reply defaults to the origin; adapters can opt into explicit
|
|
6
|
+
read/send destinations within the same credential session.
|
|
6
7
|
|
|
7
8
|
Two properties follow from that, and both are structural rather than
|
|
8
9
|
conventional:
|
|
9
10
|
|
|
10
|
-
- **
|
|
11
|
-
channel
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
walks every registered tool's input schema.
|
|
15
|
-
- **A tool that the provider cannot support is absent, not failing.** Each
|
|
11
|
+
- **Explicit targeting is a capability.** `targeting: true` adds `channels send`
|
|
12
|
+
and channel/thread arguments to `channels read`. Adapters without it retain
|
|
13
|
+
bound schemas. Reply, attach, and document tools still use the origin.
|
|
14
|
+
- **A command that the provider cannot support is absent, not failing.** Each
|
|
16
15
|
adapter declares a capability descriptor, and registration filters on it.
|
|
17
|
-
For example, an adapter with no history API has no `
|
|
16
|
+
For example, an adapter with no history API has no `read` command.
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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.
|
|
18
|
+
Agents select `tools: [channels]`. By default this exposes all operations supported
|
|
19
|
+
by the adapter. To restrict commands for the recipe, set an allowlist on the
|
|
20
|
+
connector in `package.json`:
|
|
27
21
|
|
|
28
|
-
|
|
22
|
+
```json
|
|
23
|
+
{"pi":{"channels":[{"provider":"slack","commands":["list","read","reply"]}]}}
|
|
24
|
+
```
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
The allowlist applies to all agents using this connector; an empty list exposes
|
|
27
|
+
no channel tool. Unknown or unsupported commands fail at registration. Commands
|
|
28
|
+
outside the allowlist and invalid command arguments are rejected before provider
|
|
29
|
+
calls. The host API uses `registerChannelTools(..., { commands: [...] })` for the
|
|
30
|
+
same restriction.
|
|
31
|
+
|
|
32
|
+
### Required replies
|
|
33
|
+
|
|
34
|
+
`requireReply` defaults to `true` when channel tools are enabled: inbound turns
|
|
35
|
+
must deliver a successful final `reply`. Set `requireReply: false` explicitly to
|
|
36
|
+
opt out, for example for a read-only command allowlist. UI and automation turns
|
|
37
|
+
without an origin are unaffected. Disabled channel tools remain disabled;
|
|
38
|
+
an enabled connector with required replies must expose `reply`.
|
|
39
|
+
|
|
40
|
+
`reply` accepts `final` (default `true`). Use `final: false` for progress updates.
|
|
41
|
+
Only a successful final reply satisfies the guard, not reactions or explicit
|
|
42
|
+
sends. The extension adds delivery instructions and queues one corrective
|
|
43
|
+
follow-up if the agent finishes without replying. If that also finishes without
|
|
44
|
+
a reply, a visible `channel-delivery-failed` message records the failure locally.
|
|
45
|
+
It never automatically publishes private assistant text. Aborted and provider-error
|
|
46
|
+
runs are not retried by this guard. Hosts must wait for `agent_settled`, not an
|
|
47
|
+
intermediate `agent_end`, before declaring a run complete.
|
|
48
|
+
|
|
49
|
+
Migration: rename `pi.connectors` to `pi.channels`, replace agent `channel_*` tool names with `channels`, and move any
|
|
50
|
+
operation restrictions to `commands` (without the `channel_` prefix). This is a
|
|
51
|
+
breaking interface change; old individual tool names are not registered.
|
|
52
|
+
|
|
53
|
+
Before each agent run, the extension adds origin metadata to the system prompt:
|
|
54
|
+
provider, channel/thread IDs, conversation scope, and optional name/permalink.
|
|
55
|
+
Labels are untrusted metadata; normal assistant output is not delivered to the
|
|
56
|
+
channel. Recipe instructions decide when to reply, stay silent, read history,
|
|
57
|
+
or send elsewhere; tool descriptions explain how.
|
|
58
|
+
|
|
59
|
+
User messages are not rewritten. Cloud ingress retains per-message `from`,
|
|
60
|
+
`message_id`, and `sent_at` attribution. Legacy custom origin entries are
|
|
61
|
+
filtered from model context when resuming older sessions.
|
|
62
|
+
For required replies, the single corrective reminder repeats the origin metadata
|
|
63
|
+
so a failed or omitted delivery can be retried against the correct destination.
|
|
64
|
+
An uncertain delivery must be checked before retrying to avoid duplicates.
|
|
65
|
+
Origin fields are JSON inside a single `<channel_context>` wrapper. JSON Unicode
|
|
66
|
+
escapes for `<`, `>`, and `&` keep provider labels from breaking the wrapper while
|
|
67
|
+
preserving valid JSON and the original values when parsed.
|
|
68
|
+
|
|
69
|
+
The context message is not an authorization boundary. Tools continue to resolve
|
|
70
|
+
the origin from host state, never from message text, and validate explicit targets
|
|
71
|
+
through the host's policy. Non-channel triggers receive no channel context.
|
|
72
|
+
|
|
73
|
+
## Test channel recipes
|
|
74
|
+
|
|
75
|
+
Use `introspection dev` to test local recipe files through the platform's
|
|
76
|
+
provider proxy. Standalone `SLACK_BOT_TOKEN` credentials and local destination
|
|
77
|
+
aliases are no longer supported. Originless web and automation runs can still
|
|
78
|
+
use explicit channel targets with the connected provider credentials.
|
|
79
|
+
|
|
80
|
+
## Commands
|
|
81
|
+
|
|
82
|
+
| Command (`channels` + `command`) | Additional arguments | Requires |
|
|
31
83
|
| --- | --- | --- |
|
|
32
|
-
| `
|
|
33
|
-
| `
|
|
34
|
-
| `
|
|
35
|
-
| `
|
|
36
|
-
| `
|
|
37
|
-
| `
|
|
38
|
-
| `
|
|
39
|
-
| `
|
|
40
|
-
|
|
41
|
-
`
|
|
42
|
-
|
|
43
|
-
|
|
84
|
+
| `channels reply` | `text` (Markdown), `final?` (default `true`) | always |
|
|
85
|
+
| `channels send` | `channel_id`, `thread_id?`, `text` | `targeting` |
|
|
86
|
+
| `channels list` | none | `list` |
|
|
87
|
+
| `channels read` | `channel_id?`, `thread_id?`, `limit?`, `cursor?` | `read`; addressing requires `targeting` |
|
|
88
|
+
| `channels react` | `message`, `emoji`, `action?` (`add` or `remove`) | `react` |
|
|
89
|
+
| `channels edit` | `message`, `text` | `edit` |
|
|
90
|
+
| `channels retract` | `message` | `retract` |
|
|
91
|
+
| `channels attach` | `path`, `title?`, `comment?` | `attach` |
|
|
92
|
+
| `channels fetch_file` | `file` (a `file_…` handle), `variant?` | `fetch_file` |
|
|
93
|
+
| `channels post_document` | `title`, `markdown` | `documents` |
|
|
94
|
+
|
|
95
|
+
`channels` is active immediately. Its command schema includes only supported,
|
|
96
|
+
allowed operations; no tool search is needed.
|
|
44
97
|
|
|
45
98
|
Reply content is **Markdown**. Each adapter renders it in the provider's own
|
|
46
99
|
format. There is no raw provider payload because the same tool contract must
|
|
47
100
|
work with every adapter.
|
|
48
101
|
|
|
102
|
+
### Targets and pagination
|
|
103
|
+
|
|
104
|
+
- `channels({command: "list"})` returns the channels available to the provider credential session.
|
|
105
|
+
- `channels({command: "read"})` reads the origin conversation.
|
|
106
|
+
- `channels({command: "read", channel_id: "C2"})` reads that channel's timeline.
|
|
107
|
+
- `channels({command: "read", channel_id: "C2", thread_id: "123.4"})` reads that thread.
|
|
108
|
+
- `channels({command: "read", thread_id: null})` reads the origin channel timeline.
|
|
109
|
+
- `channels({command: "send", channel_id: "C2", text: "Update"})` posts at channel level;
|
|
110
|
+
supplying `thread_id` posts inside that thread.
|
|
111
|
+
|
|
112
|
+
An explicit channel does not require an origin, but still requires a working
|
|
113
|
+
provider credential. Sending/reading never changes `channels reply`'s origin.
|
|
114
|
+
Thread IDs are provider-native roots/topics, not opaque message handles or
|
|
115
|
+
generic quoted-reply IDs. Quoted replies are not introduced in this first pass.
|
|
116
|
+
|
|
117
|
+
Read results include `target`, optional message `thread_id`/`reply_count`, and
|
|
118
|
+
`next_direction` when the adapter supplies it. Pages are chronological. Repeat
|
|
119
|
+
the same target with a cursor; cross-target cursors fail. Page size may change.
|
|
120
|
+
|
|
121
|
+
### Access boundary
|
|
122
|
+
|
|
123
|
+
Each adapter and reference store belongs to **one credential session**. Never
|
|
124
|
+
reuse either across installations. The connector loader creates fresh instances.
|
|
125
|
+
No model argument switches credentials or customer connections.
|
|
126
|
+
|
|
127
|
+
Hosts can supply `validateTarget(target, operation)` on a connector session or
|
|
128
|
+
to `registerChannelTools`. It runs for every operation, including mutations and
|
|
129
|
+
file downloads using existing references. Without it, explicit targets rely on
|
|
130
|
+
the existing credential's provider permissions.
|
|
131
|
+
|
|
132
|
+
This is a **tool-layer policy, not a sandbox-wide security boundary**. Direct
|
|
133
|
+
shell/API calls can bypass it if the sandbox has broader credentials. Binding
|
|
134
|
+
enforcement, credential selection, durable receipts, and cross-channel reply
|
|
135
|
+
routing are separate platform work. Sending elsewhere does not imply that
|
|
136
|
+
subsequent replies resume the originating task.
|
|
137
|
+
|
|
49
138
|
### Message and file references
|
|
50
139
|
|
|
51
|
-
`
|
|
140
|
+
`channels react`, `channels edit`, and `channels retract` take a `message`, which is
|
|
52
141
|
an opaque handle minted by the host for the current session. It is not a Slack
|
|
53
142
|
timestamp or another provider message ID. Handles come back from
|
|
54
|
-
`
|
|
143
|
+
`channels reply`, `channels send`, and `channels read`, so the model can only act on a message that
|
|
55
144
|
a channel tool returned.
|
|
56
145
|
|
|
57
|
-
`
|
|
146
|
+
`channels react` adds a reaction when `action` is omitted. Set `action` to
|
|
58
147
|
`remove` to remove the agent's reaction with the same emoji.
|
|
59
148
|
|
|
60
149
|
Edit and retract have an extra check. They accept only a handle for a message
|
|
61
150
|
that this agent posted. Reading the same message again keeps its original
|
|
62
151
|
handle and authorship record.
|
|
152
|
+
Each reference resolves its own destination. Handles are session-local; editing
|
|
153
|
+
a previous session's message is not supported.
|
|
63
154
|
|
|
64
|
-
`
|
|
155
|
+
`channels fetch_file` works the same way. Attachments returned by `channels read`
|
|
65
156
|
carry a `file_…` handle, and that is the only value the tool accepts. A bot can
|
|
66
157
|
usually read files from every conversation it belongs to, so accepting a raw
|
|
67
|
-
provider file ID would
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
158
|
+
provider file ID would bypass the requirement to observe the file first.
|
|
159
|
+
File handles also retain the channel/thread read scope where they were observed.
|
|
160
|
+
Fetching revalidates that scope; observing the same file through another scope
|
|
161
|
+
creates a separate handle rather than changing the authority of an earlier one.
|
|
162
|
+
|
|
163
|
+
### Listing and enrichment
|
|
164
|
+
|
|
165
|
+
`channels list` returns provider channel IDs and names for explicitly targeted
|
|
166
|
+
reads and sends. When the host supplies `validateTarget`, every listed channel
|
|
167
|
+
is checked with the `list` operation and denied entries are omitted before any
|
|
168
|
+
IDs or names become model-visible. Author names and permalinks are resolved by the adapter in trusted code and
|
|
169
|
+
attached to what the agent is already reading: `channels read` rows carry
|
|
170
|
+
`author.display_name`, and `channels reply` returns a `permalink` where the
|
|
74
171
|
provider has one. There is no `resolve_user` or `get_permalink` tool, because
|
|
75
172
|
each would require another model turn. Each lookup would also take an
|
|
76
173
|
addressing argument.
|
|
77
174
|
|
|
78
175
|
### Unsupported operations
|
|
79
176
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
concrete use case requires them.
|
|
177
|
+
Search, individual channel-info lookup, thread listing, channel joining, and directory
|
|
178
|
+
lookup are deferred. Explicit IDs can come from task context; thread IDs can
|
|
179
|
+
also come from channel reads.
|
|
84
180
|
|
|
85
181
|
Typing indicators and presence are runtime effects rather than model decisions.
|
|
86
|
-
Streaming controls how a reply is delivered.
|
|
87
|
-
|
|
182
|
+
Streaming controls how a reply is delivered. These tools do not add durable
|
|
183
|
+
send idempotency or claim exactly-once delivery.
|
|
88
184
|
|
|
89
185
|
## Declare a channel connector
|
|
90
186
|
|
|
@@ -94,7 +190,7 @@ keys, and the webhook already removes duplicate inbound events.
|
|
|
94
190
|
"@introspection-ai/recipe-channel-slack": "^0.1.0"
|
|
95
191
|
},
|
|
96
192
|
"pi": {
|
|
97
|
-
"
|
|
193
|
+
"channels": [
|
|
98
194
|
{
|
|
99
195
|
"provider": "slack"
|
|
100
196
|
}
|
|
@@ -103,11 +199,11 @@ keys, and the webhook already removes duplicate inbound events.
|
|
|
103
199
|
}
|
|
104
200
|
```
|
|
105
201
|
|
|
106
|
-
The
|
|
202
|
+
The channel declaration enables the provider package and its supported tool
|
|
107
203
|
catalog. The agent YAML file is the only place that narrows the catalog:
|
|
108
204
|
|
|
109
205
|
```yaml
|
|
110
|
-
tools: [
|
|
206
|
+
tools: [channels]
|
|
111
207
|
```
|
|
112
208
|
|
|
113
209
|
The host fails when an agent selects a tool that the provider does not support.
|
|
@@ -120,13 +216,15 @@ Each provider package declares the capabilities that it can support.
|
|
|
120
216
|
|
|
121
217
|
An adapter supplies transport and a capability descriptor. It writes no tool
|
|
122
218
|
schemas. The shared schema keeps providers from defining different forms of
|
|
123
|
-
the same operation
|
|
124
|
-
|
|
219
|
+
the same operation. Set `targeting: true` and implement `send(ctx, {text})` to
|
|
220
|
+
opt into the shared targeting schema; set `list: true` and implement `list()` to
|
|
221
|
+
expose `channels list`. Omit these capabilities for origin-bound tools.
|
|
125
222
|
|
|
126
223
|
```ts
|
|
127
224
|
import {
|
|
128
225
|
createChannelConnectorModule,
|
|
129
226
|
type ChannelAdapter,
|
|
227
|
+
type ChannelConfig,
|
|
130
228
|
} from "@introspection-ai/recipes/channels";
|
|
131
229
|
|
|
132
230
|
const capabilities = {
|
|
@@ -143,24 +241,39 @@ class MyAdapter implements ChannelAdapter {
|
|
|
143
241
|
async retract(ctx, { ref }) { /* retract an agent-authored message */ }
|
|
144
242
|
}
|
|
145
243
|
|
|
244
|
+
function targetFrom(config: ChannelConfig | null) {
|
|
245
|
+
if (!config || config.provider !== "my-channel") {
|
|
246
|
+
throw new Error("No my-channel destination is configured");
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
provider: "my-channel",
|
|
250
|
+
conversation: config.channel_ref,
|
|
251
|
+
thread: config.thread_ref,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
146
255
|
export default createChannelConnectorModule({
|
|
147
256
|
provider: "my-channel",
|
|
148
257
|
capabilities,
|
|
149
|
-
createSession: ({ env }) => ({
|
|
258
|
+
createSession: ({ config, env }) => ({
|
|
150
259
|
adapter: new MyAdapter(/* client from env */),
|
|
151
260
|
// A function, so a task with no channel origin still starts: the tools
|
|
152
261
|
// fail when called, the session does not fail to open.
|
|
153
|
-
target: () =>
|
|
262
|
+
target: () => targetFrom(config),
|
|
154
263
|
}),
|
|
155
264
|
});
|
|
156
265
|
```
|
|
157
266
|
|
|
267
|
+
The host resolves `ChannelConfig` once from the `INTROSPECTION_TASK_CHANNEL_*`
|
|
268
|
+
environment contract. Provider packages map `channel_ref` and `thread_ref` to
|
|
269
|
+
their own API fields and do not define provider-specific origin types.
|
|
270
|
+
|
|
158
271
|
Registration checks that the adapter implements every method its capabilities
|
|
159
272
|
claim, so a descriptor cannot promise a tool the adapter does not have.
|
|
160
273
|
|
|
161
|
-
The result is an ordinary `RecipeConnectorModule`. Manifest validation
|
|
162
|
-
tool selection
|
|
163
|
-
|
|
274
|
+
The result is an ordinary `RecipeConnectorModule`. Manifest validation and agent
|
|
275
|
+
tool selection work without provider-specific code in the Recipe. The unified
|
|
276
|
+
tool is active immediately and does not require `tool_search`.
|
|
164
277
|
|
|
165
278
|
## Provider pages
|
|
166
279
|
|
package/docs/host-api.md
CHANGED
|
@@ -70,6 +70,10 @@ const handle = await createAgentSession({
|
|
|
70
70
|
sessionManager,
|
|
71
71
|
additionalSkillPaths,
|
|
72
72
|
materializedSkillPaths,
|
|
73
|
+
memory: {
|
|
74
|
+
indexPath: "/workspace/memories/MEMORY.md",
|
|
75
|
+
},
|
|
76
|
+
memoryOverride,
|
|
73
77
|
transformSystemPrompt,
|
|
74
78
|
onDiagnostics,
|
|
75
79
|
onEvent,
|
|
@@ -109,6 +113,23 @@ gateway-decorated model without reimplementing Recipe semantics. The Recipe
|
|
|
109
113
|
continues to own model configuration and tool selection; host seams replace
|
|
110
114
|
transport and materialized resources, not the portable definition.
|
|
111
115
|
|
|
116
|
+
### Persistent memory context
|
|
117
|
+
|
|
118
|
+
Hosts can provide one durable memory index through `memory`. Recipes loads the
|
|
119
|
+
index once during session construction and bounds the injected index content to
|
|
120
|
+
200 lines and 25,000 UTF-8 bytes after XML escaping by default. Missing and
|
|
121
|
+
empty indexes render nothing. The host owns the directory, persistence, and
|
|
122
|
+
identity scope; Recipes assumes no filesystem layout.
|
|
123
|
+
|
|
124
|
+
The index should stay concise and can link to focused files in its directory.
|
|
125
|
+
Recipes injects it without adding usage or precedence instructions.
|
|
126
|
+
|
|
127
|
+
`memoryOverride` follows Pi's resource override pattern. It can replace, filter,
|
|
128
|
+
or disable the loaded index before rendering. The exported `loadMemoryIndex`
|
|
129
|
+
and `formatMemoryForPrompt` helpers let custom hosts use the same primitives.
|
|
130
|
+
Recipe-specific memory behavior belongs in `SYSTEM.md` or agent
|
|
131
|
+
`system_instructions`, while the host binds the actual memory resource.
|
|
132
|
+
|
|
112
133
|
The default in-process subagent controller uses that same Recipe snapshot for
|
|
113
134
|
every child, so no session reparses the package or observes a different source
|
|
114
135
|
snapshot. Injected controllers own child selection and execution after the root
|
package/docs/pi-extension.md
CHANGED
|
@@ -53,7 +53,7 @@ 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 providers from `pi.
|
|
56
|
+
4. loads providers from `pi.channels` and registers the tools selected by the agent;
|
|
57
57
|
5. loads selected skills, package prompts, and the complete Recipe extension closure;
|
|
58
58
|
6. materializes declared MCP bindings from host or local configuration;
|
|
59
59
|
7. exposes only the declared subagents through the shared `agent` tool.
|
package/docs/recipe-format.md
CHANGED
|
@@ -81,9 +81,9 @@ 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
|
-
##
|
|
84
|
+
## Channel tools
|
|
85
85
|
|
|
86
|
-
`pi.
|
|
86
|
+
`pi.channels` declares official provider tools that the host may register for
|
|
87
87
|
the Recipe. The declaration does not contain a connector ID, workspace ID, or
|
|
88
88
|
credential. A host binds those values when it starts a task.
|
|
89
89
|
|
|
@@ -93,7 +93,7 @@ credential. A host binds those values when it starts a task.
|
|
|
93
93
|
"@introspection-ai/recipe-channel-slack": "^0.1.0"
|
|
94
94
|
},
|
|
95
95
|
"pi": {
|
|
96
|
-
"
|
|
96
|
+
"channels": [
|
|
97
97
|
{
|
|
98
98
|
"provider": "slack"
|
|
99
99
|
}
|
|
@@ -109,13 +109,15 @@ and marks which tools are active by default.
|
|
|
109
109
|
|
|
110
110
|
The provider package must be in the Recipe's production dependencies and
|
|
111
111
|
lockfile. The host imports the package only when the Recipe declares the
|
|
112
|
-
provider.
|
|
113
|
-
|
|
114
|
-
`channel_reply`, in its `tools` list. The host fails when the agent names a
|
|
112
|
+
provider. An agent lists each allowed tool by its full name, such as
|
|
113
|
+
`channels`, in its `tools` list. The host fails when the agent names a
|
|
115
114
|
tool that the connector does not register.
|
|
116
115
|
|
|
117
116
|
Chat providers share one connector shape. A channel connector registers the
|
|
118
|
-
provider-neutral `
|
|
117
|
+
provider-neutral `channels` tool with commands for supported operations. An
|
|
118
|
+
optional `commands` array on the connector restricts these operations for all
|
|
119
|
+
agents using it, for example `{"provider":"slack","commands":["read","reply"]}`.
|
|
120
|
+
Omitting it allows supported commands; an empty list exposes no channel tool. See
|
|
119
121
|
[Channel tools](channels.md).
|
|
120
122
|
|
|
121
123
|
## Agents
|
package/docs/slack.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
`@introspection-ai/recipe-channel-slack` is the Slack adapter for the
|
|
4
4
|
[channel tools](channels.md). It supplies Slack Web API transport and a
|
|
5
|
-
capability descriptor
|
|
6
|
-
|
|
5
|
+
capability descriptor. The `channels` tool and its command schemas are
|
|
6
|
+
provider-neutral, so a Recipe written against it is not written against Slack.
|
|
7
7
|
|
|
8
8
|
Slack sends inbound events to the existing Events API webhook. The tools make
|
|
9
9
|
ordinary HTTP requests to the Slack Web API with the bot that received the
|
|
@@ -18,7 +18,7 @@ protocol.
|
|
|
18
18
|
"@introspection-ai/recipe-channel-slack": "^0.1.0"
|
|
19
19
|
},
|
|
20
20
|
"pi": {
|
|
21
|
-
"
|
|
21
|
+
"channels": [
|
|
22
22
|
{
|
|
23
23
|
"provider": "slack"
|
|
24
24
|
}
|
|
@@ -30,48 +30,48 @@ protocol.
|
|
|
30
30
|
Commit the package manager lockfile. The host loads the package only for a
|
|
31
31
|
Recipe that declares the connector.
|
|
32
32
|
|
|
33
|
-
The connector
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
tools are available through `tool_search`.
|
|
33
|
+
The connector registers one `channels` tool. Agents select `tools: [channels]`;
|
|
34
|
+
all supported commands are immediately visible. An optional connector `commands`
|
|
35
|
+
allowlist restricts operations for every agent using that connector.
|
|
37
36
|
|
|
38
37
|
## What Slack registers
|
|
39
38
|
|
|
40
39
|
| Tool | Slack operation |
|
|
41
40
|
| --- | --- |
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
| `
|
|
47
|
-
| `
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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`
|
|
41
|
+
| `channels reply` | `chat.postMessage` into the origin channel and thread |
|
|
42
|
+
| `channels send` | `chat.postMessage` into an explicit channel and optional thread |
|
|
43
|
+
| `channels list` | paged `conversations.list` returning accessible channels |
|
|
44
|
+
| `channels read` | `conversations.replies` in a thread, else `conversations.history` |
|
|
45
|
+
| `channels react` | `reactions.add` or `reactions.remove` |
|
|
46
|
+
| `channels edit` | `chat.update` for a message the agent posted |
|
|
47
|
+
| `channels retract` | `chat.delete` for a message the agent posted |
|
|
48
|
+
| `channels fetch_file` | `files.info` plus a private file download |
|
|
49
|
+
|
|
50
|
+
Slack history requests at most 15 messages and makes one history request per
|
|
51
|
+
tool call. Threads start at the beginning and page forward; channel timelines
|
|
52
|
+
start with recent messages and page backward. Each page is chronological, and
|
|
53
|
+
`next_direction` describes pagination. Repeat the target with the cursor.
|
|
54
|
+
This replaces the old unbounded full-thread fetch/backward session cache.
|
|
55
|
+
Provider rate limits still apply; failures are not automatically retried.
|
|
56
|
+
|
|
57
|
+
`channels attach` and `channels post_document` are not registered: `files.uploadV2`
|
|
62
58
|
and canvases are not implemented in this package yet, and the capability
|
|
63
59
|
descriptor says so rather than registering tools that fail.
|
|
64
60
|
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
`channels list` returns all non-archived public and private channels where the
|
|
62
|
+
bot is a member. `channels send` requires an explicit `channel_id` (listing first is not required); `thread_id` is
|
|
63
|
+
optional. `channels read` accepts optional targets, defaulting to the origin. Explicit channel without
|
|
64
|
+
thread means timeline/top-level, not the origin's thread. Reply stays bound.
|
|
65
|
+
Author display names (`users.info`) and
|
|
67
66
|
permalinks (`chat.getPermalink`) are resolved inside the adapter and attached to
|
|
68
67
|
message rows and reply results, so there is no user lookup or permalink tool.
|
|
69
68
|
Edit and retract also require an opaque reference for a message posted by this
|
|
70
69
|
agent. They cannot act on another author's message.
|
|
71
70
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
Search, individual channel-info lookup, joining, and directory lookup remain deferred.
|
|
72
|
+
Tools use one existing credential session; they do not select installations or
|
|
73
|
+
enforce project/customer bindings. The optional host target-policy callback
|
|
74
|
+
constrains these tools, not direct shell/API access.
|
|
75
75
|
|
|
76
76
|
## Cloud access
|
|
77
77
|
|
|
@@ -84,11 +84,16 @@ allowed path, and adds the bot token before the request leaves for Slack.
|
|
|
84
84
|
The adapter refuses to send a task locator when the provider proxy URL is
|
|
85
85
|
missing. It never falls back to sending the locator to Slack.
|
|
86
86
|
|
|
87
|
-
After `
|
|
87
|
+
After `channels reply` succeeds in cloud, the adapter posts the `connector_posted`
|
|
88
88
|
task event to the Data Plane, which checks the agent session, current run,
|
|
89
89
|
provider, and origin channel before recording the new thread root. A later Slack
|
|
90
90
|
reply then resumes the same task.
|
|
91
91
|
|
|
92
|
+
`channels send` deliberately does not emit this origin-bound bridge event, even
|
|
93
|
+
when its explicit destination matches the origin. Its result includes the
|
|
94
|
+
actual target and `bridge_recorded: false`. Cross-channel continuation is not
|
|
95
|
+
implemented by this tools-only change.
|
|
96
|
+
|
|
92
97
|
Slack writes are attempted once. The adapter does not retry `chat.postMessage`,
|
|
93
98
|
because Slack accepts no idempotency key for it. If Slack accepts the post but
|
|
94
99
|
event recording fails, the tool returns the message reference and a
|
|
@@ -101,29 +106,17 @@ development runtime starts a cloud sandbox with the local Recipe overlay, so the
|
|
|
101
106
|
adapter uses the cloud task origin and provider proxy and needs no local Slack
|
|
102
107
|
credential. Use `introspection dev --logs` for sandbox logs.
|
|
103
108
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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.
|
|
109
|
+
Standalone channel access through `introspection local` is not supported. It
|
|
110
|
+
has no webhook receiver, cloud task origin, or provider proxy. Use the same
|
|
111
|
+
`introspection dev` workflow for inbound events and outbound channel tools.
|
|
119
112
|
|
|
120
113
|
## File downloads
|
|
121
114
|
|
|
122
|
-
`
|
|
115
|
+
`channels fetch_file` writes a file under the task files directory and returns its
|
|
123
116
|
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 `
|
|
125
|
-
attachment,
|
|
126
|
-
|
|
117
|
+
not in model context. It accepts only a `file_…` handle from a `channels read`
|
|
118
|
+
attachment, and resolves that reference's channel before the host policy check.
|
|
119
|
+
On the wire it accepts only `files.slack.com` download URLs, rejects
|
|
127
120
|
redirects, caps the body at 100 MiB, checks the declared size, and removes
|
|
128
121
|
partial files after a failure. The `video_low` variant uses Slack's smaller MP4
|
|
129
122
|
rendition when one exists.
|
|
@@ -132,4 +125,4 @@ rendition when one exists.
|
|
|
132
125
|
|
|
133
126
|
The package exports `SlackChannelAdapter`, `createSlackChannelSession` and
|
|
134
127
|
`slackChannelTarget` for custom hosts and tests, alongside the default
|
|
135
|
-
`slackRecipeConnectorModule`. A normal Recipe uses `pi.
|
|
128
|
+
`slackRecipeConnectorModule`. A normal Recipe uses `pi.channels` instead.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@introspection-ai/recipes",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
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
|
+
"./memory": {
|
|
62
|
+
"types": "./dist/api/memory.d.ts",
|
|
63
|
+
"import": "./dist/api/memory.js"
|
|
64
|
+
},
|
|
61
65
|
"./channels": {
|
|
62
66
|
"types": "./dist/channels/index.d.ts",
|
|
63
67
|
"import": "./dist/channels/index.js"
|
|
@@ -102,10 +106,10 @@
|
|
|
102
106
|
"vitest": "^4.0.18"
|
|
103
107
|
},
|
|
104
108
|
"optionalDependencies": {
|
|
105
|
-
"@introspection-ai/mcp-client-linux-x64": "0.
|
|
106
|
-
"@introspection-ai/mcp-client-linux-arm64": "0.
|
|
107
|
-
"@introspection-ai/mcp-client-darwin-arm64": "0.
|
|
108
|
-
"@introspection-ai/mcp-client-darwin-x64": "0.
|
|
109
|
+
"@introspection-ai/mcp-client-linux-x64": "0.24.0",
|
|
110
|
+
"@introspection-ai/mcp-client-linux-arm64": "0.24.0",
|
|
111
|
+
"@introspection-ai/mcp-client-darwin-arm64": "0.24.0",
|
|
112
|
+
"@introspection-ai/mcp-client-darwin-x64": "0.24.0"
|
|
109
113
|
},
|
|
110
114
|
"scripts": {
|
|
111
115
|
"build": "pnpm build:ts && pnpm build:native",
|