forked from deepseek-ai/deepseek-harness
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
91 lines (80 loc) · 4.28 KB
/
Copy pathindex.ts
File metadata and controls
91 lines (80 loc) · 4.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/**
* Model-facing `web_search` and `web_fetch` tools over `ctx.web`. This package owns schemas,
* validation, prompt guidance, limits, and presentation, never concrete providers. Enablement
* controls tool registration; an enabled tool remains visible when its provider is unavailable
* and fails with a structured error at execution time.
* @module @deepseek-ai/dsh-tool-web
*/
import type { Context } from '@deepseek-ai/cordis'
import z from '@deepseek-ai/schemastery'
import type {} from '@deepseek-ai/dsh-web'
import { applyWebSearchTool, WEB_SEARCH_MAX_RESULTS } from './search.ts'
import { applyWebFetchTool } from './fetch.ts'
export { WEB_SEARCH_MAX_RESULTS, applyWebSearchTool, formatSearchOutput, parseSearchArgs, presentSearchCall, presentSearchResult, searchMetaFromValue, searchMetaFromResult } from './search.ts'
export type { WebSearchMeta } from './search.ts'
export { applyWebFetchTool, formatFetchOutput, parseFetchArgs, presentFetchCall, presentFetchResult, fetchMetaFromValue, fetchMetaFromResult } from './fetch.ts'
export type { WebFetchMeta } from './fetch.ts'
/** Cordis plugin name used by loader diagnostics. */
export const name = 'tool-web'
/** Services required by the web tool suite. */
export const inject = ['tools', 'web', 'systemPrompt']
/** Default cooperative tool-call timeout budget (ms) for the web tools. */
export const DEFAULT_WEB_TOOL_TIMEOUT_MS = 30_000
/**
* Default cap on one `web_fetch` output and on source characters converted
* synchronously. This leaves headroom above the local provider's default
* 100,000-character body cap while bounding custom providers and rendered output.
*/
export const DEFAULT_FETCH_MAX_OUTPUT_CHARS = 200_000
/** Plugin config: which web tools to register, the source cap, per-tool budgets, and the fetch output cap. */
export interface Config {
/** Register `web_search`. Defaults to true. */
search?: boolean
/** Register `web_fetch`. Defaults to true. */
fetch?: boolean
/** Upper bound on sources returned by one `web_search` call. */
searchMaxResults?: number
/** Cooperative timeout budget (ms) for `web_fetch`. Defaults to 30000. */
fetchTimeoutMs?: number
/** Cooperative timeout budget (ms) for `web_search`. Defaults to 30000. */
searchTimeoutMs?: number
/** Cap on source characters converted and complete `web_fetch` output characters. Defaults to 200000. */
fetchMaxOutputChars?: number
}
export const Config: z<Config> = z.object({
search: z.boolean().default(true),
fetch: z.boolean().default(true),
searchMaxResults: z.number().default(WEB_SEARCH_MAX_RESULTS),
fetchTimeoutMs: z.number().default(DEFAULT_WEB_TOOL_TIMEOUT_MS),
searchTimeoutMs: z.number().default(DEFAULT_WEB_TOOL_TIMEOUT_MS),
fetchMaxOutputChars: z.number().default(DEFAULT_FETCH_MAX_OUTPUT_CHARS),
})
/** Complete config after schemastery applies every field default. */
type ResolvedConfig = Required<Config>
/** Configured count, timeout, and character caps must be positive integers. */
function assertPositiveInteger(name: string, value: number): void {
if (!Number.isInteger(value) || value < 1) {
throw new Error(`tool-web: ${name} must be a positive integer`)
}
}
/**
* Register the enabled web tools. `search`/`fetch` default to true; a product
* that wants only one disables the other in config. Each tool's cooperative
* timeout budget (`fetchTimeoutMs`/`searchTimeoutMs`, default 30000) is resolved
* here and attached to the tool as `ToolDefinition.timeoutMs` for
* `@deepseek-ai/dsh-tool-call-timeout-policy` to enforce. The tools' disposers are
* fiber-scoped (the effect-based registries clean up on dispose), so no manual
* teardown is needed.
*/
export function apply(ctx: Context, config: Config): void {
// schemastery (Config) has already filled every defaulted field.
const resolved = config as ResolvedConfig
assertPositiveInteger('searchMaxResults', resolved.searchMaxResults)
assertPositiveInteger('fetchTimeoutMs', resolved.fetchTimeoutMs)
assertPositiveInteger('searchTimeoutMs', resolved.searchTimeoutMs)
assertPositiveInteger('fetchMaxOutputChars', resolved.fetchMaxOutputChars)
if (resolved.search) {
applyWebSearchTool(ctx, resolved.searchMaxResults, resolved.searchTimeoutMs, resolved.fetch)
}
if (resolved.fetch) applyWebFetchTool(ctx, resolved.fetchTimeoutMs, resolved.fetchMaxOutputChars)
}