webfox 0.0.0-test.0 → 4.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.
Files changed (118) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +256 -3
  3. package/assets/webfox-lockup-dark.png +0 -0
  4. package/assets/webfox-lockup.png +0 -0
  5. package/dist/adapter-2YBFCBCZ.js +161 -0
  6. package/dist/adapter-67TIISDW.js +753 -0
  7. package/dist/adapter-AB7LKV7N.js +324 -0
  8. package/dist/adapter-AUYLTDPM.js +73 -0
  9. package/dist/adapter-HITGYUXN.js +494 -0
  10. package/dist/adapter-HPTMLH75.js +334 -0
  11. package/dist/adapter-I6OUKBZQ.js +492 -0
  12. package/dist/adapter-ISZQTZDP.js +166 -0
  13. package/dist/adapter-MAG7X663.js +230 -0
  14. package/dist/adapter-NEXSOHGT.js +232 -0
  15. package/dist/adapter-PADXKW43.js +162 -0
  16. package/dist/adapter-SDQX2533.js +123 -0
  17. package/dist/adapter-UAZNLDSS.js +237 -0
  18. package/dist/adapter-XBAQSK7I.js +282 -0
  19. package/dist/application-types.d.ts +34 -0
  20. package/dist/application.d.ts +2 -0
  21. package/dist/chunk-EF4VMDZL.js +85 -0
  22. package/dist/chunk-G2YAQEET.js +38 -0
  23. package/dist/chunk-I2UIACY3.js +12 -0
  24. package/dist/chunk-L425U55P.js +3051 -0
  25. package/dist/chunk-QRHDXM2L.js +31 -0
  26. package/dist/chunk-SMF5ALX7.js +762 -0
  27. package/dist/chunk-U4BLULLV.js +52 -0
  28. package/dist/chunk-WCTOYZVB.js +85 -0
  29. package/dist/chunk-X6ZBIHZC.js +21 -0
  30. package/dist/chunk-YZXM4U2C.js +21 -0
  31. package/dist/chunk-ZVTVERW5.js +20 -0
  32. package/dist/cli.js +641 -0
  33. package/dist/config.schema.json +4270 -0
  34. package/dist/configuration/defaults.d.ts +3 -0
  35. package/dist/configuration/file.d.ts +17 -0
  36. package/dist/configuration/options-schema.d.ts +2 -0
  37. package/dist/configuration/planning.d.ts +10 -0
  38. package/dist/configuration/schema.d.ts +9 -0
  39. package/dist/configuration/types.d.ts +37 -0
  40. package/dist/contents.d.ts +19 -0
  41. package/dist/domain.d.ts +89 -0
  42. package/dist/errors.d.ts +17 -0
  43. package/dist/index.d.ts +8 -0
  44. package/dist/index.js +38 -0
  45. package/dist/package-metadata.d.ts +3 -0
  46. package/dist/pi-keybindings.d.ts +1 -0
  47. package/dist/pi-params.d.ts +3 -0
  48. package/dist/pi-render.d.ts +50 -0
  49. package/dist/pi-search-render.d.ts +4 -0
  50. package/dist/pi-text.d.ts +4 -0
  51. package/dist/pi-validation.d.ts +4 -0
  52. package/dist/pi.d.ts +2 -0
  53. package/dist/pi.js +563 -0
  54. package/dist/providers/brave/adapter.d.ts +7 -0
  55. package/dist/providers/brave/definition.d.ts +1 -0
  56. package/dist/providers/brave/types.d.ts +4 -0
  57. package/dist/providers/cli-json.d.ts +9 -0
  58. package/dist/providers/cloudflare/adapter.d.ts +5 -0
  59. package/dist/providers/cloudflare/definition.d.ts +1 -0
  60. package/dist/providers/cloudflare/types.d.ts +4 -0
  61. package/dist/providers/contract.d.ts +88 -0
  62. package/dist/providers/custom/adapter.d.ts +9 -0
  63. package/dist/providers/custom/definition.d.ts +1 -0
  64. package/dist/providers/custom/types.d.ts +9 -0
  65. package/dist/providers/definition.d.ts +32 -0
  66. package/dist/providers/exa/adapter.d.ts +8 -0
  67. package/dist/providers/exa/definition.d.ts +1 -0
  68. package/dist/providers/exa/types.d.ts +4 -0
  69. package/dist/providers/firecrawl/adapter.d.ts +7 -0
  70. package/dist/providers/firecrawl/definition.d.ts +1 -0
  71. package/dist/providers/firecrawl/types.d.ts +4 -0
  72. package/dist/providers/gemini/adapter.d.ts +14 -0
  73. package/dist/providers/gemini/definition.d.ts +1 -0
  74. package/dist/providers/gemini/types.d.ts +3 -0
  75. package/dist/providers/linkup/adapter.d.ts +7 -0
  76. package/dist/providers/linkup/definition.d.ts +1 -0
  77. package/dist/providers/linkup/types.d.ts +4 -0
  78. package/dist/providers/metadata.d.ts +15 -0
  79. package/dist/providers/ollama/adapter.d.ts +6 -0
  80. package/dist/providers/ollama/definition.d.ts +1 -0
  81. package/dist/providers/ollama/types.d.ts +4 -0
  82. package/dist/providers/openai/adapter.d.ts +7 -0
  83. package/dist/providers/openai/definition.d.ts +1 -0
  84. package/dist/providers/openai/types.d.ts +28 -0
  85. package/dist/providers/parallel/adapter.d.ts +6 -0
  86. package/dist/providers/parallel/definition.d.ts +1 -0
  87. package/dist/providers/parallel/types.d.ts +4 -0
  88. package/dist/providers/perplexity/adapter.d.ts +7 -0
  89. package/dist/providers/perplexity/definition.d.ts +1 -0
  90. package/dist/providers/perplexity/types.d.ts +4 -0
  91. package/dist/providers/registry.d.ts +16 -0
  92. package/dist/providers/serper/adapter.d.ts +5 -0
  93. package/dist/providers/serper/definition.d.ts +1 -0
  94. package/dist/providers/serper/types.d.ts +21 -0
  95. package/dist/providers/shared.d.ts +4 -0
  96. package/dist/providers/tavily/adapter.d.ts +6 -0
  97. package/dist/providers/tavily/definition.d.ts +1 -0
  98. package/dist/providers/tavily/types.d.ts +4 -0
  99. package/dist/providers/valyu/adapter.d.ts +8 -0
  100. package/dist/providers/valyu/definition.d.ts +1 -0
  101. package/dist/providers/valyu/types.d.ts +4 -0
  102. package/dist/render.d.ts +5 -0
  103. package/dist/runtime/credentials.d.ts +15 -0
  104. package/dist/runtime/duration.d.ts +2 -0
  105. package/dist/runtime/execute.d.ts +20 -0
  106. package/dist/runtime/lifecycle.d.ts +8 -0
  107. package/dist/runtime/outward.d.ts +11 -0
  108. package/dist/runtime/polling.d.ts +13 -0
  109. package/dist/runtime/process.d.ts +4 -0
  110. package/docs/cli-experience.md +177 -0
  111. package/docs/provider.md +177 -0
  112. package/docs/reference.md +181 -0
  113. package/example-config.yaml +36 -0
  114. package/examples/custom/README.md +57 -0
  115. package/examples/custom/provider.mjs +54 -0
  116. package/examples/custom/webfox.json +18 -0
  117. package/package.json +122 -8
  118. package/index.js +0 -2
