Websearch tweaks

This commit is contained in:
Dax Raad 2026-07-28 11:10:33 -04:00
commit ee02fb4fce

View file

@ -32,85 +32,83 @@ export const Plugin = {
yield* ctx.tool yield* ctx.tool
.transform((draft) => .transform((draft) =>
draft.add( draft.add({
{ name,
name, options: { codemode: false },
options: { codemode: false }, description,
description, input: Input,
input: Input, output: Output,
output: Output, execute: (input, context) =>
execute: (input, context) => Effect.gen(function* () {
Effect.gen(function* () { yield* permission.assert({
yield* permission.assert({ action: name,
action: name, resources: [input.query],
resources: [input.query], save: ["*"],
save: ["*"], metadata: input,
metadata: input, sessionID: context.sessionID,
sessionID: context.sessionID, agent: context.agent,
agent: context.agent, source: { type: "tool", messageID: context.messageID, callID: context.callID },
source: { type: "tool", messageID: context.messageID, callID: context.callID }, })
}) const result = yield* ctx.websearch.query(input).pipe(
const result = yield* ctx.websearch.query(input).pipe( Effect.catch((error) => {
Effect.catch((error) => { if (!Schema.is(WebSearch.ProviderRequiredError)(error)) return Effect.fail(error)
if (!Schema.is(WebSearch.ProviderRequiredError)(error)) return Effect.fail(error) return Effect.gen(function* () {
return Effect.gen(function* () { const providers = (yield* ctx.websearch.providers()).data
const providers = (yield* ctx.websearch.providers()).data if (providers.length === 0) return yield* new WebSearch.ProviderRequiredError()
if (providers.length === 0) return yield* new WebSearch.ProviderRequiredError() const response = yield* forms.ask({
const response = yield* forms.ask({ sessionID: context.sessionID,
sessionID: context.sessionID, title: "Web Search",
title: "Choose a provider so the agent can search the web", metadata: { kind: "websearch.provider" },
metadata: { kind: "websearch.provider" }, fields: [
fields: [ {
{ key: "enabled",
key: "provider", description: "Allow OpenCode to search the web?",
title: "Provider", type: "string",
description: "OpenCode will use your choice for future searches.", required: true,
type: "string", custom: false,
required: true, options: [
custom: false, { value: "yes", label: "Allow web search" },
options: [ { value: "no", label: "Disable web search" },
...providers.map((provider) => ({ value: provider.id, label: provider.name })), ],
{ value: "__disable__", label: "Disable web search" }, },
], ],
},
],
})
if (response.status === "cancelled") return yield* Effect.fail(new Error("Web search cancelled"))
const answer = response.answer.provider
if (answer === "__disable__") {
yield* kv.set("websearch:provider", false)
return yield* new WebSearch.DisabledError()
}
if (typeof answer !== "string" || !providers.some((provider) => provider.id === answer))
return yield* new WebSearch.ProviderRequiredError()
yield* kv.set("websearch:provider", answer)
return yield* ctx.websearch.query(input)
}) })
}), if (response.status === "cancelled") return yield* Effect.fail(new Error("Web search cancelled"))
) const answer = response.answer.enabled
const output = { if (answer === "no") {
provider: result.data.providerID, yield* kv.set("websearch:provider", false)
results: result.data.results, return yield* new WebSearch.DisabledError()
} }
const content = output.results.length if (answer === "yes") {
? output.results yield* kv.set("websearch:provider", providers[Math.floor(Math.random() * providers.length)].id)
.map((result) => { return yield* ctx.websearch.query(input)
const title = result.title ?? result.url }
const published = result.time.published return yield* new WebSearch.ProviderRequiredError()
? `\nPublished: ${new Date(result.time.published).toISOString()}` })
: "" }),
return `## [${title}](${result.url})${published}${result.content ? `\n\n${result.content}` : ""}` )
}) const output = {
.join("\n\n") provider: result.data.providerID,
: NO_RESULTS results: result.data.results,
return { output, content, metadata: { provider: output.provider } } }
}).pipe( const content = output.results.length
Effect.mapError( ? output.results
(error) => new ToolFailure({ message: `Unable to search the web for ${input.query}`, error }), .map((result) => {
), const title = result.title ?? result.url
const published = result.time.published
? `\nPublished: ${new Date(result.time.published).toISOString()}`
: ""
return `## [${title}](${result.url})${published}${result.content ? `\n\n${result.content}` : ""}`
})
.join("\n\n")
: NO_RESULTS
return { output, content, metadata: { provider: output.provider } }
}).pipe(
Effect.mapError(
(error) => new ToolFailure({ message: `Unable to search the web for ${input.query}`, error }),
), ),
}, ),
), }),
) )
.pipe(Effect.orDie) .pipe(Effect.orDie)