dsh-web-search-pro 0.2.0 → 0.2.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/CHANGELOG.md +179 -0
- package/README.md +197 -32
- package/assets/skills/dsh-web-search-pro/SKILL.md +14 -13
- package/assets/skills/dsh-web-search-pro/references/config.md +36 -0
- package/assets/skills/dsh-web-search-pro/references/sources.md +19 -4
- package/assets/skills/dsh-web-search-pro/references/troubleshooting.md +3 -1
- package/catalog/sources.v1.json +22 -12
- package/lib/actions/approval.js +50 -1
- package/lib/actions/approval.js.map +1 -1
- package/lib/actions/config.js +274 -0
- package/lib/actions/config.js.map +1 -0
- package/lib/actions/errors.js +8 -1
- package/lib/actions/errors.js.map +1 -1
- package/lib/actions/format.js +10 -0
- package/lib/actions/format.js.map +1 -1
- package/lib/actions/index-view.js +2 -2
- package/lib/actions/index-view.js.map +1 -1
- package/lib/actions/read.js +7 -3
- package/lib/actions/read.js.map +1 -1
- package/lib/actions/registry.js +3 -1
- package/lib/actions/registry.js.map +1 -1
- package/lib/actions/run.js +2 -2
- package/lib/actions/run.js.map +1 -1
- package/lib/actions/schema.js +18 -0
- package/lib/actions/schema.js.map +1 -1
- package/lib/actions/search.js +12 -6
- package/lib/actions/search.js.map +1 -1
- package/lib/actions/sources.js +116 -41
- package/lib/actions/sources.js.map +1 -1
- package/lib/actions/types.js +19 -1
- package/lib/actions/types.js.map +1 -1
- package/lib/browser-access.js +25 -0
- package/lib/browser-access.js.map +1 -1
- package/lib/catalog/recommend.js +11 -3
- package/lib/catalog/recommend.js.map +1 -1
- package/lib/catalog/schema.js +3 -1
- package/lib/catalog/schema.js.map +1 -1
- package/lib/cli/builtin-specs.js +341 -0
- package/lib/cli/builtin-specs.js.map +1 -0
- package/lib/cli/chain.js +193 -0
- package/lib/cli/chain.js.map +1 -0
- package/lib/cli/chains-spec.js +118 -0
- package/lib/cli/chains-spec.js.map +1 -0
- package/lib/cli/engine.js +99 -0
- package/lib/cli/engine.js.map +1 -0
- package/lib/cli/opencli-sites.js +83 -0
- package/lib/cli/opencli-sites.js.map +1 -0
- package/lib/cli/opencli.js +153 -0
- package/lib/cli/opencli.js.map +1 -0
- package/lib/cli/probe.js +128 -0
- package/lib/cli/probe.js.map +1 -0
- package/lib/cli/runner.js +564 -0
- package/lib/cli/runner.js.map +1 -0
- package/lib/cli/spec.js +496 -0
- package/lib/cli/spec.js.map +1 -0
- package/lib/cli/time-text.js +79 -0
- package/lib/cli/time-text.js.map +1 -0
- package/lib/cli/trial.js +57 -0
- package/lib/cli/trial.js.map +1 -0
- package/lib/client/SettingsCard.js +14 -32
- package/lib/client/SettingsCard.js.map +1 -1
- package/lib/client/agent-mark.js +27 -0
- package/lib/client/agent-mark.js.map +1 -0
- package/lib/client/card-frame.js +118 -0
- package/lib/client/card-frame.js.map +1 -0
- package/lib/client/cli-form.js +257 -0
- package/lib/client/cli-form.js.map +1 -0
- package/lib/client/field-docs.js +130 -0
- package/lib/client/field-docs.js.map +1 -0
- package/lib/client/field-keys.js +81 -0
- package/lib/client/field-keys.js.map +1 -0
- package/lib/client/field-rows.js +71 -0
- package/lib/client/field-rows.js.map +1 -0
- package/lib/client/fill.js +3 -0
- package/lib/client/fill.js.map +1 -0
- package/lib/client/form-specs.js +15 -1
- package/lib/client/form-specs.js.map +1 -1
- package/lib/client/form.js +296 -27
- package/lib/client/form.js.map +1 -1
- package/lib/client/group-advanced.js +23 -0
- package/lib/client/group-advanced.js.map +1 -0
- package/lib/client/group-agent.js +28 -0
- package/lib/client/group-agent.js.map +1 -0
- package/lib/client/group-cli.js +136 -0
- package/lib/client/group-cli.js.map +1 -0
- package/lib/client/group-common.js +29 -0
- package/lib/client/group-common.js.map +1 -0
- package/lib/client/group-judge.js +67 -0
- package/lib/client/group-judge.js.map +1 -0
- package/lib/client/group-order.js +201 -0
- package/lib/client/group-order.js.map +1 -0
- package/lib/client/group-runtime.js +33 -0
- package/lib/client/group-runtime.js.map +1 -0
- package/lib/client/group-sources.js +83 -0
- package/lib/client/group-sources.js.map +1 -0
- package/lib/client/groups-basic.js +36 -0
- package/lib/client/groups-basic.js.map +1 -0
- package/lib/client/index.js.map +1 -1
- package/lib/client/json-list.js +50 -0
- package/lib/client/json-list.js.map +1 -0
- package/lib/client/locales.js +666 -215
- package/lib/client/locales.js.map +1 -1
- package/lib/client/order.js +192 -0
- package/lib/client/order.js.map +1 -0
- package/lib/client/overlay-ops.js +46 -0
- package/lib/client/overlay-ops.js.map +1 -0
- package/lib/client/sources-table.js +1 -0
- package/lib/client/sources-table.js.map +1 -1
- package/lib/client/styles.js +74 -47
- package/lib/client/styles.js.map +1 -1
- package/lib/client/text-view.js +98 -0
- package/lib/client/text-view.js.map +1 -0
- package/lib/client/ui-kit.js +120 -0
- package/lib/client/ui-kit.js.map +1 -0
- package/lib/client/validators.js +22 -0
- package/lib/client/validators.js.map +1 -1
- package/lib/client.js +9151 -1987
- package/lib/client.js.map +1 -1
- package/lib/config-fillers.js +53 -0
- package/lib/config-fillers.js.map +1 -0
- package/lib/config-groups.js +49 -0
- package/lib/config-groups.js.map +1 -0
- package/lib/config.js +87 -107
- package/lib/config.js.map +1 -1
- package/lib/default-chain.js +66 -0
- package/lib/default-chain.js.map +1 -0
- package/lib/deps.js +109 -102
- package/lib/deps.js.map +1 -1
- package/lib/engine-error.js +19 -0
- package/lib/engine-error.js.map +1 -0
- package/lib/engines.js +32 -115
- package/lib/engines.js.map +1 -1
- package/lib/fetch.js +23 -4
- package/lib/fetch.js.map +1 -1
- package/lib/index.js +30 -5
- package/lib/index.js.map +1 -1
- package/lib/overlay-types.js +88 -0
- package/lib/overlay-types.js.map +1 -0
- package/lib/overlay.js +683 -0
- package/lib/overlay.js.map +1 -0
- package/lib/pipeline/candidates.js +27 -1
- package/lib/pipeline/candidates.js.map +1 -1
- package/lib/pipeline/compile.js +63 -0
- package/lib/pipeline/compile.js.map +1 -1
- package/lib/pipeline/confidence.js +64 -0
- package/lib/pipeline/confidence.js.map +1 -0
- package/lib/pipeline/fusion.js +50 -3
- package/lib/pipeline/fusion.js.map +1 -1
- package/lib/pipeline/plan.js +2 -2
- package/lib/pipeline/plan.js.map +1 -1
- package/lib/pipeline/render.js +20 -2
- package/lib/pipeline/render.js.map +1 -1
- package/lib/pipeline/run.js +21 -7
- package/lib/pipeline/run.js.map +1 -1
- package/lib/pipeline/sources-spec.js +19 -3
- package/lib/pipeline/sources-spec.js.map +1 -1
- package/lib/providers/builtin.js +13 -14
- package/lib/providers/builtin.js.map +1 -1
- package/lib/providers/deepseek.js +348 -0
- package/lib/providers/deepseek.js.map +1 -0
- package/lib/providers/http.js.map +1 -1
- package/lib/providers/keyed-meta.js +7 -0
- package/lib/providers/keyed-meta.js.map +1 -1
- package/lib/providers/platforms.js +118 -58
- package/lib/providers/platforms.js.map +1 -1
- package/lib/providers/registry.js.map +1 -1
- package/lib/restart.js +47 -0
- package/lib/restart.js.map +1 -0
- package/lib/router.js +203 -27
- package/lib/router.js.map +1 -1
- package/lib/rpc-types.js +15 -0
- package/lib/rpc-types.js.map +1 -0
- package/lib/rpc.js +85 -0
- package/lib/rpc.js.map +1 -0
- package/lib/tools.js +10 -4
- package/lib/tools.js.map +1 -1
- package/lib/types/actions/approval.d.ts +11 -0
- package/lib/types/actions/config.d.ts +54 -0
- package/lib/types/actions/format.d.ts +9 -2
- package/lib/types/actions/run.d.ts +1 -0
- package/lib/types/actions/schema.d.ts +7 -1
- package/lib/types/actions/sources.d.ts +29 -3
- package/lib/types/actions/types.d.ts +28 -2
- package/lib/types/browser-access.d.ts +17 -0
- package/lib/types/catalog/recommend.d.ts +4 -0
- package/lib/types/catalog/schema.d.ts +2 -0
- package/lib/types/cli/builtin-specs.d.ts +38 -0
- package/lib/types/cli/chain.d.ts +83 -0
- package/lib/types/cli/chains-spec.d.ts +48 -0
- package/lib/types/cli/engine.d.ts +50 -0
- package/lib/types/cli/opencli-sites.d.ts +24 -0
- package/lib/types/cli/opencli.d.ts +77 -0
- package/lib/types/cli/probe.d.ts +53 -0
- package/lib/types/cli/runner.d.ts +126 -0
- package/lib/types/cli/spec.d.ts +269 -0
- package/lib/types/cli/time-text.d.ts +12 -0
- package/lib/types/cli/trial.d.ts +19 -0
- package/lib/types/client/SettingsCard.d.ts +17 -1
- package/lib/types/client/agent-mark.d.ts +22 -0
- package/lib/types/client/card-frame.d.ts +35 -0
- package/lib/types/client/cli-form.d.ts +97 -0
- package/lib/types/client/field-docs.d.ts +15 -0
- package/lib/types/client/field-keys.d.ts +41 -0
- package/lib/types/client/field-rows.d.ts +70 -0
- package/lib/types/client/fill.d.ts +2 -0
- package/lib/types/client/form-specs.d.ts +12 -3
- package/lib/types/client/form.d.ts +79 -1
- package/lib/types/client/group-advanced.d.ts +9 -0
- package/lib/types/client/group-agent.d.ts +20 -0
- package/lib/types/client/group-cli.d.ts +52 -0
- package/lib/types/client/group-common.d.ts +12 -0
- package/lib/types/client/group-judge.d.ts +17 -0
- package/lib/types/client/group-order.d.ts +26 -0
- package/lib/types/client/group-runtime.d.ts +15 -0
- package/lib/types/client/group-sources.d.ts +46 -0
- package/lib/types/client/groups-basic.d.ts +18 -0
- package/lib/types/client/index.d.ts +8 -0
- package/lib/types/client/json-list.d.ts +21 -0
- package/lib/types/client/locales.d.ts +1079 -196
- package/lib/types/client/order.d.ts +102 -0
- package/lib/types/client/overlay-ops.d.ts +37 -0
- package/lib/types/client/styles.d.ts +56 -41
- package/lib/types/client/text-view.d.ts +22 -0
- package/lib/types/client/ui-kit.d.ts +200 -0
- package/lib/types/client/validators.d.ts +6 -0
- package/lib/types/config-fillers.d.ts +9 -0
- package/lib/types/config-groups.d.ts +23 -0
- package/lib/types/config.d.ts +265 -216
- package/lib/types/default-chain.d.ts +63 -0
- package/lib/types/deps.d.ts +25 -23
- package/lib/types/engine-error.d.ts +12 -0
- package/lib/types/engines.d.ts +45 -10
- package/lib/types/fetch.d.ts +12 -3
- package/lib/types/index.d.ts +164 -146
- package/lib/types/overlay-types.d.ts +98 -0
- package/lib/types/overlay.d.ts +141 -0
- package/lib/types/pipeline/candidates.d.ts +19 -0
- package/lib/types/pipeline/compile.d.ts +11 -0
- package/lib/types/pipeline/confidence.d.ts +35 -0
- package/lib/types/pipeline/fusion.d.ts +23 -1
- package/lib/types/pipeline/render.d.ts +16 -0
- package/lib/types/pipeline/run.d.ts +3 -1
- package/lib/types/pipeline/sources-spec.d.ts +5 -2
- package/lib/types/pipeline/types.d.ts +37 -0
- package/lib/types/providers/deepseek.d.ts +130 -0
- package/lib/types/providers/http.d.ts +2 -1
- package/lib/types/providers/keyed-meta.d.ts +5 -0
- package/lib/types/providers/platforms.d.ts +15 -3
- package/lib/types/providers/registry.d.ts +10 -0
- package/lib/types/restart.d.ts +52 -0
- package/lib/types/router.d.ts +69 -9
- package/lib/types/rpc-types.d.ts +79 -0
- package/lib/types/rpc.d.ts +41 -0
- package/lib/types/tools.d.ts +6 -0
- package/lib/types/util.d.ts +16 -1
- package/lib/util.js +17 -4
- package/lib/util.js.map +1 -1
- package/package.json +51 -43
- package/scripts/check-client-bundle.mjs +1 -1
- package/scripts/cli-login-check.mjs +214 -0
- package/lib/client/RubricEditor.js +0 -47
- package/lib/client/RubricEditor.js.map +0 -1
- package/lib/client/fields.js +0 -31
- package/lib/client/fields.js.map +0 -1
- package/lib/types/client/RubricEditor.d.ts +0 -6
- package/lib/types/client/fields.d.ts +0 -65
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The agent overlay: the settings an agent may change at run time without hand-editing the configuration.
|
|
3
|
+
*
|
|
4
|
+
* The profile configuration stays the user's baseline. The overlay is a small managed file next to the plugin's database
|
|
5
|
+
* (`$DSH_HOME/data/web-search-pro/overlay.json`, or beside `dbPath` when the user moved it) that `dynamic()` merges on top of the
|
|
6
|
+
* baseline on every read, so every consumer sees the change at once, with no watcher and no restart. It holds only what
|
|
7
|
+
* overlay-types.ts lists (engine order, source priority / disabled, confidence, platform backend chains, custom CLI specs),
|
|
8
|
+
* carries a revision for optimistic locking, a checksum, and an audit trail cut to {@link MAX_AUDIT_ENTRIES} entries.
|
|
9
|
+
*
|
|
10
|
+
* The same functions validate a change before it is written and the whole file when it is loaded: a file that does not parse,
|
|
11
|
+
* fails its checksum, holds a value the validators refuse, or no longer agrees with the baseline (a chain naming a CLI the user
|
|
12
|
+
* removed) is ignored as a whole and reported, never half applied. Validation reuses the functions the settings card and
|
|
13
|
+
* `sources.status` use (`cliIssues`, `sourcesIssues`, the CLI spec validator, the source id rules).
|
|
14
|
+
*
|
|
15
|
+
* Adding or replacing only: the overlay never deletes a baseline entry. Taking a baseline CLI out of service is
|
|
16
|
+
* `sources.disabled`; removing a CLI the overlay added is `config.remove_cli`.
|
|
17
|
+
* @module web-search-pro/overlay
|
|
18
|
+
*/
|
|
19
|
+
import type { ResolvedConfig } from './config.ts';
|
|
20
|
+
import { MAX_AUDIT_ENTRIES, OVERLAY_FILE, OVERLAY_VERSION, type AuditChange, type AuditEntry, type OverlayItem, type OverlayValues, type OverlayView, type ResetScope } from './overlay-types.ts';
|
|
21
|
+
export { MAX_AUDIT_ENTRIES, OVERLAY_FILE, OVERLAY_VERSION };
|
|
22
|
+
export interface Overlay {
|
|
23
|
+
version: 1;
|
|
24
|
+
revision: number;
|
|
25
|
+
updatedAt: string;
|
|
26
|
+
values: OverlayValues;
|
|
27
|
+
audit: AuditEntry[];
|
|
28
|
+
}
|
|
29
|
+
export declare function emptyOverlay(): Overlay;
|
|
30
|
+
export declare function checksumOf(overlay: Pick<Overlay, 'version' | 'revision' | 'updatedAt' | 'values' | 'audit'>): string;
|
|
31
|
+
/** `<dir of dbPath>/overlay.json`: the overlay sits beside the database, wherever the user put it. */
|
|
32
|
+
export declare function overlayFileFor(dbPath: string): string;
|
|
33
|
+
/** The baseline with the overlay merged on top. Never mutates its inputs. */
|
|
34
|
+
export declare function mergeOverlay(base: ResolvedConfig, values: OverlayValues): ResolvedConfig;
|
|
35
|
+
/** Where the effective value of an overlay key comes from, and what it is. */
|
|
36
|
+
export declare function effectiveValueOf(config: ResolvedConfig, key: string): unknown;
|
|
37
|
+
/** The id rules of the sources the baseline knows; supplied by the router (`registry.routeId(id) !== undefined`). */
|
|
38
|
+
export type KnownSource = (id: string) => boolean;
|
|
39
|
+
/** Problems the overlay values add to what the baseline already has (the user's own mistakes are not the overlay's to answer for). */
|
|
40
|
+
export declare function overlayErrors(base: ResolvedConfig, values: OverlayValues, known: KnownSource): string[];
|
|
41
|
+
/**
|
|
42
|
+
* Every problem with the `id` / `spec` of a `config.upsert_cli` call, one message each ([] when the call is valid). The single
|
|
43
|
+
* source of these rules: {@link OverlayStore.apply} refuses a change that has any, and the action's `precheck` asks it before the
|
|
44
|
+
* user is, so an unusable spec never reaches an approval prompt. It reads no state, so it never depends on the overlay file.
|
|
45
|
+
*/
|
|
46
|
+
export declare function cliSpecProblems(id: unknown, spec: unknown): string[];
|
|
47
|
+
/** Reason rule shared by every write: a real sentence, not a placeholder. */
|
|
48
|
+
export declare function checkReason(reason: unknown): string;
|
|
49
|
+
export type OverlayChange = {
|
|
50
|
+
kind: 'order';
|
|
51
|
+
engines?: unknown;
|
|
52
|
+
priority?: unknown;
|
|
53
|
+
disabled?: unknown;
|
|
54
|
+
platform?: unknown;
|
|
55
|
+
backends?: unknown;
|
|
56
|
+
} | {
|
|
57
|
+
kind: 'confidence';
|
|
58
|
+
id: unknown;
|
|
59
|
+
value: unknown;
|
|
60
|
+
} | {
|
|
61
|
+
kind: 'upsertCli';
|
|
62
|
+
id: unknown;
|
|
63
|
+
spec: unknown;
|
|
64
|
+
} | {
|
|
65
|
+
kind: 'removeCli';
|
|
66
|
+
id: unknown;
|
|
67
|
+
} | {
|
|
68
|
+
kind: 'reset';
|
|
69
|
+
scope: ResetScope;
|
|
70
|
+
id?: unknown;
|
|
71
|
+
}
|
|
72
|
+
/** The settings card: drop these keys (one or several), or everything when `keys` is `'all'`. */
|
|
73
|
+
| {
|
|
74
|
+
kind: 'revoke';
|
|
75
|
+
keys: readonly string[] | 'all';
|
|
76
|
+
};
|
|
77
|
+
export interface ChangeMeta {
|
|
78
|
+
actor: 'agent' | 'user';
|
|
79
|
+
/** The action name (`config.set_order`) or the card's button. */
|
|
80
|
+
action: string;
|
|
81
|
+
reason: string;
|
|
82
|
+
sessionId?: string;
|
|
83
|
+
/** When given, the change only applies if the overlay is still at this revision. */
|
|
84
|
+
expectedRevision?: number;
|
|
85
|
+
}
|
|
86
|
+
export interface AppliedChange {
|
|
87
|
+
/** False when the change left the overlay as it was (nothing was written, the revision is unchanged). */
|
|
88
|
+
changed: boolean;
|
|
89
|
+
revision: number;
|
|
90
|
+
keys: string[];
|
|
91
|
+
changes: AuditChange[];
|
|
92
|
+
audit?: AuditEntry;
|
|
93
|
+
}
|
|
94
|
+
export interface OverlayStoreOptions {
|
|
95
|
+
file: string;
|
|
96
|
+
/** The configuration the user owns (the profile), re-read on every call. */
|
|
97
|
+
baseline: () => ResolvedConfig;
|
|
98
|
+
known: KnownSource;
|
|
99
|
+
/** Changes whenever the answer of `known` can have changed (the router's registry revision), so a cached verdict is not kept past it. */
|
|
100
|
+
knownSignature?: () => string;
|
|
101
|
+
now?: () => Date;
|
|
102
|
+
}
|
|
103
|
+
export declare class OverlayStore {
|
|
104
|
+
private readonly options;
|
|
105
|
+
private overlay;
|
|
106
|
+
private signature;
|
|
107
|
+
private loadProblem;
|
|
108
|
+
private compat;
|
|
109
|
+
constructor(options: OverlayStoreOptions);
|
|
110
|
+
get file(): string;
|
|
111
|
+
private stat;
|
|
112
|
+
/** Re-read the file when its mtime or size changed. No watcher: every read of the effective config asks. */
|
|
113
|
+
private refresh;
|
|
114
|
+
private reload;
|
|
115
|
+
private readFile;
|
|
116
|
+
/** Strict parse: unknown keys, wrong types, a failed checksum or any value the validators refuse reject the whole file. */
|
|
117
|
+
private parse;
|
|
118
|
+
/** Why the overlay is being ignored, if it is: a broken file, or values that no longer agree with the baseline. */
|
|
119
|
+
get problem(): string | undefined;
|
|
120
|
+
private incompatibility;
|
|
121
|
+
/** The loaded overlay (an empty one while the file is missing or ignored). */
|
|
122
|
+
current(): Overlay;
|
|
123
|
+
/** The configuration as the plugin runs it: the baseline with the overlay on top, or the baseline alone while the overlay is ignored. */
|
|
124
|
+
effective(): ResolvedConfig;
|
|
125
|
+
baselineConfig(): ResolvedConfig;
|
|
126
|
+
/** The overlaid keys with the newest audit entry that touched each, for the card and `config.inspect`. */
|
|
127
|
+
items(): OverlayItem[];
|
|
128
|
+
view(limit?: number): OverlayView;
|
|
129
|
+
/** Compute the values a change leads to without writing anything. Throws {@link ActionArgError} for an invalid change. */
|
|
130
|
+
private plan;
|
|
131
|
+
/** Drop empty containers, and entries equal to the baseline (an override that changes nothing is not one). */
|
|
132
|
+
private normalize;
|
|
133
|
+
/**
|
|
134
|
+
* Plan, validate and write a change: re-reads the file first, checks the revision, validates the merged result with the
|
|
135
|
+
* server's own functions, writes atomically (0600) and appends the audit entry. A failed change leaves the file as it was.
|
|
136
|
+
*/
|
|
137
|
+
apply(change: OverlayChange, meta: ChangeMeta): AppliedChange;
|
|
138
|
+
private write;
|
|
139
|
+
/** Move an unreadable file aside (kept for inspection) so a fresh overlay can start. */
|
|
140
|
+
private quarantine;
|
|
141
|
+
}
|
|
@@ -13,10 +13,19 @@ export interface ProviderSource {
|
|
|
13
13
|
title?: string | null;
|
|
14
14
|
snippet?: string | null;
|
|
15
15
|
publishedAt?: string | null;
|
|
16
|
+
rerankScore?: number | null;
|
|
17
|
+
authority?: number | null;
|
|
18
|
+
/** The user-defined CLI that returned the row (`custom-cli:echo`) and the label it carries. */
|
|
19
|
+
via?: string | null;
|
|
20
|
+
tag?: string | null;
|
|
21
|
+
/** The source's confidence (0..1) when it is below 1 (see confidence.ts). */
|
|
22
|
+
confidence?: number | null;
|
|
16
23
|
}
|
|
17
24
|
/** One provider's ordered result list for one query (index 0 = rank 1). */
|
|
18
25
|
export interface ProviderOutput {
|
|
19
26
|
providerId: string;
|
|
27
|
+
/** The backend of a platform chain that answered (display only). */
|
|
28
|
+
backend?: string;
|
|
20
29
|
query: string;
|
|
21
30
|
sources: readonly ProviderSource[];
|
|
22
31
|
}
|
|
@@ -27,6 +36,16 @@ export interface MergeOptions {
|
|
|
27
36
|
export declare function candidateIdOf(canonical: string): string;
|
|
28
37
|
/** Fold snippet `next` into `current`: drop repeats, keep the longer of near-duplicates, join complements within `cap`. */
|
|
29
38
|
export declare function mergeSnippets(current: string, next: string | null | undefined, cap?: number): string;
|
|
39
|
+
/**
|
|
40
|
+
* What a result says about where it came from, for the exit: the custom CLIs that returned it (`via`) with their honest label (`tag`),
|
|
41
|
+
* and `confidence` = the best confidence among the providers that returned it, only when it is below 1 (a URL a full-confidence
|
|
42
|
+
* source also returned is as sure as that source). Empty for a result of built-in sources only.
|
|
43
|
+
*/
|
|
44
|
+
export declare function provenanceOf(candidate: Pick<Candidate, 'contributions' | 'origin'>): {
|
|
45
|
+
via?: string;
|
|
46
|
+
tag?: string;
|
|
47
|
+
confidence?: number;
|
|
48
|
+
};
|
|
30
49
|
/**
|
|
31
50
|
* Merge provider outputs into candidates keyed by canonical URL, in first-seen
|
|
32
51
|
* order (outputs in the given order, sources by rank). Sources without a URL
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
* - keyed sources (dev-plan M7c): Tavily / Linkup / Baidu Qianfan / Zhipu take domain lists (`options.sites`, capped at what
|
|
16
16
|
* each documents) and a date lower bound (`options.since`); Brave / Serper (Google) take `site:` / `-site:` / `-term`
|
|
17
17
|
* operators in the query; whatever a source does not document stays for local verification;
|
|
18
|
+
* - deepseek (DeepSeek Search API): `site:a OR site:b` / `-site:` / `-term` for HARD site / exclude_site / exclude_term and
|
|
19
|
+
* `after:YYYY-MM-DD` for a HARD time_window whose lower bound is understood, all in the query text (the API documents them as
|
|
20
|
+
* query operators); `originalQuestion` carries the task goal (or the first critical need) for the API's `ori_question`;
|
|
18
21
|
* - github*: the natural-language query returns nothing on repository search
|
|
19
22
|
* (E1: 0 of 20), so it is replaced by a short keyword query;
|
|
20
23
|
* - everything else: the plain query.
|
|
@@ -52,6 +55,7 @@ export interface CompiledQuery {
|
|
|
52
55
|
since?: string;
|
|
53
56
|
lang?: 'zh' | 'en';
|
|
54
57
|
sites?: CompiledSites;
|
|
58
|
+
originalQuestion?: string;
|
|
55
59
|
};
|
|
56
60
|
/** Broader variants to try, in order, when the provider answers ENGINE_EMPTY for `query` (GitHub: fewer keywords). */
|
|
57
61
|
fallbacks?: string[];
|
|
@@ -103,6 +107,13 @@ export declare function hardWindows(task: TaskLike, now: Date): {
|
|
|
103
107
|
* sources get `site:` / `-site:` / `-term` in the query. Soft constraints are never pushed down.
|
|
104
108
|
*/
|
|
105
109
|
export declare function compileKeyed(task: TaskLike, providerId: string, now: Date, caps: KeyedCaps): CompiledQuery;
|
|
110
|
+
/**
|
|
111
|
+
* DeepSeek Search takes `site:` (several joined by `OR`), `-site:`, `-term`, `"phrase"`, `lang:`, `after:` and `before:` inside
|
|
112
|
+
* the query. Hard constraints become those operators (the engine keeps them whole when it has to cut a long query). An operator the
|
|
113
|
+
* query already spells is not repeated; a hard site when the query already restricts to other sites stays local (two `site:`
|
|
114
|
+
* restrictions would AND into nothing).
|
|
115
|
+
*/
|
|
116
|
+
export declare function compileDeepSeek(task: TaskLike, providerId: string, now: Date): CompiledQuery;
|
|
106
117
|
export declare const GITHUB_MAX_TERMS = 5;
|
|
107
118
|
/**
|
|
108
119
|
* Short keyword query for repository search: entities, then must_terms, then a
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source confidence (0..1): how far the user trusts what one source returns. It is an input of rank fusion and a label on results,
|
|
3
|
+
* nothing else: it never removes a result, never changes what a source is asked, and every built-in source has confidence 1, so
|
|
4
|
+
* with the defaults the fused order is exactly what it was before confidence existed.
|
|
5
|
+
*
|
|
6
|
+
* factor(c) = 1 - STRENGTH · (1 - c) c in [0, 1]; undefined = 1; the factor is always in [1 - STRENGTH, 1]
|
|
7
|
+
* rrf(d) = Σ_provider factor(c_provider) / (k + bestRank_provider(d)) (fusion.ts)
|
|
8
|
+
* bonus(d) = bonus(d) · max_provider factor(c_provider) a URL only a doubted source returned earns less of the tie-break bonuses
|
|
9
|
+
*
|
|
10
|
+
* A source of confidence c therefore ranks as if its list began ((k + 1) / factor - (k + 1)) positions lower: at k = 60 about 7
|
|
11
|
+
* positions for c = 0.5 and about 16 for c = 0. Results several sources agree on lose almost nothing, a result only a doubted
|
|
12
|
+
* source has sinks towards the tail, and {@link guaranteeSeats} makes sure its best one is still within the list that is shown.
|
|
13
|
+
* Pure and free of imports: the settings card and the tests read it too.
|
|
14
|
+
* @module web-search-pro/pipeline/confidence
|
|
15
|
+
*/
|
|
16
|
+
/** How much confidence 0 takes off the contribution of a source (0.2 = a fifth). */
|
|
17
|
+
export declare const CONFIDENCE_STRENGTH = 0.2;
|
|
18
|
+
/** Confidence of a source nothing is known about: the built-in ones. */
|
|
19
|
+
export declare const FULL_CONFIDENCE = 1;
|
|
20
|
+
/** A confidence as a number in [0, 1]; anything else (missing, NaN) is full confidence. */
|
|
21
|
+
export declare function clampConfidence(value: number | undefined): number;
|
|
22
|
+
/** The multiplier of a source's rank-fusion contribution, in [1 - STRENGTH, 1]; exactly 1 for confidence 1 or none. */
|
|
23
|
+
export declare function confidenceFactor(confidence: number | undefined): number;
|
|
24
|
+
/** A contribution of one provider to a candidate; `confidence` is present only when it is below 1. */
|
|
25
|
+
export interface WeightedContribution {
|
|
26
|
+
providerId: string;
|
|
27
|
+
confidence?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Keep the best result of every doubted source within the first `size` results. A source whose confidence is below 1 and which
|
|
31
|
+
* answered, but has none of its results in the window, gets its best-ranked result moved to the end of the window (at most
|
|
32
|
+
* `size - 1` such seats, so the window never consists of nothing else). The order of everything else is kept. With no confidence
|
|
33
|
+
* below 1 anywhere the list comes back unchanged.
|
|
34
|
+
*/
|
|
35
|
+
export declare function guaranteeSeats<T>(ranked: readonly T[], size: number, contributions: (item: T) => readonly WeightedContribution[]): T[];
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* rrf(d) = Σ_provider 1 / (k + bestRank_provider(d)) one term per provider
|
|
5
5
|
* norm(d) = rrf(d) / (nProviders / (k + 1)) in [0, 1]; 1 = rank 1 everywhere
|
|
6
6
|
* score(d) = norm(d) + bonus(d) bonus added ONCE per URL
|
|
7
|
-
* bonus(d) = (freshnessBoost·fresh(d) + authorityBoost·authority(d)) · unit
|
|
7
|
+
* bonus(d) = (freshnessBoost·fresh(d) + authorityBoost·authority(d) + signalBoost·signal(d)) · unit
|
|
8
8
|
* unit = 1 / (nProviders · (k + 2)) one top-rank step of one provider, on the normalised scale
|
|
9
9
|
*
|
|
10
10
|
* `freshnessBoost` / `authorityBoost` (config, 0..1) are therefore FRACTIONS OF
|
|
@@ -13,10 +13,25 @@
|
|
|
13
13
|
* positions. They break ties and near-ties; they cannot lift a rank-10 result
|
|
14
14
|
* over a rank-1 result of the same provider. A URL returned by several
|
|
15
15
|
* providers gets one bonus, not one per hit.
|
|
16
|
+
*
|
|
17
|
+
* `signal(d)` is the provider's OWN quality grade when it gives one (DeepSeek Search: `rerank_score` 0..3, which already folds
|
|
18
|
+
* relevance, authority and freshness together, and `authority` 0..4): 0.7·rerank/3 + 0.3·authority/4 over whichever of the two
|
|
19
|
+
* the URL has (the best seen over providers, see candidates.ts), 0 for a URL no provider graded. `signalBoost` (default
|
|
20
|
+
* {@link PROVIDER_SIGNAL_BOOST}) is, like the others, a fraction of ONE top-rank step: with the default boosts the three
|
|
21
|
+
* bonuses together can never reach one rank position (0.2 + 0.25 + 0.3 = 0.75). A provider that grades its own results already
|
|
22
|
+
* orders them, so the signal mostly arbitrates between providers; it never lifts a rank-10 result over a rank-1 one.
|
|
23
|
+
*
|
|
24
|
+
* Source confidence (confidence.ts) scales each provider's RRF term by `factor(c)` in [0.8, 1] and the bonus of a URL by the best factor
|
|
25
|
+
* among the providers that returned it; a provider without a confidence, which is every built-in source, has factor exactly 1 and the
|
|
26
|
+
* scores are what they were without it.
|
|
16
27
|
* @module web-search-pro/pipeline/fusion
|
|
17
28
|
*/
|
|
18
29
|
import type { Candidate } from './types.ts';
|
|
19
30
|
export declare const AUTHORITY_DOMAINS_BUILTIN: readonly string[];
|
|
31
|
+
/** Default weight of the provider's own quality signal (fraction of one top-rank step); see the module comment. */
|
|
32
|
+
export declare const PROVIDER_SIGNAL_BOOST = 0.3;
|
|
33
|
+
/** Share of the provider signal that comes from `rerank_score` (the rest is `authority`, when the URL has one). */
|
|
34
|
+
export declare const RERANK_SIGNAL_WEIGHT = 0.7;
|
|
20
35
|
export interface FusionOptions {
|
|
21
36
|
/** RRF smoothing constant (config rrfConstant). */
|
|
22
37
|
k: number;
|
|
@@ -26,6 +41,8 @@ export interface FusionOptions {
|
|
|
26
41
|
freshnessDays: number;
|
|
27
42
|
/** Fraction of one top-rank step for an authority host (0..1). */
|
|
28
43
|
authorityBoost: number;
|
|
44
|
+
/** Fraction of one top-rank step for a result the provider itself graded best (0..1; default {@link PROVIDER_SIGNAL_BOOST}); 0 turns the signal off. */
|
|
45
|
+
signalBoost?: number;
|
|
29
46
|
/** Extra authority domains; the built-in list and .edu/.gov/.org always apply. */
|
|
30
47
|
authorityDomains: readonly string[];
|
|
31
48
|
/** Providers that took part (answered, even with few results). Defaults to the distinct providers in the candidates. */
|
|
@@ -42,6 +59,11 @@ export interface RankedCandidate {
|
|
|
42
59
|
normalized: number;
|
|
43
60
|
bonus: number;
|
|
44
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* The provider's own quality grade of a candidate in 0..1: `rerank_score` / 3 weighted 0.7 and `authority` / 4 weighted 0.3; with
|
|
64
|
+
* only one of them present that one alone; 0 when the candidate has none. Out-of-range values are clamped.
|
|
65
|
+
*/
|
|
66
|
+
export declare function providerSignal(candidate: Pick<Candidate, 'signals'>): number;
|
|
45
67
|
/** Best (lowest) rank per provider: one RRF term per provider per URL. */
|
|
46
68
|
export declare function bestRanks(candidate: Pick<Candidate, 'contributions'>): Map<string, number>;
|
|
47
69
|
export declare function isAuthorityHost(host: string, extraDomains?: readonly string[]): boolean;
|
|
@@ -10,8 +10,24 @@ export interface RenderSource {
|
|
|
10
10
|
title?: string;
|
|
11
11
|
snippet?: string;
|
|
12
12
|
publishedAt?: string;
|
|
13
|
+
rerankScore?: number;
|
|
14
|
+
authority?: number;
|
|
13
15
|
lowConfidence?: boolean;
|
|
16
|
+
via?: string;
|
|
17
|
+
confidence?: number;
|
|
18
|
+
tag?: string;
|
|
14
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* `[rerank 2.4/3, authority 3/4]`: the provider's own grades of a source (DeepSeek Search); for a custom CLI or a source the user gave a
|
|
22
|
+
* confidence below 1 also `via custom-cli:echo, confidence 0.5` and the honest label (user-defined, not verified). Empty when there is none of it.
|
|
23
|
+
*/
|
|
24
|
+
export declare function qualityTag(s: {
|
|
25
|
+
rerankScore?: number;
|
|
26
|
+
authority?: number;
|
|
27
|
+
via?: string;
|
|
28
|
+
confidence?: number;
|
|
29
|
+
tag?: string;
|
|
30
|
+
}): string;
|
|
15
31
|
/** Marker for a source / excerpt whose page only passed the S4 floor, not the relevance gate (dev-plan §3.1). */
|
|
16
32
|
export declare const LOW_RELEVANCE = " (low relevance)";
|
|
17
33
|
/** One line under the header (dev-plan M3b): "covered" is a lexical judgement, and a missing passage proves nothing. */
|
|
@@ -43,7 +43,9 @@ export interface ProviderCall {
|
|
|
43
43
|
}
|
|
44
44
|
export type ProviderOutcome = {
|
|
45
45
|
state: 'ok';
|
|
46
|
-
sources: readonly ProviderSource[];
|
|
46
|
+
sources: readonly ProviderSource[]; /** The backend of a platform chain that answered. */
|
|
47
|
+
backend?: string; /** The engine's own remarks (a query it had to cut, results it dropped); they reach the pack notes. */
|
|
48
|
+
notes?: readonly string[];
|
|
47
49
|
}
|
|
48
50
|
/** `detail` carries the provider's own explanation of an empty answer (e.g. a login hint), when it gave one. */
|
|
49
51
|
| {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Validation of the user's source preferences (`sources.priority`, `sources.disabled`, `sources.budget`), with no Node
|
|
2
|
+
* Validation of the user's source preferences (`sources.priority`, `sources.disabled`, `sources.budget`, `sources.confidence`), with no Node
|
|
3
3
|
* imports so the settings panel validates them with the code the server uses; the request counters live in ./ledger.ts.
|
|
4
4
|
* @module web-search-pro/pipeline/sources-spec
|
|
5
5
|
*/
|
|
@@ -13,11 +13,14 @@ export interface SourcesInput {
|
|
|
13
13
|
priority?: readonly string[];
|
|
14
14
|
disabled?: readonly string[];
|
|
15
15
|
budget?: Record<string, SourceBudgetInput>;
|
|
16
|
+
/** Confidence (0..1) per source or platform-backend id; absent = 1 for a built-in source, the spec's own for a custom CLI. */
|
|
17
|
+
confidence?: Record<string, number>;
|
|
16
18
|
}
|
|
17
19
|
export interface SourcesResolved {
|
|
18
20
|
priority: string[];
|
|
19
21
|
disabled: string[];
|
|
20
22
|
budget: Record<string, SourceBudgetInput>;
|
|
23
|
+
confidence: Record<string, number>;
|
|
21
24
|
/** Entries ignored, each saying why (surfaced by `sources.status` and the settings card). */
|
|
22
25
|
diagnostics: string[];
|
|
23
26
|
}
|
|
@@ -25,4 +28,4 @@ export interface SourcesResolved {
|
|
|
25
28
|
* Validate the preferences; invalid entries are dropped and reported, never thrown. `known` (optional) tells whether an
|
|
26
29
|
* id is a registered provider: unknown ids are reported and dropped, so a typo cannot silently disable nothing.
|
|
27
30
|
*/
|
|
28
|
-
export declare function resolveSources(input: SourcesInput | undefined, known?: (id: string) => boolean): SourcesResolved;
|
|
31
|
+
export declare function resolveSources(input: SourcesInput | undefined, known?: (id: string) => boolean, knownBackend?: (id: string) => boolean): SourcesResolved;
|
|
@@ -43,12 +43,27 @@ export interface TaskSpec {
|
|
|
43
43
|
constraints: Constraint[];
|
|
44
44
|
budget: BudgetProfile;
|
|
45
45
|
}
|
|
46
|
+
export interface CandidateSignals {
|
|
47
|
+
/** Provider relevance / authority / freshness rank score, 0..3. */
|
|
48
|
+
rerankScore?: number;
|
|
49
|
+
/** Provider source-authority grade, 0..4. */
|
|
50
|
+
authority?: number;
|
|
51
|
+
}
|
|
46
52
|
/** One provider hit for a candidate. `rank` is 1-based within that provider's result list. */
|
|
47
53
|
export interface Contribution {
|
|
48
54
|
providerId: string;
|
|
49
55
|
rank: number;
|
|
50
56
|
/** The exact query sent to the provider (may be a compiled variant). */
|
|
51
57
|
query: string;
|
|
58
|
+
/** The source's confidence (0..1), present only when it is below 1: a custom CLI, or a source the user set `sources.confidence` for. */
|
|
59
|
+
confidence?: number;
|
|
60
|
+
}
|
|
61
|
+
/** Where a result of a user-defined source came from: shown with the result and never merged away. */
|
|
62
|
+
export interface CandidateOrigin {
|
|
63
|
+
/** Ids of the custom CLIs that returned the URL (`custom-cli:echo`). */
|
|
64
|
+
via: string[];
|
|
65
|
+
/** The honest label of these sources: user-defined, not verified by the plugin. */
|
|
66
|
+
tag: string;
|
|
52
67
|
}
|
|
53
68
|
export type Satisfied = 'yes' | 'no' | 'unknown';
|
|
54
69
|
export interface ConstraintCheck {
|
|
@@ -81,8 +96,15 @@ export interface Candidate {
|
|
|
81
96
|
title: string;
|
|
82
97
|
snippet: string;
|
|
83
98
|
publishedAt?: string;
|
|
99
|
+
/**
|
|
100
|
+
* The providers' own quality signals for this URL (best seen over all providers that gave one): DeepSeek Search's `rerank_score`
|
|
101
|
+
* (0..3) and `authority` (0..4). Source metadata, and one small fusion signal (fusion.ts); absent for providers that give none.
|
|
102
|
+
*/
|
|
103
|
+
signals?: CandidateSignals;
|
|
84
104
|
/** Every (provider, rank, query) that returned this URL. */
|
|
85
105
|
contributions: Contribution[];
|
|
106
|
+
/** Set when a user-defined CLI returned the URL. */
|
|
107
|
+
origin?: CandidateOrigin;
|
|
86
108
|
checks?: ConstraintCheck[];
|
|
87
109
|
gate?: GateVerdict;
|
|
88
110
|
}
|
|
@@ -110,6 +132,12 @@ export interface PageBlock {
|
|
|
110
132
|
providers: string[];
|
|
111
133
|
/** The candidate only passed the S4 floor, not the relevance gate. */
|
|
112
134
|
lowConfidence?: true;
|
|
135
|
+
/** Custom CLI that returned the page's URL, the label it carries, and the best confidence among the sources that returned it (below 1 only). */
|
|
136
|
+
origin?: {
|
|
137
|
+
via?: string;
|
|
138
|
+
tag?: string;
|
|
139
|
+
confidence?: number;
|
|
140
|
+
};
|
|
113
141
|
block: Block;
|
|
114
142
|
}
|
|
115
143
|
/** `grade` is 0..3 (rule: integer buckets; Jev: the level expectation). `rank` is a finer tie-breaker. */
|
|
@@ -138,6 +166,10 @@ export interface EvidenceItem {
|
|
|
138
166
|
source: string;
|
|
139
167
|
/** The page's candidate failed the relevance gate and was kept only by the floor. */
|
|
140
168
|
lowConfidence?: true;
|
|
169
|
+
/** The custom CLI(s) that returned the page, the best confidence among its sources (below 1 only) and the honest label. */
|
|
170
|
+
via?: string;
|
|
171
|
+
confidence?: number;
|
|
172
|
+
tag?: string;
|
|
141
173
|
}
|
|
142
174
|
export type GapReason = 'no_candidates' | 'no_page_content' | 'weak_support' | 'budget';
|
|
143
175
|
export interface Gap {
|
|
@@ -230,7 +262,12 @@ export interface EvidencePack {
|
|
|
230
262
|
title?: string;
|
|
231
263
|
snippet?: string;
|
|
232
264
|
publishedAt?: string;
|
|
265
|
+
rerankScore?: number;
|
|
266
|
+
authority?: number;
|
|
233
267
|
lowConfidence?: true;
|
|
268
|
+
via?: string;
|
|
269
|
+
confidence?: number;
|
|
270
|
+
tag?: string;
|
|
234
271
|
}[];
|
|
235
272
|
engine: string;
|
|
236
273
|
enginesTried: string[];
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepSeek Search and Fetch API (https://api-docs.deepseek.com/guides/search/, online since 2026-10-17): the "常用" (common) source of
|
|
3
|
+
* this plugin. Contract: `POST {base}/search` and `POST {base}/fetch`, `Authorization: Bearer <DeepSeek API key>`, JSON; the base is
|
|
4
|
+
* `https://api.deepseek.com/v1/tools`.
|
|
5
|
+
*
|
|
6
|
+
* - Search request: `query` (1-128 characters, with the operators `site:` `-site:` `-term` `"phrase"` `lang:` `after:` `before:`),
|
|
7
|
+
* `count` (1-50, default 10), `ori_question` (optional, the caller's original question, at most 128), `localization` (not sent),
|
|
8
|
+
* `need_content` (default false: `content` stays empty, we never ask for it). Response: `results[]` of `rerank_score` (0-3),
|
|
9
|
+
* `title`, `url`, `snippet` (about 100-200 characters, for display), `summary` (about 600-800 characters, written for a model),
|
|
10
|
+
* `content`, `site_name`, `site_icon`, `date` (RFC 3339 or null), `authority` (0-4, -1 unknown). An empty array is "no results".
|
|
11
|
+
* - Fetch request `url` (at most 8192 characters, http/https, no credentials); response `title` and `content` (Markdown).
|
|
12
|
+
* - Errors are OpenAI-shaped `{ error: { message, type, param, code } }`: 400, 401, 402 (balance), 403 (Fetch refused by the security
|
|
13
|
+
* policy), 404 (Fetch could not get usable content), 408, 413, 429, 500, 504. Both APIs are read-only: 408 / 429 / 5xx are retried
|
|
14
|
+
* after a wait, every other 4xx is not.
|
|
15
|
+
* - Billing: $0.75 per 1,000 SUCCESSFUL requests, for each endpoint. Only a 200 that yields a result is billed (empty results, failures
|
|
16
|
+
* and timeouts are not), and `count` does not change the price. Calls made through DeepSeek Harness / Claude Code / Codex server-side
|
|
17
|
+
* tools are free until 2026-11-01 00:00 Beijing time; the docs do not say whether a plugin calling the API directly is inside that
|
|
18
|
+
* window, so this plugin treats every call as billed. Limits per account: Search 100 QPS, Fetch 25 QPS plus a per-domain limit.
|
|
19
|
+
*
|
|
20
|
+
* Field mapping: `summary` (else `snippet`) -> `snippet` (the long excerpt the evidence pipeline gates and scores on), `date` ->
|
|
21
|
+
* `publishedAt`, `rerank_score` -> `rerankScore`, `authority` -> `authority` (source metadata; one small fusion signal, fusion.ts).
|
|
22
|
+
* The host's own `deepseek-search-api` provider maps only snippet and date.
|
|
23
|
+
* @module web-search-pro/providers/deepseek
|
|
24
|
+
*/
|
|
25
|
+
import { EngineError, type Engine, type EngineDeps, type EngineSource } from '../engines.ts';
|
|
26
|
+
import { type ProviderResponse } from './http.ts';
|
|
27
|
+
import type { ProviderAdapter, ProviderDescriptor } from './registry.ts';
|
|
28
|
+
export declare const DEEPSEEK_ROUTE_ID = "deepseek";
|
|
29
|
+
export declare const DEEPSEEK_LABEL = "DeepSeek Search";
|
|
30
|
+
export declare const DEEPSEEK_DEFAULT_BASE = "https://api.deepseek.com/v1/tools";
|
|
31
|
+
export declare const DEEPSEEK_SEARCH_PATH = "/search";
|
|
32
|
+
export declare const DEEPSEEK_FETCH_PATH = "/fetch";
|
|
33
|
+
export declare const DEEPSEEK_KEY_ENV = "DEEPSEEK_API_KEY";
|
|
34
|
+
/** Longest `query` / `ori_question` the API takes, in characters. */
|
|
35
|
+
export declare const DEEPSEEK_QUERY_CHARS = 128;
|
|
36
|
+
export declare const DEEPSEEK_MAX_COUNT = 50;
|
|
37
|
+
export declare const DEEPSEEK_DEFAULT_COUNT = 10;
|
|
38
|
+
/** The long excerpt kept per result (the API's `summary` is about 600-800 characters). */
|
|
39
|
+
export declare const DEEPSEEK_SNIPPET_CHARS = 1000;
|
|
40
|
+
/** Longest URL the Fetch API takes. */
|
|
41
|
+
export declare const DEEPSEEK_FETCH_URL_CHARS = 8192;
|
|
42
|
+
/** Usage-ledger provider names: requests counted, tokens n/a, price unknown to the plugin. */
|
|
43
|
+
export declare const DEEPSEEK_USAGE_SEARCH = "deepseek-search";
|
|
44
|
+
export declare const DEEPSEEK_USAGE_FETCH = "deepseek-fetch";
|
|
45
|
+
/** One try plus at most two retries of a 408 / 429 / 5xx answer. */
|
|
46
|
+
export declare const DEEPSEEK_MAX_ATTEMPTS = 3;
|
|
47
|
+
export declare const DEEPSEEK_RETRY_BASE_MS = 800;
|
|
48
|
+
/** A wait longer than this (a `Retry-After` of a minute) is not slept through: the failure carries it as the cooldown instead. */
|
|
49
|
+
export declare const DEEPSEEK_RETRY_WAIT_CAP_MS = 8000;
|
|
50
|
+
export interface FittedQuery {
|
|
51
|
+
query: string;
|
|
52
|
+
cut: boolean;
|
|
53
|
+
from: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The query as the API takes it: whitespace collapsed, at most 128 characters. A longer query keeps every operator token (a
|
|
57
|
+
* `site:` restriction or an exclusion is what the caller asked for) and `OR` between site operators, and loses the tail of the free
|
|
58
|
+
* text, at a word boundary when it has words and by character when it does not (Chinese). The caller says so in the result notes.
|
|
59
|
+
*/
|
|
60
|
+
export declare function fitQuery(raw: string): FittedQuery;
|
|
61
|
+
/** `ori_question`: whitespace collapsed and cut to 128 characters; undefined when nothing remains or it adds nothing to the query. */
|
|
62
|
+
export declare function originalQuestion(raw: string | undefined, query: string): string | undefined;
|
|
63
|
+
export interface DeepSeekSearchBody {
|
|
64
|
+
query: string;
|
|
65
|
+
count: number;
|
|
66
|
+
need_content: false;
|
|
67
|
+
ori_question?: string;
|
|
68
|
+
}
|
|
69
|
+
export declare function deepseekSearchBody(query: string, count: number, question?: string): DeepSeekSearchBody;
|
|
70
|
+
/** Map `results[]`: summary (else snippet) as the excerpt, date -> publishedAt, rerank_score / authority as metadata. Rows without an http(s) URL are dropped. */
|
|
71
|
+
export declare function mapDeepSeekResults(results: readonly unknown[], count: number): EngineSource[];
|
|
72
|
+
/** Parse a 2xx Search body; an empty `results` array is ENGINE_EMPTY (the service works, nothing matched, and nothing was billed). */
|
|
73
|
+
export declare function parseDeepSeekSearch(json: unknown, count: number): EngineSource[];
|
|
74
|
+
/** Statuses the docs say to wait and retry: 408, 429 and 5xx. */
|
|
75
|
+
export declare const isRetryableStatus: (status: number) => boolean;
|
|
76
|
+
/**
|
|
77
|
+
* The error message of an OpenAI-shaped body, safe to show: the key (should it ever be echoed) and credential-looking values are
|
|
78
|
+
* redacted and the length is capped. The service's `request_id` (what DeepSeek support asks for) is returned apart, so a message can
|
|
79
|
+
* end with it instead of burying the cause.
|
|
80
|
+
*/
|
|
81
|
+
export declare function errorParts(json: unknown, key: string | undefined): {
|
|
82
|
+
text: string;
|
|
83
|
+
id?: string;
|
|
84
|
+
};
|
|
85
|
+
/** {@link errorParts} as one string: `message (request_id …)`. */
|
|
86
|
+
export declare function detailOf(json: unknown, key: string | undefined): string;
|
|
87
|
+
/**
|
|
88
|
+
* Status -> error contract for Search. 401 / 403 are `ENGINE_AUTH`; 402 is `ENGINE_QUOTA` with the balance wording (never retried,
|
|
89
|
+
* no cooldown: waiting does not refill a balance); 429 is `ENGINE_RATE_LIMIT` carrying `Retry-After`; 408 is a retryable
|
|
90
|
+
* `ENGINE_TIMEOUT`; 400 / 404 / 413 are bad requests (not retryable); 5xx is a retryable `ENGINE_ERROR`. Never contains the key.
|
|
91
|
+
*/
|
|
92
|
+
export declare function deepseekFailure(label: string, status: number, headers: Headers, json: unknown, key?: string): EngineError;
|
|
93
|
+
/** Abort-aware wait. */
|
|
94
|
+
export declare function defaultSleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
95
|
+
type Transport = Pick<EngineDeps, 'allowProxyFakeIp' | 'fetchImpl' | 'lookup' | 'sleep'>;
|
|
96
|
+
/** Wait before retry number `attempt` (1-based): the service's `Retry-After` when it gave one, else 0.8 s, 1.6 s. Undefined = not worth waiting (stop). */
|
|
97
|
+
export declare function retryWaitMs(res: Pick<ProviderResponse, 'headers'>, attempt: number): number | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* One POST with the documented retry policy: a 408 / 429 / 5xx answer is retried after a wait (at most {@link DEEPSEEK_MAX_ATTEMPTS}
|
|
100
|
+
* tries in all, never longer than {@link DEEPSEEK_RETRY_WAIT_CAP_MS} per wait); every other answer is returned at once. Retries are
|
|
101
|
+
* safe: both APIs are read-only and failed requests are not billed. Returns the final response (which may still be an error).
|
|
102
|
+
*/
|
|
103
|
+
export declare function postWithRetry(label: string, url: string, key: string, body: unknown, transport: Transport, signal: AbortSignal | undefined): Promise<ProviderResponse>;
|
|
104
|
+
export declare function deepseekEngine(deps: EngineDeps): Engine;
|
|
105
|
+
/** A Fetch API failure. `code` names what DeepSeek did; none of them describes the TARGET page's own HTTP status. */
|
|
106
|
+
export declare class DeepSeekFetchError extends Error {
|
|
107
|
+
readonly code: 'DEEPSEEK_FETCH_DENIED' | 'DEEPSEEK_FETCH_NO_CONTENT' | 'DEEPSEEK_FETCH_AUTH' | 'DEEPSEEK_FETCH_QUOTA' | 'DEEPSEEK_FETCH_RATE_LIMIT' | 'DEEPSEEK_FETCH_ERROR';
|
|
108
|
+
readonly retryable: boolean;
|
|
109
|
+
constructor(message: string, code: 'DEEPSEEK_FETCH_DENIED' | 'DEEPSEEK_FETCH_NO_CONTENT' | 'DEEPSEEK_FETCH_AUTH' | 'DEEPSEEK_FETCH_QUOTA' | 'DEEPSEEK_FETCH_RATE_LIMIT' | 'DEEPSEEK_FETCH_ERROR', retryable?: boolean);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Status -> error for Fetch. 403 and 404 are DeepSeek's own verdicts (security policy; no usable content), and the message opens by
|
|
113
|
+
* saying so: it is not the target page's HTTP status. The request id comes last.
|
|
114
|
+
*/
|
|
115
|
+
export declare function deepseekFetchFailure(status: number, headers: Headers, json: unknown, key?: string): DeepSeekFetchError;
|
|
116
|
+
export interface DeepSeekFetchAccess extends Transport {
|
|
117
|
+
apiKey: string;
|
|
118
|
+
/** Endpoint base, default {@link DEEPSEEK_DEFAULT_BASE}. */
|
|
119
|
+
baseUrl?: string;
|
|
120
|
+
usage?: EngineDeps['usage'];
|
|
121
|
+
}
|
|
122
|
+
export interface DeepSeekPage {
|
|
123
|
+
title?: string;
|
|
124
|
+
text: string;
|
|
125
|
+
}
|
|
126
|
+
/** Read one page as Markdown through the Fetch API. Throws {@link DeepSeekFetchError} (or an EngineError for transport problems). */
|
|
127
|
+
export declare function deepseekFetchPage(url: string, access: DeepSeekFetchAccess, signal?: AbortSignal): Promise<DeepSeekPage>;
|
|
128
|
+
export declare const DEEPSEEK_DESCRIPTOR: ProviderDescriptor;
|
|
129
|
+
export declare const deepseekAdapter: ProviderAdapter;
|
|
130
|
+
export {};
|
|
@@ -27,7 +27,8 @@ export interface ProviderResponse {
|
|
|
27
27
|
text: string;
|
|
28
28
|
}
|
|
29
29
|
export interface ProviderRequest {
|
|
30
|
-
|
|
30
|
+
/** Only the transport settings are read (SSRF-safe HTTP path and the test seams). */
|
|
31
|
+
deps: Pick<EngineDeps, 'allowProxyFakeIp' | 'fetchImpl' | 'lookup'>;
|
|
31
32
|
signal?: AbortSignal | undefined;
|
|
32
33
|
headers?: Record<string, string>;
|
|
33
34
|
method?: 'GET' | 'POST';
|
|
@@ -6,3 +6,8 @@
|
|
|
6
6
|
/** Default environment variable names of each keyed source's API key, first one preferred (route id -> names). */
|
|
7
7
|
export declare const KEYED_SOURCE_ENVS: Readonly<Record<string, readonly string[]>>;
|
|
8
8
|
export declare const KEYED_SOURCE_IDS: readonly string[];
|
|
9
|
+
/**
|
|
10
|
+
* The "常用" (common) sources: a test pins this list to the registry descriptors that set `common: true`. Data only, for the
|
|
11
|
+
* settings panel (client bundle), which cannot import the descriptors.
|
|
12
|
+
*/
|
|
13
|
+
export declare const COMMON_SOURCE_IDS: readonly string[];
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Platform search backends as registry providers (dev-plan M8b): one provider per site or community, with the same
|
|
3
3
|
* descriptor + adapter shape as the web engines, so a platform is planned, probed, cooled down, singleflighted,
|
|
4
|
-
* persisted and reported exactly like any other source. A platform with several backends (twitter:
|
|
5
|
-
*
|
|
4
|
+
* persisted and reported exactly like any other source. A platform with several backends (twitter: twitter-cli, standalone
|
|
5
|
+
* OpenCLI, dsh-browser OpenCLI) is ONE provider with an internal ordered chain, resolved by src/cli/chain.ts (dev-plan M12). User `customPlatforms` become providers too
|
|
6
6
|
* ({@link customPlatformAdapter}); the router registers and unregisters them as the settings change.
|
|
7
7
|
* The legacy platform ids that already were web providers (github, bilibili, v2ex, youtube, arxiv, pubmed) are
|
|
8
8
|
* declared in builtin.ts and carry `kind: 'platform'` as well.
|
|
@@ -10,9 +10,15 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { type Engine } from '../engines.ts';
|
|
12
12
|
import type { CustomPlatformSpec } from '../config.ts';
|
|
13
|
-
import type
|
|
13
|
+
import { type CliAdapterSpec } from '../cli/spec.ts';
|
|
14
|
+
import type { ProviderAdapter, ProviderDescriptor } from './registry.ts';
|
|
14
15
|
/** Chain `engines` into one provider: the first available leg that answers wins; empty and failing legs fall through in order. */
|
|
15
16
|
export declare function chainEngine(id: string, label: string, chain: readonly Engine[]): Engine;
|
|
17
|
+
/**
|
|
18
|
+
* A platform provider whose backends are an ordered chain (`resolveChain`): the engine is the chain, the local probe is the
|
|
19
|
+
* readiness of every leg (cached contract probes, no search, no login), and `chain` reports each leg for `sources.status`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function chainProvider(platformId: string, d: ProviderDescriptor): ProviderAdapter;
|
|
16
22
|
export declare const platformAdapters: readonly ProviderAdapter[];
|
|
17
23
|
/** Registry id of a custom platform: its key when that is a valid id, else a stable hash of it (the key stays the route alias). */
|
|
18
24
|
export declare function customProviderId(key: string): string;
|
|
@@ -23,3 +29,9 @@ export declare function customKeyProblem(key: string): string | undefined;
|
|
|
23
29
|
* reaches the next call even before the router re-registers the provider.
|
|
24
30
|
*/
|
|
25
31
|
export declare function customPlatformAdapter(key: string, spec: CustomPlatformSpec): ProviderAdapter;
|
|
32
|
+
/** Registry id and route id of a user-defined CLI adapter: `custom-cli:<id>` (also its backend id in `platformBackends`). */
|
|
33
|
+
export declare const customCliProviderId: (id: string) => string;
|
|
34
|
+
/** A user-defined CLI adapter as a platform provider whose chain is the adapter itself (an edit of `platformBackends` can still reorder it). */
|
|
35
|
+
export declare function customCliAdapter(id: string, spec: CliAdapterSpec): ProviderAdapter;
|
|
36
|
+
/** A user spec as validated for registration: the problem text, or undefined when it can be registered. */
|
|
37
|
+
export declare function customCliProblem(id: string, raw: unknown): string | undefined;
|