@@ -0,0 +1,324 @@
1
+ import {
2
+ executeAsyncResearch
3
+ } from "./chunk-EF4VMDZL.js";
4
+ import "./chunk-I2UIACY3.js";
5
+ import "./chunk-WCTOYZVB.js";
6
+ import "./chunk-U4BLULLV.js";
7
+
8
+ // src/providers/gemini/adapter.ts
9
+ import { GoogleGenAI } from "@google/genai";
10
+ var DEFAULT_ANSWER_MODEL = "gemini-3.8-flash";
11
+ var DEFAULT_RESEARCH_AGENT = "deep-research-preview-04-2026";
12
+ var geminiImplementation = {
13
+ async answer(query, config, context, options) {
14
+ const ai = this.createClient(config);
15
+ const request = buildGeminiGenerateContentRequest({
16
+ defaultModel: DEFAULT_ANSWER_MODEL,
17
+ prompt: query,
18
+ options,
19
+ toolConfig: { googleSearch: {} }
20
+ });
21
+ const response = await ai.models.generateContent({
22
+ model: request.model,
23
+ contents: request.contents,
24
+ config: addAbortSignalToGeminiConfig(request.config, context.signal)
25
+ });
26
+ const lines = [];
27
+ lines.push(response.text?.trim() || "No answer returned.");
28
+ const sources = extractGroundingSources(
29
+ response.candidates?.[0]?.groundingMetadata?.groundingChunks
30
+ );
31
+ if (sources.length > 0) {
32
+ lines.push("");
33
+ lines.push("Sources:");
34
+ for (const [index, source] of sources.entries()) {
35
+ lines.push(`${index + 1}. ${source.title}`);
36
+ if (source.url) {
37
+ lines.push(` ${source.url}`);
38
+ }
39
+ }
40
+ }
41
+ return {
42
+ provider: "gemini",
43
+ text: lines.join("\n").trimEnd(),
44
+ itemCount: sources.length
45
+ };
46
+ },
47
+ async research(input, config, context, options) {
48
+ return await executeAsyncResearch({
49
+ providerLabel: "Gemini",
50
+ providerId: "gemini",
51
+ context,
52
+ start: (researchContext) => this.startResearch(input, config, researchContext, options),
53
+ poll: (id, researchContext) => this.pollResearch(id, config, researchContext, options)
54
+ });
55
+ },
56
+ async startResearch(input, config, context, options) {
57
+ const ai = this.createClient(config);
58
+ const requestOptions = getGeminiResearchRequestOptions(options);
59
+ const interaction = await ai.interactions.create(
60
+ {
61
+ ...requestOptions,
62
+ input,
63
+ agent: DEFAULT_RESEARCH_AGENT,
64
+ background: true
65
+ },
66
+ buildGeminiRequestOptions(context.signal, context.idempotencyKey)
67
+ );
68
+ return { id: interaction.id };
69
+ },
70
+ async pollResearch(id, config, context, _options) {
71
+ const ai = this.createClient(config);
72
+ const interaction = await ai.interactions.get(
73
+ id,
74
+ void 0,
75
+ buildGeminiRequestOptions(context.signal)
76
+ );
77
+ const status = readNonEmptyString(interaction.status) ?? "unknown";
78
+ if (status === "completed") {
79
+ const text = formatInteractionSteps(readInteractionSteps(interaction));
80
+ return {
81
+ status: "completed",
82
+ output: {
83
+ provider: "gemini",
84
+ text: text || "Gemini research completed without textual output."
85
+ }
86
+ };
87
+ }
88
+ if (status === "failed") {
89
+ return {
90
+ status: "failed",
91
+ error: "research failed"
92
+ };
93
+ }
94
+ if (status === "cancelled") {
95
+ return {
96
+ status: "cancelled",
97
+ error: "research was canceled"
98
+ };
99
+ }
100
+ if (status === "incomplete") {
101
+ return {
102
+ status: "failed",
103
+ error: "research ended incomplete"
104
+ };
105
+ }
106
+ if (status === "requires_action") {
107
+ return {
108
+ status: "failed",
109
+ error: describeGeminiRequiredAction(readInteractionSteps(interaction))
110
+ };
111
+ }
112
+ return status === "in_progress" ? { status: "in_progress" } : { status: "in_progress", statusText: status };
113
+ },
114
+ createClient(config) {
115
+ const apiKey = config.credentials?.api;
116
+ if (!apiKey) {
117
+ throw new Error("is missing an API key");
118
+ }
119
+ return new GoogleGenAI({
120
+ httpOptions: { retryOptions: { attempts: 1 } },
121
+ apiKey
122
+ });
123
+ }
124
+ };
125
+ function buildGeminiRequestOptions(signal, idempotencyKey) {
126
+ return {
127
+ maxRetries: 0,
128
+ ...signal ? { signal } : {},
129
+ ...idempotencyKey ? { idempotencyKey } : {}
130
+ };
131
+ }
132
+ function addAbortSignalToGeminiConfig(config, signal) {
133
+ if (!signal) {
134
+ return config;
135
+ }
136
+ return {
137
+ ...config ?? {},
138
+ abortSignal: signal
139
+ };
140
+ }
141
+ function readInteractionSteps(interaction) {
142
+ return typeof interaction === "object" && interaction !== null ? interaction.steps : void 0;
143
+ }
144
+ function extractGroundingSources(chunks) {
145
+ const seen = /* @__PURE__ */ new Set();
146
+ const sources = [];
147
+ const maxSources = 5;
148
+ if (!Array.isArray(chunks)) {
149
+ return sources;
150
+ }
151
+ for (const chunk of chunks) {
152
+ const web = typeof chunk === "object" && chunk !== null && "web" in chunk && typeof chunk.web === "object" && chunk.web !== null ? chunk.web : void 0;
153
+ if (!web) continue;
154
+ const rawUrl = typeof web.uri === "string" ? web.uri : "";
155
+ const title = formatGroundingSourceTitle(
156
+ typeof web.title === "string" ? web.title : rawUrl,
157
+ rawUrl
158
+ );
159
+ const url = formatGroundingSourceUrl(rawUrl);
160
+ const key = [title.toLowerCase(), url.toLowerCase()].join("::");
161
+ if (seen.has(key)) continue;
162
+ seen.add(key);
163
+ sources.push({
164
+ title,
165
+ url
166
+ });
167
+ if (sources.length >= maxSources) {
168
+ break;
169
+ }
170
+ }
171
+ return sources;
172
+ }
173
+ function formatInteractionSteps(steps) {
174
+ const lines = [];
175
+ if (!Array.isArray(steps)) {
176
+ return "";
177
+ }
178
+ for (const step of steps) {
179
+ if (typeof step !== "object" || step === null || !("type" in step) || step.type !== "model_output" || !("content" in step) || !Array.isArray(step.content)) {
180
+ continue;
181
+ }
182
+ for (const part of step.content) {
183
+ if (typeof part === "object" && part !== null && "type" in part && part.type === "text" && "text" in part && typeof part.text === "string") {
184
+ const text = part.text.trim();
185
+ if (text) {
186
+ lines.push(text);
187
+ }
188
+ }
189
+ }
190
+ }
191
+ return lines.join("\n\n").trim();
192
+ }
193
+ function formatGroundingSourceTitle(title, url) {
194
+ const trimmedTitle = title?.trim();
195
+ if (trimmedTitle) {
196
+ return trimmedTitle;
197
+ }
198
+ if (url) {
199
+ try {
200
+ return new URL(url).hostname;
201
+ } catch {
202
+ return url;
203
+ }
204
+ }
205
+ return "Untitled";
206
+ }
207
+ function formatGroundingSourceUrl(url) {
208
+ if (!url) {
209
+ return "";
210
+ }
211
+ if (isGoogleGroundingRedirect(url)) {
212
+ return "";
213
+ }
214
+ return url;
215
+ }
216
+ function isGoogleGroundingRedirect(url) {
217
+ try {
218
+ const parsed = new URL(url);
219
+ return parsed.hostname === "vertexaisearch.cloud.google.com" && parsed.pathname.startsWith("/grounding-api-redirect/");
220
+ } catch {
221
+ return false;
222
+ }
223
+ }
224
+ function buildGeminiGenerateContentRequest({
225
+ defaultModel,
226
+ prompt,
227
+ options,
228
+ toolConfig
229
+ }) {
230
+ const requestOptions = isPlainObject(options) ? options : {};
231
+ const explicitConfig = isPlainObject(requestOptions.config) ? requestOptions.config : {};
232
+ return {
233
+ model: readNonEmptyString(requestOptions.model) ?? defaultModel,
234
+ contents: prompt,
235
+ config: {
236
+ ...explicitConfig,
237
+ tools: [toolConfig]
238
+ }
239
+ };
240
+ }
241
+ function describeGeminiRequiredAction(steps) {
242
+ if (!Array.isArray(steps) || steps.length === 0) {
243
+ return "research requires additional action";
244
+ }
245
+ const lastStep = [...steps].reverse().find((value) => typeof value === "object" && value !== null);
246
+ const type = readNonEmptyString(lastStep?.type);
247
+ if (!type) {
248
+ return "research requires additional action";
249
+ }
250
+ return `research requires additional action (${type})`;
251
+ }
252
+ function getGeminiResearchRequestOptions(options) {
253
+ if (!isPlainObject(options)) {
254
+ return {};
255
+ }
256
+ const unknownKeys = Object.keys(options).filter(
257
+ (key) => key !== "agent_config"
258
+ );
259
+ if (unknownKeys.length > 0) {
260
+ throw new Error(
261
+ `Unsupported Gemini research options: ${unknownKeys.join(", ")}.`
262
+ );
263
+ }
264
+ const requestOptions = {};
265
+ const agentConfig = getGeminiDeepResearchAgentConfig(options.agent_config);
266
+ if (agentConfig) {
267
+ requestOptions.agent_config = agentConfig;
268
+ }
269
+ return requestOptions;
270
+ }
271
+ function getGeminiDeepResearchAgentConfig(value) {
272
+ if (!isPlainObject(value)) {
273
+ return void 0;
274
+ }
275
+ if (Object.keys(value).length === 0) {
276
+ return void 0;
277
+ }
278
+ const unknownKeys = Object.keys(value).filter(
279
+ (key) => key !== "thinking_summaries"
280
+ );
281
+ if (unknownKeys.length > 0) {
282
+ throw new Error(
283
+ `Unsupported Gemini agent_config options: ${unknownKeys.join(", ")}.`
284
+ );
285
+ }
286
+ const thinkingSummaries = readNonEmptyString(value.thinking_summaries);
287
+ if (thinkingSummaries !== "auto" && thinkingSummaries !== "none") {
288
+ throw new Error(
289
+ "Gemini agent_config.thinking_summaries must be 'auto' or 'none'."
290
+ );
291
+ }
292
+ return {
293
+ type: "deep-research",
294
+ thinking_summaries: thinkingSummaries
295
+ };
296
+ }
297
+ function isPlainObject(value) {
298
+ return typeof value === "object" && value !== null && !Array.isArray(value);
299
+ }
300
+ function readNonEmptyString(value) {
301
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
302
+ }
303
+ var adapter = {
304
+ async answer(input, config, context) {
305
+ return await geminiImplementation.answer(
306
+ input.query,
307
+ config,
308
+ context,
309
+ input.options
310
+ );
311
+ },
312
+ async research(input, config, context) {
313
+ return await geminiImplementation.research(
314
+ input.input,
315
+ config,
316
+ context,
317
+ input.options
318
+ );
319
+ }
320
+ };
321
+ export {
322
+ adapter,
323
+ geminiImplementation
324
+ };
@@ -0,0 +1,73 @@
1
+ import {
2
+ orderedContents
3
+ } from "./chunk-YZXM4U2C.js";
4
+ import {
5
+ asWebfoxError
6
+ } from "./chunk-U4BLULLV.js";
7
+
8
+ // src/providers/cloudflare/adapter.ts
9
+ import CloudflareClient from "cloudflare";
10
+ var cloudflareImplementation = {
11
+ async contents(urls, config, context, options) {
12
+ const client = createClient(config);
13
+ const accountId = config.accountId;
14
+ if (!accountId) {
15
+ throw new Error("is missing an account ID");
16
+ }
17
+ const answers = await Promise.all(
18
+ urls.map(async (url) => {
19
+ try {
20
+ const markdown = await client.browserRendering.markdown.create(
21
+ {
22
+ ...options ?? {},
23
+ account_id: accountId,
24
+ url
25
+ },
26
+ buildRequestOptions(context)
27
+ );
28
+ return {
29
+ url,
30
+ content: markdown
31
+ };
32
+ } catch (error) {
33
+ return {
34
+ url,
35
+ error: asWebfoxError(error).toJSON()
36
+ };
37
+ }
38
+ })
39
+ );
40
+ return {
41
+ provider: "cloudflare",
42
+ answers
43
+ };
44
+ }
45
+ };
46
+ function createClient(config) {
47
+ const apiToken = config.credentials?.api;
48
+ if (!apiToken) {
49
+ throw new Error("is missing an API token");
50
+ }
51
+ return new CloudflareClient({
52
+ maxRetries: 0,
53
+ apiToken
54
+ });
55
+ }
56
+ function buildRequestOptions(context) {
57
+ return context.signal ? { signal: context.signal } : void 0;
58
+ }
59
+ var adapter = {
60
+ async contents(input, config, context) {
61
+ return orderedContents(
62
+ await cloudflareImplementation.contents(
63
+ input.urls,
64
+ config,
65
+ context,
66
+ input.options
67
+ )
68
+ );
69
+ }
70
+ };
71
+ export {
72
+ adapter
73
+ };