@morlay/dsh-web-search-ollama 0.0.1 → 0.0.3
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 +17 -83
- package/dist/client.cjs +0 -9
- package/dist/client.d.cts +0 -9
- package/dist/client.d.mts +0 -9
- package/dist/index.d.cts +0 -25
- package/dist/index.d.mts +0 -25
- package/dist/index.mjs +0 -15
- package/dist/rows.d.cts +0 -9
- package/dist/rows.d.mts +0 -9
- package/dist/rows.mjs +0 -1
- package/package.json +10 -10
- package/src/client/index.ts +8 -13
- package/src/client/locales.ts +1 -1
- package/src/index.ts +10 -16
- package/src/provider.ts +13 -13
- package/src/rows.ts +6 -9
- package/src/types.ts +8 -10
package/README.md
CHANGED
|
@@ -1,81 +1,11 @@
|
|
|
1
1
|
# @morlay/dsh-web-search-ollama
|
|
2
2
|
|
|
3
3
|
往 `ctx.web` 注册一个搜索后端:`web_search` 的检索走 Ollama 自己的
|
|
4
|
-
`POST https://ollama.com/api/web_search`,用与 `llm-pi-ai` 的 ollama route 同一个
|
|
5
|
-
`OLLAMA_API_KEY`。
|
|
4
|
+
`POST https://ollama.com/api/web_search`,用与 `llm-pi-ai` 的 ollama route 同一个 `OLLAMA_API_KEY`。
|
|
6
5
|
|
|
7
|
-
##
|
|
6
|
+
## 用法
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
`web_search_20250305` server tool,看起来只要把 `baseURL` 指到 `https://ollama.com/v1` 就能白拿
|
|
11
|
-
Ollama 的搜索。**实测不行**:真发一次
|
|
12
|
-
|
|
13
|
-
```sh
|
|
14
|
-
curl https://ollama.com/v1/messages -H "Authorization: Bearer $OLLAMA_API_KEY" \
|
|
15
|
-
-H "anthropic-version: 2023-06-01" -H "content-type: application/json" \
|
|
16
|
-
-d '{"model":"deepseek-v4.1-flash","max_tokens":4096,
|
|
17
|
-
"messages":[{"role":"user","content":[{"type":"text","text":"Perform a web search for the query: cordis plugin framework"}]}],
|
|
18
|
-
"tools":[{"type":"web_search_20250305","name":"web_search","max_uses":5}]}'
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
回的 `content` 块只有 `thinking` + `tool_use`(`stop_reason: tool_use`)——**Ollama 把这个 server
|
|
22
|
-
tool 降级成普通客户端工具,它不自己执行搜索**,要求调用方执行后再回传 `tool_result`。而那个上游
|
|
23
|
-
provider 只认服务端自执行后返回的 `web_search_tool_result` 块,找不到就报
|
|
24
|
-
`WEB_PROVIDER_ERROR`("returned no web_search_tool_result blocks")。Ollama 官方文档那句
|
|
25
|
-
"hosted web search are not fully supported"([docs.ollama.com/api/anthropic-compatibility](https://docs.ollama.com/api/anthropic-compatibility))
|
|
26
|
-
就是这个意思,[issue #17283](https://github.com/ollama/ollama/issues/17283) 里说的
|
|
27
|
-
`WebSearchAnthropicWriter` 拦截只发生在本地 server 的 cloud 模型路径上。
|
|
28
|
-
|
|
29
|
-
Ollama 真正对外提供搜索的是它自己的 REST 接口——同一个 key、一次 HTTP、返回扁平
|
|
30
|
-
`{results:[{title,url,content}]}`:
|
|
31
|
-
|
|
32
|
-
```sh
|
|
33
|
-
curl https://ollama.com/api/web_search -H "Authorization: Bearer $OLLAMA_API_KEY" \
|
|
34
|
-
-H "content-type: application/json" -d '{"query":"cordis plugin framework"}'
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
本包就是把这一条接进 `ctx.web`,代价只有一个 ~200 行的 provider。
|
|
38
|
-
|
|
39
|
-
## 配置
|
|
40
|
-
|
|
41
|
-
| 字段 | 默认 | 含义 |
|
|
42
|
-
| ------------ | ------------------------ | ---------------------------------------------------------- |
|
|
43
|
-
| `apiKey` | — | 字面 key;优先用下面那个引用,别把密钥写进配置文件 |
|
|
44
|
-
| `apiKeyEnv` | `OLLAMA_API_KEY` | 每次搜索解析一次的凭证引用(凭证服务,缺席时回退启动环境) |
|
|
45
|
-
| `baseURL` | `https://ollama.com` | 端点根;`/api/web_search` 由 provider 拼 |
|
|
46
|
-
| `maxResults` | —(Ollama 自己的默认 5) | 请求没带 `maxResults` 时的默认结果数 |
|
|
47
|
-
|
|
48
|
-
## 行为
|
|
49
|
-
|
|
50
|
-
- **结果映射**:每条 `results[]` 给一个 source;`title` / `content` 空串视为缺失
|
|
51
|
-
(`content` → `snippet`),**没有 `url` 的条目直接丢掉**(seam 的 source 必须有 url)。
|
|
52
|
-
Ollama 不返回生成式答案,所以结果里没有 `content` 字段。
|
|
53
|
-
- **`max_results` 上限 10**:Ollama 的硬上限;请求与配置给出的更大值在发出前压到 10。
|
|
54
|
-
- **错误码**:HTTP 失败 → `WEB_PROVIDER_ERROR`(优先用响应体里的 `error` 文案,非 JSON 体退回
|
|
55
|
-
`Ollama API error (HTTP <status>)`);网络失败 → `WEB_PROVIDER_ERROR`;取消 → `WEB_ABORTED`
|
|
56
|
-
(任何阶段,含读体);取不到 key → `WEB_PROVIDER_CREDENTIAL_MISSING` 且不发请求。
|
|
57
|
-
- **可用性检查不联网**:`available()` 只看 key 有没有来源、`baseURL` 能否解析。
|
|
58
|
-
|
|
59
|
-
## 验证
|
|
60
|
-
|
|
61
|
-
`src/__tests__/provider.spec.ts` 是 mock 单测,默认 `just test` 覆盖它。链路是否真的成立由
|
|
62
|
-
[`e2e/provider.e2e.spec.ts`](./e2e/provider.e2e.spec.ts) 打真端点守——**它刻意放在 `src/__tests__/` 之外**:
|
|
63
|
-
根 `vitest.config.ts` 的 include 收不到它,默认全量测试不会去打外网,只由显式命令触发(`OLLAMA_API_KEY`
|
|
64
|
-
从启动环境注入,缺席则整体跳过):
|
|
65
|
-
|
|
66
|
-
```sh
|
|
67
|
-
mise exec -- pnpm --filter @morlay/dsh-web-search-ollama run test:e2e
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
两条都过才算通过:provider 直连拿回可引用 source,以及 provider 装进 `ctx.web` 后选中它再搜一次。别用
|
|
71
|
-
mock 全绿替代它——这个包的第一版就是"配置指到 Ollama 的 messages 端点"、mock 也全绿,真调用却是错的。
|
|
72
|
-
触发方式、门控与判据的 home 是[包层规范](./.agents/standards/how-to-verify.md)。
|
|
73
|
-
|
|
74
|
-
## 装配
|
|
75
|
-
|
|
76
|
-
注册行由**本包的 bundle patch**([`src/rows.ts`](./src/rows.ts))插在 **host 层**;
|
|
77
|
-
基础 bundle 的 `web` 行由 [`@morlay/dsh-profile`](../../bundles/sandbox-profile/README.md) 的配置层切到
|
|
78
|
-
`ollama`——装配归本包、配置归 profile:
|
|
8
|
+
本包只提供行数据;采用它的部署 bundle 渲染出的装配(节选):
|
|
79
9
|
|
|
80
10
|
```yaml
|
|
81
11
|
- id: web
|
|
@@ -85,17 +15,21 @@ mock 全绿替代它——这个包的第一版就是"配置指到 Ollama 的 me
|
|
|
85
15
|
- insert:
|
|
86
16
|
- id: web-search-ollama
|
|
87
17
|
name: "@morlay/dsh-web-search-ollama"
|
|
88
|
-
|
|
89
|
-
|
|
18
|
+
- id: web-search-ollama
|
|
19
|
+
config:
|
|
20
|
+
apiKeyEnv: OLLAMA_API_KEY
|
|
90
21
|
```
|
|
91
22
|
|
|
92
|
-
|
|
93
|
-
`
|
|
23
|
+
配置四个字段:`apiKey`(字面 key)、`apiKeyEnv`(凭证引用,默认 `OLLAMA_API_KEY`)、`baseURL`(默认
|
|
24
|
+
`https://ollama.com`)、`maxResults`(缺省用 Ollama 的默认,硬上限 10)。四个都可实时改,不用重挂这一行。
|
|
94
25
|
|
|
95
|
-
|
|
26
|
+
上游的 Anthropic Messages 后端在 Ollama 上不成立(Ollama 把 `web_search_20250305` 降级成客户端工具、不执行搜索),
|
|
27
|
+
所以本包直接接 Ollama 的 REST——原因、结果映射、错误面与装配链路见
|
|
28
|
+
[设计 Ollama 搜索后端](./.agents/designs/20260929-ollama搜索后端.md)。
|
|
29
|
+
|
|
30
|
+
## 装配
|
|
96
31
|
|
|
97
|
-
|
|
98
|
-
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
[dsh-profile 的设计记录](../../bundles/ollama-provider-profile/README.md))。
|
|
32
|
+
注册行由本包的 `./rows` 出口给出,采用它的部署 bundle 是
|
|
33
|
+
[`@morlay/ollama-provider-profile`](../../bundles/ollama-provider-profile/README.md):它渲染 patch,并在同一份 patch
|
|
34
|
+
里给 `web` 行的 `searchProvider: ollama` 与 key 引用。注册行在 host 平面只装一次,同一个 provider id 注册两次会撞
|
|
35
|
+
`WEB_DUPLICATE_PROVIDER`。
|
package/dist/client.cjs
CHANGED
|
@@ -5,7 +5,6 @@ window.__ModuleLoader__.load({
|
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
//#region src/client/locales.ts
|
|
8
|
-
/** 本包在配置页上的字段文案(命名空间 `settings.web-search-ollama`)。 */
|
|
9
8
|
const zh = {
|
|
10
9
|
apiKey: "API key",
|
|
11
10
|
apiKeyHint: "字面值;能走凭证服务时优先用下面的引用名,别把密钥写进配置文件。",
|
|
@@ -28,23 +27,15 @@ window.__ModuleLoader__.load({
|
|
|
28
27
|
};
|
|
29
28
|
//#endregion
|
|
30
29
|
//#region src/client/index.ts
|
|
31
|
-
/** 本包 host 行 id:行配置页读的就是这个命名空间。 */
|
|
32
30
|
const WEB_SEARCH_NS = "web-search-ollama";
|
|
33
|
-
/** 本页字典的命名空间。 */
|
|
34
31
|
const NS = "settings.web-search-ollama";
|
|
35
|
-
/** 认领的字段名。 */
|
|
36
32
|
const FIELDS = [
|
|
37
33
|
"apiKey",
|
|
38
34
|
"apiKeyEnv",
|
|
39
35
|
"baseURL",
|
|
40
36
|
"maxResults"
|
|
41
37
|
];
|
|
42
|
-
/** 需要的服务:槽位(字段槽)与字典。 */
|
|
43
38
|
const inject = ["locale"];
|
|
44
|
-
/**
|
|
45
|
-
* 给这一行的四个字段补文案。
|
|
46
|
-
* @param ctx - 浏览器插件上下文。
|
|
47
|
-
*/
|
|
48
39
|
function apply(ctx) {
|
|
49
40
|
const t = ctx.locale.bind(NS);
|
|
50
41
|
ctx.effect(() => ctx.locale.register(NS, {
|
package/dist/client.d.cts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Context } from "@deepseek-ai/cordis";
|
|
2
2
|
//#region src/client/locales.d.ts
|
|
3
|
-
/** 本包在配置页上的字段文案(命名空间 `settings.web-search-ollama`)。 */
|
|
4
3
|
declare const zh: {
|
|
5
4
|
readonly apiKey: "API key";
|
|
6
5
|
readonly apiKeyHint: "字面值;能走凭证服务时优先用下面的引用名,别把密钥写进配置文件。";
|
|
@@ -14,22 +13,14 @@ declare const zh: {
|
|
|
14
13
|
type WebSearchFieldLocaleKey = keyof typeof zh;
|
|
15
14
|
//#endregion
|
|
16
15
|
//#region src/client/index.d.ts
|
|
17
|
-
/** 本包 host 行 id:行配置页读的就是这个命名空间。 */
|
|
18
16
|
declare const WEB_SEARCH_NS = "web-search-ollama";
|
|
19
|
-
/** 本页字典的命名空间。 */
|
|
20
17
|
declare const NS = "settings.web-search-ollama";
|
|
21
18
|
declare module "@deepseek-ai/dsh-client-ui-slots" {
|
|
22
19
|
interface LocaleNamespaceMap {
|
|
23
|
-
/** 设置页里这一行的字段文案。 */
|
|
24
20
|
"settings.web-search-ollama": WebSearchFieldLocaleKey;
|
|
25
21
|
}
|
|
26
22
|
}
|
|
27
|
-
/** 需要的服务:槽位(字段槽)与字典。 */
|
|
28
23
|
declare const inject: string[];
|
|
29
|
-
/**
|
|
30
|
-
* 给这一行的四个字段补文案。
|
|
31
|
-
* @param ctx - 浏览器插件上下文。
|
|
32
|
-
*/
|
|
33
24
|
declare function apply(ctx: Context): void;
|
|
34
25
|
//#endregion
|
|
35
26
|
export { NS, WEB_SEARCH_NS, apply, inject };
|
package/dist/client.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Context } from "@deepseek-ai/cordis";
|
|
2
2
|
//#region src/client/locales.d.ts
|
|
3
|
-
/** 本包在配置页上的字段文案(命名空间 `settings.web-search-ollama`)。 */
|
|
4
3
|
declare const zh: {
|
|
5
4
|
readonly apiKey: "API key";
|
|
6
5
|
readonly apiKeyHint: "字面值;能走凭证服务时优先用下面的引用名,别把密钥写进配置文件。";
|
|
@@ -14,22 +13,14 @@ declare const zh: {
|
|
|
14
13
|
type WebSearchFieldLocaleKey = keyof typeof zh;
|
|
15
14
|
//#endregion
|
|
16
15
|
//#region src/client/index.d.ts
|
|
17
|
-
/** 本包 host 行 id:行配置页读的就是这个命名空间。 */
|
|
18
16
|
declare const WEB_SEARCH_NS = "web-search-ollama";
|
|
19
|
-
/** 本页字典的命名空间。 */
|
|
20
17
|
declare const NS = "settings.web-search-ollama";
|
|
21
18
|
declare module "@deepseek-ai/dsh-client-ui-slots" {
|
|
22
19
|
interface LocaleNamespaceMap {
|
|
23
|
-
/** 设置页里这一行的字段文案。 */
|
|
24
20
|
"settings.web-search-ollama": WebSearchFieldLocaleKey;
|
|
25
21
|
}
|
|
26
22
|
}
|
|
27
|
-
/** 需要的服务:槽位(字段槽)与字典。 */
|
|
28
23
|
declare const inject: string[];
|
|
29
|
-
/**
|
|
30
|
-
* 给这一行的四个字段补文案。
|
|
31
|
-
* @param ctx - 浏览器插件上下文。
|
|
32
|
-
*/
|
|
33
24
|
declare function apply(ctx: Context): void;
|
|
34
25
|
//#endregion
|
|
35
26
|
export { NS, WEB_SEARCH_NS, apply, inject };
|
package/dist/index.d.cts
CHANGED
|
@@ -3,72 +3,47 @@ import { Volatile } from "@deepseek-ai/cosmokit";
|
|
|
3
3
|
import z from "@deepseek-ai/schemastery";
|
|
4
4
|
import { WebSearchProvider, WebSearchRequest, WebSearchResult, WebSearchSource } from "@deepseek-ai/dsh-web";
|
|
5
5
|
//#region src/types.d.ts
|
|
6
|
-
/** `results[]` 的一条;字段都可能缺失或为空串。 */
|
|
7
6
|
interface OllamaSearchResult {
|
|
8
7
|
title?: string | null;
|
|
9
8
|
url?: string | null;
|
|
10
9
|
content?: string | null;
|
|
11
10
|
}
|
|
12
|
-
/** 成功响应信封。 */
|
|
13
11
|
interface OllamaSearchResponse {
|
|
14
12
|
results?: OllamaSearchResult[];
|
|
15
13
|
}
|
|
16
14
|
//#endregion
|
|
17
15
|
//#region src/provider.d.ts
|
|
18
|
-
/** 注册进 `ctx.web` 的 id;与 llm route 同名,配置里看到的就是同一个"ollama"。 */
|
|
19
16
|
declare const OLLAMA_PROVIDER_ID = "ollama";
|
|
20
|
-
/** 默认端点;`/api/web_search` 是操作。 */
|
|
21
17
|
declare const OLLAMA_DEFAULT_BASE_URL = "https://ollama.com";
|
|
22
|
-
/** Ollama 服务端自己的默认结果数。 */
|
|
23
18
|
declare const OLLAMA_DEFAULT_MAX_RESULTS = 5;
|
|
24
|
-
/** Ollama `max_results` 的硬上限;超过它的值不发给服务端。 */
|
|
25
19
|
declare const OLLAMA_MAX_RESULTS_LIMIT = 10;
|
|
26
20
|
interface OllamaSearchProviderOptions {
|
|
27
|
-
/** 字面 key;给了就压过 {@link resolveApiKey}。 */
|
|
28
21
|
apiKey?: string | undefined;
|
|
29
|
-
/** 运行期取 key 的入口(凭证服务 / 环境);返回空表示取不到。 */
|
|
30
22
|
resolveApiKey?: () => Promise<string | undefined>;
|
|
31
|
-
/** 取不到 key 时报出来的引用名,便于用户知道去哪配。 */
|
|
32
23
|
apiKeyEnv: string;
|
|
33
24
|
baseURL: string;
|
|
34
|
-
/** 请求没给 `maxResults` 时用的默认值;省略表示让 Ollama 用它自己的默认。 */
|
|
35
25
|
maxResults?: number | undefined;
|
|
36
26
|
}
|
|
37
|
-
/** 一条 Ollama 结果 → 一个 source;没有 url 就丢掉(seam 的 source 必须有 url)。 */
|
|
38
27
|
declare function mapOllamaResult(result: OllamaSearchResult): WebSearchSource | undefined;
|
|
39
|
-
/** 响应信封 → 归一化结果;形状不对就抛(由调用方包成 `WEB_PROVIDER_ERROR`)。 */
|
|
40
28
|
declare function mapOllamaResponse(response: OllamaSearchResponse): WebSearchResult;
|
|
41
|
-
/** Ollama 的搜索后端;HTTP 重定向按 `WEB_PROVIDER_ERROR` 失败。 */
|
|
42
29
|
declare class OllamaSearchProvider implements WebSearchProvider {
|
|
43
30
|
private readonly options;
|
|
44
31
|
readonly id = "ollama";
|
|
45
32
|
constructor(options: OllamaSearchProviderOptions);
|
|
46
33
|
available(): boolean;
|
|
47
34
|
search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>;
|
|
48
|
-
/** 一次操作一份 key,不留在 provider 上;没有可用的 key 就点名引用,而不是发无授权请求。 */
|
|
49
35
|
private apiKey;
|
|
50
36
|
}
|
|
51
37
|
//#endregion
|
|
52
38
|
//#region src/index.d.ts
|
|
53
39
|
declare const name = "web-search-ollama";
|
|
54
|
-
/** 只往 `ctx.web` 注册后端,不发布服务。 */
|
|
55
40
|
declare const inject: string[];
|
|
56
41
|
interface Config {
|
|
57
|
-
/** 字面 key;优先用 `apiKeyEnv` 走凭证服务,别把密钥写进配置文件。 */
|
|
58
42
|
apiKey?: string;
|
|
59
|
-
/** 每次搜索解析一次的凭证引用;缺省 `OLLAMA_API_KEY`。 */
|
|
60
43
|
apiKeyEnv?: string;
|
|
61
|
-
/** 端点根;`/api/web_search` 由 provider 拼。缺省 ollama.com。 */
|
|
62
44
|
baseURL?: string;
|
|
63
|
-
/** 请求没带 `maxResults` 时的默认结果数;省略表示让 Ollama 用自己的默认。 */
|
|
64
45
|
maxResults?: number;
|
|
65
46
|
}
|
|
66
|
-
/**
|
|
67
|
-
* schema 解析之后的形状:四个字段都是 **volatile 稳定引用**,读它要过 `.get()`。
|
|
68
|
-
*
|
|
69
|
-
* 它们都标了 `.volatile()`(插件行里唯一可实时改的字段),所以设置页改完不用重挂这一行:provider 的每一次
|
|
70
|
-
* 请求、每一次取 key 都现场读引用。
|
|
71
|
-
*/
|
|
72
47
|
interface ResolvedConfig {
|
|
73
48
|
readonly apiKey: Volatile<string | undefined>;
|
|
74
49
|
readonly apiKeyEnv: Volatile<string | undefined>;
|
package/dist/index.d.mts
CHANGED
|
@@ -3,72 +3,47 @@ import { WebSearchProvider, WebSearchRequest, WebSearchResult, WebSearchSource }
|
|
|
3
3
|
import { Context } from "@deepseek-ai/cordis";
|
|
4
4
|
import { Volatile } from "@deepseek-ai/cosmokit";
|
|
5
5
|
//#region src/types.d.ts
|
|
6
|
-
/** `results[]` 的一条;字段都可能缺失或为空串。 */
|
|
7
6
|
interface OllamaSearchResult {
|
|
8
7
|
title?: string | null;
|
|
9
8
|
url?: string | null;
|
|
10
9
|
content?: string | null;
|
|
11
10
|
}
|
|
12
|
-
/** 成功响应信封。 */
|
|
13
11
|
interface OllamaSearchResponse {
|
|
14
12
|
results?: OllamaSearchResult[];
|
|
15
13
|
}
|
|
16
14
|
//#endregion
|
|
17
15
|
//#region src/provider.d.ts
|
|
18
|
-
/** 注册进 `ctx.web` 的 id;与 llm route 同名,配置里看到的就是同一个"ollama"。 */
|
|
19
16
|
declare const OLLAMA_PROVIDER_ID = "ollama";
|
|
20
|
-
/** 默认端点;`/api/web_search` 是操作。 */
|
|
21
17
|
declare const OLLAMA_DEFAULT_BASE_URL = "https://ollama.com";
|
|
22
|
-
/** Ollama 服务端自己的默认结果数。 */
|
|
23
18
|
declare const OLLAMA_DEFAULT_MAX_RESULTS = 5;
|
|
24
|
-
/** Ollama `max_results` 的硬上限;超过它的值不发给服务端。 */
|
|
25
19
|
declare const OLLAMA_MAX_RESULTS_LIMIT = 10;
|
|
26
20
|
interface OllamaSearchProviderOptions {
|
|
27
|
-
/** 字面 key;给了就压过 {@link resolveApiKey}。 */
|
|
28
21
|
apiKey?: string | undefined;
|
|
29
|
-
/** 运行期取 key 的入口(凭证服务 / 环境);返回空表示取不到。 */
|
|
30
22
|
resolveApiKey?: () => Promise<string | undefined>;
|
|
31
|
-
/** 取不到 key 时报出来的引用名,便于用户知道去哪配。 */
|
|
32
23
|
apiKeyEnv: string;
|
|
33
24
|
baseURL: string;
|
|
34
|
-
/** 请求没给 `maxResults` 时用的默认值;省略表示让 Ollama 用它自己的默认。 */
|
|
35
25
|
maxResults?: number | undefined;
|
|
36
26
|
}
|
|
37
|
-
/** 一条 Ollama 结果 → 一个 source;没有 url 就丢掉(seam 的 source 必须有 url)。 */
|
|
38
27
|
declare function mapOllamaResult(result: OllamaSearchResult): WebSearchSource | undefined;
|
|
39
|
-
/** 响应信封 → 归一化结果;形状不对就抛(由调用方包成 `WEB_PROVIDER_ERROR`)。 */
|
|
40
28
|
declare function mapOllamaResponse(response: OllamaSearchResponse): WebSearchResult;
|
|
41
|
-
/** Ollama 的搜索后端;HTTP 重定向按 `WEB_PROVIDER_ERROR` 失败。 */
|
|
42
29
|
declare class OllamaSearchProvider implements WebSearchProvider {
|
|
43
30
|
private readonly options;
|
|
44
31
|
readonly id = "ollama";
|
|
45
32
|
constructor(options: OllamaSearchProviderOptions);
|
|
46
33
|
available(): boolean;
|
|
47
34
|
search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>;
|
|
48
|
-
/** 一次操作一份 key,不留在 provider 上;没有可用的 key 就点名引用,而不是发无授权请求。 */
|
|
49
35
|
private apiKey;
|
|
50
36
|
}
|
|
51
37
|
//#endregion
|
|
52
38
|
//#region src/index.d.ts
|
|
53
39
|
declare const name = "web-search-ollama";
|
|
54
|
-
/** 只往 `ctx.web` 注册后端,不发布服务。 */
|
|
55
40
|
declare const inject: string[];
|
|
56
41
|
interface Config {
|
|
57
|
-
/** 字面 key;优先用 `apiKeyEnv` 走凭证服务,别把密钥写进配置文件。 */
|
|
58
42
|
apiKey?: string;
|
|
59
|
-
/** 每次搜索解析一次的凭证引用;缺省 `OLLAMA_API_KEY`。 */
|
|
60
43
|
apiKeyEnv?: string;
|
|
61
|
-
/** 端点根;`/api/web_search` 由 provider 拼。缺省 ollama.com。 */
|
|
62
44
|
baseURL?: string;
|
|
63
|
-
/** 请求没带 `maxResults` 时的默认结果数;省略表示让 Ollama 用自己的默认。 */
|
|
64
45
|
maxResults?: number;
|
|
65
46
|
}
|
|
66
|
-
/**
|
|
67
|
-
* schema 解析之后的形状:四个字段都是 **volatile 稳定引用**,读它要过 `.get()`。
|
|
68
|
-
*
|
|
69
|
-
* 它们都标了 `.volatile()`(插件行里唯一可实时改的字段),所以设置页改完不用重挂这一行:provider 的每一次
|
|
70
|
-
* 请求、每一次取 key 都现场读引用。
|
|
71
|
-
*/
|
|
72
47
|
interface ResolvedConfig {
|
|
73
48
|
readonly apiKey: Volatile<string | undefined>;
|
|
74
49
|
readonly apiKeyEnv: Volatile<string | undefined>;
|
package/dist/index.mjs
CHANGED
|
@@ -3,17 +3,11 @@ import { launchEnvironmentOf } from "@deepseek-ai/dsh-launch-environment";
|
|
|
3
3
|
import z from "@deepseek-ai/schemastery";
|
|
4
4
|
import { WebError } from "@deepseek-ai/dsh-web";
|
|
5
5
|
//#region src/provider.ts
|
|
6
|
-
/** 注册进 `ctx.web` 的 id;与 llm route 同名,配置里看到的就是同一个"ollama"。 */
|
|
7
6
|
const OLLAMA_PROVIDER_ID = "ollama";
|
|
8
|
-
/** 默认端点;`/api/web_search` 是操作。 */
|
|
9
7
|
const OLLAMA_DEFAULT_BASE_URL = "https://ollama.com";
|
|
10
|
-
/** Ollama 服务端自己的默认结果数。 */
|
|
11
8
|
const OLLAMA_DEFAULT_MAX_RESULTS = 5;
|
|
12
|
-
/** Ollama `max_results` 的硬上限;超过它的值不发给服务端。 */
|
|
13
9
|
const OLLAMA_MAX_RESULTS_LIMIT = 10;
|
|
14
|
-
/** 每次请求带的归属头。 */
|
|
15
10
|
const USER_AGENT = "morlay-dsh-plugin/0.0.1";
|
|
16
|
-
/** 一条 Ollama 结果 → 一个 source;没有 url 就丢掉(seam 的 source 必须有 url)。 */
|
|
17
11
|
function mapOllamaResult(result) {
|
|
18
12
|
const url = result.url;
|
|
19
13
|
if (typeof url !== "string" || url.length === 0) return void 0;
|
|
@@ -25,7 +19,6 @@ function mapOllamaResult(result) {
|
|
|
25
19
|
...snippet === void 0 ? {} : { snippet }
|
|
26
20
|
};
|
|
27
21
|
}
|
|
28
|
-
/** 响应信封 → 归一化结果;形状不对就抛(由调用方包成 `WEB_PROVIDER_ERROR`)。 */
|
|
29
22
|
function mapOllamaResponse(response) {
|
|
30
23
|
const results = response.results;
|
|
31
24
|
if (results !== void 0 && !Array.isArray(results)) throw new TypeError("Ollama returned a non-array `results` field");
|
|
@@ -34,7 +27,6 @@ function mapOllamaResponse(response) {
|
|
|
34
27
|
truncated: false
|
|
35
28
|
};
|
|
36
29
|
}
|
|
37
|
-
/** Ollama 的搜索后端;HTTP 重定向按 `WEB_PROVIDER_ERROR` 失败。 */
|
|
38
30
|
var OllamaSearchProvider = class {
|
|
39
31
|
options;
|
|
40
32
|
id = OLLAMA_PROVIDER_ID;
|
|
@@ -86,7 +78,6 @@ var OllamaSearchProvider = class {
|
|
|
86
78
|
throw new WebError(`Ollama returned an unprocessable response body: ${String(error)}`, "WEB_PROVIDER_ERROR", { cause: error });
|
|
87
79
|
}
|
|
88
80
|
}
|
|
89
|
-
/** 一次操作一份 key,不留在 provider 上;没有可用的 key 就点名引用,而不是发无授权请求。 */
|
|
90
81
|
async apiKey() {
|
|
91
82
|
const literal = this.options.apiKey;
|
|
92
83
|
if (literal !== void 0 && literal.length > 0) return literal;
|
|
@@ -117,14 +108,8 @@ function searchAborted(cause) {
|
|
|
117
108
|
//#endregion
|
|
118
109
|
//#region src/index.ts
|
|
119
110
|
const name = "web-search-ollama";
|
|
120
|
-
/** 只往 `ctx.web` 注册后端,不发布服务。 */
|
|
121
111
|
const inject = ["web"];
|
|
122
|
-
/** 与 `llm-pi-ai` 的 ollama route 共用同一个 key 引用。 */
|
|
123
112
|
const DEFAULT_API_KEY_ENV = "OLLAMA_API_KEY";
|
|
124
|
-
/**
|
|
125
|
-
* 本地化说明:`description()` 的类型签名只声明 `string`,而 meta 本身接受 `Dict<string>`
|
|
126
|
-
* (`vendor/schemastery/src/index.ts` 的 `mergeDesc` 就是按字典合并的),所以这里只做一次类型放行。
|
|
127
|
-
*/
|
|
128
113
|
const localized = (text) => text;
|
|
129
114
|
const Config = z.object({
|
|
130
115
|
apiKey: z.string().role("secret").description(localized({
|
package/dist/rows.d.cts
CHANGED
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
//#region src/rows.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* 本包作为能力包发布的**装配数据**:行本身在部署那一层装
|
|
4
|
-
* (`packages/bundles/ollama-provider-profile` 引用它渲染 patch;那里同时给 `web.searchProvider` 与 key 引用)。
|
|
5
|
-
*
|
|
6
|
-
* 注册行必须在 host 平面只装一次——同一个 provider id 注册两份会撞 `WEB_DUPLICATE_PROVIDER`。
|
|
7
|
-
*/
|
|
8
|
-
/** 一行装配条目:与 `cordis.patch.yml` 的顶层结构同形。 */
|
|
9
2
|
interface PatchRow {
|
|
10
3
|
readonly id?: string;
|
|
11
4
|
readonly insert?: readonly RowEntry[];
|
|
12
5
|
}
|
|
13
|
-
/** `insert` 里的一个条目。 */
|
|
14
6
|
interface RowEntry {
|
|
15
7
|
readonly id: string;
|
|
16
8
|
readonly name: string;
|
|
17
9
|
readonly config?: Readonly<Record<string, unknown>>;
|
|
18
10
|
}
|
|
19
|
-
/** 搜索后端的注册行(config 的值由部署那层按 id 覆盖)。 */
|
|
20
11
|
declare function webSearchRows(): readonly PatchRow[];
|
|
21
12
|
//#endregion
|
|
22
13
|
export { PatchRow, RowEntry, webSearchRows };
|
package/dist/rows.d.mts
CHANGED
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
//#region src/rows.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* 本包作为能力包发布的**装配数据**:行本身在部署那一层装
|
|
4
|
-
* (`packages/bundles/ollama-provider-profile` 引用它渲染 patch;那里同时给 `web.searchProvider` 与 key 引用)。
|
|
5
|
-
*
|
|
6
|
-
* 注册行必须在 host 平面只装一次——同一个 provider id 注册两份会撞 `WEB_DUPLICATE_PROVIDER`。
|
|
7
|
-
*/
|
|
8
|
-
/** 一行装配条目:与 `cordis.patch.yml` 的顶层结构同形。 */
|
|
9
2
|
interface PatchRow {
|
|
10
3
|
readonly id?: string;
|
|
11
4
|
readonly insert?: readonly RowEntry[];
|
|
12
5
|
}
|
|
13
|
-
/** `insert` 里的一个条目。 */
|
|
14
6
|
interface RowEntry {
|
|
15
7
|
readonly id: string;
|
|
16
8
|
readonly name: string;
|
|
17
9
|
readonly config?: Readonly<Record<string, unknown>>;
|
|
18
10
|
}
|
|
19
|
-
/** 搜索后端的注册行(config 的值由部署那层按 id 覆盖)。 */
|
|
20
11
|
declare function webSearchRows(): readonly PatchRow[];
|
|
21
12
|
//#endregion
|
|
22
13
|
export { PatchRow, RowEntry, webSearchRows };
|
package/dist/rows.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morlay/dsh-web-search-ollama",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Ollama-backed search provider for the DeepSeek Harness web seam (ctx.web): one web_search backend calling POST https://ollama.com/api/web_search.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
@@ -35,19 +35,19 @@
|
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@deepseek-ai/cosmokit": "1.8.5",
|
|
38
|
-
"@deepseek-ai/dsh-client-locale": "0.
|
|
39
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.
|
|
40
|
-
"@morlay/dsh-client-ui-primitives": "0.0.
|
|
38
|
+
"@deepseek-ai/dsh-client-locale": "0.2.0-rc.1",
|
|
39
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.1",
|
|
40
|
+
"@morlay/dsh-client-ui-primitives": "0.0.5"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
44
44
|
"@deepseek-ai/cosmokit": "^1.8.5",
|
|
45
|
-
"@deepseek-ai/dsh-client-locale": "^0.
|
|
46
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.
|
|
47
|
-
"@deepseek-ai/dsh-credentials": "^0.
|
|
48
|
-
"@deepseek-ai/dsh-launch-environment": "^0.
|
|
49
|
-
"@deepseek-ai/dsh-web": "^0.
|
|
50
|
-
"@morlay/dsh-client-ui-primitives": "0.0.
|
|
45
|
+
"@deepseek-ai/dsh-client-locale": "^0.2.0-rc.1",
|
|
46
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.2.0-rc.1",
|
|
47
|
+
"@deepseek-ai/dsh-credentials": "^0.2.0-rc.1",
|
|
48
|
+
"@deepseek-ai/dsh-launch-environment": "^0.2.0-rc.1",
|
|
49
|
+
"@deepseek-ai/dsh-web": "^0.2.0-rc.1",
|
|
50
|
+
"@morlay/dsh-client-ui-primitives": "0.0.5"
|
|
51
51
|
},
|
|
52
52
|
"dsh": {
|
|
53
53
|
"client": {
|
package/src/client/index.ts
CHANGED
|
@@ -1,36 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* 生效),本包只把英文键名换成中文标签与说明。
|
|
4
|
-
*/
|
|
1
|
+
// client 半:这一行的配置页由通用 schema 表单按 volatile 字段生成(四个字段都能在页面上改,改完下一次请求就
|
|
2
|
+
// 生效),本包只把英文键名换成中文标签与说明。
|
|
5
3
|
|
|
6
4
|
import type { Context } from "@deepseek-ai/cordis";
|
|
7
5
|
import type {} from "@deepseek-ai/dsh-client-locale/client";
|
|
8
6
|
import type {} from "@deepseek-ai/dsh-client-ui-slots";
|
|
9
7
|
import { en, zh, type WebSearchFieldLocaleKey } from "./locales.ts";
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
// 本包 host 行 id:行配置页读的就是这个命名空间。
|
|
12
10
|
export const WEB_SEARCH_NS = "web-search-ollama";
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
// 本页字典的命名空间。
|
|
15
13
|
export const NS = "settings.web-search-ollama";
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
// 认领的字段名。
|
|
18
16
|
const FIELDS = ["apiKey", "apiKeyEnv", "baseURL", "maxResults"] as const;
|
|
19
17
|
|
|
20
18
|
declare module "@deepseek-ai/dsh-client-ui-slots" {
|
|
21
19
|
interface LocaleNamespaceMap {
|
|
22
|
-
|
|
20
|
+
// 设置页里这一行的字段文案。
|
|
23
21
|
"settings.web-search-ollama": WebSearchFieldLocaleKey;
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
// 需要的服务:槽位(字段槽)与字典。
|
|
28
26
|
export const inject = ["locale"];
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
* 给这一行的四个字段补文案。
|
|
32
|
-
* @param ctx - 浏览器插件上下文。
|
|
33
|
-
*/
|
|
28
|
+
// 给这一行的四个字段补文案。
|
|
34
29
|
export function apply(ctx: Context): void {
|
|
35
30
|
const t = ctx.locale.bind(NS);
|
|
36
31
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "web-search-ollama: field locale");
|
package/src/client/locales.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -19,29 +19,25 @@ export type { OllamaSearchProviderOptions } from "./provider.ts";
|
|
|
19
19
|
|
|
20
20
|
export const name = "web-search-ollama";
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// 只往 `ctx.web` 注册后端,不发布服务。
|
|
23
23
|
export const inject = ["web"];
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
// 与 `llm-pi-ai` 的 ollama route 共用同一个 key 引用。
|
|
26
26
|
const DEFAULT_API_KEY_ENV = "OLLAMA_API_KEY";
|
|
27
27
|
|
|
28
28
|
export interface Config {
|
|
29
|
-
|
|
29
|
+
// 字面 key;优先用 `apiKeyEnv` 走凭证服务,别把密钥写进配置文件。
|
|
30
30
|
apiKey?: string;
|
|
31
|
-
|
|
31
|
+
// 每次搜索解析一次的凭证引用;缺省 `OLLAMA_API_KEY`。
|
|
32
32
|
apiKeyEnv?: string;
|
|
33
|
-
|
|
33
|
+
// 端点根;`/api/web_search` 由 provider 拼。缺省 ollama.com。
|
|
34
34
|
baseURL?: string;
|
|
35
|
-
|
|
35
|
+
// 请求没带 `maxResults` 时的默认结果数;省略表示让 Ollama 用自己的默认。
|
|
36
36
|
maxResults?: number;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
*
|
|
42
|
-
* 它们都标了 `.volatile()`(插件行里唯一可实时改的字段),所以设置页改完不用重挂这一行:provider 的每一次
|
|
43
|
-
* 请求、每一次取 key 都现场读引用。
|
|
44
|
-
*/
|
|
39
|
+
// schema 解析之后的形状:四个字段都是 **volatile 稳定引用**(插件行里唯一可实时改的字段),读它要过 `.get()`。
|
|
40
|
+
// 设置页改完不用重挂这一行:provider 的每次请求、每次取 key 都现场读引用。
|
|
45
41
|
export interface ResolvedConfig {
|
|
46
42
|
readonly apiKey: Volatile<string | undefined>;
|
|
47
43
|
readonly apiKeyEnv: Volatile<string | undefined>;
|
|
@@ -49,10 +45,8 @@ export interface ResolvedConfig {
|
|
|
49
45
|
readonly maxResults: Volatile<number | undefined>;
|
|
50
46
|
}
|
|
51
47
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* (`vendor/schemastery/src/index.ts` 的 `mergeDesc` 就是按字典合并的),所以这里只做一次类型放行。
|
|
55
|
-
*/
|
|
48
|
+
// 本地化说明:`description()` 的类型签名只声明 `string`,而 meta 本身接受 `Dict<string>`
|
|
49
|
+
// (`vendor/schemastery/src/index.ts` 的 `mergeDesc` 就是按字典合并的),所以这里只做一次类型放行。
|
|
56
50
|
const localized = (text: { zh: string; en: string }): string => text as unknown as string;
|
|
57
51
|
|
|
58
52
|
export const Config: z<Config, ResolvedConfig> = z.object({
|
package/src/provider.ts
CHANGED
|
@@ -7,34 +7,34 @@ import type {
|
|
|
7
7
|
} from "@deepseek-ai/dsh-web";
|
|
8
8
|
import type { OllamaError, OllamaSearchResponse, OllamaSearchResult } from "./types.ts";
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
// 注册进 `ctx.web` 的 id;与 llm route 同名,配置里看到的就是同一个"ollama"。
|
|
11
11
|
export const OLLAMA_PROVIDER_ID = "ollama";
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
// 默认端点;`/api/web_search` 是操作。
|
|
14
14
|
export const OLLAMA_DEFAULT_BASE_URL = "https://ollama.com";
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
// Ollama 服务端自己的默认结果数。
|
|
17
17
|
export const OLLAMA_DEFAULT_MAX_RESULTS = 5;
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
// Ollama `max_results` 的硬上限;超过它的值不发给服务端。
|
|
20
20
|
export const OLLAMA_MAX_RESULTS_LIMIT = 10;
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// 每次请求带的归属头。
|
|
23
23
|
const USER_AGENT = "morlay-dsh-plugin/0.0.1";
|
|
24
24
|
|
|
25
25
|
export interface OllamaSearchProviderOptions {
|
|
26
|
-
|
|
26
|
+
// 字面 key;给了就压过 `resolveApiKey`。
|
|
27
27
|
apiKey?: string | undefined;
|
|
28
|
-
|
|
28
|
+
// 运行期取 key 的入口(凭证服务 / 环境);返回空表示取不到。
|
|
29
29
|
resolveApiKey?: () => Promise<string | undefined>;
|
|
30
|
-
|
|
30
|
+
// 取不到 key 时报出来的引用名,便于用户知道去哪配。
|
|
31
31
|
apiKeyEnv: string;
|
|
32
32
|
baseURL: string;
|
|
33
|
-
|
|
33
|
+
// 请求没给 `maxResults` 时用的默认值;省略表示让 Ollama 用它自己的默认。
|
|
34
34
|
maxResults?: number | undefined;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
// 一条 Ollama 结果 → 一个 source;没有 url 就丢掉(seam 的 source 必须有 url)。
|
|
38
38
|
export function mapOllamaResult(result: OllamaSearchResult): WebSearchSource | undefined {
|
|
39
39
|
const url = result.url;
|
|
40
40
|
if (typeof url !== "string" || url.length === 0) return undefined;
|
|
@@ -49,7 +49,7 @@ export function mapOllamaResult(result: OllamaSearchResult): WebSearchSource | u
|
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
// 响应信封 → 归一化结果;形状不对就抛(由调用方包成 `WEB_PROVIDER_ERROR`)。
|
|
53
53
|
export function mapOllamaResponse(response: OllamaSearchResponse): WebSearchResult {
|
|
54
54
|
const results = response.results;
|
|
55
55
|
if (results !== undefined && !Array.isArray(results)) {
|
|
@@ -63,7 +63,7 @@ export function mapOllamaResponse(response: OllamaSearchResponse): WebSearchResu
|
|
|
63
63
|
return { sources, truncated: false };
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
// Ollama 的搜索后端;HTTP 重定向按 `WEB_PROVIDER_ERROR` 失败。
|
|
67
67
|
export class OllamaSearchProvider implements WebSearchProvider {
|
|
68
68
|
readonly id = OLLAMA_PROVIDER_ID;
|
|
69
69
|
|
|
@@ -133,7 +133,7 @@ export class OllamaSearchProvider implements WebSearchProvider {
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
// 一次操作一份 key,不留在 provider 上;没有可用的 key 就点名引用,而不是发无授权请求。
|
|
137
137
|
private async apiKey(): Promise<string> {
|
|
138
138
|
const literal = this.options.apiKey;
|
|
139
139
|
if (literal !== undefined && literal.length > 0) return literal;
|
package/src/rows.ts
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
* 注册行必须在 host 平面只装一次——同一个 provider id 注册两份会撞 `WEB_DUPLICATE_PROVIDER`。
|
|
6
|
-
*/
|
|
1
|
+
// 本包作为能力包发布的**装配数据**:行本身在部署那一层装(`packages/bundles/ollama-provider-profile` 引用它
|
|
2
|
+
// 渲染 patch,那里同时给 `web.searchProvider` 与 key 引用)。注册行在 host 平面只装一次——同一个 provider id
|
|
3
|
+
// 注册两份会撞 `WEB_DUPLICATE_PROVIDER`。
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
// 一行装配条目:与 `cordis.patch.yml` 的顶层结构同形。
|
|
9
6
|
export interface PatchRow {
|
|
10
7
|
readonly id?: string;
|
|
11
8
|
readonly insert?: readonly RowEntry[];
|
|
12
9
|
}
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
// `insert` 里的一个条目。
|
|
15
12
|
export interface RowEntry {
|
|
16
13
|
readonly id: string;
|
|
17
14
|
readonly name: string;
|
|
18
15
|
readonly config?: Readonly<Record<string, unknown>>;
|
|
19
16
|
}
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
// 搜索后端的注册行(config 的值由部署那层按 id 覆盖)。
|
|
22
19
|
export function webSearchRows(): readonly PatchRow[] {
|
|
23
20
|
return [{ insert: [{ id: "web-search-ollama", name: "@morlay/dsh-web-search-ollama" }] }];
|
|
24
21
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,29 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* 网页片段(不是生成式答案),所以它只映射到 `WebSearchSource.snippet`。
|
|
6
|
-
*/
|
|
1
|
+
// POST https://ollama.com/api/web_search 的 wire 类型。只有类型,没有运行期代码。
|
|
2
|
+
//
|
|
3
|
+
// 响应是扁平 `results[]`,每条带 title / url / content;`content` 是 Ollama 截出来的网页片段(不是生成式
|
|
4
|
+
// 答案),只映射到 `WebSearchSource.snippet`。
|
|
7
5
|
|
|
8
|
-
|
|
6
|
+
// 请求体。`max_results` 缺省时由服务端按自己的默认值(5)处理。
|
|
9
7
|
export interface OllamaSearchRequest {
|
|
10
8
|
query: string;
|
|
11
9
|
max_results?: number;
|
|
12
10
|
}
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
// `results[]` 的一条;字段都可能缺失或为空串。
|
|
15
13
|
export interface OllamaSearchResult {
|
|
16
14
|
title?: string | null;
|
|
17
15
|
url?: string | null;
|
|
18
16
|
content?: string | null;
|
|
19
17
|
}
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
// 成功响应信封。
|
|
22
20
|
export interface OllamaSearchResponse {
|
|
23
21
|
results?: OllamaSearchResult[];
|
|
24
22
|
}
|
|
25
23
|
|
|
26
|
-
|
|
24
|
+
// 错误响应信封;Ollama 失败时给 `{"error": "..."}`。
|
|
27
25
|
export interface OllamaError {
|
|
28
26
|
error?: string;
|
|
29
27
|
}
|