@tokensapi/dsh-progressive-tools 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/state.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import type { ActiveGroupState, ResolvedConfig, SearchResultValue, StateSnapshot, ToolCatalog } from './types.js';
2
+ export interface ProgressiveState {
3
+ catalog: ToolCatalog;
4
+ readonly active: Map<string, ActiveGroupState>;
5
+ currentTurn: number;
6
+ }
7
+ export declare function createProgressiveState(catalog: ToolCatalog, currentTurn?: number): ProgressiveState;
8
+ export declare function snapshotState(state: ProgressiveState): StateSnapshot;
9
+ export declare function restoreSnapshot(state: ProgressiveState, snapshot: StateSnapshot): void;
10
+ export declare function activateGroups(state: ProgressiveState, groupIds: readonly string[], turn: number, config: ResolvedConfig): {
11
+ activated: string[];
12
+ evicted: string[];
13
+ };
14
+ export declare function expireGroups(state: ProgressiveState, turn: number, config: ResolvedConfig): string[];
15
+ export declare function touchTool(state: ProgressiveState, toolName: string, turn: number): void;
16
+ export declare function proposeSearch(source: ProgressiveState, action: SearchResultValue['action'], query: string, limit: number, config: ResolvedConfig): SearchResultValue;
package/lib/state.js ADDED
@@ -0,0 +1,110 @@
1
+ import { searchCatalog } from './catalog.js';
2
+ export function createProgressiveState(catalog, currentTurn = 0) {
3
+ return { catalog, active: new Map(), currentTurn };
4
+ }
5
+ export function snapshotState(state) {
6
+ return {
7
+ activeGroups: [...state.active.values()].sort((left, right) => left.id.localeCompare(right.id)),
8
+ };
9
+ }
10
+ export function restoreSnapshot(state, snapshot) {
11
+ state.active.clear();
12
+ for (const entry of snapshot.activeGroups) {
13
+ if (!state.catalog.groups.has(entry.id))
14
+ continue;
15
+ state.active.set(entry.id, { ...entry });
16
+ }
17
+ }
18
+ function activeTokenEstimate(state) {
19
+ return [...state.active.keys()].reduce((total, id) => total + (state.catalog.groups.get(id)?.estimatedTokens ?? 0), 0);
20
+ }
21
+ function evictToBudget(state, config, protectedGroups) {
22
+ const evicted = [];
23
+ const candidates = () => [...state.active.values()]
24
+ .filter(entry => !protectedGroups.has(entry.id))
25
+ .sort((left, right) => left.lastUsedTurn - right.lastUsedTurn
26
+ || left.activatedAtTurn - right.activatedAtTurn
27
+ || left.id.localeCompare(right.id));
28
+ while (state.active.size > config.maxActiveGroups || activeTokenEstimate(state) > config.maxActiveToolTokens) {
29
+ const candidate = candidates()[0];
30
+ if (candidate === undefined)
31
+ break;
32
+ state.active.delete(candidate.id);
33
+ evicted.push(candidate.id);
34
+ }
35
+ return evicted;
36
+ }
37
+ export function activateGroups(state, groupIds, turn, config) {
38
+ const activated = [];
39
+ for (const id of groupIds) {
40
+ if (!state.catalog.groups.has(id))
41
+ continue;
42
+ const current = state.active.get(id);
43
+ state.active.set(id, {
44
+ id,
45
+ activatedAtTurn: current?.activatedAtTurn ?? turn,
46
+ lastUsedTurn: turn,
47
+ });
48
+ activated.push(id);
49
+ }
50
+ return {
51
+ activated,
52
+ evicted: evictToBudget(state, config, new Set(activated)),
53
+ };
54
+ }
55
+ export function expireGroups(state, turn, config) {
56
+ if (config.retentionTurns === 0)
57
+ return [];
58
+ const expired = [];
59
+ for (const entry of state.active.values()) {
60
+ if (turn - entry.lastUsedTurn < config.retentionTurns)
61
+ continue;
62
+ state.active.delete(entry.id);
63
+ expired.push(entry.id);
64
+ }
65
+ return expired;
66
+ }
67
+ export function touchTool(state, toolName, turn) {
68
+ const groupId = state.catalog.toolToGroup.get(toolName);
69
+ if (groupId === undefined)
70
+ return;
71
+ const current = state.active.get(groupId);
72
+ if (current === undefined)
73
+ return;
74
+ state.active.set(groupId, { ...current, lastUsedTurn: turn });
75
+ }
76
+ function resultValue(state, action, query, matches, activatedGroups, evictedGroups) {
77
+ const activeGroups = [...state.active.keys()].sort();
78
+ const activeTools = activeGroups.flatMap(id => state.catalog.groups.get(id)?.tools.map(tool => tool.name) ?? []).sort();
79
+ const estimatedActiveTokens = activeTokenEstimate(state);
80
+ return {
81
+ protocol: 'dsh-progressive-tools/v1',
82
+ action,
83
+ query,
84
+ matches,
85
+ activatedGroups,
86
+ evictedGroups,
87
+ activeGroups,
88
+ activeTools,
89
+ estimatedActiveTokens,
90
+ estimatedCatalogTokens: state.catalog.totalEstimatedTokens,
91
+ estimatedSavedTokens: Math.max(0, state.catalog.totalEstimatedTokens - estimatedActiveTokens),
92
+ catalogTools: state.catalog.tools.size,
93
+ state: snapshotState(state),
94
+ };
95
+ }
96
+ export function proposeSearch(source, action, query, limit, config) {
97
+ const state = createProgressiveState(source.catalog, source.currentTurn);
98
+ restoreSnapshot(state, snapshotState(source));
99
+ if (action === 'status')
100
+ return resultValue(state, action, '', [], [], []);
101
+ if (action === 'reset') {
102
+ const evicted = [...state.active.keys()].sort();
103
+ state.active.clear();
104
+ return resultValue(state, action, '', [], [], evicted);
105
+ }
106
+ const matches = searchCatalog(state.catalog, query, limit);
107
+ const selected = matches.slice(0, config.activationGroupLimit).map(match => match.group);
108
+ const { activated, evicted } = activateGroups(state, selected, state.currentTurn, config);
109
+ return resultValue(state, action, query, matches, activated, evicted);
110
+ }
package/lib/types.d.ts ADDED
@@ -0,0 +1,120 @@
1
+ export interface ToolSchemaView {
2
+ readonly name: string;
3
+ readonly description: string;
4
+ readonly parameters: Readonly<Record<string, unknown>>;
5
+ }
6
+ export interface ToolGroupConfig {
7
+ readonly id: string;
8
+ readonly description?: string;
9
+ readonly aliases?: readonly string[];
10
+ readonly include: readonly string[];
11
+ readonly exclude?: readonly string[];
12
+ }
13
+ export interface SkillBindingConfig {
14
+ readonly skill: string;
15
+ readonly groups: readonly string[];
16
+ }
17
+ export type ProgressiveMode = 'stable-proxy' | 'dynamic';
18
+ export interface ResolvedConfig {
19
+ readonly mode: ProgressiveMode;
20
+ readonly toolName: string;
21
+ readonly dispatchToolName: string;
22
+ readonly alwaysVisible: readonly string[];
23
+ readonly groups: readonly ToolGroupConfig[];
24
+ readonly skillBindings: readonly SkillBindingConfig[];
25
+ readonly maxResults: number;
26
+ readonly activationGroupLimit: number;
27
+ readonly maxActiveGroups: number;
28
+ readonly maxActiveToolTokens: number;
29
+ readonly retentionTurns: number;
30
+ readonly charactersPerToken: number;
31
+ readonly requireDiscovery: boolean;
32
+ readonly statusGrantsDiscovery: boolean;
33
+ readonly deferToolGuidance: boolean;
34
+ }
35
+ export interface CatalogTool extends ToolSchemaView {
36
+ readonly estimatedTokens: number;
37
+ readonly searchText: string;
38
+ }
39
+ export interface ToolGroup {
40
+ readonly id: string;
41
+ readonly description: string;
42
+ readonly aliases: readonly string[];
43
+ readonly tools: readonly CatalogTool[];
44
+ readonly estimatedTokens: number;
45
+ readonly searchText: string;
46
+ }
47
+ export interface ToolCatalog {
48
+ readonly tools: ReadonlyMap<string, CatalogTool>;
49
+ readonly groups: ReadonlyMap<string, ToolGroup>;
50
+ readonly toolToGroup: ReadonlyMap<string, string>;
51
+ readonly totalEstimatedTokens: number;
52
+ }
53
+ export interface SearchMatch {
54
+ readonly group: string;
55
+ readonly description: string;
56
+ readonly score: number;
57
+ readonly estimatedTokens: number;
58
+ readonly tools: readonly string[];
59
+ }
60
+ /** One exact deferred definition returned by stable-proxy discovery. */
61
+ export interface DeferredToolMatch extends ToolSchemaView {
62
+ readonly group: string;
63
+ readonly score: number;
64
+ readonly estimatedTokens: number;
65
+ /** Every member name of the owning family, so siblings surface in one search. */
66
+ readonly groupTools: readonly string[];
67
+ }
68
+ /** One browsable deferred family listed by the stable-proxy status action. */
69
+ export interface DeferredGroupSummary {
70
+ readonly id: string;
71
+ readonly description: string;
72
+ readonly tools: readonly string[];
73
+ }
74
+ export interface ProxySearchResultValue {
75
+ readonly protocol: 'dsh-progressive-tools/v2';
76
+ readonly mode: 'stable-proxy';
77
+ readonly action: 'search' | 'status';
78
+ readonly query: string;
79
+ readonly matches: readonly DeferredToolMatch[];
80
+ /** Complete deferred family catalog, included by the status action. */
81
+ readonly groups?: readonly DeferredGroupSummary[];
82
+ readonly stableTools: readonly string[];
83
+ /** Names newly discovered by this call; earlier discoveries are not repeated. */
84
+ readonly discoveredTools: readonly string[];
85
+ /** Cumulative number of discovered deferred tools. */
86
+ readonly discoveredCount: number;
87
+ /**
88
+ * Cumulative discovered names. Carried in presentation metadata for resume
89
+ * and stripped from the rendered text to keep conversation growth bounded.
90
+ */
91
+ readonly allDiscoveredTools: readonly string[];
92
+ readonly catalogTools: number;
93
+ readonly estimatedVisibleTokens: number;
94
+ readonly estimatedCatalogTokens: number;
95
+ readonly estimatedSavedTokens: number;
96
+ readonly instruction: string;
97
+ }
98
+ export interface ActiveGroupState {
99
+ readonly id: string;
100
+ readonly activatedAtTurn: number;
101
+ readonly lastUsedTurn: number;
102
+ }
103
+ export interface StateSnapshot {
104
+ readonly activeGroups: readonly ActiveGroupState[];
105
+ }
106
+ export interface SearchResultValue {
107
+ readonly protocol: 'dsh-progressive-tools/v1';
108
+ readonly action: 'search' | 'status' | 'reset';
109
+ readonly query: string;
110
+ readonly matches: readonly SearchMatch[];
111
+ readonly activatedGroups: readonly string[];
112
+ readonly evictedGroups: readonly string[];
113
+ readonly activeGroups: readonly string[];
114
+ readonly activeTools: readonly string[];
115
+ readonly estimatedActiveTokens: number;
116
+ readonly estimatedCatalogTokens: number;
117
+ readonly estimatedSavedTokens: number;
118
+ readonly catalogTools: number;
119
+ readonly state: StateSnapshot;
120
+ }
package/lib/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "@tokensapi/dsh-progressive-tools",
3
+ "version": "0.1.0",
4
+ "description": "TokensCowork cache-stable progressive tool discovery and dispatch for DeepSeek Harness",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/index.d.ts",
11
+ "default": "./lib/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "lib/**/*.js",
16
+ "lib/**/*.d.ts",
17
+ "cordis.patch.yml",
18
+ "docs/**/*.md",
19
+ "README.md",
20
+ "README.zh-CN.md",
21
+ "CHANGELOG.md",
22
+ "CONTRIBUTING.md",
23
+ "SECURITY.md",
24
+ "LICENSE",
25
+ "THIRD_PARTY_NOTICES.md"
26
+ ],
27
+ "scripts": {
28
+ "build": "tsc -p tsconfig.build.json",
29
+ "typecheck": "tsc -p tsconfig.json --noEmit",
30
+ "lint": "oxlint src tests",
31
+ "test": "vitest run",
32
+ "test:coverage": "vitest run --coverage",
33
+ "audit:session": "node scripts/audit-session.mjs",
34
+ "check": "node --check scripts/audit-session.mjs && pnpm run typecheck && pnpm run lint && pnpm run test && pnpm run build && pnpm run publint",
35
+ "publint": "publint",
36
+ "prepare": "pnpm run build",
37
+ "prepack": "pnpm run check"
38
+ },
39
+ "engines": {
40
+ "node": "^22.19.0 || >=24.0.0"
41
+ },
42
+ "packageManager": "pnpm@11.19.0",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/TokensAPI/tokens_DshProgressiveTools_code.git"
46
+ },
47
+ "bugs": {
48
+ "url": "https://github.com/TokensAPI/tokens_DshProgressiveTools_code/issues"
49
+ },
50
+ "homepage": "https://github.com/TokensAPI/tokens_DshProgressiveTools_code#readme",
51
+ "keywords": [
52
+ "deepseek-harness",
53
+ "dsh",
54
+ "cordis",
55
+ "tokenscowork",
56
+ "tools",
57
+ "progressive-disclosure",
58
+ "token-optimization"
59
+ ],
60
+ "author": "TokensAPI contributors",
61
+ "license": "MIT",
62
+ "publishConfig": {
63
+ "access": "public"
64
+ },
65
+ "dsh": {
66
+ "bundle": {
67
+ "patch": "./cordis.patch.yml"
68
+ }
69
+ },
70
+ "peerDependencies": {
71
+ "@deepseek-ai/cordis": "4.0.1",
72
+ "@deepseek-ai/dsh-agent": "0.1.0-rc.8",
73
+ "@deepseek-ai/dsh-llm": "0.1.0-rc.8",
74
+ "@deepseek-ai/dsh-system-prompt": "0.1.0-rc.8",
75
+ "@deepseek-ai/dsh-tools": "0.1.0-rc.8"
76
+ },
77
+ "dependencies": {
78
+ "@deepseek-ai/schemastery": "^3.18.1"
79
+ },
80
+ "devDependencies": {
81
+ "@deepseek-ai/cordis": "4.0.1",
82
+ "@deepseek-ai/dsh-agent": "0.1.0-rc.8",
83
+ "@deepseek-ai/dsh-agent-loop": "0.1.0-rc.8",
84
+ "@deepseek-ai/dsh-llm": "0.1.0-rc.8",
85
+ "@deepseek-ai/dsh-scope": "0.1.0-rc.8",
86
+ "@deepseek-ai/dsh-session": "0.1.0-rc.8",
87
+ "@deepseek-ai/dsh-system-prompt": "0.1.0-rc.8",
88
+ "@deepseek-ai/dsh-tools": "0.1.0-rc.8",
89
+ "@types/node": "^22.19.0",
90
+ "@vitest/coverage-v8": "^4.1.8",
91
+ "oxlint": "^1.76.0",
92
+ "publint": "^0.3.21",
93
+ "typescript": "^6.0.3",
94
+ "vitest": "^4.1.8"
95
+ }
96
+ }