@zetaloop/chappie 0.1.0 → 0.2.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/docs/tools.md +21 -7
- package/package.json +54 -53
- package/src/broker.ts +26 -25
- package/src/instructions.md +7 -3
- package/src/server.ts +24 -9
- package/src/transfer.ts +15 -5
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ Start otunnel with this configuration and add its tunnel as a developer-mode app
|
|
|
25
25
|
pi --provider chappie --model chatgpt
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Open Pi with the Chappie provider, then ask ChatGPT to call `init`. Chappie pairs the chat with an online Pi session; the first remote operation starts its turn.
|
|
29
29
|
|
|
30
30
|
## Usage
|
|
31
31
|
|
package/docs/tools.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
| Tool | Purpose |
|
|
4
4
|
|---|---|
|
|
5
|
-
| `init` | Connect to a Pi session and read its environment,
|
|
5
|
+
| `init` | Connect to a Pi session and read its environment, tool catalog, skills, global `AGENTS.md`, and pending input. |
|
|
6
6
|
| `sessions` | List connected Pi sessions and the chat's default session. |
|
|
7
|
-
| `tools` | Read
|
|
7
|
+
| `tools` | Read complete definitions for selected active tools. |
|
|
8
8
|
| `chat` | Send an assistant message to Pi. |
|
|
9
9
|
| `call` | Run one or more tools as a Pi batch. |
|
|
10
10
|
| `read` | Read local text or images. |
|
|
@@ -13,9 +13,17 @@
|
|
|
13
13
|
| `write` | Write text to a file. |
|
|
14
14
|
| `transfer` | Copy files between ChatGPT and Pi, or export a Pi image as a file. |
|
|
15
15
|
|
|
16
|
+
## Model environment
|
|
17
|
+
|
|
18
|
+
The active model is the current ChatGPT conversation. A Pi tool that starts another `chappie/chatgpt` agent cannot create a new browser conversation, so that child waits without a model response. Subagents configured with another provider use that provider normally.
|
|
19
|
+
|
|
20
|
+
Use ChatGPT's web search, connectors, and cloud tools for remote research and cloud-side work. Chappie tools operate on local files, processes, Pi extensions, and Pi user interfaces. Pi project-memory tools access their local stores; Pi context-reduction tools do not alter the current ChatGPT conversation.
|
|
21
|
+
|
|
22
|
+
Use `chat` for progress or results that should appear in Pi. When a Pi user decision is needed, load the installed interactive tool definition with `tools` and invoke it through `call`.
|
|
23
|
+
|
|
16
24
|
## Sessions
|
|
17
25
|
|
|
18
|
-
Call `init` with `{}` to reuse the chat's session or pair with the
|
|
26
|
+
Call `init` with `{}` to reuse the chat's session or pair with the first online, unbound Pi session. A newly opened Pi session can be selected before its first user message; the first remote operation starts its Chappie provider turn.
|
|
19
27
|
|
|
20
28
|
`sessions` lists session IDs, working directories, names, and status. `ready` means the provider is accepting output, `executing` means Pi is handling an operation, and `idle` means the next operation will start a turn.
|
|
21
29
|
|
|
@@ -31,15 +39,21 @@ The optional `sessionId` on other tools selects a session for that operation. Fo
|
|
|
31
39
|
{ "path": "package.json", "sessionId": "<session-id>" }
|
|
32
40
|
```
|
|
33
41
|
|
|
34
|
-
`sessions({ sessionId })`
|
|
42
|
+
`sessions({ sessionId })` filters the online list and retrieves available input when that session is connected. The call returns immediately when the selected or bound session is offline; the saved binding is still shown, and deferred results remain available.
|
|
35
43
|
|
|
36
44
|
Several chats can select the same Pi session, and one chat can address several sessions. Defaults are saved in `chappie.state.json` under Pi's agent directory. An existing binding waits for its Pi session to reconnect; `init` with another ID selects a different target.
|
|
37
45
|
|
|
38
46
|
## Tool calls
|
|
39
47
|
|
|
40
|
-
`read`, `bash`, `edit`, and `write` accept Pi's tool parameters plus `sessionId`. Their descriptions provide the current schemas.
|
|
48
|
+
`read`, `bash`, `edit`, and `write` accept Pi's tool parameters plus `sessionId`. Their descriptions provide the current schemas. `init` lists every active tool by name with a short description. Load complete definitions for installed extension tools before calling them:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{ "names": ["ask_user", "ctx_search"] }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Omit `names` to return every active definition. Definitions already present in the current ChatGPT context can be reused without another query.
|
|
41
55
|
|
|
42
|
-
A single tool uses a one-item `calls` array. To request a batch:
|
|
56
|
+
A single extension tool uses a one-item `calls` array. To request a batch:
|
|
43
57
|
|
|
44
58
|
```json
|
|
45
59
|
{
|
|
@@ -64,7 +78,7 @@ Call `chat` to display a reply in Pi:
|
|
|
64
78
|
{ "text": "Updated the parser and its callers." }
|
|
65
79
|
```
|
|
66
80
|
|
|
67
|
-
Each call completes one assistant message. Later operations start another turn when Pi is idle.
|
|
81
|
+
Each call completes one assistant message. Later operations start another turn when Pi is idle. The result returns the target session and any new Pi input without repeating the message text.
|
|
68
82
|
|
|
69
83
|
User messages consumed by Pi accompany later Chappie replies, including images. Steering is delivered when Pi consumes it; follow-up uses Pi's normal follow-up timing.
|
|
70
84
|
|
package/package.json
CHANGED
|
@@ -1,54 +1,55 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
2
|
+
"name": "@zetaloop/chappie",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Connect ChatGPT to Pi",
|
|
5
|
+
"devDependencies": {
|
|
6
|
+
"@earendil-works/pi-ai": "^0.85.1",
|
|
7
|
+
"@earendil-works/pi-coding-agent": "^0.85.1",
|
|
8
|
+
"@types/node": "^26.5.1",
|
|
9
|
+
"typebox": "^1.3.30",
|
|
10
|
+
"typescript": "^7.0.2"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"format": "biome check --write .",
|
|
14
|
+
"check": "biome check . && tsc"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"pi-package",
|
|
18
|
+
"chatgpt",
|
|
19
|
+
"mcp"
|
|
20
|
+
],
|
|
21
|
+
"author": "zetaloop",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"packageManager": "pnpm@12.4.1",
|
|
24
|
+
"type": "module",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=26",
|
|
27
|
+
"pnpm": ">=12"
|
|
28
|
+
},
|
|
29
|
+
"pi": {
|
|
30
|
+
"extensions": [
|
|
31
|
+
"./src/index.ts"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@earendil-works/pi-ai": "*",
|
|
36
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
37
|
+
"typebox": "*"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/server": "^2.0.0",
|
|
41
|
+
"mime": "^4.1.0",
|
|
42
|
+
"zod": "^4.6.4"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"src",
|
|
46
|
+
"docs"
|
|
47
|
+
],
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "git+https://github.com/zetaloop/chappie.git"
|
|
54
|
+
}
|
|
55
|
+
}
|
package/src/broker.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import type {
|
|
5
|
-
AssistantMessage,
|
|
6
|
-
ToolCall,
|
|
7
|
-
ToolResultMessage,
|
|
8
|
-
} from "@earendil-works/pi-ai";
|
|
4
|
+
import type { ToolCall, ToolResultMessage } from "@earendil-works/pi-ai";
|
|
9
5
|
import {
|
|
10
6
|
type DeliveryRecord,
|
|
11
7
|
type ResolvedDelivery,
|
|
@@ -45,9 +41,10 @@ interface ChangeWaiter {
|
|
|
45
41
|
onAbort(): void;
|
|
46
42
|
}
|
|
47
43
|
|
|
48
|
-
export interface InitializedSession extends SessionInspection {
|
|
44
|
+
export interface InitializedSession extends Omit<SessionInspection, "tools"> {
|
|
49
45
|
globalAgents?: string;
|
|
50
46
|
inputs: SessionInput[];
|
|
47
|
+
tools: { name: string; description: string }[];
|
|
51
48
|
}
|
|
52
49
|
|
|
53
50
|
export interface InspectedSession extends SessionInspection {
|
|
@@ -55,7 +52,7 @@ export interface InspectedSession extends SessionInspection {
|
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
export interface ChatResult {
|
|
58
|
-
|
|
55
|
+
sessionId: string;
|
|
59
56
|
inputs: SessionInput[];
|
|
60
57
|
}
|
|
61
58
|
|
|
@@ -70,7 +67,6 @@ export class Broker {
|
|
|
70
67
|
readonly #ipc: IpcServer;
|
|
71
68
|
readonly #state: State;
|
|
72
69
|
readonly #sessions = new Map<string, RegisteredSession>();
|
|
73
|
-
readonly #ready = new Set<string>();
|
|
74
70
|
readonly #pending = new Map<number, PendingRequest>();
|
|
75
71
|
readonly #waiters = new Set<ChangeWaiter>();
|
|
76
72
|
#nextRequestId = 1;
|
|
@@ -102,7 +98,6 @@ export class Broker {
|
|
|
102
98
|
}
|
|
103
99
|
this.#waiters.clear();
|
|
104
100
|
this.#sessions.clear();
|
|
105
|
-
this.#ready.clear();
|
|
106
101
|
await this.#ipc.close();
|
|
107
102
|
}
|
|
108
103
|
|
|
@@ -127,7 +122,15 @@ export class Broker {
|
|
|
127
122
|
const { inspection, inputs } = await this.#inspect(target, signal);
|
|
128
123
|
const globalAgents = await this.#readGlobalAgents();
|
|
129
124
|
await this.#ackInputs(target, inputs);
|
|
130
|
-
return {
|
|
125
|
+
return {
|
|
126
|
+
...inspection,
|
|
127
|
+
tools: inspection.tools.map(({ name, description }) => ({
|
|
128
|
+
name,
|
|
129
|
+
description: description.split("\n", 1)[0] ?? description,
|
|
130
|
+
})),
|
|
131
|
+
inputs,
|
|
132
|
+
...(globalAgents ? { globalAgents } : {}),
|
|
133
|
+
};
|
|
131
134
|
}
|
|
132
135
|
|
|
133
136
|
async chat(
|
|
@@ -144,7 +147,7 @@ export class Broker {
|
|
|
144
147
|
);
|
|
145
148
|
if ("message" in result) {
|
|
146
149
|
await this.#ackInputs(target, result.inputs);
|
|
147
|
-
return {
|
|
150
|
+
return { sessionId: target, inputs: result.inputs };
|
|
148
151
|
}
|
|
149
152
|
throw new Error("Pi session returned no assistant message");
|
|
150
153
|
}
|
|
@@ -152,12 +155,20 @@ export class Broker {
|
|
|
152
155
|
async tools(
|
|
153
156
|
chatId: string,
|
|
154
157
|
sessionId: string | undefined,
|
|
158
|
+
names: string[] | undefined,
|
|
155
159
|
signal: AbortSignal,
|
|
156
160
|
): Promise<InspectedSession> {
|
|
157
161
|
const target = await this.#selectSession(chatId, sessionId, signal, false);
|
|
158
162
|
const { inspection, inputs } = await this.#inspect(target, signal);
|
|
159
163
|
await this.#ackInputs(target, inputs);
|
|
160
|
-
|
|
164
|
+
const selected = names ? new Set(names) : undefined;
|
|
165
|
+
return {
|
|
166
|
+
...inspection,
|
|
167
|
+
tools: selected
|
|
168
|
+
? inspection.tools.filter(({ name }) => selected.has(name))
|
|
169
|
+
: inspection.tools,
|
|
170
|
+
inputs,
|
|
171
|
+
};
|
|
161
172
|
}
|
|
162
173
|
|
|
163
174
|
async call(
|
|
@@ -201,8 +212,7 @@ export class Broker {
|
|
|
201
212
|
signal: AbortSignal,
|
|
202
213
|
): Promise<SessionInput[]> {
|
|
203
214
|
const target = sessionId ?? this.#state.binding(chatId);
|
|
204
|
-
if (!target) return [];
|
|
205
|
-
await this.#waitForSession(target, signal);
|
|
215
|
+
if (!target || !this.#sessions.has(target)) return [];
|
|
206
216
|
const { inputs } = await this.#inspect(target, signal);
|
|
207
217
|
await this.#ackInputs(target, inputs);
|
|
208
218
|
return inputs;
|
|
@@ -242,17 +252,10 @@ export class Broker {
|
|
|
242
252
|
): Promise<void> {
|
|
243
253
|
switch (message.type) {
|
|
244
254
|
case "sync": {
|
|
245
|
-
const previous = this.#sessions.get(message.session.id);
|
|
246
255
|
this.#sessions.set(message.session.id, {
|
|
247
256
|
description: message.session,
|
|
248
257
|
peer,
|
|
249
258
|
});
|
|
250
|
-
if (message.session.status === "ready") {
|
|
251
|
-
if (previous?.description.status !== "ready")
|
|
252
|
-
this.#ready.add(message.session.id);
|
|
253
|
-
} else {
|
|
254
|
-
this.#ready.delete(message.session.id);
|
|
255
|
-
}
|
|
256
259
|
this.#notifyChange();
|
|
257
260
|
await peer.send({
|
|
258
261
|
type: "synced",
|
|
@@ -307,9 +310,8 @@ export class Broker {
|
|
|
307
310
|
|
|
308
311
|
for (;;) {
|
|
309
312
|
const occupied = this.#state.boundSessions();
|
|
310
|
-
const candidate = [...this.#
|
|
311
|
-
(sessionId) =>
|
|
312
|
-
this.#sessions.has(sessionId) && !occupied.has(sessionId),
|
|
313
|
+
const candidate = [...this.#sessions.keys()].find(
|
|
314
|
+
(sessionId) => !occupied.has(sessionId),
|
|
313
315
|
);
|
|
314
316
|
if (candidate) {
|
|
315
317
|
await this.#state.setBinding(chatId, candidate);
|
|
@@ -427,7 +429,6 @@ export class Broker {
|
|
|
427
429
|
|
|
428
430
|
#removeSession(sessionId: string): void {
|
|
429
431
|
this.#sessions.delete(sessionId);
|
|
430
|
-
this.#ready.delete(sessionId);
|
|
431
432
|
this.#notifyChange();
|
|
432
433
|
}
|
|
433
434
|
|
package/src/instructions.md
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
Chappie connects this ChatGPT conversation to local Pi sessions. Call init before starting work. Omitting sessionId reuses the current binding or pairs with the
|
|
1
|
+
Chappie connects this ChatGPT conversation to local Pi sessions. Call init before starting work. Omitting sessionId reuses the current binding or pairs with the first online, unbound Pi session; specifying sessionId on init selects that Pi session as the new default. A sessionId on any other tool affects only that operation. Use sessions to inspect connected sessions without changing the binding.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The active model is this existing ChatGPT conversation. A Pi tool that starts another chappie/chatgpt agent has no ChatGPT conversation to attach to and will wait indefinitely. Subagents targeting another configured model keep that provider's normal behavior.
|
|
4
|
+
|
|
5
|
+
Prefer ChatGPT's web search, connectors, and cloud tools for remote research and cloud-side work. Use Chappie for local files, processes, Pi extensions, and Pi user interfaces. Pi project-memory tools operate on their local stores; Pi context-reduction tools do not change this ChatGPT conversation.
|
|
6
|
+
|
|
7
|
+
Use chat to send progress and final messages that should appear in Pi. Use read, bash, edit, and write directly. init lists active tools with short descriptions; call tools with their names to load complete definitions before using other Pi tools through call. Use an installed interactive tool through call when input is needed in Pi. Separate calls remain separate Pi turns; use a call array when tools should share a batch.
|
|
4
8
|
|
|
5
9
|
Use transfer with paths and files to copy ChatGPT files into Pi. Omit files to expose existing Pi paths or chappie:// image references as MCP resources. Relative paths use the Pi working directory, existing targets require overwrite: true, and resource materialization may require host confirmation.
|
|
6
10
|
|
|
7
|
-
Tool replies may contain user input consumed by Pi or results from an earlier explicitly cancelled request. Continue from those results instead of repeating completed work.
|
|
11
|
+
Tool replies may contain user input consumed by Pi or results from an earlier explicitly cancelled request. Continue from those results instead of repeating completed work. Host request deadlines include queueing and execution; use local persistent-process facilities for work intended to outlive one request.
|
package/src/server.ts
CHANGED
|
@@ -36,7 +36,8 @@ export function createServer(broker: Broker): McpServer {
|
|
|
36
36
|
"init",
|
|
37
37
|
{
|
|
38
38
|
title: "Connect to Pi",
|
|
39
|
-
description:
|
|
39
|
+
description:
|
|
40
|
+
"Connect this ChatGPT conversation to an online Pi session. A sessionId on init becomes the new default.",
|
|
40
41
|
inputSchema: z.object({
|
|
41
42
|
sessionId: z
|
|
42
43
|
.string()
|
|
@@ -44,6 +45,7 @@ export function createServer(broker: Broker): McpServer {
|
|
|
44
45
|
.describe("Pi session to select explicitly"),
|
|
45
46
|
}),
|
|
46
47
|
annotations: {
|
|
48
|
+
destructiveHint: false,
|
|
47
49
|
openWorldHint: false,
|
|
48
50
|
},
|
|
49
51
|
},
|
|
@@ -62,7 +64,7 @@ export function createServer(broker: Broker): McpServer {
|
|
|
62
64
|
"chat",
|
|
63
65
|
{
|
|
64
66
|
title: "Reply in Pi",
|
|
65
|
-
description: "
|
|
67
|
+
description: "Display one complete assistant message in Pi.",
|
|
66
68
|
inputSchema: z.object({
|
|
67
69
|
text: z.string().min(1).describe("Assistant message to display in Pi"),
|
|
68
70
|
sessionId: z
|
|
@@ -71,18 +73,19 @@ export function createServer(broker: Broker): McpServer {
|
|
|
71
73
|
.describe("Pi session for this operation only"),
|
|
72
74
|
}),
|
|
73
75
|
annotations: {
|
|
76
|
+
destructiveHint: false,
|
|
74
77
|
openWorldHint: false,
|
|
75
78
|
},
|
|
76
79
|
},
|
|
77
80
|
async (args, context) => {
|
|
78
81
|
const chatId = requireChatId(context);
|
|
79
|
-
const {
|
|
82
|
+
const { sessionId, inputs } = await broker.chat(
|
|
80
83
|
chatId,
|
|
81
84
|
args.sessionId,
|
|
82
85
|
args.text,
|
|
83
86
|
context.mcpReq.signal,
|
|
84
87
|
);
|
|
85
|
-
return finishResult(broker, context, textResult({
|
|
88
|
+
return finishResult(broker, context, textResult({ sessionId }, inputs));
|
|
86
89
|
},
|
|
87
90
|
);
|
|
88
91
|
|
|
@@ -90,8 +93,14 @@ export function createServer(broker: Broker): McpServer {
|
|
|
90
93
|
"tools",
|
|
91
94
|
{
|
|
92
95
|
title: "Pi tools",
|
|
93
|
-
description:
|
|
96
|
+
description:
|
|
97
|
+
"Return complete definitions for active Pi tools. Provide names to inspect only those tools.",
|
|
94
98
|
inputSchema: z.object({
|
|
99
|
+
names: z
|
|
100
|
+
.array(z.string())
|
|
101
|
+
.min(1)
|
|
102
|
+
.optional()
|
|
103
|
+
.describe("Tool names to describe; omit to return every active tool"),
|
|
95
104
|
sessionId: z
|
|
96
105
|
.string()
|
|
97
106
|
.optional()
|
|
@@ -99,6 +108,7 @@ export function createServer(broker: Broker): McpServer {
|
|
|
99
108
|
}),
|
|
100
109
|
annotations: {
|
|
101
110
|
readOnlyHint: true,
|
|
111
|
+
destructiveHint: false,
|
|
102
112
|
idempotentHint: true,
|
|
103
113
|
openWorldHint: false,
|
|
104
114
|
},
|
|
@@ -107,6 +117,7 @@ export function createServer(broker: Broker): McpServer {
|
|
|
107
117
|
const { inputs, ...inspected } = await broker.tools(
|
|
108
118
|
requireChatId(context),
|
|
109
119
|
args.sessionId,
|
|
120
|
+
args.names,
|
|
110
121
|
context.mcpReq.signal,
|
|
111
122
|
);
|
|
112
123
|
return finishResult(
|
|
@@ -124,7 +135,8 @@ export function createServer(broker: Broker): McpServer {
|
|
|
124
135
|
"call",
|
|
125
136
|
{
|
|
126
137
|
title: "Call Pi tools",
|
|
127
|
-
description:
|
|
138
|
+
description:
|
|
139
|
+
"Execute one or more active Pi tools as one native batch. Arguments must match definitions returned by tools.",
|
|
128
140
|
inputSchema: z.object({
|
|
129
141
|
calls: z
|
|
130
142
|
.array(
|
|
@@ -140,6 +152,7 @@ export function createServer(broker: Broker): McpServer {
|
|
|
140
152
|
.describe("Pi session for this operation only"),
|
|
141
153
|
}),
|
|
142
154
|
annotations: {
|
|
155
|
+
destructiveHint: true,
|
|
143
156
|
openWorldHint: true,
|
|
144
157
|
},
|
|
145
158
|
},
|
|
@@ -167,8 +180,9 @@ export function createServer(broker: Broker): McpServer {
|
|
|
167
180
|
inputSchema: tool.inputSchema,
|
|
168
181
|
annotations: {
|
|
169
182
|
readOnlyHint: tool.name === "read",
|
|
183
|
+
destructiveHint: tool.name !== "read",
|
|
170
184
|
idempotentHint: tool.name === "read",
|
|
171
|
-
openWorldHint: tool.name === "bash",
|
|
185
|
+
openWorldHint: tool.name === "bash" || tool.name === "transfer",
|
|
172
186
|
},
|
|
173
187
|
...(tool.fileParams
|
|
174
188
|
? { _meta: { "openai/fileParams": tool.fileParams } }
|
|
@@ -201,15 +215,16 @@ export function createServer(broker: Broker): McpServer {
|
|
|
201
215
|
{
|
|
202
216
|
title: "Local sessions",
|
|
203
217
|
description:
|
|
204
|
-
"List
|
|
218
|
+
"List online Pi sessions and the current conversation binding without waiting for offline sessions.",
|
|
205
219
|
inputSchema: z.object({
|
|
206
220
|
sessionId: z
|
|
207
221
|
.string()
|
|
208
222
|
.optional()
|
|
209
|
-
.describe("Return
|
|
223
|
+
.describe("Return this Pi session when it is online"),
|
|
210
224
|
}),
|
|
211
225
|
annotations: {
|
|
212
226
|
readOnlyHint: true,
|
|
227
|
+
destructiveHint: false,
|
|
213
228
|
idempotentHint: true,
|
|
214
229
|
openWorldHint: false,
|
|
215
230
|
},
|
package/src/transfer.ts
CHANGED
|
@@ -18,8 +18,8 @@ interface TransferDetails {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export const transferFile = Type.Object({
|
|
21
|
-
file_id: Type.String(),
|
|
22
|
-
download_url: Type.String(),
|
|
21
|
+
file_id: Type.String({ description: "Host file identifier" }),
|
|
22
|
+
download_url: Type.String({ description: "Host-provided download URL" }),
|
|
23
23
|
file_name: Type.Optional(Type.String()),
|
|
24
24
|
mime_type: Type.Optional(Type.String()),
|
|
25
25
|
});
|
|
@@ -28,10 +28,20 @@ export const transfer = {
|
|
|
28
28
|
name: "transfer",
|
|
29
29
|
label: "transfer",
|
|
30
30
|
description:
|
|
31
|
-
"
|
|
31
|
+
"Copy ChatGPT files into Pi paths, or export Pi paths and Chappie image references as MCP resources. The paths field always names Pi-side sources or destinations.",
|
|
32
32
|
parameters: Type.Object({
|
|
33
|
-
paths: Type.Array(Type.String(), {
|
|
34
|
-
|
|
33
|
+
paths: Type.Array(Type.String(), {
|
|
34
|
+
minItems: 1,
|
|
35
|
+
description:
|
|
36
|
+
"Pi paths to import into or export from; chappie:// image references can be exported",
|
|
37
|
+
}),
|
|
38
|
+
files: Type.Optional(
|
|
39
|
+
Type.Array(transferFile, {
|
|
40
|
+
minItems: 1,
|
|
41
|
+
description:
|
|
42
|
+
"ChatGPT files matched to paths by index; omit to export Pi paths",
|
|
43
|
+
}),
|
|
44
|
+
),
|
|
35
45
|
overwrite: Type.Optional(
|
|
36
46
|
Type.Boolean({ description: "Overwrite existing target files" }),
|
|
37
47
|
),
|