@deepthonk/providers 0.1.0 → 0.1.2
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 +13 -7
- package/dist/defaults.d.ts +2 -0
- package/dist/defaults.js +3 -0
- package/dist/defaults.js.map +1 -1
- package/dist/env.d.ts +3 -0
- package/dist/env.js +36 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/jsonExtract.d.ts +3 -0
- package/dist/jsonExtract.js +35 -0
- package/dist/jsonExtract.js.map +1 -0
- package/dist/profileRegistry.d.ts +34 -0
- package/dist/profileRegistry.js +139 -0
- package/dist/profileRegistry.js.map +1 -0
- package/dist/registry.js +15 -1
- package/dist/registry.js.map +1 -1
- package/dist/sampling.d.ts +25 -0
- package/dist/sampling.js +159 -0
- package/dist/sampling.js.map +1 -0
- package/dist/types.d.ts +8 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ DeepThonk implements the OpenDeepThink algorithm (Zhou et al., 2026, [arXiv:2605
|
|
|
6
6
|
|
|
7
7
|
DeepThonk runs a population of candidate answers through pairwise judging, Bradley-Terry ranking, critique-guided mutation, elite preservation, and a final dense ranking pass. The CLI and MCP server both call the same TypeScript core engine.
|
|
8
8
|
|
|
9
|
-
**Designed for agents.** Every algorithm dimension — population shape (`n`, `k`, `t`, `m`), regularization (`lambda`), per-phase temperatures, prompt style, and per-phase prompt templates — is reachable inline through MCP arguments and CLI flags.
|
|
9
|
+
**Designed for agents.** Every algorithm dimension — population shape (`n`, `k`, `t`, `m`), regularization (`lambda`), per-phase temperatures, prompt style, and per-phase prompt templates — is reachable inline through MCP arguments and CLI flags. CLI can load prompt files with `--prompts` or inline JSON with `--prompts-json`; MCP accepts inline structured prompt args. Every intermediate artifact (config, candidates, populations, comparisons, scores, per-call usage, status) is exposed as an MCP resource so an agent can inspect any step. See [Customization](https://github.com/linxule/deepthonk/blob/main/docs/customization.md) for the full agent-composable surface.
|
|
10
10
|
|
|
11
11
|
Use it for hard, verifiable reasoning, coding, planning, and synthesis where breadth plus judgment can beat one expensive single shot. Avoid it for highly subjective tasks where judge noise dominates.
|
|
12
12
|
|
|
@@ -111,6 +111,8 @@ The MCP server exposes the same engine the CLI runs. Once wired into an MCP host
|
|
|
111
111
|
|
|
112
112
|
Provider API keys come from the host process's environment, not from DeepThonk's config alone. Each host handles env passthrough slightly differently — see the concrete patterns below.
|
|
113
113
|
|
|
114
|
+
MCP Sampling is supported as `provider: "sampling"` when the connected host advertises the MCP sampling capability. Sampling is not available from standalone CLI runs; use `deepseek`, `openrouter`, or `openai-compatible` there.
|
|
115
|
+
|
|
114
116
|
### Claude Code
|
|
115
117
|
|
|
116
118
|
```bash
|
|
@@ -198,7 +200,9 @@ All tools accept inline provider/model fields, or `config_path` pointing at a De
|
|
|
198
200
|
|
|
199
201
|
- `deepthonk://runs` — JSON index of all runs in `runs/`.
|
|
200
202
|
- `deepthonk://runs/{run_id}/summary` — run summary (JSON).
|
|
201
|
-
- `deepthonk://runs/{run_id}/
|
|
203
|
+
- `deepthonk://runs/{run_id}/config` — redacted run config (JSON).
|
|
204
|
+
- `deepthonk://runs/{run_id}/{candidates|comparisons|scores|usage|trace}` — per-phase and per-call NDJSON.
|
|
205
|
+
- `deepthonk://runs/{run_id}/population/{generation}` — population snapshot for a generation (JSON).
|
|
202
206
|
- `deepthonk://runs/{run_id}/{winner|final}` — text artifacts.
|
|
203
207
|
- `deepthonk://runs/{run_id}/status` — run state (JSON).
|
|
204
208
|
- `deepthonk://jobs/{job_id}/{status|result}?run_dir=...` — job-scoped lookup; the `run_dir` query param is required.
|
|
@@ -209,7 +213,7 @@ Four templates mirror the core loop: `deepthonk/generate`, `deepthonk/compare`,
|
|
|
209
213
|
|
|
210
214
|
### Limits
|
|
211
215
|
|
|
212
|
-
|
|
216
|
+
`deepthonk.resume` reports trace state and safe phase boundaries but does not replay interrupted runs. The HTTP transport is loopback-only by design. MCP Sampling depends on the host's sampling implementation; model hints are preferences, token usage may be unavailable, and sampling concurrency is capped at 4.
|
|
213
217
|
|
|
214
218
|
## Customization
|
|
215
219
|
|
|
@@ -218,7 +222,7 @@ Every algorithm dimension is reachable through MCP arguments and CLI flags:
|
|
|
218
222
|
- **Population shape**: `n`, `k`, `t`, `m` — override profile defaults inline.
|
|
219
223
|
- **Algorithm constants**: `lambda`, `sample_temperature`, `mutate_temperature`, `judge_temperature`.
|
|
220
224
|
- **Prompt style**: `general` or `paper-programming`.
|
|
221
|
-
- **Per-phase prompt templates**: override `generate`, `compare`, `mutate`, or `finalize` with custom system/user templates and variable substitution (`{task}`, `{rubric}`, `{candidate}`, `{candidateA}`, `{candidateB}`, `{critique}`). Unknown variables throw a fail-fast error at run-start.
|
|
225
|
+
- **Per-phase prompt templates**: override `generate`, `compare`, `mutate`, or `finalize` with custom system/user templates and variable substitution (`{task}`, `{rubric}`, `{candidate}`, `{candidateA}`, `{candidateB}`, `{critique}`). CLI supports `--prompts <yaml>` and `--prompts-json <json>`; MCP supports inline `prompts`. Unknown variables throw a fail-fast error at run-start.
|
|
222
226
|
- **Concurrency**: per-phase caps for `generate`, `judge`, `mutate`.
|
|
223
227
|
|
|
224
228
|
Example agent call (MCP), no YAML file required:
|
|
@@ -237,9 +241,11 @@ Example agent call (MCP), no YAML file required:
|
|
|
237
241
|
}
|
|
238
242
|
```
|
|
239
243
|
|
|
240
|
-
CLI accepts the same surface
|
|
244
|
+
CLI accepts the same surface. Use `--prompts <yaml>` for reusable prompt files or `--prompts-json <json>` for one-off inline overrides. MCP and CLI both merge over any `--config`/`config_path` YAML defaults.
|
|
245
|
+
|
|
246
|
+
Save reusable bundles as **named profiles** at `~/.config/deepthonk/profiles/<name>.yaml` and load them with `--profile-name <name>` (CLI) or `profile_name: "<name>"` (MCP). A named profile is a standalone bundle that replaces the main config file for that run; CLI flags and MCP inline arguments still override fields inside it. See `examples/profiles/legal-drafting.yaml` for the shape. The [Customization guide](https://github.com/linxule/deepthonk/blob/main/docs/customization.md#managing-named-profiles) covers listing, showing, saving, and deleting named profiles from both CLI and MCP.
|
|
241
247
|
|
|
242
|
-
See the [Customization guide](https://github.com/linxule/deepthonk/blob/main/docs/customization.md) for the complete variable contract, the compare-phase JSON safety rule, and three worked examples. Per-role provider routing (`providers.judge.provider = openrouter`) and per-model pricing remain YAML-only — they're nested structured config, not inline ergonomics.
|
|
248
|
+
See the [Customization guide](https://github.com/linxule/deepthonk/blob/main/docs/customization.md) for the complete variable contract, the compare-phase JSON safety rule, the named-profile schema, and three worked examples. Per-role provider routing (`providers.judge.provider = openrouter`) and per-model pricing remain YAML-only — they're nested structured config, not inline ergonomics.
|
|
243
249
|
|
|
244
250
|
## Trace Files
|
|
245
251
|
|
|
@@ -280,7 +286,7 @@ This repository is source-only. Generated run traces, paper notes, build output,
|
|
|
280
286
|
Known limits for this release:
|
|
281
287
|
|
|
282
288
|
- Conservative resume reports trace state and safe phase boundaries, but does not replay interrupted runs yet.
|
|
283
|
-
- MCP Sampling is
|
|
289
|
+
- MCP Sampling is MCP-host-only. Standalone CLI runs need a direct provider.
|
|
284
290
|
- `maxUsd` requires known model pricing; add explicit prices in YAML for custom providers and model IDs. Optional fields `longContextThresholdTokens`, `inputUsdPerMillionLong`, and `outputUsdPerMillionLong` enable tiered pricing for models with a long-context surcharge (e.g., Gemini at 200K input tokens). Cache hit/miss rates remain flat.
|
|
285
291
|
|
|
286
292
|
## Acknowledgments
|
package/dist/defaults.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SamplingTransport } from "./sampling.js";
|
|
1
2
|
import type { ProviderConfig, ProviderRole, RoleProviderConfig } from "./types.js";
|
|
2
3
|
export type DirectProviderName = "fake" | "openai-compatible" | "deepseek" | "openrouter";
|
|
3
4
|
export interface ProviderModelOverrides {
|
|
@@ -14,6 +15,7 @@ export interface ProviderConfigOptions {
|
|
|
14
15
|
models?: ProviderModelOverrides;
|
|
15
16
|
retry?: ProviderConfig["retry"];
|
|
16
17
|
supportsJsonMode?: boolean;
|
|
18
|
+
samplingTransport?: SamplingTransport;
|
|
17
19
|
roleProviders?: Partial<Record<ProviderRole, Partial<Omit<RoleProviderConfig, "model">> & {
|
|
18
20
|
model?: string;
|
|
19
21
|
}>>;
|
package/dist/defaults.js
CHANGED
|
@@ -16,6 +16,7 @@ export function resolveProviderConfig(options) {
|
|
|
16
16
|
models,
|
|
17
17
|
retry: options.retry,
|
|
18
18
|
supportsJsonMode: options.supportsJsonMode,
|
|
19
|
+
samplingTransport: options.samplingTransport,
|
|
19
20
|
roleProviders: resolveRoleProviders(options.provider, models, options.roleProviders, options.retry)
|
|
20
21
|
};
|
|
21
22
|
}
|
|
@@ -26,6 +27,8 @@ export function defaultModel(provider, role) {
|
|
|
26
27
|
return role === "judge" ? "deepseek-v4-pro" : "deepseek-v4-flash";
|
|
27
28
|
if (provider === "fake")
|
|
28
29
|
return "fake-model";
|
|
30
|
+
if (provider === "sampling")
|
|
31
|
+
return "sampling";
|
|
29
32
|
if (provider === "openrouter")
|
|
30
33
|
return "openrouter/auto";
|
|
31
34
|
return role === "judge" ? "provider/model-large" : "provider/model-small";
|
package/dist/defaults.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"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"}
|
package/dist/env.d.ts
ADDED
package/dist/env.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
export const defaultConfigPath = join(homedir(), ".config", "deepthonk", "config.yaml");
|
|
6
|
+
export const defaultEnvPath = join(dirname(defaultConfigPath), "env");
|
|
7
|
+
export async function loadDeepThonkEnv(path = process.env.DEEPTHONK_ENV ?? defaultEnvPath) {
|
|
8
|
+
if (!existsSync(path))
|
|
9
|
+
return;
|
|
10
|
+
const text = await readFile(path, "utf8");
|
|
11
|
+
for (const line of text.split("\n")) {
|
|
12
|
+
const parsed = parseEnvLine(line);
|
|
13
|
+
if (!parsed)
|
|
14
|
+
continue;
|
|
15
|
+
const [key, value] = parsed;
|
|
16
|
+
if (process.env[key] === undefined || process.env[key] === "")
|
|
17
|
+
process.env[key] = value;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function parseEnvLine(line) {
|
|
21
|
+
const trimmed = line.trim();
|
|
22
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
23
|
+
return undefined;
|
|
24
|
+
const match = trimmed.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
|
|
25
|
+
if (!match)
|
|
26
|
+
return undefined;
|
|
27
|
+
return [match[1], unquoteEnvValue(match[2].trim())];
|
|
28
|
+
}
|
|
29
|
+
function unquoteEnvValue(value) {
|
|
30
|
+
if ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith('"') && value.endsWith('"'))) {
|
|
31
|
+
const inner = value.slice(1, -1);
|
|
32
|
+
return value.startsWith("'") ? inner.replace(/'\\''/g, "'") : inner.replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;AACxF,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,CAAC;AAEtE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,cAAc;IACvF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO;IAC9B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM;YAAE,SAAS;QACtB,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,MAAM,CAAC;QAC5B,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC1F,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAC7E,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,eAAe,CAAC,KAAa;IACpC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QACrG,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACjC,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export * from "./fake.js";
|
|
2
2
|
export * from "./defaults.js";
|
|
3
|
+
export * from "./env.js";
|
|
4
|
+
export * from "./jsonExtract.js";
|
|
5
|
+
export * from "./profileRegistry.js";
|
|
3
6
|
export * from "./openaiCompatible.js";
|
|
4
7
|
export * from "./pricing.js";
|
|
5
8
|
export * from "./registry.js";
|
|
9
|
+
export * from "./sampling.js";
|
|
6
10
|
export * from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export * from "./fake.js";
|
|
2
2
|
export * from "./defaults.js";
|
|
3
|
+
export * from "./env.js";
|
|
4
|
+
export * from "./jsonExtract.js";
|
|
5
|
+
export * from "./profileRegistry.js";
|
|
3
6
|
export * from "./openaiCompatible.js";
|
|
4
7
|
export * from "./pricing.js";
|
|
5
8
|
export * from "./registry.js";
|
|
9
|
+
export * from "./sampling.js";
|
|
6
10
|
export * from "./types.js";
|
|
7
11
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { JsonParseError } from "@deepthonk/core";
|
|
2
|
+
export const MAX_EXTRACTION_BYTES = 131_072;
|
|
3
|
+
export function extractJsonObjectText(text) {
|
|
4
|
+
if (text.length > MAX_EXTRACTION_BYTES) {
|
|
5
|
+
throw new JsonParseError(`Response text exceeds ${MAX_EXTRACTION_BYTES}-byte JSON extraction cap; refusing to parse.`);
|
|
6
|
+
}
|
|
7
|
+
const trimmed = text.trim();
|
|
8
|
+
const candidates = [trimmed, extractFence(trimmed), extractBalancedObject(trimmed)].filter((candidate) => Boolean(candidate));
|
|
9
|
+
for (const candidate of candidates) {
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(candidate);
|
|
12
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
13
|
+
return candidate;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// Try the next extraction strategy.
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
throw new JsonParseError("Model output did not contain a valid JSON object.");
|
|
20
|
+
}
|
|
21
|
+
export function extractJsonObject(text) {
|
|
22
|
+
return JSON.parse(extractJsonObjectText(text));
|
|
23
|
+
}
|
|
24
|
+
function extractFence(text) {
|
|
25
|
+
const match = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
26
|
+
return match?.[1]?.trim();
|
|
27
|
+
}
|
|
28
|
+
function extractBalancedObject(text) {
|
|
29
|
+
const start = text.indexOf("{");
|
|
30
|
+
const end = text.lastIndexOf("}");
|
|
31
|
+
if (start === -1 || end === -1 || end <= start)
|
|
32
|
+
return undefined;
|
|
33
|
+
return text.slice(start, end + 1);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=jsonExtract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonExtract.js","sourceRoot":"","sources":["../src/jsonExtract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAE5C,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,IAAI,IAAI,CAAC,MAAM,GAAG,oBAAoB,EAAE,CAAC;QACvC,MAAM,IAAI,cAAc,CAAC,yBAAyB,oBAAoB,+CAA+C,CAAC,CAAC;IACzH,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CACxF,CAAC,SAAS,EAAuB,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CACvD,CAAC;IACF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACrC,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,OAAO,SAAS,CAAC;QACvF,CAAC;QAAC,MAAM,CAAC;YACP,oCAAoC;QACtC,CAAC;IACH,CAAC;IACD,MAAM,IAAI,cAAc,CAAC,mDAAmD,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC1D,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,KAAK,KAAK,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,IAAI,KAAK;QAAE,OAAO,SAAS,CAAC;IACjE,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare const NAMED_PROFILE_NAME_RE: RegExp;
|
|
2
|
+
export declare const RAW_API_KEY_RE: RegExp;
|
|
3
|
+
export declare const SECRET_KEY_RE: RegExp;
|
|
4
|
+
export interface NamedProfileBundle {
|
|
5
|
+
profile?: "quick" | "balanced" | "paper";
|
|
6
|
+
prompt_style?: "general" | "paper-programming";
|
|
7
|
+
provider?: string;
|
|
8
|
+
base_url?: string;
|
|
9
|
+
api_key_env?: string;
|
|
10
|
+
models?: {
|
|
11
|
+
generator?: string;
|
|
12
|
+
mutator?: string;
|
|
13
|
+
judge?: string;
|
|
14
|
+
finalizer?: string;
|
|
15
|
+
};
|
|
16
|
+
providers?: Record<string, unknown>;
|
|
17
|
+
algorithm?: Record<string, unknown>;
|
|
18
|
+
prompts?: Record<string, {
|
|
19
|
+
system?: string;
|
|
20
|
+
user?: string;
|
|
21
|
+
}>;
|
|
22
|
+
budget?: unknown;
|
|
23
|
+
concurrency?: unknown;
|
|
24
|
+
retry?: unknown;
|
|
25
|
+
output?: unknown;
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
export declare function profilesDir(): string;
|
|
29
|
+
export declare function profilePath(name: string): string;
|
|
30
|
+
export declare function listProfiles(): Promise<string[]>;
|
|
31
|
+
export declare function loadNamedProfile(name: string): Promise<NamedProfileBundle>;
|
|
32
|
+
export declare function validateNamedProfileBundle(bundle: NamedProfileBundle, name?: string): void;
|
|
33
|
+
export declare function rejectRawApiKeyFields(value: unknown, name?: string): void;
|
|
34
|
+
export declare function rejectAllSecretShapedFields(value: unknown, name?: string): void;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import YAML from "yaml";
|
|
5
|
+
import { ConfigError } from "@deepthonk/core";
|
|
6
|
+
import { defaultConfigPath } from "./env.js";
|
|
7
|
+
export const NAMED_PROFILE_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/;
|
|
8
|
+
export const RAW_API_KEY_RE = /^api[_-]?key$/i;
|
|
9
|
+
export const SECRET_KEY_RE = /^(api[_-]?key|token|secret|password|authorization|bearer|cookie|credential)$/i;
|
|
10
|
+
const SECRET_KEY_FIX = "Remove raw secret fields from the profile. Rejected key shapes: api_key/api-key, token, secret, password, authorization, bearer, cookie, credential. Use api_key_env to reference an environment variable name instead.";
|
|
11
|
+
export function profilesDir() {
|
|
12
|
+
return process.env.DEEPTHONK_PROFILES_DIR ?? join(dirname(defaultConfigPath), "profiles");
|
|
13
|
+
}
|
|
14
|
+
export function profilePath(name) {
|
|
15
|
+
return join(profilesDir(), `${name}.yaml`);
|
|
16
|
+
}
|
|
17
|
+
export async function listProfiles() {
|
|
18
|
+
const dir = profilesDir();
|
|
19
|
+
if (!existsSync(dir))
|
|
20
|
+
return [];
|
|
21
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
22
|
+
return entries
|
|
23
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".yaml"))
|
|
24
|
+
.map((entry) => entry.name.replace(/\.yaml$/, ""))
|
|
25
|
+
.sort();
|
|
26
|
+
}
|
|
27
|
+
export async function loadNamedProfile(name) {
|
|
28
|
+
validateProfileName(name);
|
|
29
|
+
const path = profilePath(name);
|
|
30
|
+
if (!existsSync(path)) {
|
|
31
|
+
const available = await listProfiles();
|
|
32
|
+
const availableHint = available.length ? `Available profiles: ${available.join(", ")}.` : `No saved profiles yet in ${profilesDir()}.`;
|
|
33
|
+
throw new ConfigError(`Named profile '${name}' not found at ${path}. ${availableHint}`, {
|
|
34
|
+
code: "config.profile_not_found",
|
|
35
|
+
retryable: false,
|
|
36
|
+
fix: `Create ${path} with at least { provider, prompt_style, models.{generator,mutator,judge} } and either profile or algorithm fields. See docs/customization.md for the schema.`
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
let parsed;
|
|
40
|
+
try {
|
|
41
|
+
parsed = YAML.parse(await readFile(path, "utf8"));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
throw new ConfigError(`Named profile '${name}' is not valid YAML: ${error.message}`, {
|
|
45
|
+
code: "config.profile_invalid_yaml",
|
|
46
|
+
retryable: false,
|
|
47
|
+
fix: `Fix YAML syntax in ${path}.`
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const config = validateNamedProfileValue(parsed, name);
|
|
51
|
+
return config;
|
|
52
|
+
}
|
|
53
|
+
export function validateNamedProfileBundle(bundle, name = "profile") {
|
|
54
|
+
validateNamedProfileValue(bundle, name);
|
|
55
|
+
}
|
|
56
|
+
function validateProfileName(name) {
|
|
57
|
+
if (!NAMED_PROFILE_NAME_RE.test(name)) {
|
|
58
|
+
throw new ConfigError(`Invalid profile name '${name}'. Names must start with a letter and contain only letters, digits, hyphens, and underscores (max 64 chars).`, {
|
|
59
|
+
code: "config.profile_invalid_name",
|
|
60
|
+
retryable: false,
|
|
61
|
+
fix: "Rename the profile to match /^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/."
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function validateRequiredFields(config, name) {
|
|
66
|
+
const missing = [];
|
|
67
|
+
if (!config.profile && !config.algorithm)
|
|
68
|
+
missing.push("profile (built-in name) or algorithm (block)");
|
|
69
|
+
if (!config.prompt_style)
|
|
70
|
+
missing.push("prompt_style");
|
|
71
|
+
if (!config.provider)
|
|
72
|
+
missing.push("provider");
|
|
73
|
+
if (!config.models?.generator)
|
|
74
|
+
missing.push("models.generator");
|
|
75
|
+
if (!config.models?.mutator)
|
|
76
|
+
missing.push("models.mutator");
|
|
77
|
+
if (!config.models?.judge)
|
|
78
|
+
missing.push("models.judge");
|
|
79
|
+
if (missing.length > 0) {
|
|
80
|
+
throw new ConfigError(`Named profile '${name}' is missing required fields: ${missing.join(", ")}.`, {
|
|
81
|
+
code: "config.profile_missing_fields",
|
|
82
|
+
retryable: false,
|
|
83
|
+
fix: "Standalone named profiles must declare the algorithm shape (profile or algorithm block), prompt_style, provider, and at least generator/mutator/judge models. See docs/customization.md."
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function validateNamedProfileValue(value, name) {
|
|
88
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
89
|
+
throw new ConfigError(`Named profile '${name}' must be a YAML mapping at the top level.`, {
|
|
90
|
+
code: "config.profile_invalid_shape",
|
|
91
|
+
retryable: false,
|
|
92
|
+
fix: `Top-level YAML should have keys like provider, prompt_style, models, algorithm.`
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const config = value;
|
|
96
|
+
rejectRawApiKeyFields(config, name);
|
|
97
|
+
validateRequiredFields(config, name);
|
|
98
|
+
return config;
|
|
99
|
+
}
|
|
100
|
+
export function rejectRawApiKeyFields(value, name = "profile") {
|
|
101
|
+
rejectMatchingProfileKeys(value, RAW_API_KEY_RE, "config.profile_raw_api_key", (key, path) => ({
|
|
102
|
+
message: `Named profile '${name}' must not contain a raw '${key}' value at ${path}.`,
|
|
103
|
+
fix: "Use api_key_env to reference an environment variable name instead. Raw secrets must not be written to profile files."
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
export function rejectAllSecretShapedFields(value, name = "profile") {
|
|
107
|
+
rejectMatchingProfileKeys(value, SECRET_KEY_RE, "config.profile_raw_secret", (key, path) => ({
|
|
108
|
+
message: `Named profile '${name}' must not contain a raw secret-shaped '${key}' value at ${path}.`,
|
|
109
|
+
fix: SECRET_KEY_FIX
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
function rejectMatchingProfileKeys(value, keyPattern, code, describe) {
|
|
113
|
+
const seen = new WeakSet();
|
|
114
|
+
const visit = (current, path) => {
|
|
115
|
+
if (!current || typeof current !== "object")
|
|
116
|
+
return;
|
|
117
|
+
if (seen.has(current))
|
|
118
|
+
return;
|
|
119
|
+
seen.add(current);
|
|
120
|
+
if (Array.isArray(current)) {
|
|
121
|
+
current.forEach((item, index) => visit(item, `${path}[${index}]`));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
for (const [key, inner] of Object.entries(current)) {
|
|
125
|
+
const childPath = path ? `${path}.${key}` : key;
|
|
126
|
+
if (keyPattern.test(key)) {
|
|
127
|
+
const description = describe(key, childPath);
|
|
128
|
+
throw new ConfigError(description.message, {
|
|
129
|
+
code,
|
|
130
|
+
retryable: false,
|
|
131
|
+
fix: description.fix
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
visit(inner, childPath);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
visit(value, "");
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=profileRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profileRegistry.js","sourceRoot":"","sources":["../src/profileRegistry.ts"],"names":[],"mappings":"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"}
|
package/dist/registry.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FakeDriver } from "./fake.js";
|
|
2
2
|
import { createDeepSeekDriver, OpenAiCompatibleDriver } from "./openaiCompatible.js";
|
|
3
|
-
import { ProviderError } from "@deepthonk/core";
|
|
3
|
+
import { ConfigError, ProviderError } from "@deepthonk/core";
|
|
4
|
+
import { SamplingDriver } from "./sampling.js";
|
|
4
5
|
export function createDriver(config) {
|
|
5
6
|
const baseDriver = createSingleDriver({ ...config, roleProviders: undefined });
|
|
6
7
|
if (config.roleProviders)
|
|
@@ -10,6 +11,19 @@ export function createDriver(config) {
|
|
|
10
11
|
function createSingleDriver(config) {
|
|
11
12
|
if (config.provider === "fake")
|
|
12
13
|
return new FakeDriver();
|
|
14
|
+
if (config.provider === "sampling") {
|
|
15
|
+
if (!config.samplingTransport) {
|
|
16
|
+
throw new ConfigError("MCP Sampling provider requires running as an MCP server. Use a direct provider mode (deepseek, openrouter, openai-compatible) for CLI runs.", {
|
|
17
|
+
code: "provider.sampling_requires_mcp",
|
|
18
|
+
retryable: false,
|
|
19
|
+
fix: "Run DeepThonk through an MCP host that advertises sampling, or choose a direct provider for CLI runs."
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return new SamplingDriver(config.samplingTransport, {
|
|
23
|
+
...config,
|
|
24
|
+
requestTimeoutMs: config.retry?.requestTimeoutMs ?? config.requestTimeoutMs
|
|
25
|
+
});
|
|
26
|
+
}
|
|
13
27
|
if (config.provider === "deepseek")
|
|
14
28
|
return createDeepSeekDriver(config);
|
|
15
29
|
if (config.provider === "openai-compatible")
|
package/dist/registry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type CompareInput, type FinalizeInput, type GenerateInput, type ModelDriver, type ModelTextResult, type MutateInput } from "@deepthonk/core";
|
|
2
|
+
import type { RequestOptions } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
3
|
+
import type { CreateMessageRequestParamsBase, CreateMessageResult, ModelPreferences } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
export interface SamplingDriverConfig {
|
|
5
|
+
modelHints?: string[];
|
|
6
|
+
costPriority?: number;
|
|
7
|
+
speedPriority?: number;
|
|
8
|
+
intelligencePriority?: number;
|
|
9
|
+
includeRawOutputs?: boolean;
|
|
10
|
+
requestTimeoutMs?: number;
|
|
11
|
+
}
|
|
12
|
+
export type SamplingTransport = (params: CreateMessageRequestParamsBase, options?: RequestOptions) => Promise<CreateMessageResult>;
|
|
13
|
+
export declare class SamplingDriver implements ModelDriver {
|
|
14
|
+
private readonly createMessage;
|
|
15
|
+
private readonly config;
|
|
16
|
+
readonly maxConcurrency = 4;
|
|
17
|
+
constructor(createMessage: SamplingTransport, config?: SamplingDriverConfig);
|
|
18
|
+
generate(input: GenerateInput): Promise<ModelTextResult>;
|
|
19
|
+
compare(input: CompareInput): Promise<ModelTextResult>;
|
|
20
|
+
mutate(input: MutateInput): Promise<ModelTextResult>;
|
|
21
|
+
finalize(input: FinalizeInput): Promise<ModelTextResult>;
|
|
22
|
+
private sample;
|
|
23
|
+
private callCreateMessage;
|
|
24
|
+
}
|
|
25
|
+
export declare function buildModelPreferences(roleModel: string | undefined, config: SamplingDriverConfig): ModelPreferences | undefined;
|
package/dist/sampling.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { ProviderError } from "@deepthonk/core";
|
|
2
|
+
import { extractJsonObjectText } from "./jsonExtract.js";
|
|
3
|
+
const DEFAULT_SAMPLING_TIMEOUT_MS = 60_000;
|
|
4
|
+
export class SamplingDriver {
|
|
5
|
+
createMessage;
|
|
6
|
+
config;
|
|
7
|
+
maxConcurrency = 4;
|
|
8
|
+
constructor(createMessage, config = {}) {
|
|
9
|
+
this.createMessage = createMessage;
|
|
10
|
+
this.config = config;
|
|
11
|
+
}
|
|
12
|
+
async generate(input) {
|
|
13
|
+
return this.sample(input.model, input.temperature, promptMessages(input.prompt));
|
|
14
|
+
}
|
|
15
|
+
async compare(input) {
|
|
16
|
+
const result = await this.sample(input.model, input.temperature, promptMessages(input.prompt));
|
|
17
|
+
return { ...result, text: extractJsonTextOrOriginal(result.text) };
|
|
18
|
+
}
|
|
19
|
+
async mutate(input) {
|
|
20
|
+
return this.sample(input.model, input.temperature, promptMessages(input.prompt));
|
|
21
|
+
}
|
|
22
|
+
async finalize(input) {
|
|
23
|
+
return this.sample(input.model, 0.2, promptMessages(input.prompt));
|
|
24
|
+
}
|
|
25
|
+
async sample(model, temperature, prompt) {
|
|
26
|
+
const started = Date.now();
|
|
27
|
+
const result = await this.callCreateMessage({
|
|
28
|
+
messages: prompt.user.trim()
|
|
29
|
+
? [
|
|
30
|
+
{
|
|
31
|
+
role: "user",
|
|
32
|
+
content: {
|
|
33
|
+
type: "text",
|
|
34
|
+
text: prompt.user
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
: [],
|
|
39
|
+
systemPrompt: prompt.system.trim() ? prompt.system : undefined,
|
|
40
|
+
modelPreferences: buildModelPreferences(model, this.config),
|
|
41
|
+
includeContext: "none",
|
|
42
|
+
temperature,
|
|
43
|
+
maxTokens: 4096
|
|
44
|
+
});
|
|
45
|
+
if (result.stopReason === "maxTokens") {
|
|
46
|
+
throw new ProviderError("MCP Sampling response was truncated by maxTokens.", {
|
|
47
|
+
code: "provider.output_truncated",
|
|
48
|
+
retryable: false,
|
|
49
|
+
fix: "Use a smaller prompt, a host model with larger output support, or reduce answer length."
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const text = textContent(result);
|
|
53
|
+
return {
|
|
54
|
+
text,
|
|
55
|
+
model: result.model ?? model,
|
|
56
|
+
provider: "sampling",
|
|
57
|
+
usage: {
|
|
58
|
+
inputTokens: undefined,
|
|
59
|
+
outputTokens: undefined
|
|
60
|
+
},
|
|
61
|
+
latencyMs: Date.now() - started,
|
|
62
|
+
retryCount: 0,
|
|
63
|
+
raw: this.config.includeRawOutputs ? result : undefined
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
async callCreateMessage(params) {
|
|
67
|
+
const timeoutMs = this.config.requestTimeoutMs ?? DEFAULT_SAMPLING_TIMEOUT_MS;
|
|
68
|
+
try {
|
|
69
|
+
return await callWithTimeout(this.createMessage, params, timeoutMs);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (error instanceof SamplingTimeoutError) {
|
|
73
|
+
throw new ProviderError(`MCP Sampling request timed out after ${error.timeoutMs}ms.`, {
|
|
74
|
+
code: "provider.sampling_timeout",
|
|
75
|
+
retryable: false,
|
|
76
|
+
fix: "Increase retry.requestTimeoutMs, switch to a direct provider, or check the MCP host responsiveness. Use 'deepthonk resume <run-dir> --continue' to retry an interrupted run."
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
throw new ProviderError(`MCP Sampling request failed: ${error instanceof Error ? error.message : String(error)}`, {
|
|
80
|
+
code: "provider.sampling_request_failed",
|
|
81
|
+
retryable: false,
|
|
82
|
+
fix: "The MCP host refused or errored the sampling request. Use 'deepthonk resume <run-dir> --continue' to retry an interrupted run, or switch to a direct provider."
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
class SamplingTimeoutError extends Error {
|
|
88
|
+
timeoutMs;
|
|
89
|
+
constructor(timeoutMs) {
|
|
90
|
+
super(`MCP Sampling request timed out after ${timeoutMs}ms.`);
|
|
91
|
+
this.timeoutMs = timeoutMs;
|
|
92
|
+
this.name = "SamplingTimeoutError";
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function callWithTimeout(fn, params, timeoutMs) {
|
|
96
|
+
const controller = new AbortController();
|
|
97
|
+
let timer;
|
|
98
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
99
|
+
timer = setTimeout(() => {
|
|
100
|
+
controller.abort();
|
|
101
|
+
reject(new SamplingTimeoutError(timeoutMs));
|
|
102
|
+
}, timeoutMs);
|
|
103
|
+
});
|
|
104
|
+
try {
|
|
105
|
+
return await Promise.race([fn(params, { signal: controller.signal, timeout: timeoutMs }), timeoutPromise]);
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
if (timer)
|
|
109
|
+
clearTimeout(timer);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export function buildModelPreferences(roleModel, config) {
|
|
113
|
+
const hintNames = uniqueNonEmpty([roleModel, ...(config.modelHints ?? [])]);
|
|
114
|
+
const preferences = {};
|
|
115
|
+
if (hintNames.length > 0)
|
|
116
|
+
preferences.hints = hintNames.map((name) => ({ name }));
|
|
117
|
+
if (config.costPriority !== undefined)
|
|
118
|
+
preferences.costPriority = config.costPriority;
|
|
119
|
+
if (config.speedPriority !== undefined)
|
|
120
|
+
preferences.speedPriority = config.speedPriority;
|
|
121
|
+
if (config.intelligencePriority !== undefined)
|
|
122
|
+
preferences.intelligencePriority = config.intelligencePriority;
|
|
123
|
+
return Object.keys(preferences).length > 0 ? preferences : undefined;
|
|
124
|
+
}
|
|
125
|
+
function promptMessages(prompt) {
|
|
126
|
+
if (!prompt)
|
|
127
|
+
throw new ProviderError("Core did not provide prompt messages.");
|
|
128
|
+
return prompt;
|
|
129
|
+
}
|
|
130
|
+
function textContent(result) {
|
|
131
|
+
if (result.content.type === "text")
|
|
132
|
+
return result.content.text;
|
|
133
|
+
throw new ProviderError(`MCP Sampling returned unsupported ${result.content.type} content.`, {
|
|
134
|
+
code: "provider.sampling_non_text_response",
|
|
135
|
+
retryable: false,
|
|
136
|
+
fix: "Use an MCP client/model that can return text content for sampling requests."
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function extractJsonTextOrOriginal(text) {
|
|
140
|
+
try {
|
|
141
|
+
return extractJsonObjectText(text);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return text;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function uniqueNonEmpty(values) {
|
|
148
|
+
const seen = new Set();
|
|
149
|
+
const unique = [];
|
|
150
|
+
for (const value of values) {
|
|
151
|
+
const trimmed = value?.trim();
|
|
152
|
+
if (!trimmed || seen.has(trimmed))
|
|
153
|
+
continue;
|
|
154
|
+
seen.add(trimmed);
|
|
155
|
+
unique.push(trimmed);
|
|
156
|
+
}
|
|
157
|
+
return unique;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=sampling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampling.js","sourceRoot":"","sources":["../src/sampling.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SamplingDriverConfig, SamplingTransport } from "./sampling.js";
|
|
1
2
|
export type { CompareInput, FinalizeInput, GenerateInput, ModelDriver, ModelTextResult, MutateInput } from "@deepthonk/core";
|
|
2
3
|
export type ProviderRole = "generator" | "mutator" | "judge" | "finalizer";
|
|
3
4
|
export interface RoleProviderConfig {
|
|
@@ -12,11 +13,12 @@ export interface RoleProviderConfig {
|
|
|
12
13
|
};
|
|
13
14
|
supportsJsonMode?: boolean;
|
|
14
15
|
}
|
|
15
|
-
export interface
|
|
16
|
+
export interface BaseProviderConfig extends SamplingDriverConfig {
|
|
16
17
|
provider: "fake" | "openai-compatible" | "deepseek" | string;
|
|
17
18
|
baseUrl?: string;
|
|
18
19
|
apiKeyEnv?: string;
|
|
19
20
|
apiKey?: string;
|
|
21
|
+
samplingTransport?: SamplingTransport;
|
|
20
22
|
models: {
|
|
21
23
|
generator: string;
|
|
22
24
|
mutator: string;
|
|
@@ -30,3 +32,8 @@ export interface ProviderConfig {
|
|
|
30
32
|
supportsJsonMode?: boolean;
|
|
31
33
|
roleProviders?: Partial<Record<ProviderRole, RoleProviderConfig>>;
|
|
32
34
|
}
|
|
35
|
+
export type SamplingProviderConfig = BaseProviderConfig & SamplingDriverConfig & {
|
|
36
|
+
provider: "sampling";
|
|
37
|
+
samplingTransport?: SamplingTransport;
|
|
38
|
+
};
|
|
39
|
+
export type ProviderConfig = BaseProviderConfig | SamplingProviderConfig;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepthonk/providers",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Provider drivers and routing for DeepThonk.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Xule Lin",
|
|
@@ -32,8 +32,9 @@
|
|
|
32
32
|
"directory": "packages/providers"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
35
36
|
"zod": "^3.25.28",
|
|
36
|
-
"@deepthonk/core": "0.1.
|
|
37
|
+
"@deepthonk/core": "0.1.2"
|
|
37
38
|
},
|
|
38
39
|
"scripts": {
|
|
39
40
|
"build": "tsc -p tsconfig.json",
|