@aliou/pi-synthetic 0.4.4 → 0.4.6
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/CHANGELOG.md +13 -0
- package/package.json +6 -1
- package/src/hooks/search-tool-availability.ts +129 -0
- package/src/index.ts +3 -2
- package/src/providers/models.ts +14 -89
- package/src/tools/search.ts +14 -88
- package/.pi/settings.json +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @aliou/pi-synthetic
|
|
2
2
|
|
|
3
|
+
## 0.4.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 6180572: mark pi SDK peer deps as optional to prevent koffi OOM in Gondolin VMs
|
|
8
|
+
- fe8094f: register synthetic web search tool at init time and move availability checks to hooks
|
|
9
|
+
|
|
10
|
+
## 0.4.5
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- 7489bc0: update model list: add nvidia/Kimi-K2.5-NVFP4, remove 6 discontinued models
|
|
15
|
+
|
|
3
16
|
## 0.4.4
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aliou/pi-synthetic",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/aliou/pi-synthetic"
|
|
@@ -27,6 +27,11 @@
|
|
|
27
27
|
"husky": "^9.1.7",
|
|
28
28
|
"typescript": "^5.9.3"
|
|
29
29
|
},
|
|
30
|
+
"peerDependenciesMeta": {
|
|
31
|
+
"@mariozechner/pi-coding-agent": {
|
|
32
|
+
"optional": true
|
|
33
|
+
}
|
|
34
|
+
},
|
|
30
35
|
"scripts": {
|
|
31
36
|
"typecheck": "tsc --noEmit",
|
|
32
37
|
"lint": "biome check",
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtensionAPI,
|
|
3
|
+
ExtensionContext,
|
|
4
|
+
} from "@mariozechner/pi-coding-agent";
|
|
5
|
+
import { SYNTHETIC_WEB_SEARCH_TOOL } from "../tools/search";
|
|
6
|
+
|
|
7
|
+
function notifyDebug(ctx: ExtensionContext, message: string): void {
|
|
8
|
+
ctx.ui.notify(`[pi-synthetic:web-search] ${message}`, "info");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function checkSubscriptionAccess(
|
|
12
|
+
apiKey: string,
|
|
13
|
+
): Promise<{ ok: true } | { ok: false; reason: string }> {
|
|
14
|
+
try {
|
|
15
|
+
const response = await fetch("https://api.synthetic.new/v2/quotas", {
|
|
16
|
+
method: "GET",
|
|
17
|
+
headers: {
|
|
18
|
+
Authorization: `Bearer ${apiKey}`,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
return {
|
|
24
|
+
ok: false,
|
|
25
|
+
reason: `Quotas check failed (HTTP ${response.status})`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const data = await response.json();
|
|
30
|
+
if (data?.subscription?.limit > 0) {
|
|
31
|
+
return { ok: true };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
reason: "No active subscription (search requires a subscription plan)",
|
|
37
|
+
};
|
|
38
|
+
} catch (error) {
|
|
39
|
+
const message =
|
|
40
|
+
error instanceof Error ? error.message : "Unknown error occurred";
|
|
41
|
+
return { ok: false, reason: `Quotas check failed: ${message}` };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function registerSyntheticWebSearchHooks(pi: ExtensionAPI): void {
|
|
46
|
+
let accessCheckPromise:
|
|
47
|
+
| Promise<{ ok: true } | { ok: false; reason: string }>
|
|
48
|
+
| undefined;
|
|
49
|
+
let hasAccess = false;
|
|
50
|
+
let deniedReason: string | undefined;
|
|
51
|
+
let didNotifyDenied = false;
|
|
52
|
+
|
|
53
|
+
// Keep tool inactive at session start. Availability is decided before each agent run.
|
|
54
|
+
pi.on("session_start", (_event, ctx) => {
|
|
55
|
+
notifyDebug(ctx, "session_start: preparing web search tool");
|
|
56
|
+
|
|
57
|
+
const current = pi.getActiveTools();
|
|
58
|
+
if (current.includes(SYNTHETIC_WEB_SEARCH_TOOL)) {
|
|
59
|
+
pi.setActiveTools(
|
|
60
|
+
current.filter((toolName) => toolName !== SYNTHETIC_WEB_SEARCH_TOOL),
|
|
61
|
+
);
|
|
62
|
+
notifyDebug(ctx, "session_start: tool disabled until subscription check");
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Verify subscription only when user starts agent execution.
|
|
67
|
+
pi.on("before_agent_start", async (_event, ctx) => {
|
|
68
|
+
notifyDebug(ctx, "before_agent_start: ensuring tool availability");
|
|
69
|
+
|
|
70
|
+
const apiKey = process.env.SYNTHETIC_API_KEY;
|
|
71
|
+
if (!apiKey) {
|
|
72
|
+
hasAccess = false;
|
|
73
|
+
deniedReason = "SYNTHETIC_API_KEY is not configured";
|
|
74
|
+
accessCheckPromise = undefined;
|
|
75
|
+
notifyDebug(ctx, "before_agent_start: access denied (missing API key)");
|
|
76
|
+
} else {
|
|
77
|
+
if (deniedReason === "SYNTHETIC_API_KEY is not configured") {
|
|
78
|
+
deniedReason = undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!hasAccess && !deniedReason) {
|
|
82
|
+
notifyDebug(ctx, "before_agent_start: checking subscription access");
|
|
83
|
+
accessCheckPromise ??= checkSubscriptionAccess(apiKey);
|
|
84
|
+
const access = await accessCheckPromise;
|
|
85
|
+
|
|
86
|
+
if (!access.ok) {
|
|
87
|
+
deniedReason = access.reason;
|
|
88
|
+
notifyDebug(
|
|
89
|
+
ctx,
|
|
90
|
+
`before_agent_start: access denied (${access.reason})`,
|
|
91
|
+
);
|
|
92
|
+
} else {
|
|
93
|
+
hasAccess = true;
|
|
94
|
+
didNotifyDenied = false;
|
|
95
|
+
notifyDebug(ctx, "before_agent_start: access granted");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (deniedReason) {
|
|
101
|
+
const current = pi.getActiveTools();
|
|
102
|
+
if (current.includes(SYNTHETIC_WEB_SEARCH_TOOL)) {
|
|
103
|
+
pi.setActiveTools(
|
|
104
|
+
current.filter((toolName) => toolName !== SYNTHETIC_WEB_SEARCH_TOOL),
|
|
105
|
+
);
|
|
106
|
+
notifyDebug(ctx, "before_agent_start: tool kept disabled");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (ctx.hasUI && !didNotifyDenied) {
|
|
110
|
+
ctx.ui.notify(
|
|
111
|
+
`Synthetic web search disabled: ${deniedReason}`,
|
|
112
|
+
"warning",
|
|
113
|
+
);
|
|
114
|
+
didNotifyDenied = true;
|
|
115
|
+
notifyDebug(
|
|
116
|
+
ctx,
|
|
117
|
+
"before_agent_start: user notified about disabled tool",
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const current = pi.getActiveTools();
|
|
124
|
+
if (!current.includes(SYNTHETIC_WEB_SEARCH_TOOL)) {
|
|
125
|
+
pi.setActiveTools([...current, SYNTHETIC_WEB_SEARCH_TOOL]);
|
|
126
|
+
notifyDebug(ctx, "before_agent_start: tool enabled");
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
import { registerQuotasCommand } from "./commands/quotas";
|
|
3
|
+
import { registerSyntheticWebSearchHooks } from "./hooks/search-tool-availability";
|
|
3
4
|
import { registerSyntheticProvider } from "./providers/index";
|
|
4
5
|
import { registerSyntheticWebSearchTool } from "./tools/search";
|
|
5
6
|
|
|
6
7
|
export default async function (pi: ExtensionAPI) {
|
|
7
8
|
registerSyntheticProvider(pi);
|
|
9
|
+
registerSyntheticWebSearchTool(pi);
|
|
10
|
+
registerSyntheticWebSearchHooks(pi);
|
|
8
11
|
|
|
9
|
-
// Only register quotas command and web search tool if API key is available
|
|
10
12
|
if (process.env.SYNTHETIC_API_KEY) {
|
|
11
13
|
registerQuotasCommand(pi);
|
|
12
|
-
registerSyntheticWebSearchTool(pi);
|
|
13
14
|
}
|
|
14
15
|
}
|
package/src/providers/models.ts
CHANGED
|
@@ -100,36 +100,6 @@ export const SYNTHETIC_MODELS: SyntheticModelConfig[] = [
|
|
|
100
100
|
contextWindow: 131072,
|
|
101
101
|
maxTokens: 128000,
|
|
102
102
|
},
|
|
103
|
-
// models.dev: synthetic/hf:deepseek-ai/DeepSeek-V3.1 → ctx=128000, out=128000
|
|
104
|
-
{
|
|
105
|
-
id: "hf:deepseek-ai/DeepSeek-V3.1",
|
|
106
|
-
name: "deepseek-ai/DeepSeek-V3.1",
|
|
107
|
-
reasoning: false,
|
|
108
|
-
input: ["text"],
|
|
109
|
-
cost: {
|
|
110
|
-
input: 0.56,
|
|
111
|
-
output: 1.68,
|
|
112
|
-
cacheRead: 0.56,
|
|
113
|
-
cacheWrite: 0,
|
|
114
|
-
},
|
|
115
|
-
contextWindow: 131072,
|
|
116
|
-
maxTokens: 128000,
|
|
117
|
-
},
|
|
118
|
-
// models.dev: synthetic/hf:deepseek-ai/DeepSeek-V3.1-Terminus → ctx=128000, out=128000
|
|
119
|
-
{
|
|
120
|
-
id: "hf:deepseek-ai/DeepSeek-V3.1-Terminus",
|
|
121
|
-
name: "deepseek-ai/DeepSeek-V3.1-Terminus",
|
|
122
|
-
reasoning: false,
|
|
123
|
-
input: ["text"],
|
|
124
|
-
cost: {
|
|
125
|
-
input: 1.2,
|
|
126
|
-
output: 1.2,
|
|
127
|
-
cacheRead: 1.2,
|
|
128
|
-
cacheWrite: 0,
|
|
129
|
-
},
|
|
130
|
-
contextWindow: 131072,
|
|
131
|
-
maxTokens: 128000,
|
|
132
|
-
},
|
|
133
103
|
// models.dev: synthetic/hf:deepseek-ai/DeepSeek-V3.2 → ctx=162816, out=8000
|
|
134
104
|
{
|
|
135
105
|
id: "hf:deepseek-ai/DeepSeek-V3.2",
|
|
@@ -145,21 +115,6 @@ export const SYNTHETIC_MODELS: SyntheticModelConfig[] = [
|
|
|
145
115
|
contextWindow: 162816,
|
|
146
116
|
maxTokens: 8000,
|
|
147
117
|
},
|
|
148
|
-
// NOTE: not present in models.dev synthetic provider; maxTokens unchanged
|
|
149
|
-
{
|
|
150
|
-
id: "hf:Qwen/Qwen3-VL-235B-A22B-Instruct",
|
|
151
|
-
name: "Qwen/Qwen3-VL-235B-A22B-Instruct",
|
|
152
|
-
reasoning: true,
|
|
153
|
-
input: ["text", "image"],
|
|
154
|
-
cost: {
|
|
155
|
-
input: 0.22,
|
|
156
|
-
output: 0.88,
|
|
157
|
-
cacheRead: 0.22,
|
|
158
|
-
cacheWrite: 0,
|
|
159
|
-
},
|
|
160
|
-
contextWindow: 256000,
|
|
161
|
-
maxTokens: 4096,
|
|
162
|
-
},
|
|
163
118
|
// models.dev: synthetic/hf:moonshotai/Kimi-K2-Instruct-0905 → ctx=262144, out=32768
|
|
164
119
|
{
|
|
165
120
|
id: "hf:moonshotai/Kimi-K2-Instruct-0905",
|
|
@@ -220,61 +175,31 @@ export const SYNTHETIC_MODELS: SyntheticModelConfig[] = [
|
|
|
220
175
|
contextWindow: 262144,
|
|
221
176
|
maxTokens: 32000,
|
|
222
177
|
},
|
|
223
|
-
// models.dev: synthetic/hf:
|
|
224
|
-
{
|
|
225
|
-
id: "hf:Qwen/Qwen3-235B-A22B-Instruct-2507",
|
|
226
|
-
name: "Qwen/Qwen3-235B-A22B-Instruct-2507",
|
|
227
|
-
reasoning: false,
|
|
228
|
-
input: ["text"],
|
|
229
|
-
cost: {
|
|
230
|
-
input: 0.22,
|
|
231
|
-
output: 0.88,
|
|
232
|
-
cacheRead: 0.22,
|
|
233
|
-
cacheWrite: 0,
|
|
234
|
-
},
|
|
235
|
-
contextWindow: 262144,
|
|
236
|
-
maxTokens: 32000,
|
|
237
|
-
},
|
|
238
|
-
// models.dev: synthetic/hf:zai-org/GLM-4.6 → ctx=200000, out=64000
|
|
239
|
-
{
|
|
240
|
-
id: "hf:zai-org/GLM-4.6",
|
|
241
|
-
name: "zai-org/GLM-4.6",
|
|
242
|
-
reasoning: true,
|
|
243
|
-
input: ["text"],
|
|
244
|
-
cost: {
|
|
245
|
-
input: 0.55,
|
|
246
|
-
output: 2.19,
|
|
247
|
-
cacheRead: 0.55,
|
|
248
|
-
cacheWrite: 0,
|
|
249
|
-
},
|
|
250
|
-
contextWindow: 202752,
|
|
251
|
-
maxTokens: 64000,
|
|
252
|
-
},
|
|
253
|
-
// models.dev: synthetic/hf:MiniMaxAI/MiniMax-M2 → ctx=196608, out=131000
|
|
178
|
+
// models.dev: synthetic/hf:moonshotai/Kimi-K2.5 → ctx=262144, out=65536
|
|
254
179
|
{
|
|
255
|
-
id: "hf:
|
|
256
|
-
name: "
|
|
180
|
+
id: "hf:moonshotai/Kimi-K2.5",
|
|
181
|
+
name: "moonshotai/Kimi-K2.5",
|
|
257
182
|
reasoning: true,
|
|
258
|
-
input: ["text"],
|
|
183
|
+
input: ["text", "image"],
|
|
259
184
|
cost: {
|
|
260
|
-
input:
|
|
185
|
+
input: 1.2,
|
|
261
186
|
output: 1.2,
|
|
262
|
-
cacheRead:
|
|
187
|
+
cacheRead: 1.2,
|
|
263
188
|
cacheWrite: 0,
|
|
264
189
|
},
|
|
265
|
-
contextWindow:
|
|
266
|
-
maxTokens:
|
|
190
|
+
contextWindow: 262144,
|
|
191
|
+
maxTokens: 65536,
|
|
267
192
|
},
|
|
268
|
-
//
|
|
193
|
+
// API: hf:nvidia/Kimi-K2.5-NVFP4 → ctx=262144, out=65536 (NVFP4 quantized)
|
|
269
194
|
{
|
|
270
|
-
id: "hf:
|
|
271
|
-
name: "
|
|
195
|
+
id: "hf:nvidia/Kimi-K2.5-NVFP4",
|
|
196
|
+
name: "nvidia/Kimi-K2.5-NVFP4",
|
|
272
197
|
reasoning: true,
|
|
273
198
|
input: ["text", "image"],
|
|
274
199
|
cost: {
|
|
275
|
-
input:
|
|
276
|
-
output:
|
|
277
|
-
cacheRead:
|
|
200
|
+
input: 0.6,
|
|
201
|
+
output: 3,
|
|
202
|
+
cacheRead: 0.6,
|
|
278
203
|
cacheWrite: 0,
|
|
279
204
|
},
|
|
280
205
|
contextWindow: 262144,
|
package/src/tools/search.ts
CHANGED
|
@@ -8,7 +8,8 @@ import type {
|
|
|
8
8
|
import { Text } from "@mariozechner/pi-tui";
|
|
9
9
|
import { type Static, Type } from "@sinclair/typebox";
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
export const SYNTHETIC_WEB_SEARCH_TOOL = "synthetic_web_search" as const;
|
|
12
|
+
|
|
12
13
|
interface SyntheticSearchResult {
|
|
13
14
|
url: string;
|
|
14
15
|
title: string;
|
|
@@ -27,7 +28,6 @@ interface WebSearchDetails {
|
|
|
27
28
|
isError?: boolean;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
// Schema
|
|
31
31
|
const SearchParams = Type.Object({
|
|
32
32
|
query: Type.String({
|
|
33
33
|
description: "The search query. Be specific for best results.",
|
|
@@ -36,80 +36,9 @@ const SearchParams = Type.Object({
|
|
|
36
36
|
|
|
37
37
|
type SearchParamsType = Static<typeof SearchParams>;
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
// Returns "ok" if the user has access, or an error message if not.
|
|
41
|
-
async function checkSubscriptionAccess(
|
|
42
|
-
apiKey: string,
|
|
43
|
-
): Promise<{ ok: true } | { ok: false; reason: string }> {
|
|
44
|
-
try {
|
|
45
|
-
const response = await fetch("https://api.synthetic.new/v2/quotas", {
|
|
46
|
-
method: "GET",
|
|
47
|
-
headers: {
|
|
48
|
-
Authorization: `Bearer ${apiKey}`,
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
if (!response.ok) {
|
|
53
|
-
return {
|
|
54
|
-
ok: false,
|
|
55
|
-
reason: `Quotas check failed (HTTP ${response.status})`,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const data = await response.json();
|
|
60
|
-
if (data?.subscription?.limit > 0) {
|
|
61
|
-
return { ok: true };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
ok: false,
|
|
66
|
-
reason: "No active subscription (search requires a subscription plan)",
|
|
67
|
-
};
|
|
68
|
-
} catch (error) {
|
|
69
|
-
const message =
|
|
70
|
-
error instanceof Error ? error.message : "Unknown error occurred";
|
|
71
|
-
return { ok: false, reason: `Quotas check failed: ${message}` };
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Tool Registration
|
|
76
|
-
export function registerSyntheticWebSearchTool(pi: ExtensionAPI) {
|
|
77
|
-
const apiKey = process.env.SYNTHETIC_API_KEY;
|
|
78
|
-
if (!apiKey) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Register tool immediately so it's available when tools are collected
|
|
83
|
-
registerTool(pi, apiKey);
|
|
84
|
-
|
|
85
|
-
// On session start, remove tool from active set, check subscription, re-add if valid
|
|
86
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
87
|
-
// Disable tool until subscription is verified
|
|
88
|
-
const activeTools = pi.getActiveTools();
|
|
89
|
-
pi.setActiveTools(activeTools.filter((t) => t !== "synthetic_web_search"));
|
|
90
|
-
|
|
91
|
-
const access = await checkSubscriptionAccess(apiKey);
|
|
92
|
-
if (!access.ok) {
|
|
93
|
-
if (ctx.hasUI) {
|
|
94
|
-
ctx.ui.notify(
|
|
95
|
-
`Synthetic web search disabled: ${access.reason}`,
|
|
96
|
-
"warning",
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Add tool back to active tools
|
|
103
|
-
const current = pi.getActiveTools();
|
|
104
|
-
if (!current.includes("synthetic_web_search")) {
|
|
105
|
-
pi.setActiveTools([...current, "synthetic_web_search"]);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function registerTool(pi: ExtensionAPI, apiKey: string) {
|
|
39
|
+
export function registerSyntheticWebSearchTool(pi: ExtensionAPI): void {
|
|
111
40
|
pi.registerTool<typeof SearchParams, WebSearchDetails>({
|
|
112
|
-
name:
|
|
41
|
+
name: SYNTHETIC_WEB_SEARCH_TOOL,
|
|
113
42
|
label: "Synthetic: Web Search",
|
|
114
43
|
description:
|
|
115
44
|
"Search the web using Synthetic's zero-data-retention API. Returns search results with titles, URLs, content snippets, and publication dates. Use for finding documentation, articles, recent information, or any web content. Results are fresh and not cached by Synthetic.",
|
|
@@ -124,14 +53,21 @@ function registerTool(pi: ExtensionAPI, apiKey: string) {
|
|
|
124
53
|
| undefined,
|
|
125
54
|
_ctx: ExtensionContext,
|
|
126
55
|
): Promise<AgentToolResult<WebSearchDetails>> {
|
|
127
|
-
// Send progress update
|
|
128
56
|
onUpdate?.({
|
|
129
57
|
content: [{ type: "text", text: "Searching..." }],
|
|
130
58
|
details: { query: params.query },
|
|
131
59
|
});
|
|
132
60
|
|
|
133
61
|
try {
|
|
134
|
-
|
|
62
|
+
const apiKey = process.env.SYNTHETIC_API_KEY;
|
|
63
|
+
if (!apiKey) {
|
|
64
|
+
const error = "SYNTHETIC_API_KEY is not configured";
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: "text", text: `Error: ${error}` }],
|
|
67
|
+
details: { error, isError: true },
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
135
71
|
const response = await fetch("https://api.synthetic.new/v2/search", {
|
|
136
72
|
method: "POST",
|
|
137
73
|
headers: {
|
|
@@ -151,7 +87,6 @@ function registerTool(pi: ExtensionAPI, apiKey: string) {
|
|
|
151
87
|
};
|
|
152
88
|
}
|
|
153
89
|
|
|
154
|
-
// Parse response
|
|
155
90
|
let data: SyntheticSearchResponse;
|
|
156
91
|
try {
|
|
157
92
|
data = await response.json();
|
|
@@ -166,7 +101,6 @@ function registerTool(pi: ExtensionAPI, apiKey: string) {
|
|
|
166
101
|
};
|
|
167
102
|
}
|
|
168
103
|
|
|
169
|
-
// Format results for LLM
|
|
170
104
|
let content = `Found ${data.results.length} result(s):\n\n`;
|
|
171
105
|
for (const result of data.results) {
|
|
172
106
|
content += `## ${result.title}\n`;
|
|
@@ -184,7 +118,6 @@ function registerTool(pi: ExtensionAPI, apiKey: string) {
|
|
|
184
118
|
},
|
|
185
119
|
};
|
|
186
120
|
} catch (error) {
|
|
187
|
-
// Handle abort signal
|
|
188
121
|
if (error instanceof Error && error.name === "AbortError") {
|
|
189
122
|
return {
|
|
190
123
|
content: [{ type: "text", text: "Search cancelled" }],
|
|
@@ -192,7 +125,6 @@ function registerTool(pi: ExtensionAPI, apiKey: string) {
|
|
|
192
125
|
};
|
|
193
126
|
}
|
|
194
127
|
|
|
195
|
-
// Handle other errors
|
|
196
128
|
const message =
|
|
197
129
|
error instanceof Error ? error.message : "Unknown error occurred";
|
|
198
130
|
return {
|
|
@@ -215,7 +147,6 @@ function registerTool(pi: ExtensionAPI, apiKey: string) {
|
|
|
215
147
|
): Text {
|
|
216
148
|
const { expanded, isPartial } = options;
|
|
217
149
|
|
|
218
|
-
// Handle partial/loading state
|
|
219
150
|
if (isPartial) {
|
|
220
151
|
const text =
|
|
221
152
|
result.content?.[0]?.type === "text"
|
|
@@ -225,8 +156,6 @@ function registerTool(pi: ExtensionAPI, apiKey: string) {
|
|
|
225
156
|
}
|
|
226
157
|
|
|
227
158
|
const details = result.details;
|
|
228
|
-
|
|
229
|
-
// Handle error state
|
|
230
159
|
if (details?.isError) {
|
|
231
160
|
const errorMsg =
|
|
232
161
|
result.content?.[0]?.type === "text"
|
|
@@ -235,21 +164,18 @@ function registerTool(pi: ExtensionAPI, apiKey: string) {
|
|
|
235
164
|
return new Text(theme.fg("error", errorMsg), 0, 0);
|
|
236
165
|
}
|
|
237
166
|
|
|
238
|
-
// Handle success state
|
|
239
167
|
const results = details?.results || [];
|
|
240
168
|
let text = theme.fg("success", `✓ Found ${results.length} result(s)`);
|
|
241
169
|
|
|
242
|
-
// Collapsed view
|
|
243
170
|
if (!expanded && results.length > 0) {
|
|
244
171
|
const first = results[0];
|
|
245
172
|
text += `\n ${theme.fg("dim", `${first.title}`)}`;
|
|
246
173
|
if (results.length > 1) {
|
|
247
174
|
text += theme.fg("dim", ` (${results.length - 1} more)`);
|
|
248
175
|
}
|
|
249
|
-
text += theme.fg("muted",
|
|
176
|
+
text += theme.fg("muted", " [Ctrl+O to expand]");
|
|
250
177
|
}
|
|
251
178
|
|
|
252
|
-
// Expanded view
|
|
253
179
|
if (expanded) {
|
|
254
180
|
for (const r of results) {
|
|
255
181
|
text += `\n\n${theme.fg("accent", theme.bold(r.title))}`;
|
package/.pi/settings.json
DELETED