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.
- package/LICENSE +21 -0
- package/README.md +256 -3
- package/assets/webfox-lockup-dark.png +0 -0
- package/assets/webfox-lockup.png +0 -0
- package/dist/adapter-2YBFCBCZ.js +161 -0
- package/dist/adapter-67TIISDW.js +753 -0
- package/dist/adapter-AB7LKV7N.js +324 -0
- package/dist/adapter-AUYLTDPM.js +73 -0
- package/dist/adapter-HITGYUXN.js +494 -0
- package/dist/adapter-HPTMLH75.js +334 -0
- package/dist/adapter-I6OUKBZQ.js +492 -0
- package/dist/adapter-ISZQTZDP.js +166 -0
- package/dist/adapter-MAG7X663.js +230 -0
- package/dist/adapter-NEXSOHGT.js +232 -0
- package/dist/adapter-PADXKW43.js +162 -0
- package/dist/adapter-SDQX2533.js +123 -0
- package/dist/adapter-UAZNLDSS.js +237 -0
- package/dist/adapter-XBAQSK7I.js +282 -0
- package/dist/application-types.d.ts +34 -0
- package/dist/application.d.ts +2 -0
- package/dist/chunk-EF4VMDZL.js +85 -0
- package/dist/chunk-G2YAQEET.js +38 -0
- package/dist/chunk-I2UIACY3.js +12 -0
- package/dist/chunk-L425U55P.js +3051 -0
- package/dist/chunk-QRHDXM2L.js +31 -0
- package/dist/chunk-SMF5ALX7.js +762 -0
- package/dist/chunk-U4BLULLV.js +52 -0
- package/dist/chunk-WCTOYZVB.js +85 -0
- package/dist/chunk-X6ZBIHZC.js +21 -0
- package/dist/chunk-YZXM4U2C.js +21 -0
- package/dist/chunk-ZVTVERW5.js +20 -0
- package/dist/cli.js +641 -0
- package/dist/config.schema.json +4270 -0
- package/dist/configuration/defaults.d.ts +3 -0
- package/dist/configuration/file.d.ts +17 -0
- package/dist/configuration/options-schema.d.ts +2 -0
- package/dist/configuration/planning.d.ts +10 -0
- package/dist/configuration/schema.d.ts +9 -0
- package/dist/configuration/types.d.ts +37 -0
- package/dist/contents.d.ts +19 -0
- package/dist/domain.d.ts +89 -0
- package/dist/errors.d.ts +17 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +38 -0
- package/dist/package-metadata.d.ts +3 -0
- package/dist/pi-keybindings.d.ts +1 -0
- package/dist/pi-params.d.ts +3 -0
- package/dist/pi-render.d.ts +50 -0
- package/dist/pi-search-render.d.ts +4 -0
- package/dist/pi-text.d.ts +4 -0
- package/dist/pi-validation.d.ts +4 -0
- package/dist/pi.d.ts +2 -0
- package/dist/pi.js +563 -0
- package/dist/providers/brave/adapter.d.ts +7 -0
- package/dist/providers/brave/definition.d.ts +1 -0
- package/dist/providers/brave/types.d.ts +4 -0
- package/dist/providers/cli-json.d.ts +9 -0
- package/dist/providers/cloudflare/adapter.d.ts +5 -0
- package/dist/providers/cloudflare/definition.d.ts +1 -0
- package/dist/providers/cloudflare/types.d.ts +4 -0
- package/dist/providers/contract.d.ts +88 -0
- package/dist/providers/custom/adapter.d.ts +9 -0
- package/dist/providers/custom/definition.d.ts +1 -0
- package/dist/providers/custom/types.d.ts +9 -0
- package/dist/providers/definition.d.ts +32 -0
- package/dist/providers/exa/adapter.d.ts +8 -0
- package/dist/providers/exa/definition.d.ts +1 -0
- package/dist/providers/exa/types.d.ts +4 -0
- package/dist/providers/firecrawl/adapter.d.ts +7 -0
- package/dist/providers/firecrawl/definition.d.ts +1 -0
- package/dist/providers/firecrawl/types.d.ts +4 -0
- package/dist/providers/gemini/adapter.d.ts +14 -0
- package/dist/providers/gemini/definition.d.ts +1 -0
- package/dist/providers/gemini/types.d.ts +3 -0
- package/dist/providers/linkup/adapter.d.ts +7 -0
- package/dist/providers/linkup/definition.d.ts +1 -0
- package/dist/providers/linkup/types.d.ts +4 -0
- package/dist/providers/metadata.d.ts +15 -0
- package/dist/providers/ollama/adapter.d.ts +6 -0
- package/dist/providers/ollama/definition.d.ts +1 -0
- package/dist/providers/ollama/types.d.ts +4 -0
- package/dist/providers/openai/adapter.d.ts +7 -0
- package/dist/providers/openai/definition.d.ts +1 -0
- package/dist/providers/openai/types.d.ts +28 -0
- package/dist/providers/parallel/adapter.d.ts +6 -0
- package/dist/providers/parallel/definition.d.ts +1 -0
- package/dist/providers/parallel/types.d.ts +4 -0
- package/dist/providers/perplexity/adapter.d.ts +7 -0
- package/dist/providers/perplexity/definition.d.ts +1 -0
- package/dist/providers/perplexity/types.d.ts +4 -0
- package/dist/providers/registry.d.ts +16 -0
- package/dist/providers/serper/adapter.d.ts +5 -0
- package/dist/providers/serper/definition.d.ts +1 -0
- package/dist/providers/serper/types.d.ts +21 -0
- package/dist/providers/shared.d.ts +4 -0
- package/dist/providers/tavily/adapter.d.ts +6 -0
- package/dist/providers/tavily/definition.d.ts +1 -0
- package/dist/providers/tavily/types.d.ts +4 -0
- package/dist/providers/valyu/adapter.d.ts +8 -0
- package/dist/providers/valyu/definition.d.ts +1 -0
- package/dist/providers/valyu/types.d.ts +4 -0
- package/dist/render.d.ts +5 -0
- package/dist/runtime/credentials.d.ts +15 -0
- package/dist/runtime/duration.d.ts +2 -0
- package/dist/runtime/execute.d.ts +20 -0
- package/dist/runtime/lifecycle.d.ts +8 -0
- package/dist/runtime/outward.d.ts +11 -0
- package/dist/runtime/polling.d.ts +13 -0
- package/dist/runtime/process.d.ts +4 -0
- package/docs/cli-experience.md +177 -0
- package/docs/provider.md +177 -0
- package/docs/reference.md +181 -0
- package/example-config.yaml +36 -0
- package/examples/custom/README.md +57 -0
- package/examples/custom/provider.mjs +54 -0
- package/examples/custom/webfox.json +18 -0
- package/package.json +122 -8
- package/index.js +0 -2
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
import {
|
|
2
|
+
executeAsyncResearch
|
|
3
|
+
} from "./chunk-EF4VMDZL.js";
|
|
4
|
+
import "./chunk-I2UIACY3.js";
|
|
5
|
+
import "./chunk-WCTOYZVB.js";
|
|
6
|
+
import {
|
|
7
|
+
trimSnippet
|
|
8
|
+
} from "./chunk-X6ZBIHZC.js";
|
|
9
|
+
import "./chunk-U4BLULLV.js";
|
|
10
|
+
|
|
11
|
+
// src/providers/openai/adapter.ts
|
|
12
|
+
import OpenAI from "openai";
|
|
13
|
+
var DEFAULT_SEARCH_MODEL = "gpt-4.1";
|
|
14
|
+
var DEFAULT_ANSWER_MODEL = "gpt-4.1";
|
|
15
|
+
var DEFAULT_RESEARCH_MODEL = "o4-mini-deep-research";
|
|
16
|
+
var searchResultSchema = {
|
|
17
|
+
type: "object",
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
required: ["sources"],
|
|
20
|
+
properties: {
|
|
21
|
+
sources: {
|
|
22
|
+
type: "array",
|
|
23
|
+
items: {
|
|
24
|
+
type: "object",
|
|
25
|
+
additionalProperties: false,
|
|
26
|
+
required: ["title", "url", "snippet"],
|
|
27
|
+
properties: {
|
|
28
|
+
title: { type: "string" },
|
|
29
|
+
url: { type: "string" },
|
|
30
|
+
snippet: { type: "string" }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var openaiImplementation = {
|
|
37
|
+
async search(query, maxResults, config, context, options) {
|
|
38
|
+
const client = createClient(config);
|
|
39
|
+
const response = await client.responses.create(
|
|
40
|
+
buildOpenAISearchRequest(query, maxResults, options),
|
|
41
|
+
buildRequestOptions(context.signal, context.idempotencyKey)
|
|
42
|
+
);
|
|
43
|
+
return parseSearchResponse(response, maxResults);
|
|
44
|
+
},
|
|
45
|
+
async answer(query, config, context, options) {
|
|
46
|
+
const client = createClient(config);
|
|
47
|
+
const response = await client.responses.create(
|
|
48
|
+
buildOpenAIAnswerRequest(query, options),
|
|
49
|
+
buildRequestOptions(context.signal, context.idempotencyKey)
|
|
50
|
+
);
|
|
51
|
+
return ensureCompletedResponse(response, "answer");
|
|
52
|
+
},
|
|
53
|
+
async research(input, config, context, options) {
|
|
54
|
+
return await executeAsyncResearch({
|
|
55
|
+
providerLabel: "OpenAI",
|
|
56
|
+
providerId: "openai",
|
|
57
|
+
context,
|
|
58
|
+
start: (researchContext) => openaiImplementation.startResearch(
|
|
59
|
+
input,
|
|
60
|
+
config,
|
|
61
|
+
researchContext,
|
|
62
|
+
options
|
|
63
|
+
),
|
|
64
|
+
poll: (id, researchContext) => openaiImplementation.pollResearch(id, config, researchContext, options)
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
async startResearch(input, config, context, options) {
|
|
68
|
+
const client = createClient(config);
|
|
69
|
+
const response = await client.responses.create(
|
|
70
|
+
buildOpenAIResearchRequest(input, options),
|
|
71
|
+
buildRequestOptions(context.signal, context.idempotencyKey)
|
|
72
|
+
);
|
|
73
|
+
return { id: response.id };
|
|
74
|
+
},
|
|
75
|
+
async pollResearch(id, config, context, _options) {
|
|
76
|
+
const client = createClient(config);
|
|
77
|
+
const response = await client.responses.retrieve(
|
|
78
|
+
id,
|
|
79
|
+
void 0,
|
|
80
|
+
buildRequestOptions(context.signal)
|
|
81
|
+
);
|
|
82
|
+
const status = response.status ?? "completed";
|
|
83
|
+
if (status === "completed") {
|
|
84
|
+
return {
|
|
85
|
+
status: "completed",
|
|
86
|
+
output: formatResponseOutput(response, "research")
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (status === "failed") {
|
|
90
|
+
return {
|
|
91
|
+
status: "failed",
|
|
92
|
+
error: response.error?.message ?? "research failed"
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (status === "cancelled") {
|
|
96
|
+
return {
|
|
97
|
+
status: "cancelled",
|
|
98
|
+
error: "research was canceled"
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (status === "incomplete") {
|
|
102
|
+
return {
|
|
103
|
+
status: "failed",
|
|
104
|
+
error: formatIncompleteError(response, "research")
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
status: "in_progress",
|
|
109
|
+
statusText: status
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
function createClient(config) {
|
|
114
|
+
const apiKey = config.credentials?.api;
|
|
115
|
+
if (!apiKey) {
|
|
116
|
+
throw new Error("is missing an API key");
|
|
117
|
+
}
|
|
118
|
+
const baseUrl = config.baseUrl;
|
|
119
|
+
return new OpenAI({
|
|
120
|
+
maxRetries: 0,
|
|
121
|
+
apiKey,
|
|
122
|
+
...baseUrl ? { baseURL: baseUrl } : {}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function generationControls(options) {
|
|
126
|
+
const reasoning = options?.reasoning;
|
|
127
|
+
const effort = readStringUnion(reasoning?.effort, [
|
|
128
|
+
"none",
|
|
129
|
+
"minimal",
|
|
130
|
+
"low",
|
|
131
|
+
"medium",
|
|
132
|
+
"high",
|
|
133
|
+
"xhigh",
|
|
134
|
+
"max"
|
|
135
|
+
]);
|
|
136
|
+
const maxTokens = readPositiveInteger(options?.max_output_tokens);
|
|
137
|
+
return {
|
|
138
|
+
...effort ? { reasoning: { effort } } : {},
|
|
139
|
+
...maxTokens ? { max_output_tokens: maxTokens } : {}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function buildOpenAISearchRequest(query, maxResults, options) {
|
|
143
|
+
const mergedOptions = resolveOpenAISearchOptions(options);
|
|
144
|
+
const model = mergedOptions.model ?? DEFAULT_SEARCH_MODEL;
|
|
145
|
+
const instructions = mergedOptions.instructions;
|
|
146
|
+
return {
|
|
147
|
+
model,
|
|
148
|
+
...generationControls(options),
|
|
149
|
+
input: [
|
|
150
|
+
"Search the public web and return only the most relevant sources for the user's query.",
|
|
151
|
+
`Return at most ${maxResults} sources.`,
|
|
152
|
+
"Prefer official, primary, or highly reputable sources when available.",
|
|
153
|
+
"Each snippet should be short, specific, and grounded in the retrieved source.",
|
|
154
|
+
"Return only data matching the provided JSON schema.",
|
|
155
|
+
"",
|
|
156
|
+
`User query: ${query}`
|
|
157
|
+
].join("\n"),
|
|
158
|
+
tools: [buildOpenAIWebSearchTool(mergedOptions)],
|
|
159
|
+
text: {
|
|
160
|
+
format: {
|
|
161
|
+
type: "json_schema",
|
|
162
|
+
name: "openai_web_search_results",
|
|
163
|
+
schema: searchResultSchema,
|
|
164
|
+
strict: true
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
...instructions ? { instructions } : {}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function buildOpenAIAnswerRequest(query, options) {
|
|
171
|
+
const mergedOptions = resolveOpenAIAnswerOptions(options);
|
|
172
|
+
const model = mergedOptions.model ?? DEFAULT_ANSWER_MODEL;
|
|
173
|
+
const instructions = mergedOptions.instructions;
|
|
174
|
+
return {
|
|
175
|
+
model,
|
|
176
|
+
...generationControls(options),
|
|
177
|
+
input: query,
|
|
178
|
+
tools: [buildOpenAIWebSearchTool(mergedOptions)],
|
|
179
|
+
...instructions ? { instructions } : {}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function buildOpenAIResearchRequest(input, options) {
|
|
183
|
+
const mergedOptions = resolveOpenAIResearchOptions(options);
|
|
184
|
+
const model = mergedOptions.model ?? DEFAULT_RESEARCH_MODEL;
|
|
185
|
+
const instructions = mergedOptions.instructions;
|
|
186
|
+
const maxToolCalls = mergedOptions.max_tool_calls;
|
|
187
|
+
return {
|
|
188
|
+
model,
|
|
189
|
+
...generationControls(options),
|
|
190
|
+
input,
|
|
191
|
+
background: true,
|
|
192
|
+
tools: [buildOpenAIWebSearchTool(mergedOptions)],
|
|
193
|
+
...instructions ? { instructions } : {},
|
|
194
|
+
...maxToolCalls ? { max_tool_calls: maxToolCalls } : {}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function buildOpenAIWebSearchTool(options) {
|
|
198
|
+
const tool = { type: "web_search" };
|
|
199
|
+
if (options.externalWebAccess !== void 0)
|
|
200
|
+
tool.external_web_access = options.externalWebAccess;
|
|
201
|
+
if (options.searchContextSize) {
|
|
202
|
+
tool.search_context_size = options.searchContextSize;
|
|
203
|
+
}
|
|
204
|
+
if (options.allowedDomains && options.allowedDomains.length > 0) {
|
|
205
|
+
tool.filters = { allowed_domains: options.allowedDomains };
|
|
206
|
+
}
|
|
207
|
+
if (options.userLocation) {
|
|
208
|
+
tool.user_location = {
|
|
209
|
+
type: "approximate",
|
|
210
|
+
...options.userLocation
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
return tool;
|
|
214
|
+
}
|
|
215
|
+
function resolveOpenAIWebSearchToolOptions(merged) {
|
|
216
|
+
const searchContextSize = readStringUnion(merged.searchContextSize, [
|
|
217
|
+
"low",
|
|
218
|
+
"medium",
|
|
219
|
+
"high"
|
|
220
|
+
]);
|
|
221
|
+
const allowedDomains = readStringArray(merged.allowedDomains);
|
|
222
|
+
const userLocation = readUserLocation(merged.userLocation);
|
|
223
|
+
return {
|
|
224
|
+
...typeof merged.externalWebAccess === "boolean" ? { externalWebAccess: merged.externalWebAccess } : {},
|
|
225
|
+
...searchContextSize ? { searchContextSize } : {},
|
|
226
|
+
...allowedDomains ? { allowedDomains } : {},
|
|
227
|
+
...userLocation ? { userLocation } : {}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function resolveOpenAISearchOptions(options) {
|
|
231
|
+
const mergedOptions = {
|
|
232
|
+
...options ?? {}
|
|
233
|
+
};
|
|
234
|
+
const model = readNonEmptyString(mergedOptions.model);
|
|
235
|
+
const instructions = readNonEmptyString(mergedOptions.instructions);
|
|
236
|
+
return {
|
|
237
|
+
...model ? { model } : {},
|
|
238
|
+
...instructions ? { instructions } : {},
|
|
239
|
+
...resolveOpenAIWebSearchToolOptions(mergedOptions)
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
function resolveOpenAIAnswerOptions(options) {
|
|
243
|
+
const mergedOptions = {
|
|
244
|
+
...options ?? {}
|
|
245
|
+
};
|
|
246
|
+
const model = readNonEmptyString(mergedOptions.model);
|
|
247
|
+
const instructions = readNonEmptyString(mergedOptions.instructions);
|
|
248
|
+
return {
|
|
249
|
+
...model ? { model } : {},
|
|
250
|
+
...instructions ? { instructions } : {},
|
|
251
|
+
...resolveOpenAIWebSearchToolOptions(mergedOptions)
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function resolveOpenAIResearchOptions(options) {
|
|
255
|
+
const mergedOptions = {
|
|
256
|
+
...options ?? {}
|
|
257
|
+
};
|
|
258
|
+
const model = readNonEmptyString(mergedOptions.model);
|
|
259
|
+
const instructions = readNonEmptyString(mergedOptions.instructions);
|
|
260
|
+
const maxToolCalls = readPositiveInteger(mergedOptions.max_tool_calls);
|
|
261
|
+
return {
|
|
262
|
+
...model ? { model } : {},
|
|
263
|
+
...instructions ? { instructions } : {},
|
|
264
|
+
...maxToolCalls ? { max_tool_calls: maxToolCalls } : {},
|
|
265
|
+
...resolveOpenAIWebSearchToolOptions(mergedOptions)
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function buildRequestOptions(signal, idempotencyKey) {
|
|
269
|
+
if (!signal && !idempotencyKey) {
|
|
270
|
+
return void 0;
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
...signal ? { signal } : {},
|
|
274
|
+
...idempotencyKey ? { idempotencyKey } : {}
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function parseSearchResponse(response, maxResults) {
|
|
278
|
+
const status = response.status ?? "completed";
|
|
279
|
+
if (status === "failed") {
|
|
280
|
+
throw new Error(response.error?.message ?? "search failed");
|
|
281
|
+
}
|
|
282
|
+
if (status === "cancelled") {
|
|
283
|
+
throw new Error("search was canceled");
|
|
284
|
+
}
|
|
285
|
+
if (status === "incomplete") {
|
|
286
|
+
throw new Error(formatIncompleteError(response, "search"));
|
|
287
|
+
}
|
|
288
|
+
if (status !== "completed") {
|
|
289
|
+
throw new Error(`search did not complete (status: ${status})`);
|
|
290
|
+
}
|
|
291
|
+
const payload = parseSearchPayload(response.output_text);
|
|
292
|
+
return {
|
|
293
|
+
provider: "openai",
|
|
294
|
+
results: payload.sources.slice(0, maxResults).map((source) => ({
|
|
295
|
+
title: source.title.trim(),
|
|
296
|
+
url: source.url.trim(),
|
|
297
|
+
snippet: trimSnippet(source.snippet)
|
|
298
|
+
}))
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function ensureCompletedResponse(response, operation) {
|
|
302
|
+
const status = response.status ?? "completed";
|
|
303
|
+
if (status === "completed") {
|
|
304
|
+
return formatResponseOutput(response, operation);
|
|
305
|
+
}
|
|
306
|
+
if (status === "failed") {
|
|
307
|
+
throw new Error(response.error?.message ?? `${operation} failed`);
|
|
308
|
+
}
|
|
309
|
+
if (status === "cancelled") {
|
|
310
|
+
throw new Error(`${operation} was canceled`);
|
|
311
|
+
}
|
|
312
|
+
if (status === "incomplete") {
|
|
313
|
+
throw new Error(formatIncompleteError(response, operation));
|
|
314
|
+
}
|
|
315
|
+
throw new Error(`${operation} did not complete (status: ${status})`);
|
|
316
|
+
}
|
|
317
|
+
function formatResponseOutput(response, operation) {
|
|
318
|
+
const lines = [];
|
|
319
|
+
lines.push(
|
|
320
|
+
response.output_text?.trim() || `OpenAI ${operation} completed without textual output.`
|
|
321
|
+
);
|
|
322
|
+
const citations = extractUrlCitations(response);
|
|
323
|
+
if (citations.length > 0) {
|
|
324
|
+
lines.push("");
|
|
325
|
+
lines.push("Sources:");
|
|
326
|
+
for (const [index, citation] of citations.entries()) {
|
|
327
|
+
lines.push(`${index + 1}. ${citation.title}`);
|
|
328
|
+
lines.push(` ${citation.url}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
provider: "openai",
|
|
333
|
+
text: lines.join("\n").trimEnd(),
|
|
334
|
+
itemCount: citations.length,
|
|
335
|
+
metadata: {
|
|
336
|
+
responseId: response.id,
|
|
337
|
+
model: response.model,
|
|
338
|
+
citations
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
function extractUrlCitations(response) {
|
|
343
|
+
const citations = [];
|
|
344
|
+
const seen = /* @__PURE__ */ new Set();
|
|
345
|
+
for (const item of response.output) {
|
|
346
|
+
if (item.type !== "message" || !item.content) {
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
for (const content of item.content) {
|
|
350
|
+
if (content.type !== "output_text" || !content.annotations) {
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
for (const annotation of content.annotations) {
|
|
354
|
+
if (annotation.type !== "url_citation") {
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
const title = readNonEmptyString(annotation.title);
|
|
358
|
+
const url = readNonEmptyString(annotation.url);
|
|
359
|
+
const startIndex = readInteger(annotation.start_index);
|
|
360
|
+
const endIndex = readInteger(annotation.end_index);
|
|
361
|
+
if (!title || !url || startIndex === void 0 || endIndex === void 0) {
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
const citation = {
|
|
365
|
+
title,
|
|
366
|
+
url,
|
|
367
|
+
startIndex,
|
|
368
|
+
endIndex
|
|
369
|
+
};
|
|
370
|
+
const key = [
|
|
371
|
+
citation.title,
|
|
372
|
+
citation.url,
|
|
373
|
+
String(citation.startIndex),
|
|
374
|
+
String(citation.endIndex)
|
|
375
|
+
].join("::");
|
|
376
|
+
if (seen.has(key)) {
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
seen.add(key);
|
|
380
|
+
citations.push(citation);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return citations;
|
|
385
|
+
}
|
|
386
|
+
function parseSearchPayload(text) {
|
|
387
|
+
let parsed;
|
|
388
|
+
try {
|
|
389
|
+
parsed = JSON.parse(text ?? "");
|
|
390
|
+
} catch (error) {
|
|
391
|
+
throw new Error(
|
|
392
|
+
`search returned invalid JSON: ${error.message}`
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
if (typeof parsed !== "object" || parsed === null || !("sources" in parsed) || !Array.isArray(parsed.sources)) {
|
|
396
|
+
throw new Error("search output must include a 'sources' array");
|
|
397
|
+
}
|
|
398
|
+
return {
|
|
399
|
+
sources: parsed.sources.map((source, index) => {
|
|
400
|
+
if (typeof source !== "object" || source === null) {
|
|
401
|
+
throw new Error(`search source at index ${index} must be an object`);
|
|
402
|
+
}
|
|
403
|
+
const entry = source;
|
|
404
|
+
const title = readNonEmptyString(entry.title);
|
|
405
|
+
const url = readNonEmptyString(entry.url);
|
|
406
|
+
const snippet = readNonEmptyString(entry.snippet);
|
|
407
|
+
if (!title) {
|
|
408
|
+
throw new Error(`search source at index ${index} is missing title`);
|
|
409
|
+
}
|
|
410
|
+
if (!url) {
|
|
411
|
+
throw new Error(`search source at index ${index} is missing url`);
|
|
412
|
+
}
|
|
413
|
+
if (!snippet) {
|
|
414
|
+
throw new Error(`search source at index ${index} is missing snippet`);
|
|
415
|
+
}
|
|
416
|
+
return { title, url, snippet };
|
|
417
|
+
})
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
function formatIncompleteError(response, operation) {
|
|
421
|
+
const reason = response.incomplete_details?.reason;
|
|
422
|
+
if (reason) {
|
|
423
|
+
return `${operation} ended incomplete (${reason})`;
|
|
424
|
+
}
|
|
425
|
+
return `${operation} ended incomplete`;
|
|
426
|
+
}
|
|
427
|
+
function readNonEmptyString(value) {
|
|
428
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
429
|
+
}
|
|
430
|
+
function readStringArray(value) {
|
|
431
|
+
if (!Array.isArray(value)) {
|
|
432
|
+
return void 0;
|
|
433
|
+
}
|
|
434
|
+
const strings = value.filter(
|
|
435
|
+
(item) => typeof item === "string" && item.trim() !== ""
|
|
436
|
+
);
|
|
437
|
+
return strings.length > 0 ? strings : void 0;
|
|
438
|
+
}
|
|
439
|
+
function readStringUnion(value, values) {
|
|
440
|
+
return typeof value === "string" && values.includes(value) ? value : void 0;
|
|
441
|
+
}
|
|
442
|
+
function readUserLocation(value) {
|
|
443
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
444
|
+
return void 0;
|
|
445
|
+
}
|
|
446
|
+
const location = value;
|
|
447
|
+
const city = readNonEmptyString(location.city);
|
|
448
|
+
const country = readNonEmptyString(location.country);
|
|
449
|
+
const region = readNonEmptyString(location.region);
|
|
450
|
+
const timezone = readNonEmptyString(location.timezone);
|
|
451
|
+
const result = {
|
|
452
|
+
...city ? { city } : {},
|
|
453
|
+
...country ? { country } : {},
|
|
454
|
+
...region ? { region } : {},
|
|
455
|
+
...timezone ? { timezone } : {}
|
|
456
|
+
};
|
|
457
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
458
|
+
}
|
|
459
|
+
function readPositiveInteger(value) {
|
|
460
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : void 0;
|
|
461
|
+
}
|
|
462
|
+
function readInteger(value) {
|
|
463
|
+
return typeof value === "number" && Number.isInteger(value) ? value : void 0;
|
|
464
|
+
}
|
|
465
|
+
var adapter = {
|
|
466
|
+
async search(input, config, context) {
|
|
467
|
+
return await openaiImplementation.search(
|
|
468
|
+
input.query,
|
|
469
|
+
input.maxResults,
|
|
470
|
+
config,
|
|
471
|
+
context,
|
|
472
|
+
input.options
|
|
473
|
+
);
|
|
474
|
+
},
|
|
475
|
+
async answer(input, config, context) {
|
|
476
|
+
return await openaiImplementation.answer(
|
|
477
|
+
input.query,
|
|
478
|
+
config,
|
|
479
|
+
context,
|
|
480
|
+
input.options
|
|
481
|
+
);
|
|
482
|
+
},
|
|
483
|
+
async research(input, config, context) {
|
|
484
|
+
return await openaiImplementation.research(
|
|
485
|
+
input.input,
|
|
486
|
+
config,
|
|
487
|
+
context,
|
|
488
|
+
input.options
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
export {
|
|
493
|
+
adapter
|
|
494
|
+
};
|