@pi-unipi/web-api 0.1.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 +179 -0
- package/package.json +50 -0
- package/skills/web/SKILL.md +108 -0
- package/src/cache.ts +240 -0
- package/src/commands.ts +45 -0
- package/src/index.ts +100 -0
- package/src/providers/base.ts +108 -0
- package/src/providers/duckduckgo.ts +115 -0
- package/src/providers/firecrawl.ts +105 -0
- package/src/providers/jina-reader.ts +89 -0
- package/src/providers/jina-search.ts +88 -0
- package/src/providers/llm-summarize.ts +71 -0
- package/src/providers/perplexity.ts +191 -0
- package/src/providers/registry.ts +128 -0
- package/src/providers/serpapi.ts +86 -0
- package/src/providers/tavily.ts +95 -0
- package/src/settings.ts +263 -0
- package/src/tools.ts +329 -0
- package/src/tui/provider-selector.ts +71 -0
- package/src/tui/settings-dialog.ts +177 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @unipi/web-api — Settings TUI dialog
|
|
3
|
+
*
|
|
4
|
+
* Interactive TUI for API key management.
|
|
5
|
+
* Uses pi's TUI components for provider selection and key input.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
9
|
+
import { registry } from "../providers/registry.js";
|
|
10
|
+
import {
|
|
11
|
+
getApiKey,
|
|
12
|
+
setApiKey,
|
|
13
|
+
removeApiKey,
|
|
14
|
+
isProviderEnabled,
|
|
15
|
+
setProviderEnabled,
|
|
16
|
+
validateApiKeyFormat,
|
|
17
|
+
} from "../settings.js";
|
|
18
|
+
import { getProviderOptions, getProviderStatuses } from "./provider-selector.js";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Show settings dialog.
|
|
22
|
+
* This is the main entry point for /unipi:web-settings command.
|
|
23
|
+
*/
|
|
24
|
+
export async function showSettingsDialog(pi: ExtensionAPI): Promise<void> {
|
|
25
|
+
let running = true;
|
|
26
|
+
|
|
27
|
+
while (running) {
|
|
28
|
+
const options = getProviderOptions();
|
|
29
|
+
|
|
30
|
+
// Add exit option
|
|
31
|
+
options.push({
|
|
32
|
+
label: "← Back",
|
|
33
|
+
value: "__exit__",
|
|
34
|
+
description: "Exit settings",
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Show provider list
|
|
38
|
+
const selected = await pi.ui.select({
|
|
39
|
+
title: "Web API Settings",
|
|
40
|
+
message: "Select a provider to configure:",
|
|
41
|
+
options,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (!selected || selected === "__exit__") {
|
|
45
|
+
running = false;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Show provider configuration
|
|
50
|
+
await configureProvider(pi, selected);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Configure a specific provider.
|
|
56
|
+
*/
|
|
57
|
+
async function configureProvider(
|
|
58
|
+
pi: ExtensionAPI,
|
|
59
|
+
providerId: string
|
|
60
|
+
): Promise<void> {
|
|
61
|
+
const provider = registry.getProvider(providerId);
|
|
62
|
+
if (!provider) {
|
|
63
|
+
await pi.ui.notify({
|
|
64
|
+
message: `Provider "${providerId}" not found`,
|
|
65
|
+
level: "error",
|
|
66
|
+
});
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const hasApiKey = !!getApiKey(providerId);
|
|
71
|
+
const enabled = isProviderEnabled(providerId);
|
|
72
|
+
|
|
73
|
+
const options = [];
|
|
74
|
+
|
|
75
|
+
// Toggle enable/disable
|
|
76
|
+
options.push({
|
|
77
|
+
label: enabled ? "✓ Enabled" : "✗ Disabled",
|
|
78
|
+
value: "__toggle__",
|
|
79
|
+
description: enabled
|
|
80
|
+
? "Click to disable this provider"
|
|
81
|
+
: "Click to enable this provider",
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// API key management (only for providers that require it)
|
|
85
|
+
if (provider.requiresApiKey) {
|
|
86
|
+
if (hasApiKey) {
|
|
87
|
+
options.push({
|
|
88
|
+
label: "🔑 Update API Key",
|
|
89
|
+
value: "__update_key__",
|
|
90
|
+
description: "Update the API key",
|
|
91
|
+
});
|
|
92
|
+
options.push({
|
|
93
|
+
label: "🗑️ Remove API Key",
|
|
94
|
+
value: "__remove_key__",
|
|
95
|
+
description: "Remove the stored API key",
|
|
96
|
+
});
|
|
97
|
+
} else {
|
|
98
|
+
options.push({
|
|
99
|
+
label: "🔑 Add API Key",
|
|
100
|
+
value: "__add_key__",
|
|
101
|
+
description: "Add an API key for this provider",
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Back option
|
|
107
|
+
options.push({
|
|
108
|
+
label: "← Back",
|
|
109
|
+
value: "__back__",
|
|
110
|
+
description: "Return to provider list",
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const selected = await pi.ui.select({
|
|
114
|
+
title: `Configure ${provider.name}`,
|
|
115
|
+
message: `Capabilities: ${provider.capabilities.join(", ")}`,
|
|
116
|
+
options,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
switch (selected) {
|
|
120
|
+
case "__toggle__":
|
|
121
|
+
setProviderEnabled(providerId, !enabled);
|
|
122
|
+
await pi.ui.notify({
|
|
123
|
+
message: `${provider.name} ${!enabled ? "enabled" : "disabled"}`,
|
|
124
|
+
level: "success",
|
|
125
|
+
});
|
|
126
|
+
break;
|
|
127
|
+
|
|
128
|
+
case "__add_key__":
|
|
129
|
+
case "__update_key__":
|
|
130
|
+
await inputApiKey(pi, providerId, provider.name);
|
|
131
|
+
break;
|
|
132
|
+
|
|
133
|
+
case "__remove_key__":
|
|
134
|
+
removeApiKey(providerId);
|
|
135
|
+
await pi.ui.notify({
|
|
136
|
+
message: `API key removed for ${provider.name}`,
|
|
137
|
+
level: "success",
|
|
138
|
+
});
|
|
139
|
+
break;
|
|
140
|
+
|
|
141
|
+
case "__back__":
|
|
142
|
+
default:
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Input API key for a provider.
|
|
149
|
+
*/
|
|
150
|
+
async function inputApiKey(
|
|
151
|
+
pi: ExtensionAPI,
|
|
152
|
+
providerId: string,
|
|
153
|
+
providerName: string
|
|
154
|
+
): Promise<void> {
|
|
155
|
+
const apiKey = await pi.ui.input({
|
|
156
|
+
title: `API Key for ${providerName}`,
|
|
157
|
+
message: `Enter API key (env: ${registry.getProvider(providerId)?.apiKeyEnv || "N/A"}):`,
|
|
158
|
+
placeholder: "sk-...",
|
|
159
|
+
validate: async (value: string) => {
|
|
160
|
+
if (!value || value.trim().length === 0) {
|
|
161
|
+
return "API key cannot be empty";
|
|
162
|
+
}
|
|
163
|
+
if (!validateApiKeyFormat(providerId, value)) {
|
|
164
|
+
return "API key format looks invalid";
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
if (apiKey) {
|
|
171
|
+
setApiKey(providerId, apiKey);
|
|
172
|
+
await pi.ui.notify({
|
|
173
|
+
message: `API key saved for ${providerName}`,
|
|
174
|
+
level: "success",
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|