droid-acp 0.5.0 → 0.6.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/dist/{acp-agent-k2cYadeP.mjs → acp-agent-DYlR7vNB.mjs} +351 -24
- package/dist/acp-agent-DYlR7vNB.mjs.map +1 -0
- package/dist/index.mjs +25 -1
- package/dist/index.mjs.map +1 -1
- package/dist/lib.d.mts.map +1 -1
- package/dist/lib.mjs +1 -1
- package/package.json +1 -1
- package/dist/acp-agent-k2cYadeP.mjs.map +0 -1
|
@@ -2,14 +2,14 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { ReadableStream, WritableStream } from "node:stream/web";
|
|
4
4
|
import { open, readFile, stat } from "node:fs/promises";
|
|
5
|
-
import os from "node:os";
|
|
6
|
-
import path from "node:path";
|
|
5
|
+
import os, { homedir } from "node:os";
|
|
6
|
+
import path, { join } from "node:path";
|
|
7
7
|
import { createInterface } from "node:readline";
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { createServer } from "node:http";
|
|
10
10
|
import { Readable } from "node:stream";
|
|
11
11
|
import { pipeline } from "node:stream/promises";
|
|
12
|
-
import { createReadStream, promises } from "node:fs";
|
|
12
|
+
import { createReadStream, promises, readFileSync, statSync } from "node:fs";
|
|
13
13
|
import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
|
|
14
14
|
|
|
15
15
|
//#region src/utils.ts
|
|
@@ -1534,7 +1534,7 @@ function parseWebsearchRequestBody(bodyBuffer) {
|
|
|
1534
1534
|
numResults: typeof numResultsRaw === "number" && Number.isFinite(numResultsRaw) ? Math.max(1, numResultsRaw) : 10
|
|
1535
1535
|
};
|
|
1536
1536
|
}
|
|
1537
|
-
async function readBody(req, maxBytes) {
|
|
1537
|
+
async function readBody$1(req, maxBytes) {
|
|
1538
1538
|
const chunks = [];
|
|
1539
1539
|
let total = 0;
|
|
1540
1540
|
for await (const chunk of req) {
|
|
@@ -1706,7 +1706,7 @@ async function startWebsearchProxy(options) {
|
|
|
1706
1706
|
websearchRequests += 1;
|
|
1707
1707
|
lastWebsearchAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1708
1708
|
try {
|
|
1709
|
-
bodyBuffer = await readBody(req, 1e6);
|
|
1709
|
+
bodyBuffer = await readBody$1(req, 1e6);
|
|
1710
1710
|
} catch {
|
|
1711
1711
|
res.writeHead(413, { "Content-Type": "application/json" });
|
|
1712
1712
|
res.end(JSON.stringify({ error: "Request body too large" }));
|
|
@@ -1803,6 +1803,310 @@ async function startWebsearchProxy(options) {
|
|
|
1803
1803
|
};
|
|
1804
1804
|
}
|
|
1805
1805
|
|
|
1806
|
+
//#endregion
|
|
1807
|
+
//#region src/websearch-native.ts
|
|
1808
|
+
/**
|
|
1809
|
+
* WebSearch Native Provider Mode (experimental)
|
|
1810
|
+
*
|
|
1811
|
+
* Uses model's native websearch capability based on ~/.factory/settings.json configuration.
|
|
1812
|
+
* Supported providers:
|
|
1813
|
+
* - Anthropic: web_search_20250305 server tool
|
|
1814
|
+
* - OpenAI: web_search tool via /responses endpoint
|
|
1815
|
+
*/
|
|
1816
|
+
let cachedSettings = null;
|
|
1817
|
+
let settingsLastModified = 0;
|
|
1818
|
+
function getFactorySettings(logger) {
|
|
1819
|
+
const settingsPath = join(homedir(), ".factory", "settings.json");
|
|
1820
|
+
try {
|
|
1821
|
+
const stats = statSync(settingsPath);
|
|
1822
|
+
if (cachedSettings && stats.mtimeMs === settingsLastModified) return cachedSettings;
|
|
1823
|
+
cachedSettings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
1824
|
+
settingsLastModified = stats.mtimeMs;
|
|
1825
|
+
return cachedSettings;
|
|
1826
|
+
} catch (e) {
|
|
1827
|
+
logger.error("[websearch-native] Failed to load settings.json:", e.message);
|
|
1828
|
+
return null;
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
function getCurrentModelConfig(logger) {
|
|
1832
|
+
const settings = getFactorySettings(logger);
|
|
1833
|
+
if (!settings) return null;
|
|
1834
|
+
const currentModelId = settings.sessionDefaultSettings?.model;
|
|
1835
|
+
if (!currentModelId) return null;
|
|
1836
|
+
const modelConfig = (settings.customModels || []).find((m) => m.id === currentModelId);
|
|
1837
|
+
if (modelConfig) {
|
|
1838
|
+
logger.log("[websearch-native] Model:", modelConfig.displayName || modelConfig.id, "| Provider:", modelConfig.provider);
|
|
1839
|
+
return modelConfig;
|
|
1840
|
+
}
|
|
1841
|
+
if (!currentModelId.startsWith("custom:")) return null;
|
|
1842
|
+
logger.log("[websearch-native] Model not found:", currentModelId);
|
|
1843
|
+
return null;
|
|
1844
|
+
}
|
|
1845
|
+
async function searchAnthropicNative(query, numResults, modelConfig, logger) {
|
|
1846
|
+
const { baseUrl, apiKey, model } = modelConfig;
|
|
1847
|
+
try {
|
|
1848
|
+
const requestBody = {
|
|
1849
|
+
model,
|
|
1850
|
+
max_tokens: 4096,
|
|
1851
|
+
stream: false,
|
|
1852
|
+
system: "You are a web search assistant. Use the web_search tool to find relevant information and return the results.",
|
|
1853
|
+
tools: [{
|
|
1854
|
+
type: "web_search_20250305",
|
|
1855
|
+
name: "web_search",
|
|
1856
|
+
max_uses: 1
|
|
1857
|
+
}],
|
|
1858
|
+
tool_choice: {
|
|
1859
|
+
type: "tool",
|
|
1860
|
+
name: "web_search"
|
|
1861
|
+
},
|
|
1862
|
+
messages: [{
|
|
1863
|
+
role: "user",
|
|
1864
|
+
content: `Search the web for: ${query}\n\nReturn up to ${numResults} relevant results.`
|
|
1865
|
+
}]
|
|
1866
|
+
};
|
|
1867
|
+
let endpoint = baseUrl;
|
|
1868
|
+
if (!endpoint.endsWith("/v1/messages")) endpoint = endpoint.replace(/\/$/, "") + "/v1/messages";
|
|
1869
|
+
logger.log("[websearch-native] Anthropic search:", query, "→", endpoint);
|
|
1870
|
+
const data = await (await fetch(endpoint, {
|
|
1871
|
+
method: "POST",
|
|
1872
|
+
headers: {
|
|
1873
|
+
"Content-Type": "application/json",
|
|
1874
|
+
"anthropic-version": "2023-06-01",
|
|
1875
|
+
"x-api-key": apiKey
|
|
1876
|
+
},
|
|
1877
|
+
body: JSON.stringify(requestBody)
|
|
1878
|
+
})).json();
|
|
1879
|
+
if (data.error) {
|
|
1880
|
+
logger.error("[websearch-native] Anthropic API error:", data.error.message);
|
|
1881
|
+
return null;
|
|
1882
|
+
}
|
|
1883
|
+
const results = [];
|
|
1884
|
+
for (const block of data.content || []) if (block.type === "web_search_tool_result") {
|
|
1885
|
+
for (const result of block.content || []) if (result.type === "web_search_result") results.push({
|
|
1886
|
+
title: result.title || "",
|
|
1887
|
+
url: result.url || "",
|
|
1888
|
+
content: result.snippet || result.page_content || ""
|
|
1889
|
+
});
|
|
1890
|
+
}
|
|
1891
|
+
logger.log("[websearch-native] Anthropic results:", results.length);
|
|
1892
|
+
return results.length > 0 ? results.slice(0, numResults) : null;
|
|
1893
|
+
} catch (e) {
|
|
1894
|
+
logger.error("[websearch-native] Anthropic error:", e.message);
|
|
1895
|
+
return null;
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
async function searchOpenAINative(query, numResults, modelConfig, logger) {
|
|
1899
|
+
const { baseUrl, apiKey, model } = modelConfig;
|
|
1900
|
+
try {
|
|
1901
|
+
const requestBody = {
|
|
1902
|
+
model,
|
|
1903
|
+
stream: false,
|
|
1904
|
+
tools: [{ type: "web_search" }],
|
|
1905
|
+
tool_choice: "required",
|
|
1906
|
+
input: `Search the web for: ${query}\n\nReturn up to ${numResults} relevant results.`
|
|
1907
|
+
};
|
|
1908
|
+
let endpoint = baseUrl;
|
|
1909
|
+
if (!endpoint.endsWith("/responses")) endpoint = endpoint.replace(/\/$/, "") + "/responses";
|
|
1910
|
+
logger.log("[websearch-native] OpenAI search:", query, "→", endpoint);
|
|
1911
|
+
const data = await (await fetch(endpoint, {
|
|
1912
|
+
method: "POST",
|
|
1913
|
+
headers: {
|
|
1914
|
+
"Content-Type": "application/json",
|
|
1915
|
+
Authorization: `Bearer ${apiKey}`
|
|
1916
|
+
},
|
|
1917
|
+
body: JSON.stringify(requestBody)
|
|
1918
|
+
})).json();
|
|
1919
|
+
if (data.error) {
|
|
1920
|
+
logger.error("[websearch-native] OpenAI API error:", data.error.message);
|
|
1921
|
+
return null;
|
|
1922
|
+
}
|
|
1923
|
+
const results = [];
|
|
1924
|
+
for (const item of data.output || []) if (item.type === "message" && Array.isArray(item.content)) {
|
|
1925
|
+
for (const content of item.content) if (content.type === "output_text" && Array.isArray(content.annotations)) {
|
|
1926
|
+
for (const annotation of content.annotations) if (annotation.type === "url_citation" && annotation.url) results.push({
|
|
1927
|
+
title: annotation.title || "",
|
|
1928
|
+
url: annotation.url || "",
|
|
1929
|
+
content: annotation.title || ""
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
logger.log("[websearch-native] OpenAI results:", results.length);
|
|
1934
|
+
return results.length > 0 ? results.slice(0, numResults) : null;
|
|
1935
|
+
} catch (e) {
|
|
1936
|
+
logger.error("[websearch-native] OpenAI error:", e.message);
|
|
1937
|
+
return null;
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
async function search(query, numResults, logger) {
|
|
1941
|
+
logger.log("[websearch-native] Search:", query);
|
|
1942
|
+
const modelConfig = getCurrentModelConfig(logger);
|
|
1943
|
+
if (!modelConfig) {
|
|
1944
|
+
logger.log("[websearch-native] No custom model configured");
|
|
1945
|
+
return {
|
|
1946
|
+
results: [],
|
|
1947
|
+
source: "none"
|
|
1948
|
+
};
|
|
1949
|
+
}
|
|
1950
|
+
const provider = modelConfig.provider;
|
|
1951
|
+
let results = null;
|
|
1952
|
+
if (provider === "anthropic") results = await searchAnthropicNative(query, numResults, modelConfig, logger);
|
|
1953
|
+
else if (provider === "openai") results = await searchOpenAINative(query, numResults, modelConfig, logger);
|
|
1954
|
+
else logger.log("[websearch-native] Unsupported provider:", provider);
|
|
1955
|
+
if (results && results.length > 0) return {
|
|
1956
|
+
results,
|
|
1957
|
+
source: `native-${provider}`
|
|
1958
|
+
};
|
|
1959
|
+
return {
|
|
1960
|
+
results: [],
|
|
1961
|
+
source: "none"
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1964
|
+
function parseRequestBody(body) {
|
|
1965
|
+
try {
|
|
1966
|
+
const parsed = JSON.parse(body);
|
|
1967
|
+
const query = typeof parsed.query === "string" ? parsed.query.trim() : "";
|
|
1968
|
+
if (!query) return null;
|
|
1969
|
+
return {
|
|
1970
|
+
query,
|
|
1971
|
+
numResults: typeof parsed.numResults === "number" && Number.isFinite(parsed.numResults) ? Math.max(1, parsed.numResults) : 10
|
|
1972
|
+
};
|
|
1973
|
+
} catch {
|
|
1974
|
+
return null;
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
async function readBody(req, maxBytes) {
|
|
1978
|
+
const chunks = [];
|
|
1979
|
+
let total = 0;
|
|
1980
|
+
for await (const chunk of req) {
|
|
1981
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
1982
|
+
total += buf.length;
|
|
1983
|
+
if (total > maxBytes) throw new Error(`Request body too large (${total} bytes)`);
|
|
1984
|
+
chunks.push(buf);
|
|
1985
|
+
}
|
|
1986
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
1987
|
+
}
|
|
1988
|
+
async function startNativeWebsearchProxy(options) {
|
|
1989
|
+
const logger = options.logger ?? console;
|
|
1990
|
+
const host = options.host ?? "127.0.0.1";
|
|
1991
|
+
const port = options.port ?? 0;
|
|
1992
|
+
const factoryApiUrl = options.factoryApiUrl ?? "https://api.factory.ai";
|
|
1993
|
+
let totalRequests = 0;
|
|
1994
|
+
let websearchRequests = 0;
|
|
1995
|
+
let lastWebsearchAt = null;
|
|
1996
|
+
let lastWebsearchSource = null;
|
|
1997
|
+
const server = createServer((req, res) => {
|
|
1998
|
+
(async () => {
|
|
1999
|
+
totalRequests += 1;
|
|
2000
|
+
const rawUrl = req.url;
|
|
2001
|
+
if (!rawUrl) {
|
|
2002
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
2003
|
+
res.end(JSON.stringify({ error: "Missing URL" }));
|
|
2004
|
+
return;
|
|
2005
|
+
}
|
|
2006
|
+
const requestUrl = new URL(rawUrl, `http://${req.headers.host ?? "127.0.0.1"}`);
|
|
2007
|
+
if (requestUrl.pathname === "/health") {
|
|
2008
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2009
|
+
res.end(JSON.stringify({
|
|
2010
|
+
status: "ok",
|
|
2011
|
+
mode: "native-provider",
|
|
2012
|
+
requests: {
|
|
2013
|
+
total: totalRequests,
|
|
2014
|
+
websearch: websearchRequests,
|
|
2015
|
+
lastWebsearchAt,
|
|
2016
|
+
lastWebsearchSource
|
|
2017
|
+
}
|
|
2018
|
+
}));
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
2021
|
+
if (requestUrl.pathname === "/api/tools/exa/search" && req.method === "POST") {
|
|
2022
|
+
websearchRequests += 1;
|
|
2023
|
+
lastWebsearchAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2024
|
+
try {
|
|
2025
|
+
const parsed = parseRequestBody(await readBody(req, 1e6));
|
|
2026
|
+
if (!parsed) {
|
|
2027
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
2028
|
+
res.end(JSON.stringify({
|
|
2029
|
+
error: "Invalid request body",
|
|
2030
|
+
results: []
|
|
2031
|
+
}));
|
|
2032
|
+
return;
|
|
2033
|
+
}
|
|
2034
|
+
const result = await search(parsed.query, parsed.numResults, logger);
|
|
2035
|
+
lastWebsearchSource = result.source;
|
|
2036
|
+
logger.log("[websearch-native] Results:", result.results.length, "from", result.source);
|
|
2037
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2038
|
+
res.end(JSON.stringify({ results: result.results }));
|
|
2039
|
+
} catch (e) {
|
|
2040
|
+
logger.error("[websearch-native] Search error:", e.message);
|
|
2041
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2042
|
+
res.end(JSON.stringify({
|
|
2043
|
+
error: String(e),
|
|
2044
|
+
results: []
|
|
2045
|
+
}));
|
|
2046
|
+
}
|
|
2047
|
+
return;
|
|
2048
|
+
}
|
|
2049
|
+
const pathAndQuery = `${requestUrl.pathname}${requestUrl.search || ""}`;
|
|
2050
|
+
const targetUrl = new URL(pathAndQuery, factoryApiUrl);
|
|
2051
|
+
logger.log("[websearch-native] Proxy:", req.method ?? "GET", pathAndQuery);
|
|
2052
|
+
const headers = new Headers();
|
|
2053
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
2054
|
+
if (value === void 0) continue;
|
|
2055
|
+
if (key.toLowerCase() === "host") continue;
|
|
2056
|
+
if (key.toLowerCase() === "accept-encoding") continue;
|
|
2057
|
+
if (Array.isArray(value)) for (const v of value) headers.append(key, v);
|
|
2058
|
+
else headers.set(key, value);
|
|
2059
|
+
}
|
|
2060
|
+
headers.set("accept-encoding", "identity");
|
|
2061
|
+
try {
|
|
2062
|
+
let body;
|
|
2063
|
+
if (req.method !== "GET" && req.method !== "HEAD") body = await readBody(req, 1e7);
|
|
2064
|
+
const response = await fetch(targetUrl, {
|
|
2065
|
+
method: req.method,
|
|
2066
|
+
headers,
|
|
2067
|
+
body,
|
|
2068
|
+
redirect: "manual"
|
|
2069
|
+
});
|
|
2070
|
+
for (const [key, value] of response.headers) {
|
|
2071
|
+
if (key.toLowerCase() === "content-encoding") continue;
|
|
2072
|
+
if (key.toLowerCase() === "content-length") continue;
|
|
2073
|
+
res.setHeader(key, value);
|
|
2074
|
+
}
|
|
2075
|
+
res.statusCode = response.status;
|
|
2076
|
+
if (!response.body) {
|
|
2077
|
+
res.end();
|
|
2078
|
+
return;
|
|
2079
|
+
}
|
|
2080
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
2081
|
+
res.end(Buffer.from(arrayBuffer));
|
|
2082
|
+
} catch (e) {
|
|
2083
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
2084
|
+
res.end(JSON.stringify({ error: "Proxy failed: " + e.message }));
|
|
2085
|
+
}
|
|
2086
|
+
})();
|
|
2087
|
+
});
|
|
2088
|
+
await new Promise((resolve, reject) => {
|
|
2089
|
+
server.once("error", reject);
|
|
2090
|
+
server.listen(port, host, () => {
|
|
2091
|
+
server.off("error", reject);
|
|
2092
|
+
resolve();
|
|
2093
|
+
});
|
|
2094
|
+
});
|
|
2095
|
+
const address = server.address();
|
|
2096
|
+
if (!address || typeof address === "string") {
|
|
2097
|
+
server.close();
|
|
2098
|
+
throw new Error("Failed to bind native websearch proxy server");
|
|
2099
|
+
}
|
|
2100
|
+
const baseUrl = `http://${host}:${address.port}`;
|
|
2101
|
+
logger.log("[websearch-native] proxy listening on", baseUrl);
|
|
2102
|
+
return {
|
|
2103
|
+
baseUrl,
|
|
2104
|
+
close: () => new Promise((resolve) => {
|
|
2105
|
+
server.close(() => resolve());
|
|
2106
|
+
})
|
|
2107
|
+
};
|
|
2108
|
+
}
|
|
2109
|
+
|
|
1806
2110
|
//#endregion
|
|
1807
2111
|
//#region src/droid-adapter.ts
|
|
1808
2112
|
function createDroidAdapter(options) {
|
|
@@ -2044,18 +2348,8 @@ function createDroidAdapter(options) {
|
|
|
2044
2348
|
};
|
|
2045
2349
|
const reasoningEffort = env.DROID_ACP_REASONING_EFFORT;
|
|
2046
2350
|
if (typeof reasoningEffort === "string" && reasoningEffort.trim().length > 0) args.push("--reasoning-effort", reasoningEffort.trim());
|
|
2047
|
-
|
|
2048
|
-
const smitheryConfigured = typeof env.SMITHERY_API_KEY === "string" && env.SMITHERY_API_KEY.trim().length > 0 && typeof env.SMITHERY_PROFILE === "string" && env.SMITHERY_PROFILE.trim().length > 0;
|
|
2049
|
-
const forwardConfigured = typeof env.DROID_ACP_WEBSEARCH_FORWARD_URL === "string" && env.DROID_ACP_WEBSEARCH_FORWARD_URL.trim().length > 0;
|
|
2050
|
-
if (hasExplicitToggle ? isEnvEnabled(env.DROID_ACP_WEBSEARCH) : smitheryConfigured || forwardConfigured) {
|
|
2351
|
+
if (isEnvEnabled(env.DROID_ACP_WEBSEARCH_NATIVE)) {
|
|
2051
2352
|
stopWebsearchProxy();
|
|
2052
|
-
const upstreamBaseUrl = env.DROID_ACP_WEBSEARCH_UPSTREAM_URL ?? env.FACTORY_API_BASE_URL_OVERRIDE ?? "https://api.factory.ai";
|
|
2053
|
-
const forwardModeRaw = env.DROID_ACP_WEBSEARCH_FORWARD_MODE;
|
|
2054
|
-
const forwardUrlRaw = typeof env.DROID_ACP_WEBSEARCH_FORWARD_URL === "string" ? env.DROID_ACP_WEBSEARCH_FORWARD_URL.trim() : "";
|
|
2055
|
-
const forwardPrefixMatch = forwardUrlRaw.match(/^mcp:(.*)$/i);
|
|
2056
|
-
const websearchForwardUrl = forwardUrlRaw.length > 0 ? forwardUrlRaw : void 0;
|
|
2057
|
-
const forwardModeNormalized = typeof forwardModeRaw === "string" ? forwardModeRaw.trim().toLowerCase() : "";
|
|
2058
|
-
const websearchForwardMode = forwardModeNormalized === "mcp" ? "mcp" : forwardModeNormalized === "http" ? "http" : forwardPrefixMatch ? "mcp" : "http";
|
|
2059
2353
|
const host = env.DROID_ACP_WEBSEARCH_HOST ?? "127.0.0.1";
|
|
2060
2354
|
const portRaw = env.DROID_ACP_WEBSEARCH_PORT;
|
|
2061
2355
|
let port;
|
|
@@ -2064,12 +2358,10 @@ function createDroidAdapter(options) {
|
|
|
2064
2358
|
if (Number.isNaN(parsed) || parsed < 0 || parsed > 65535) throw new Error(`Invalid DROID_ACP_WEBSEARCH_PORT: ${portRaw}`);
|
|
2065
2359
|
port = parsed;
|
|
2066
2360
|
}
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
smitheryApiKey: env.SMITHERY_API_KEY,
|
|
2072
|
-
smitheryProfile: env.SMITHERY_PROFILE,
|
|
2361
|
+
const factoryApiUrl = env.DROID_ACP_WEBSEARCH_UPSTREAM_URL ?? env.FACTORY_API_BASE_URL_OVERRIDE ?? "https://api.factory.ai";
|
|
2362
|
+
logger.log("[websearch] Starting native provider proxy (experimental)...");
|
|
2363
|
+
websearchProxy = await startNativeWebsearchProxy({
|
|
2364
|
+
factoryApiUrl,
|
|
2073
2365
|
host,
|
|
2074
2366
|
port,
|
|
2075
2367
|
logger
|
|
@@ -2077,6 +2369,41 @@ function createDroidAdapter(options) {
|
|
|
2077
2369
|
if (!env.FACTORY_API_KEY) env.FACTORY_API_KEY = "droid-acp-websearch";
|
|
2078
2370
|
env.FACTORY_API_BASE_URL_OVERRIDE = websearchProxy.baseUrl;
|
|
2079
2371
|
env.FACTORY_API_BASE_URL = websearchProxy.baseUrl;
|
|
2372
|
+
} else {
|
|
2373
|
+
const hasExplicitToggle = typeof env.DROID_ACP_WEBSEARCH === "string";
|
|
2374
|
+
const smitheryConfigured = typeof env.SMITHERY_API_KEY === "string" && env.SMITHERY_API_KEY.trim().length > 0 && typeof env.SMITHERY_PROFILE === "string" && env.SMITHERY_PROFILE.trim().length > 0;
|
|
2375
|
+
const forwardConfigured = typeof env.DROID_ACP_WEBSEARCH_FORWARD_URL === "string" && env.DROID_ACP_WEBSEARCH_FORWARD_URL.trim().length > 0;
|
|
2376
|
+
if (hasExplicitToggle ? isEnvEnabled(env.DROID_ACP_WEBSEARCH) : smitheryConfigured || forwardConfigured) {
|
|
2377
|
+
stopWebsearchProxy();
|
|
2378
|
+
const upstreamBaseUrl = env.DROID_ACP_WEBSEARCH_UPSTREAM_URL ?? env.FACTORY_API_BASE_URL_OVERRIDE ?? "https://api.factory.ai";
|
|
2379
|
+
const forwardModeRaw = env.DROID_ACP_WEBSEARCH_FORWARD_MODE;
|
|
2380
|
+
const forwardUrlRaw = typeof env.DROID_ACP_WEBSEARCH_FORWARD_URL === "string" ? env.DROID_ACP_WEBSEARCH_FORWARD_URL.trim() : "";
|
|
2381
|
+
const forwardPrefixMatch = forwardUrlRaw.match(/^mcp:(.*)$/i);
|
|
2382
|
+
const websearchForwardUrl = forwardUrlRaw.length > 0 ? forwardUrlRaw : void 0;
|
|
2383
|
+
const forwardModeNormalized = typeof forwardModeRaw === "string" ? forwardModeRaw.trim().toLowerCase() : "";
|
|
2384
|
+
const websearchForwardMode = forwardModeNormalized === "mcp" ? "mcp" : forwardModeNormalized === "http" ? "http" : forwardPrefixMatch ? "mcp" : "http";
|
|
2385
|
+
const host = env.DROID_ACP_WEBSEARCH_HOST ?? "127.0.0.1";
|
|
2386
|
+
const portRaw = env.DROID_ACP_WEBSEARCH_PORT;
|
|
2387
|
+
let port;
|
|
2388
|
+
if (typeof portRaw === "string" && portRaw.length > 0) {
|
|
2389
|
+
const parsed = Number.parseInt(portRaw, 10);
|
|
2390
|
+
if (Number.isNaN(parsed) || parsed < 0 || parsed > 65535) throw new Error(`Invalid DROID_ACP_WEBSEARCH_PORT: ${portRaw}`);
|
|
2391
|
+
port = parsed;
|
|
2392
|
+
}
|
|
2393
|
+
websearchProxy = await startWebsearchProxy({
|
|
2394
|
+
upstreamBaseUrl,
|
|
2395
|
+
websearchForwardUrl: forwardPrefixMatch ? forwardPrefixMatch[1]?.trim() : websearchForwardUrl,
|
|
2396
|
+
websearchForwardMode,
|
|
2397
|
+
smitheryApiKey: env.SMITHERY_API_KEY,
|
|
2398
|
+
smitheryProfile: env.SMITHERY_PROFILE,
|
|
2399
|
+
host,
|
|
2400
|
+
port,
|
|
2401
|
+
logger
|
|
2402
|
+
});
|
|
2403
|
+
if (!env.FACTORY_API_KEY) env.FACTORY_API_KEY = "droid-acp-websearch";
|
|
2404
|
+
env.FACTORY_API_BASE_URL_OVERRIDE = websearchProxy.baseUrl;
|
|
2405
|
+
env.FACTORY_API_BASE_URL = websearchProxy.baseUrl;
|
|
2406
|
+
}
|
|
2080
2407
|
}
|
|
2081
2408
|
process$1 = spawn(executable, args, {
|
|
2082
2409
|
stdio: [
|
|
@@ -3858,5 +4185,5 @@ function runAcp() {
|
|
|
3858
4185
|
}
|
|
3859
4186
|
|
|
3860
4187
|
//#endregion
|
|
3861
|
-
export {
|
|
3862
|
-
//# sourceMappingURL=acp-agent-
|
|
4188
|
+
export { startWebsearchProxy as a, findDroidExecutable as c, startNativeWebsearchProxy as i, isEnvEnabled as l, DroidAcpAgent as n, ACP_MODES as o, createDroidAdapter as r, Pushable as s, runAcp as t, isWindows as u };
|
|
4189
|
+
//# sourceMappingURL=acp-agent-DYlR7vNB.mjs.map
|