@pasko70/pibo 1.16.5 → 2.0.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/dist/agent-runtime/auth.js +28 -0
- package/dist/agent-runtime/capabilities.js +221 -0
- package/dist/agent-runtime/context-build.js +313 -0
- package/dist/agent-runtime/contract.js +45 -0
- package/dist/agent-runtime/errors.js +57 -0
- package/dist/agent-runtime/events.js +1 -0
- package/dist/agent-runtime/history.js +1 -0
- package/dist/agent-runtime/profile-validation.js +109 -0
- package/dist/agent-runtime/registry.js +608 -0
- package/dist/agent-runtime/resource-files.js +87 -0
- package/dist/agent-runtime/resource-service.js +635 -0
- package/dist/agent-runtime/resources.js +1 -0
- package/dist/agent-runtime/routed-session.js +931 -0
- package/dist/agent-runtime/testing/contract.js +51 -0
- package/dist/agent-runtime/testing/fake-adapter.js +192 -0
- package/dist/agent-runtime/types.js +3 -0
- package/dist/agent-runtimes/codex-native/adapter.js +905 -0
- package/dist/agent-runtimes/codex-native/auth.js +476 -0
- package/dist/agent-runtimes/codex-native/client.js +734 -0
- package/dist/agent-runtimes/codex-native/config.js +152 -0
- package/dist/agent-runtimes/codex-native/history.js +283 -0
- package/dist/agent-runtimes/codex-native/mcp-stdio-launcher.js +89 -0
- package/dist/agent-runtimes/codex-native/models.js +581 -0
- package/dist/agent-runtimes/codex-native/process.js +459 -0
- package/dist/agent-runtimes/codex-native/protocol-types.js +1 -0
- package/dist/agent-runtimes/codex-native/protocol-version.js +7 -0
- package/dist/agent-runtimes/codex-native/redaction.js +31 -0
- package/dist/agent-runtimes/codex-native/requests.js +378 -0
- package/dist/agent-runtimes/codex-native/resource-delivery.js +445 -0
- package/dist/agent-runtimes/codex-native/thread.js +388 -0
- package/dist/agent-runtimes/codex-native/turn.js +849 -0
- package/dist/agent-runtimes/pi/adapter.js +653 -0
- package/dist/agent-runtimes/pi/auth.js +455 -0
- package/dist/agent-runtimes/pi/history.js +640 -0
- package/dist/agent-runtimes/pi/model-catalog.js +87 -0
- package/dist/agent-runtimes/pi/routed-session.js +1464 -0
- package/dist/agent-runtimes/pi/runtime.js +534 -0
- package/dist/agent-runtimes/pi/tool-compiler.js +69 -0
- package/dist/apps/chat/agent-profiles.js +40 -23
- package/dist/apps/chat/agent-store.js +111 -64
- package/dist/apps/chat/chat-api-routes.js +1 -1
- package/dist/apps/chat/chat-request-normalizers.js +47 -0
- package/dist/apps/chat/data/chat-data-mappers.js +25 -9
- package/dist/apps/chat/data/history-query-service.js +108 -0
- package/dist/apps/chat/data/session-query-service.js +24 -3
- package/dist/apps/chat/data/timeline-query-service.js +3 -3
- package/dist/apps/chat/model-catalog.js +1 -55
- package/dist/apps/chat/provider-auth-actions.js +171 -23
- package/dist/apps/chat/stream.js +12 -0
- package/dist/apps/chat/trace-v2.js +1 -0
- package/dist/apps/chat/trace.js +126 -415
- package/dist/apps/chat/web-app.js +582 -157
- package/dist/apps/chat-ui/assets/{dist-QXwINWYY.js → dist-9v2ZXT6V.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CvZNkkOi.js → dist-B1LVAytl.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-_SP-MjLq.js → dist-C6LPDFXU.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Bad4Yz4P.js → dist-DVtXxfHc.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-xy-zomwl.js → dist-DW4Qrfbd.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DI4i80O2.js → dist-DmbsHdMC.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-D17yAUqp.js → dist-DyvwuSFO.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Bc3Vbgjh.js → dist-I26VB0QO.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BzqH7w58.js → dist-RtHbJRPV.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CMDJ-WZm.js → dist-sZgJkWZb.js} +1 -1
- package/dist/apps/chat-ui/assets/index-BPbNvcZe.css +1 -0
- package/dist/apps/chat-ui/assets/index-CIOf2uL2.js +237 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-1ivRyjFs.js +41 -0
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.0.0.vsix +0 -0
- package/dist/auth/login-actions.js +5 -251
- package/dist/cli-session/localSessionSource.js +8 -1
- package/dist/core/context-build.js +124 -20
- package/dist/core/default-profile.js +8 -0
- package/dist/core/profiles.js +30 -3
- package/dist/core/routed-session.js +5 -1446
- package/dist/core/runtime.js +5 -561
- package/dist/core/session-router.js +637 -83
- package/dist/data/cli.js +20 -3
- package/dist/data/schema.js +104 -1
- package/dist/data/session-store.js +24 -1
- package/dist/debug/events.js +25 -10
- package/dist/debug/failures.js +23 -3
- package/dist/debug/index.js +24 -6
- package/dist/debug/messages.js +87 -7
- package/dist/debug/persisted-payloads.js +31 -0
- package/dist/debug/pty.js +7 -6
- package/dist/debug/runtime-binding.js +29 -0
- package/dist/debug/session.js +137 -0
- package/dist/debug/summary.js +12 -0
- package/dist/debug/telemetry.js +28 -0
- package/dist/debug/tools.js +12 -2
- package/dist/debug/trace.js +154 -76
- package/dist/gateway/server.js +87 -2
- package/dist/gateway/tool.js +5 -5
- package/dist/index.js +21 -2
- package/dist/loops/tools.js +13 -12
- package/dist/mcp/agent-context.js +13 -4
- package/dist/mcp/client.js +10 -6
- package/dist/mcp/config.js +5 -2
- package/dist/mcp/runtime-session.js +166 -0
- package/dist/plugins/builtin.js +191 -53
- package/dist/plugins/codex-native.js +29 -0
- package/dist/plugins/registry.js +66 -2
- package/dist/runs/tools.js +26 -25
- package/dist/session-ui/terminalRows.js +2 -2
- package/dist/sessions/pibo-data-store.js +125 -16
- package/dist/sessions/runtime-binding.js +107 -0
- package/dist/sessions/sqlite-store.js +239 -18
- package/dist/sessions/store.js +86 -7
- package/dist/shared/trace-engine.js +18 -9
- package/dist/shared/trace-event-projection.js +29 -11
- package/dist/shared/{trace-transcript.js → trace-history.js} +193 -195
- package/dist/shared/trace-order.js +9 -4
- package/dist/shared/trace-page-merge.js +1 -1
- package/dist/signals/projector.js +20 -2
- package/dist/signals/registry.js +11 -0
- package/dist/subagents/tool.js +8 -6
- package/dist/tools/codex-browser.js +20 -19
- package/dist/tools/codex-compat.js +10 -9
- package/dist/tools/codex-image-generation.js +8 -6
- package/dist/tools/contract.js +45 -0
- package/dist/tools/credential-registry.js +182 -0
- package/dist/tools/mcp-bridge.js +511 -0
- package/dist/tools/payload-writer.js +17 -0
- package/dist/tools/runtime/tool.js +10 -9
- package/dist/tools/schema.js +9 -0
- package/dist/tools/session-service.js +193 -0
- package/dist/tools/session-tool-set.js +85 -0
- package/dist/web-annotations/tools.js +17 -16
- package/docs/README.md +11 -0
- package/package.json +3 -2
- package/skills/builtin/pibo-agent-runtime-adapter/SKILL.md +183 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/README.md +10 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/evals.json +45 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/orion-full-harness.md +60 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/relay-partial-harness.md +52 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/capabilities-and-designer.md +194 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/history-debug-and-security.md +213 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/interfaces-and-registration.md +214 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/lifecycle-bindings-and-events.md +193 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/portable-delivery-and-native-behavior.md +226 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/testing-migration-and-validation.md +256 -0
- package/dist/apps/chat-ui/assets/index-C45B0rw7.js +0 -237
- package/dist/apps/chat-ui/assets/index-E0RmuCkY.css +0 -1
- package/dist/apps/chat-vscode-web/assets/index-D-tSsXLG.js +0 -41
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.16.5.vsix +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export const TRACE_SOURCE_RANK = {
|
|
2
2
|
transcript: 0,
|
|
3
|
+
"product-history": 1,
|
|
3
4
|
"event-log": 1,
|
|
4
5
|
live: 2,
|
|
5
6
|
};
|
|
@@ -17,15 +18,19 @@ export const TRACE_PHASE_RANK = {
|
|
|
17
18
|
"assistant.message": 8,
|
|
18
19
|
error: 9,
|
|
19
20
|
};
|
|
20
|
-
export function
|
|
21
|
+
export function historyTraceOrder(historyIndex, contentPartIndex, type, source) {
|
|
21
22
|
return {
|
|
22
|
-
sourceRank: TRACE_SOURCE_RANK
|
|
23
|
-
turnSeq:
|
|
24
|
-
transcriptIndex,
|
|
23
|
+
sourceRank: TRACE_SOURCE_RANK[source],
|
|
24
|
+
turnSeq: historyIndex,
|
|
25
|
+
transcriptIndex: historyIndex,
|
|
25
26
|
contentPartIndex,
|
|
26
27
|
phaseRank: TRACE_PHASE_RANK[type],
|
|
27
28
|
};
|
|
28
29
|
}
|
|
30
|
+
/** @deprecated Use historyTraceOrder. */
|
|
31
|
+
export function transcriptTraceOrder(transcriptIndex, contentPartIndex, type) {
|
|
32
|
+
return historyTraceOrder(transcriptIndex, contentPartIndex, type, "transcript");
|
|
33
|
+
}
|
|
29
34
|
export function eventTraceOrder(eventSequence, type) {
|
|
30
35
|
return {
|
|
31
36
|
sourceRank: TRACE_SOURCE_RANK["event-log"],
|
|
@@ -85,7 +85,7 @@ function clearRemovedParentIds(nodes, removedIds) {
|
|
|
85
85
|
function transcriptEventIds(nodes) {
|
|
86
86
|
const eventIds = new Set();
|
|
87
87
|
for (const node of nodes) {
|
|
88
|
-
if (node.source === "transcript" && node.eventId)
|
|
88
|
+
if ((node.source === "transcript" || node.source === "product-history") && node.eventId)
|
|
89
89
|
eventIds.add(node.eventId);
|
|
90
90
|
}
|
|
91
91
|
return eventIds;
|
|
@@ -35,7 +35,17 @@ export const sessionLifecycleSignalProducer = {
|
|
|
35
35
|
const session = data.session;
|
|
36
36
|
const existing = context.getNode(`session:${session.id}`);
|
|
37
37
|
const rootPiboSessionId = session.parentId ? context.getSessionRoot(session.parentId) : session.id;
|
|
38
|
-
|
|
38
|
+
const binding = session.runtimeBinding;
|
|
39
|
+
if (existing
|
|
40
|
+
&& existing.parentPiboSessionId === session.parentId
|
|
41
|
+
&& existing.rootPiboSessionId === rootPiboSessionId
|
|
42
|
+
&& existing.metadata?.kind === session.kind
|
|
43
|
+
&& existing.metadata?.channel === session.channel
|
|
44
|
+
&& existing.metadata?.profile === session.profile
|
|
45
|
+
&& existing.metadata?.runtimeInstanceId === binding?.runtimeInstanceId
|
|
46
|
+
&& existing.metadata?.runtimeAdapterId === binding?.adapterId
|
|
47
|
+
&& existing.metadata?.runtimeBindingState === binding?.state
|
|
48
|
+
&& existing.metadata?.nativeSessionId === binding?.nativeSessionId)
|
|
39
49
|
return [];
|
|
40
50
|
return [{ type: "upsert_node", node: node({
|
|
41
51
|
id: `session:${session.id}`,
|
|
@@ -44,7 +54,15 @@ export const sessionLifecycleSignalProducer = {
|
|
|
44
54
|
rootPiboSessionId,
|
|
45
55
|
piboSessionId: session.id,
|
|
46
56
|
parentPiboSessionId: session.parentId,
|
|
47
|
-
metadata: {
|
|
57
|
+
metadata: {
|
|
58
|
+
kind: session.kind,
|
|
59
|
+
channel: session.channel,
|
|
60
|
+
profile: session.profile,
|
|
61
|
+
runtimeInstanceId: session.runtimeBinding?.runtimeInstanceId,
|
|
62
|
+
runtimeAdapterId: session.runtimeBinding?.adapterId,
|
|
63
|
+
runtimeBindingState: session.runtimeBinding?.state,
|
|
64
|
+
nativeSessionId: session.runtimeBinding?.nativeSessionId,
|
|
65
|
+
},
|
|
48
66
|
}, context) }];
|
|
49
67
|
}
|
|
50
68
|
if (data.type === "message_accepted") {
|
package/dist/signals/registry.js
CHANGED
|
@@ -180,6 +180,9 @@ function runSummaryEqual(a, b) {
|
|
|
180
180
|
&& a.startedAt === b.startedAt
|
|
181
181
|
&& a.updatedAt === b.updatedAt;
|
|
182
182
|
}
|
|
183
|
+
function isRuntimeBindingState(value) {
|
|
184
|
+
return value === "unbound" || value === "bound" || value === "missing" || value === "error";
|
|
185
|
+
}
|
|
183
186
|
function childSummaryEqual(a, b) {
|
|
184
187
|
return a.nodeId === b.nodeId
|
|
185
188
|
&& a.piboSessionId === b.piboSessionId
|
|
@@ -193,6 +196,10 @@ function sessionSnapshotSemanticallyEqual(a, b) {
|
|
|
193
196
|
return false;
|
|
194
197
|
return a.piboSessionId === b.piboSessionId
|
|
195
198
|
&& a.piSessionId === b.piSessionId
|
|
199
|
+
&& a.runtimeInstanceId === b.runtimeInstanceId
|
|
200
|
+
&& a.runtimeAdapterId === b.runtimeAdapterId
|
|
201
|
+
&& a.runtimeBindingState === b.runtimeBindingState
|
|
202
|
+
&& a.nativeSessionId === b.nativeSessionId
|
|
196
203
|
&& a.parentPiboSessionId === b.parentPiboSessionId
|
|
197
204
|
&& a.rootPiboSessionId === b.rootPiboSessionId
|
|
198
205
|
&& a.localStatus === b.localStatus
|
|
@@ -535,6 +542,10 @@ export class InMemoryPiboSignalRegistry {
|
|
|
535
542
|
const hasActiveDescendant = childSnapshots.some((snapshot) => snapshot.isTreeActive);
|
|
536
543
|
return {
|
|
537
544
|
piboSessionId,
|
|
545
|
+
runtimeInstanceId: typeof sessionNode?.metadata?.runtimeInstanceId === "string" ? sessionNode.metadata.runtimeInstanceId : undefined,
|
|
546
|
+
runtimeAdapterId: typeof sessionNode?.metadata?.runtimeAdapterId === "string" ? sessionNode.metadata.runtimeAdapterId : undefined,
|
|
547
|
+
runtimeBindingState: isRuntimeBindingState(sessionNode?.metadata?.runtimeBindingState) ? sessionNode.metadata.runtimeBindingState : undefined,
|
|
548
|
+
nativeSessionId: typeof sessionNode?.metadata?.nativeSessionId === "string" ? sessionNode.metadata.nativeSessionId : undefined,
|
|
538
549
|
parentPiboSessionId: this.parentSessionIdByChildId.get(piboSessionId),
|
|
539
550
|
rootPiboSessionId,
|
|
540
551
|
version,
|
package/dist/subagents/tool.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { Type } from "
|
|
3
|
-
import {
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
import { definePiboTool } from "../tools/contract.js";
|
|
4
4
|
function hashPart(value) {
|
|
5
5
|
return createHash("sha256").update(value).digest("hex").slice(0, 12);
|
|
6
6
|
}
|
|
@@ -28,26 +28,28 @@ export function createSubagentToolDefinitions(subagents, runner) {
|
|
|
28
28
|
}
|
|
29
29
|
function createSubagentToolDefinition(subagent, runner) {
|
|
30
30
|
const name = createSubagentToolName(subagent.name);
|
|
31
|
-
return
|
|
31
|
+
return definePiboTool({
|
|
32
32
|
name,
|
|
33
|
-
|
|
33
|
+
title: `Pibo Subagent ${subagent.name}`,
|
|
34
34
|
description: subagent.description ??
|
|
35
35
|
`Send a message to the ${subagent.name} subagent. Use threadKey to continue the same subagent session.`,
|
|
36
36
|
promptSnippet: subagent.description ??
|
|
37
37
|
`Send a message to the ${subagent.name} subagent. Pass the same threadKey when you want to continue the same subagent session.`,
|
|
38
38
|
executionMode: "parallel",
|
|
39
|
-
|
|
39
|
+
inputSchema: Type.Object({
|
|
40
40
|
message: Type.String({ description: "Message to send to the subagent" }),
|
|
41
41
|
threadKey: Type.Optional(Type.String({
|
|
42
42
|
description: "Stable key for continuing a previous subagent conversation. Omit it to create a new subagent session.",
|
|
43
|
+
maxLength: 256,
|
|
43
44
|
})),
|
|
44
45
|
}),
|
|
45
|
-
async execute(toolCallId, params) {
|
|
46
|
+
async execute(toolCallId, params, signal) {
|
|
46
47
|
const result = await runner.runSubagent({
|
|
47
48
|
subagent,
|
|
48
49
|
message: params.message,
|
|
49
50
|
threadKey: params.threadKey,
|
|
50
51
|
toolCallId,
|
|
52
|
+
signal,
|
|
51
53
|
});
|
|
52
54
|
return {
|
|
53
55
|
content: [
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { Type } from "typebox";
|
|
4
|
+
import { piboStringEnum } from "./schema.js";
|
|
5
|
+
import { definePiboTool } from "./contract.js";
|
|
5
6
|
import { connectCdpTarget, listCdpTargets } from "./cdp-client.js";
|
|
6
7
|
import { browserPoolPaths, releaseBrowserPoolLease } from "./browser-pool.js";
|
|
7
8
|
import { browserUseLeaseEnvironment, findActiveBrowserUseLeaseForHolder } from "./browser-use-leases.js";
|
|
@@ -203,24 +204,24 @@ export function createCodexBrowserToolProfiles() {
|
|
|
203
204
|
export function createCodexBrowserToolDefinitions(controller, enabledNames = CODEX_BROWSER_TOOL_NAMES) {
|
|
204
205
|
const enabled = new Set(enabledNames);
|
|
205
206
|
const tools = [
|
|
206
|
-
[BROWSER_USE_OPEN_TABS_TOOL_NAME,
|
|
207
|
+
[BROWSER_USE_OPEN_TABS_TOOL_NAME, definePiboTool({
|
|
207
208
|
name: BROWSER_USE_OPEN_TABS_TOOL_NAME,
|
|
208
|
-
|
|
209
|
+
title: "browser_use.open_tabs",
|
|
209
210
|
description: "List open tabs in the persistent Browser Use session. Returns stable target IDs, short tab IDs, titles, URLs, and tab indices.",
|
|
210
211
|
promptSnippet: "Use browser_use_open_tabs (browser_use.open_tabs) to discover tabs before targeting a screenshot or tab-specific action.",
|
|
211
212
|
executionMode: "parallel",
|
|
212
|
-
|
|
213
|
+
inputSchema: Type.Object({}),
|
|
213
214
|
async execute() {
|
|
214
215
|
return toolResult(await controller.openTabs());
|
|
215
216
|
},
|
|
216
217
|
})],
|
|
217
|
-
[BROWSER_USE_TAKE_SCREENSHOT_TOOL_NAME,
|
|
218
|
+
[BROWSER_USE_TAKE_SCREENSHOT_TOOL_NAME, definePiboTool({
|
|
218
219
|
name: BROWSER_USE_TAKE_SCREENSHOT_TOOL_NAME,
|
|
219
|
-
|
|
220
|
+
title: "browser_use.take_screenshot",
|
|
220
221
|
description: "Take a PNG screenshot from the persistent Browser Use session. Omit tabId to capture the first attachable page tab.",
|
|
221
222
|
promptSnippet: "Use browser_use_take_screenshot (browser_use.take_screenshot) when visual page state matters.",
|
|
222
223
|
executionMode: "parallel",
|
|
223
|
-
|
|
224
|
+
inputSchema: Type.Object({
|
|
224
225
|
tabId: Type.Optional(Type.String({ description: "Full target ID or short tab ID returned by browser_use_open_tabs." })),
|
|
225
226
|
fullPage: Type.Optional(Type.Boolean({ description: "Capture the full scrollable page instead of only the viewport." })),
|
|
226
227
|
timeoutMs: Type.Optional(Type.Number({ description: "Screenshot timeout in milliseconds." })),
|
|
@@ -237,20 +238,20 @@ export function createCodexBrowserToolDefinitions(controller, enabledNames = COD
|
|
|
237
238
|
};
|
|
238
239
|
},
|
|
239
240
|
})],
|
|
240
|
-
[BROWSER_USE_TOOL_NAME,
|
|
241
|
+
[BROWSER_USE_TOOL_NAME, definePiboTool({
|
|
241
242
|
name: BROWSER_USE_TOOL_NAME,
|
|
242
|
-
|
|
243
|
+
title: "browser_use.browser_use",
|
|
243
244
|
description: "Control one persistent Browser Use session with a structured action. State and element indices persist through the same Pibo session and managed browser-pool lease.",
|
|
244
245
|
promptSnippet: "Use browser_use_browser_use (browser_use.browser_use) for structured navigation and interaction; call state before index-based clicks or input.",
|
|
245
246
|
executionMode: "sequential",
|
|
246
|
-
|
|
247
|
-
action:
|
|
247
|
+
inputSchema: Type.Object({
|
|
248
|
+
action: piboStringEnum(["navigate", "state", "click", "input", "type", "scroll", "back", "switch_tab", "close_tab", "keys", "evaluate", "wait_selector", "wait_text"], { description: "Browser action." }),
|
|
248
249
|
url: Type.Optional(Type.String({ description: "URL for navigate." })),
|
|
249
250
|
index: Type.Optional(Type.Number({ description: "Interactive element index for click or input." })),
|
|
250
251
|
coordinateX: Type.Optional(Type.Number({ description: "Viewport X coordinate for click; use with coordinateY." })),
|
|
251
252
|
coordinateY: Type.Optional(Type.Number({ description: "Viewport Y coordinate for click; use with coordinateX." })),
|
|
252
253
|
text: Type.Optional(Type.String({ description: "Text for input, type, or wait_text." })),
|
|
253
|
-
direction: Type.Optional(
|
|
254
|
+
direction: Type.Optional(piboStringEnum(["up", "down"], { description: "Scroll direction." })),
|
|
254
255
|
amount: Type.Optional(Type.Number({ description: "Scroll amount in pixels." })),
|
|
255
256
|
tab: Type.Optional(Type.Number({ description: "Browser Use tab index for switch_tab or close_tab." })),
|
|
256
257
|
keys: Type.Optional(Type.String({ description: "Keys to send, such as Enter or Control+a." })),
|
|
@@ -262,13 +263,13 @@ export function createCodexBrowserToolDefinitions(controller, enabledNames = COD
|
|
|
262
263
|
return toolResult(await controller.use(params, signal));
|
|
263
264
|
},
|
|
264
265
|
})],
|
|
265
|
-
[NODE_REPL_JS_TOOL_NAME,
|
|
266
|
+
[NODE_REPL_JS_TOOL_NAME, definePiboTool({
|
|
266
267
|
name: NODE_REPL_JS_TOOL_NAME,
|
|
267
|
-
|
|
268
|
+
title: "node_repl.js",
|
|
268
269
|
description: "Execute JavaScript in a persistent, session-scoped Node REPL with top-level await. Top-level bindings persist. The sandbox omits require and process, and exposes browser.openTabs() plus browser.use(action, params) for the same Browser Use session.",
|
|
269
270
|
promptSnippet: "Use node_repl_js (node_repl.js) for persistent JavaScript state and browser-bound analysis. Top-level await and reusable top-level bindings are supported.",
|
|
270
271
|
executionMode: "sequential",
|
|
271
|
-
|
|
272
|
+
inputSchema: Type.Object({
|
|
272
273
|
code: Type.String({ description: "JavaScript to execute. Top-level declarations persist across calls." }),
|
|
273
274
|
timeoutMs: Type.Optional(Type.Number({ description: "Execution timeout in milliseconds." })),
|
|
274
275
|
}),
|
|
@@ -276,13 +277,13 @@ export function createCodexBrowserToolDefinitions(controller, enabledNames = COD
|
|
|
276
277
|
return nodeReplToolResult(await controller.js(params.code, params.timeoutMs));
|
|
277
278
|
},
|
|
278
279
|
})],
|
|
279
|
-
[NODE_REPL_JS_RESET_TOOL_NAME,
|
|
280
|
+
[NODE_REPL_JS_RESET_TOOL_NAME, definePiboTool({
|
|
280
281
|
name: NODE_REPL_JS_RESET_TOOL_NAME,
|
|
281
|
-
|
|
282
|
+
title: "node_repl.js_reset",
|
|
282
283
|
description: "Reset the persistent node_repl.js namespace for the current Pibo session.",
|
|
283
284
|
promptSnippet: "Use node_repl_js_reset (node_repl.js_reset) only when persistent JavaScript state should be discarded.",
|
|
284
285
|
executionMode: "sequential",
|
|
285
|
-
|
|
286
|
+
inputSchema: Type.Object({}),
|
|
286
287
|
async execute() {
|
|
287
288
|
return nodeReplToolResult(await controller.jsReset());
|
|
288
289
|
},
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { extname, isAbsolute, resolve } from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { Type } from "typebox";
|
|
5
|
+
import { piboStringEnum } from "./schema.js";
|
|
6
|
+
import { definePiboTool } from "./contract.js";
|
|
6
7
|
function resolveCwd(baseCwd, workdir) {
|
|
7
8
|
if (!workdir || workdir.trim().length === 0)
|
|
8
9
|
return baseCwd;
|
|
@@ -22,13 +23,13 @@ function mimeTypeForPath(path) {
|
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
export function createCodexCompatToolDefinitions() {
|
|
25
|
-
const applyPatch =
|
|
26
|
+
const applyPatch = definePiboTool({
|
|
26
27
|
name: "apply_patch",
|
|
27
|
-
|
|
28
|
+
title: "Apply Patch",
|
|
28
29
|
description: "Applies a Codex-style patch to files in the workspace.",
|
|
29
30
|
promptSnippet: "Use apply_patch for manual file edits by passing the complete patch text.",
|
|
30
31
|
executionMode: "sequential",
|
|
31
|
-
|
|
32
|
+
inputSchema: Type.Object({
|
|
32
33
|
patch: Type.String({ description: "Patch text starting with *** Begin Patch and ending with *** End Patch." }),
|
|
33
34
|
workdir: Type.Optional(Type.String({ description: "Working directory. Defaults to the runtime cwd." })),
|
|
34
35
|
}),
|
|
@@ -59,15 +60,15 @@ export function createCodexCompatToolDefinitions() {
|
|
|
59
60
|
};
|
|
60
61
|
},
|
|
61
62
|
});
|
|
62
|
-
const viewImage =
|
|
63
|
+
const viewImage = definePiboTool({
|
|
63
64
|
name: "view_image",
|
|
64
|
-
|
|
65
|
+
title: "View Image",
|
|
65
66
|
description: "Reads a local image file and returns it as an inline image result.",
|
|
66
67
|
promptSnippet: "Use view_image to inspect a local image path when visual details matter.",
|
|
67
68
|
executionMode: "parallel",
|
|
68
|
-
|
|
69
|
+
inputSchema: Type.Object({
|
|
69
70
|
path: Type.String({ description: "Local filesystem path to an image file." }),
|
|
70
|
-
detail: Type.Optional(
|
|
71
|
+
detail: Type.Optional(piboStringEnum(["original"], { description: "Use original resolution when set." })),
|
|
71
72
|
}),
|
|
72
73
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
73
74
|
const path = resolveCwd(ctx.cwd, params.path);
|
|
@@ -2,8 +2,8 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { platform, release, arch } from "node:os";
|
|
3
3
|
import { dirname, extname, isAbsolute, join, resolve } from "node:path";
|
|
4
4
|
import { AuthStorage } from "@earendil-works/pi-coding-agent";
|
|
5
|
-
import { Type } from "
|
|
6
|
-
import {
|
|
5
|
+
import { Type } from "typebox";
|
|
6
|
+
import { definePiboTool } from "./contract.js";
|
|
7
7
|
import { getPiboHome } from "../core/pibo-home.js";
|
|
8
8
|
const OPENAI_CODEX_PROVIDER = "openai-codex";
|
|
9
9
|
const DEFAULT_CODEX_BACKEND_BASE_URL = "https://chatgpt.com/backend-api";
|
|
@@ -215,9 +215,9 @@ async function collectEditImages(params, cwd, sessionEntries) {
|
|
|
215
215
|
return [];
|
|
216
216
|
}
|
|
217
217
|
export function createCodexImageGenerationToolDefinition(context = {}, options = {}) {
|
|
218
|
-
return
|
|
218
|
+
return definePiboTool({
|
|
219
219
|
name: "codex_image_generation",
|
|
220
|
-
|
|
220
|
+
title: "Codex Image Generation",
|
|
221
221
|
description: "Generates or edits images through the ChatGPT/Codex backend API using openai-codex OAuth entitlement. Does not use the public OpenAI Images API.",
|
|
222
222
|
promptSnippet: "Use codex_image_generation to create an image from a prompt, or to edit referenced/recent images with the Codex/ChatGPT image backend.",
|
|
223
223
|
promptGuidelines: [
|
|
@@ -225,14 +225,16 @@ export function createCodexImageGenerationToolDefinition(context = {}, options =
|
|
|
225
225
|
"For edits, pass either referenced_image_paths for local image files or num_last_images_to_include for recent conversation images, but not both.",
|
|
226
226
|
],
|
|
227
227
|
executionMode: "sequential",
|
|
228
|
-
|
|
228
|
+
inputSchema: Type.Object({
|
|
229
229
|
prompt: Type.String({ description: "Image generation/editing prompt. Be specific about the desired final image." }),
|
|
230
230
|
referenced_image_paths: Type.Optional(Type.Array(Type.String({ description: "Local filesystem image path to edit." }), { description: `Optional local image paths to edit. At most ${MAX_EDIT_IMAGES}.` })),
|
|
231
231
|
num_last_images_to_include: Type.Optional(Type.Number({ description: `Use the last N conversation images as edit references. Must be between 1 and ${MAX_EDIT_IMAGES}.` })),
|
|
232
232
|
}),
|
|
233
233
|
async execute(toolCallId, params, signal, _onUpdate, ctx) {
|
|
234
234
|
validateImageArgs(params);
|
|
235
|
-
const
|
|
235
|
+
const legacySessionManager = ctx.sessionManager;
|
|
236
|
+
const sessionEntries = [...(ctx.getConversationEntries?.() ?? context.getConversationEntries?.() ?? legacySessionManager?.getBranch?.() ?? [])];
|
|
237
|
+
const images = await collectEditImages(params, ctx.cwd, sessionEntries);
|
|
236
238
|
const operation = images.length > 0 ? "edit" : "generate";
|
|
237
239
|
const endpoint = operation === "edit" ? "edits" : "generations";
|
|
238
240
|
const auth = await getCodexImageAuth();
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Identity helper that preserves schema-derived input types. */
|
|
2
|
+
export function definePiboTool(definition) {
|
|
3
|
+
definition.label ??= definition.title;
|
|
4
|
+
definition.parameters ??= definition.inputSchema;
|
|
5
|
+
return definition;
|
|
6
|
+
}
|
|
7
|
+
export function isPiboToolDefinition(value) {
|
|
8
|
+
return Boolean(value
|
|
9
|
+
&& typeof value === "object"
|
|
10
|
+
&& "inputSchema" in value
|
|
11
|
+
&& "execute" in value
|
|
12
|
+
&& typeof value.execute === "function");
|
|
13
|
+
}
|
|
14
|
+
export function normalizePiboToolResult(result) {
|
|
15
|
+
return {
|
|
16
|
+
content: result.content.map((content) => ({ ...content })),
|
|
17
|
+
...(result.details !== undefined ? { details: result.details } : {}),
|
|
18
|
+
...(result.isError !== undefined ? { isError: result.isError } : {}),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Convert a legacy Pi-shaped definition without leaking Pi types into generic code. */
|
|
22
|
+
export function normalizePiboToolDefinition(definition) {
|
|
23
|
+
if (isPiboToolDefinition(definition))
|
|
24
|
+
return definition;
|
|
25
|
+
return definePiboTool({
|
|
26
|
+
name: definition.name,
|
|
27
|
+
title: definition.label,
|
|
28
|
+
description: definition.description,
|
|
29
|
+
...(definition.promptSnippet ? { promptSnippet: definition.promptSnippet } : {}),
|
|
30
|
+
...(definition.promptGuidelines ? { promptGuidelines: [...definition.promptGuidelines] } : {}),
|
|
31
|
+
inputSchema: definition.parameters,
|
|
32
|
+
...(definition.executionMode ? { executionMode: definition.executionMode } : {}),
|
|
33
|
+
portable: false,
|
|
34
|
+
...(definition.prepareArguments ? { prepareInput: definition.prepareArguments } : {}),
|
|
35
|
+
async execute(toolCallId, input, signal, onUpdate, context) {
|
|
36
|
+
if (context.nativeContext === undefined) {
|
|
37
|
+
throw new Error(`Tool "${definition.name}" uses the deprecated Pi-native definition contract and cannot be delivered through portable MCP.`);
|
|
38
|
+
}
|
|
39
|
+
const result = await definition.execute(toolCallId, input, signal, onUpdate
|
|
40
|
+
? (update) => onUpdate(normalizePiboToolResult(update))
|
|
41
|
+
: undefined, context.nativeContext);
|
|
42
|
+
return normalizePiboToolResult(result);
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
|
+
const TOKEN_PREFIX = "pibo_tool_";
|
|
3
|
+
const DEFAULT_TTL_MS = 5 * 60_000;
|
|
4
|
+
const DEFAULT_MAX_LIFETIME_MS = 30 * 60_000;
|
|
5
|
+
export class PiboToolCredentialError extends Error {
|
|
6
|
+
code;
|
|
7
|
+
constructor(code, message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "PiboToolCredentialError";
|
|
10
|
+
this.code = code;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function positiveDuration(value, fallback, label) {
|
|
14
|
+
const resolved = value ?? fallback;
|
|
15
|
+
if (!Number.isFinite(resolved) || resolved <= 0)
|
|
16
|
+
throw new Error(`${label} must be a positive finite duration`);
|
|
17
|
+
return Math.floor(resolved);
|
|
18
|
+
}
|
|
19
|
+
function normalizeScope(scope) {
|
|
20
|
+
const piboSessionId = scope.piboSessionId.trim();
|
|
21
|
+
const runtimeInstanceId = scope.runtimeInstanceId.trim();
|
|
22
|
+
const adapterId = scope.adapterId.trim();
|
|
23
|
+
const sessionGeneration = scope.sessionGeneration.trim();
|
|
24
|
+
const cwd = scope.cwd.trim();
|
|
25
|
+
if (!piboSessionId || !runtimeInstanceId || !adapterId || !sessionGeneration || !cwd) {
|
|
26
|
+
throw new PiboToolCredentialError("credential_scope_invalid", "Tool credentials require a Pibo Session, runtime instance, adapter, session generation, and working directory.");
|
|
27
|
+
}
|
|
28
|
+
const allowedToolNames = [...new Set(scope.allowedToolNames.map((name) => name.trim()).filter(Boolean))].sort();
|
|
29
|
+
if (allowedToolNames.length === 0) {
|
|
30
|
+
throw new PiboToolCredentialError("credential_scope_invalid", "Tool credentials require at least one allowed tool.");
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
piboSessionId,
|
|
34
|
+
...(scope.piboRoomId?.trim() ? { piboRoomId: scope.piboRoomId.trim() } : {}),
|
|
35
|
+
...(scope.profileName?.trim() ? { profileName: scope.profileName.trim() } : {}),
|
|
36
|
+
runtimeInstanceId,
|
|
37
|
+
adapterId,
|
|
38
|
+
sessionGeneration,
|
|
39
|
+
cwd,
|
|
40
|
+
allowedToolNames,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function tokenHash(secret) {
|
|
44
|
+
return createHash("sha256").update(secret, "utf8").digest();
|
|
45
|
+
}
|
|
46
|
+
function parseToken(token) {
|
|
47
|
+
if (!token.startsWith(TOKEN_PREFIX))
|
|
48
|
+
return undefined;
|
|
49
|
+
const separator = token.indexOf(".", TOKEN_PREFIX.length);
|
|
50
|
+
if (separator < 0)
|
|
51
|
+
return undefined;
|
|
52
|
+
const credentialId = token.slice(TOKEN_PREFIX.length, separator);
|
|
53
|
+
const secret = token.slice(separator + 1);
|
|
54
|
+
if (!credentialId || !secret)
|
|
55
|
+
return undefined;
|
|
56
|
+
return { credentialId, secret };
|
|
57
|
+
}
|
|
58
|
+
function iso(value) {
|
|
59
|
+
return value === undefined ? undefined : new Date(value).toISOString();
|
|
60
|
+
}
|
|
61
|
+
function infoFor(record) {
|
|
62
|
+
return {
|
|
63
|
+
credentialId: record.credentialId,
|
|
64
|
+
...record.scope,
|
|
65
|
+
allowedToolNames: [...record.scope.allowedToolNames],
|
|
66
|
+
issuedAt: new Date(record.issuedAtMs).toISOString(),
|
|
67
|
+
expiresAt: new Date(record.expiresAtMs).toISOString(),
|
|
68
|
+
...(iso(record.lastAliveAtMs) ? { lastAliveAt: iso(record.lastAliveAtMs) } : {}),
|
|
69
|
+
...(iso(record.revokedAtMs) ? { revokedAt: iso(record.revokedAtMs) } : {}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export class PiboToolCredentialRegistry {
|
|
73
|
+
records = new Map();
|
|
74
|
+
defaultTtlMs;
|
|
75
|
+
maxLifetimeMs;
|
|
76
|
+
now;
|
|
77
|
+
constructor(options = {}) {
|
|
78
|
+
this.defaultTtlMs = positiveDuration(options.defaultTtlMs, DEFAULT_TTL_MS, "defaultTtlMs");
|
|
79
|
+
this.maxLifetimeMs = positiveDuration(options.maxLifetimeMs, DEFAULT_MAX_LIFETIME_MS, "maxLifetimeMs");
|
|
80
|
+
if (this.defaultTtlMs > this.maxLifetimeMs) {
|
|
81
|
+
throw new Error("defaultTtlMs must not exceed maxLifetimeMs");
|
|
82
|
+
}
|
|
83
|
+
this.now = options.now ?? Date.now;
|
|
84
|
+
}
|
|
85
|
+
issue(scope, ttlMs = this.defaultTtlMs) {
|
|
86
|
+
const normalizedScope = normalizeScope(scope);
|
|
87
|
+
const lifetime = Math.min(positiveDuration(ttlMs, this.defaultTtlMs, "ttlMs"), this.maxLifetimeMs);
|
|
88
|
+
const now = this.now();
|
|
89
|
+
const credentialId = randomBytes(16).toString("base64url");
|
|
90
|
+
const secret = randomBytes(32).toString("base64url");
|
|
91
|
+
const record = {
|
|
92
|
+
credentialId,
|
|
93
|
+
tokenHash: tokenHash(secret),
|
|
94
|
+
scope: normalizedScope,
|
|
95
|
+
issuedAtMs: now,
|
|
96
|
+
expiresAtMs: now + lifetime,
|
|
97
|
+
};
|
|
98
|
+
this.records.set(credentialId, record);
|
|
99
|
+
return {
|
|
100
|
+
token: `${TOKEN_PREFIX}${credentialId}.${secret}`,
|
|
101
|
+
info: infoFor(record),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
authenticate(token, options = {}) {
|
|
105
|
+
const parsed = parseToken(token);
|
|
106
|
+
const record = parsed ? this.records.get(parsed.credentialId) : undefined;
|
|
107
|
+
if (!parsed || !record) {
|
|
108
|
+
throw new PiboToolCredentialError("credential_invalid", "Invalid Pibo tool credential.");
|
|
109
|
+
}
|
|
110
|
+
const presentedHash = tokenHash(parsed.secret);
|
|
111
|
+
if (presentedHash.length !== record.tokenHash.length || !timingSafeEqual(presentedHash, record.tokenHash)) {
|
|
112
|
+
throw new PiboToolCredentialError("credential_invalid", "Invalid Pibo tool credential.");
|
|
113
|
+
}
|
|
114
|
+
if (record.revokedAtMs !== undefined) {
|
|
115
|
+
throw new PiboToolCredentialError("credential_revoked", "Pibo tool credential has been revoked.");
|
|
116
|
+
}
|
|
117
|
+
const now = this.now();
|
|
118
|
+
if (record.expiresAtMs <= now) {
|
|
119
|
+
throw new PiboToolCredentialError("credential_expired", "Pibo tool credential has expired.");
|
|
120
|
+
}
|
|
121
|
+
if (options.touch !== false)
|
|
122
|
+
record.lastAliveAtMs = now;
|
|
123
|
+
return infoFor(record);
|
|
124
|
+
}
|
|
125
|
+
renew(token, ttlMs = this.defaultTtlMs) {
|
|
126
|
+
const parsed = parseToken(token);
|
|
127
|
+
this.authenticate(token, { touch: false });
|
|
128
|
+
const record = parsed ? this.records.get(parsed.credentialId) : undefined;
|
|
129
|
+
if (!record)
|
|
130
|
+
throw new PiboToolCredentialError("credential_invalid", "Invalid Pibo tool credential.");
|
|
131
|
+
const now = this.now();
|
|
132
|
+
const requested = positiveDuration(ttlMs, this.defaultTtlMs, "ttlMs");
|
|
133
|
+
const maximumExpiry = record.issuedAtMs + this.maxLifetimeMs;
|
|
134
|
+
record.expiresAtMs = Math.min(now + requested, maximumExpiry);
|
|
135
|
+
if (record.expiresAtMs <= now) {
|
|
136
|
+
record.revokedAtMs = now;
|
|
137
|
+
throw new PiboToolCredentialError("credential_expired", "Pibo tool credential reached its maximum lifetime.");
|
|
138
|
+
}
|
|
139
|
+
record.lastAliveAtMs = now;
|
|
140
|
+
return infoFor(record);
|
|
141
|
+
}
|
|
142
|
+
revoke(token) {
|
|
143
|
+
const parsed = parseToken(token);
|
|
144
|
+
if (!parsed)
|
|
145
|
+
return false;
|
|
146
|
+
return this.revokeCredentialId(parsed.credentialId);
|
|
147
|
+
}
|
|
148
|
+
revokeCredentialId(credentialId) {
|
|
149
|
+
const record = this.records.get(credentialId);
|
|
150
|
+
if (!record || record.revokedAtMs !== undefined)
|
|
151
|
+
return false;
|
|
152
|
+
record.revokedAtMs = this.now();
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
revokeSessionGeneration(piboSessionId, sessionGeneration) {
|
|
156
|
+
let revoked = 0;
|
|
157
|
+
for (const record of this.records.values()) {
|
|
158
|
+
if (record.scope.piboSessionId === piboSessionId
|
|
159
|
+
&& record.scope.sessionGeneration === sessionGeneration
|
|
160
|
+
&& record.revokedAtMs === undefined) {
|
|
161
|
+
record.revokedAtMs = this.now();
|
|
162
|
+
revoked += 1;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return revoked;
|
|
166
|
+
}
|
|
167
|
+
getInfo(credentialId) {
|
|
168
|
+
const record = this.records.get(credentialId);
|
|
169
|
+
return record ? infoFor(record) : undefined;
|
|
170
|
+
}
|
|
171
|
+
cleanupExpired() {
|
|
172
|
+
const now = this.now();
|
|
173
|
+
let removed = 0;
|
|
174
|
+
for (const [credentialId, record] of this.records.entries()) {
|
|
175
|
+
if (record.expiresAtMs <= now || record.revokedAtMs !== undefined) {
|
|
176
|
+
this.records.delete(credentialId);
|
|
177
|
+
removed += 1;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return removed;
|
|
181
|
+
}
|
|
182
|
+
}
|