@sqdr2/dsh-fusion 0.0.0-stage → 0.3.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/INSTALL.md +89 -0
- package/INSTALL.zh.md +86 -0
- package/LICENSE +201 -0
- package/README.en.md +193 -0
- package/README.md +182 -2
- package/RELEASING.md +123 -0
- package/RELEASING.zh.md +115 -0
- package/contracts/fusion.ts +279 -0
- package/contracts/storage.sql +86 -0
- package/cordis.patch.yml +3 -0
- package/docs/COMPATIBILITY.md +162 -0
- package/docs/EVIDENCE.md +141 -0
- package/dshx.yml +39 -0
- package/lib/client.js +1920 -0
- package/lib/client.js.map +1 -0
- package/lib/dsh-fusion.js +12664 -0
- package/lib/types/activity.d.ts +20 -0
- package/lib/types/approval/logical.d.ts +10 -0
- package/lib/types/benchmark/naive.d.ts +37 -0
- package/lib/types/benchmark/native-run.d.ts +68 -0
- package/lib/types/benchmark/output-limits.d.ts +19 -0
- package/lib/types/bilingual.d.ts +2 -0
- package/lib/types/client/ActivityRows.d.ts +8 -0
- package/lib/types/client/FusionCache.d.ts +4 -0
- package/lib/types/client/FusionHint.d.ts +9 -0
- package/lib/types/client/FusionHistory.d.ts +5 -0
- package/lib/types/client/FusionPanelIcon.d.ts +13 -0
- package/lib/types/client/FusionRecovery.d.ts +5 -0
- package/lib/types/client/FusionSettings.d.ts +9 -0
- package/lib/types/client/FusionStatus.d.ts +5 -0
- package/lib/types/client/FusionTool.d.ts +4 -0
- package/lib/types/client/activity-model.d.ts +14 -0
- package/lib/types/client/i18n.d.ts +15 -0
- package/lib/types/client/index.d.ts +22 -0
- package/lib/types/client/settings-events.d.ts +2 -0
- package/lib/types/client/status-polling.d.ts +9 -0
- package/lib/types/context/guard.d.ts +21 -0
- package/lib/types/context/handoff.d.ts +17 -0
- package/lib/types/contracts.d.ts +449 -0
- package/lib/types/digest.d.ts +5 -0
- package/lib/types/dsh-fusion.d.ts +13 -0
- package/lib/types/errors.d.ts +28 -0
- package/lib/types/evidence/gate.d.ts +23 -0
- package/lib/types/evidence/receipts.d.ts +65 -0
- package/lib/types/execution/write-lease.d.ts +42 -0
- package/lib/types/host/bindings.d.ts +30 -0
- package/lib/types/host/cache-defaults.d.ts +48 -0
- package/lib/types/host/cache-policy.d.ts +155 -0
- package/lib/types/host/change-evidence.d.ts +38 -0
- package/lib/types/host/compaction-routing.d.ts +15 -0
- package/lib/types/host/coordinator.d.ts +169 -0
- package/lib/types/host/evidence-page.d.ts +13 -0
- package/lib/types/host/history.d.ts +88 -0
- package/lib/types/host/http.d.ts +4 -0
- package/lib/types/host/model-output.d.ts +13 -0
- package/lib/types/host/native-activity.d.ts +26 -0
- package/lib/types/host/native-approvals.d.ts +29 -0
- package/lib/types/host/native-auxiliary.d.ts +17 -0
- package/lib/types/host/native-budget.d.ts +33 -0
- package/lib/types/host/native-checks.d.ts +104 -0
- package/lib/types/host/native-compaction.d.ts +8 -0
- package/lib/types/host/native-context.d.ts +36 -0
- package/lib/types/host/native-effects.d.ts +75 -0
- package/lib/types/host/native-evidence.d.ts +4 -0
- package/lib/types/host/native-exploration.d.ts +15 -0
- package/lib/types/host/native-keepalive.d.ts +82 -0
- package/lib/types/host/native-model-control.d.ts +99 -0
- package/lib/types/host/native-on-demand-context.d.ts +39 -0
- package/lib/types/host/native-request.d.ts +5 -0
- package/lib/types/host/native-review.d.ts +11 -0
- package/lib/types/host/native-role-sandbox.d.ts +49 -0
- package/lib/types/host/native-scopes.d.ts +49 -0
- package/lib/types/host/native-selection.d.ts +29 -0
- package/lib/types/host/native-task-context.d.ts +39 -0
- package/lib/types/host/native-usage.d.ts +46 -0
- package/lib/types/host/native-worker-brief.d.ts +74 -0
- package/lib/types/host/native-worker-notices.d.ts +15 -0
- package/lib/types/host/native-worker.d.ts +44 -0
- package/lib/types/host/native-workflow.d.ts +41 -0
- package/lib/types/host/route-transport.d.ts +22 -0
- package/lib/types/host/settings.d.ts +39 -0
- package/lib/types/host/shell.d.ts +11 -0
- package/lib/types/host/status.d.ts +7 -0
- package/lib/types/host/subagent-seam.d.ts +10 -0
- package/lib/types/host/tool-table.d.ts +35 -0
- package/lib/types/host/worker-terminal.d.ts +68 -0
- package/lib/types/host/workspace-guard.d.ts +13 -0
- package/lib/types/host/workspace.d.ts +52 -0
- package/lib/types/identity.d.ts +64 -0
- package/lib/types/index.d.ts +34 -0
- package/lib/types/message-source.d.ts +29 -0
- package/lib/types/profile/compactor.d.ts +5 -0
- package/lib/types/profile/keepalive.d.ts +3 -0
- package/lib/types/profile/resolve.d.ts +17 -0
- package/lib/types/prompts.d.ts +8 -0
- package/lib/types/recovery/reconcile.d.ts +28 -0
- package/lib/types/review/dispatch.d.ts +20 -0
- package/lib/types/review/protocol.d.ts +51 -0
- package/lib/types/review/ticket.d.ts +32 -0
- package/lib/types/status.d.ts +88 -0
- package/lib/types/store-migration.d.ts +29 -0
- package/lib/types/task/deletion.d.ts +64 -0
- package/lib/types/task/reducer.d.ts +6 -0
- package/lib/types/task/sqlite-store.d.ts +71 -0
- package/lib/types/task/state.d.ts +51 -0
- package/lib/types/task/status-index.d.ts +28 -0
- package/lib/types/task/store.d.ts +48 -0
- package/lib/types/usage/budget.d.ts +27 -0
- package/lib/types/usage/ledger.d.ts +66 -0
- package/lib/types/usage/normalize.d.ts +50 -0
- package/lib/types/usage/pricing.d.ts +18 -0
- package/package.json +178 -4
- package/profiles/fusion-auto.example.json +45 -0
- package/prompts/compact.md +7 -0
- package/prompts/lead.md +42 -0
- package/prompts/model-lead.md +13 -0
- package/prompts/model-worker.md +5 -0
- package/prompts/worker.md +21 -0
- package/src/activity.ts +23 -0
- package/src/approval/logical.ts +44 -0
- package/src/benchmark/naive.ts +216 -0
- package/src/benchmark/native-run.ts +215 -0
- package/src/benchmark/output-limits.ts +33 -0
- package/src/bilingual.ts +2 -0
- package/src/client/ActivityRows.tsx +59 -0
- package/src/client/FusionCache.tsx +130 -0
- package/src/client/FusionHint.tsx +39 -0
- package/src/client/FusionHistory.tsx +247 -0
- package/src/client/FusionPanelIcon.tsx +39 -0
- package/src/client/FusionRecovery.tsx +69 -0
- package/src/client/FusionSettings.tsx +205 -0
- package/src/client/FusionStatus.tsx +103 -0
- package/src/client/FusionTool.tsx +66 -0
- package/src/client/activity-model.ts +31 -0
- package/src/client/i18n.ts +30 -0
- package/src/client/index.ts +50 -0
- package/src/client/settings-events.ts +3 -0
- package/src/client/status-polling.ts +88 -0
- package/src/context/guard.ts +81 -0
- package/src/context/handoff.ts +28 -0
- package/src/contracts.ts +449 -0
- package/src/digest.ts +28 -0
- package/src/dsh-fusion.ts +321 -0
- package/src/errors.ts +34 -0
- package/src/evidence/gate.ts +290 -0
- package/src/evidence/receipts.ts +175 -0
- package/src/execution/write-lease.ts +187 -0
- package/src/host/bindings.ts +91 -0
- package/src/host/cache-defaults.ts +103 -0
- package/src/host/cache-policy.ts +168 -0
- package/src/host/change-evidence.ts +156 -0
- package/src/host/compaction-routing.ts +46 -0
- package/src/host/coordinator.ts +2160 -0
- package/src/host/evidence-page.ts +25 -0
- package/src/host/history.ts +114 -0
- package/src/host/http.ts +30 -0
- package/src/host/model-output.ts +22 -0
- package/src/host/native-activity.ts +199 -0
- package/src/host/native-approvals.ts +196 -0
- package/src/host/native-auxiliary.ts +19 -0
- package/src/host/native-budget.ts +112 -0
- package/src/host/native-checks.ts +474 -0
- package/src/host/native-compaction.ts +34 -0
- package/src/host/native-context.ts +204 -0
- package/src/host/native-effects.ts +260 -0
- package/src/host/native-evidence.ts +31 -0
- package/src/host/native-exploration.ts +114 -0
- package/src/host/native-keepalive.ts +292 -0
- package/src/host/native-model-control.ts +298 -0
- package/src/host/native-on-demand-context.ts +74 -0
- package/src/host/native-request.ts +12 -0
- package/src/host/native-review.ts +51 -0
- package/src/host/native-role-sandbox.ts +171 -0
- package/src/host/native-scopes.ts +203 -0
- package/src/host/native-selection.ts +110 -0
- package/src/host/native-task-context.ts +264 -0
- package/src/host/native-usage.ts +121 -0
- package/src/host/native-worker-brief.ts +122 -0
- package/src/host/native-worker-notices.ts +72 -0
- package/src/host/native-worker.ts +215 -0
- package/src/host/native-workflow.ts +103 -0
- package/src/host/route-transport.ts +54 -0
- package/src/host/settings.ts +93 -0
- package/src/host/shell.ts +13 -0
- package/src/host/status.ts +112 -0
- package/src/host/subagent-seam.ts +20 -0
- package/src/host/tool-table.ts +56 -0
- package/src/host/worker-terminal.ts +91 -0
- package/src/host/workspace-guard.ts +17 -0
- package/src/host/workspace.ts +184 -0
- package/src/identity.ts +76 -0
- package/src/index.ts +50 -0
- package/src/message-source.ts +31 -0
- package/src/profile/compactor.ts +26 -0
- package/src/profile/keepalive.ts +13 -0
- package/src/profile/resolve.ts +131 -0
- package/src/prompts.ts +32 -0
- package/src/recovery/reconcile.ts +38 -0
- package/src/review/dispatch.ts +48 -0
- package/src/review/protocol.ts +212 -0
- package/src/review/ticket.ts +166 -0
- package/src/status.ts +55 -0
- package/src/store-migration.ts +65 -0
- package/src/task/deletion.ts +105 -0
- package/src/task/reducer.ts +679 -0
- package/src/task/sqlite-store.ts +386 -0
- package/src/task/state.ts +72 -0
- package/src/task/status-index.ts +198 -0
- package/src/task/store.ts +287 -0
- package/src/usage/budget.ts +88 -0
- package/src/usage/ledger.ts +218 -0
- package/src/usage/normalize.ts +308 -0
- package/src/usage/pricing.ts +95 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default prompt-cache behaviour for the models most people pair in Fusion, from each provider's official
|
|
3
|
+
* documentation. Matching uses the model id (stable across DSH setups), never the route name, except for the
|
|
4
|
+
* routes of this project's own OAuth plugins, whose billing we know. Everything here is a default: the user's
|
|
5
|
+
* per-model setting always wins, and the runtime can shorten an interval it observes to be too long.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CACHE_DEFAULTS_CHECKED = "2026-09-27";
|
|
8
|
+
/** Safe for every provider documented here (the shortest documented lifetime is 5 minutes). */
|
|
9
|
+
export declare const GENERIC_INTERVAL_SECONDS = 285;
|
|
10
|
+
export type CacheMode = 'auto' | 'on' | 'off';
|
|
11
|
+
export interface CacheFamily {
|
|
12
|
+
id: string;
|
|
13
|
+
label: string;
|
|
14
|
+
match: RegExp;
|
|
15
|
+
/** Official lifetime text as documented (not a guarantee; caches are best-effort). */
|
|
16
|
+
lifetime: {
|
|
17
|
+
zh: string;
|
|
18
|
+
en: string;
|
|
19
|
+
};
|
|
20
|
+
/** Cached input price relative to uncached input, as documented. */
|
|
21
|
+
discount: string;
|
|
22
|
+
keepalive: CacheMode;
|
|
23
|
+
intervalSeconds: number;
|
|
24
|
+
docs: string;
|
|
25
|
+
}
|
|
26
|
+
export declare const CACHE_FAMILIES: readonly CacheFamily[];
|
|
27
|
+
/** Routes of this project's OAuth plugins (dsh-oauth-login, dsh-antigravity-oauth): billing we know. */
|
|
28
|
+
export interface RouteBilling {
|
|
29
|
+
match: RegExp;
|
|
30
|
+
label: string;
|
|
31
|
+
keepalive: CacheMode;
|
|
32
|
+
reason: {
|
|
33
|
+
zh: string;
|
|
34
|
+
en: string;
|
|
35
|
+
};
|
|
36
|
+
/** Interval measured on this route; overrides the model family default. */
|
|
37
|
+
intervalSeconds?: number;
|
|
38
|
+
}
|
|
39
|
+
export declare const OWN_ROUTES: readonly RouteBilling[];
|
|
40
|
+
export interface CacheDefaults {
|
|
41
|
+
keepalive: CacheMode;
|
|
42
|
+
intervalSeconds: number;
|
|
43
|
+
source: 'route' | 'family' | 'generic';
|
|
44
|
+
family?: CacheFamily;
|
|
45
|
+
route?: RouteBilling;
|
|
46
|
+
}
|
|
47
|
+
/** Defaults for one physical route; the model id selects the family, our own routes set the billing mode. */
|
|
48
|
+
export declare function cacheDefaults(provider: string, model: string): CacheDefaults;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type { Role } from '../contracts.js';
|
|
2
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
3
|
+
import { type CacheDefaults, type CacheMode } from './cache-defaults.js';
|
|
4
|
+
/** The user's choice for one physical model route; absent fields fall back to learned/default values. */
|
|
5
|
+
export interface ModelCacheSetting {
|
|
6
|
+
mode?: CacheMode;
|
|
7
|
+
intervalSeconds?: number;
|
|
8
|
+
}
|
|
9
|
+
/** One model request that followed a wait: the evidence the policy learns from and the settings page shows. */
|
|
10
|
+
export interface CacheSample {
|
|
11
|
+
at: string;
|
|
12
|
+
gapSeconds: number;
|
|
13
|
+
ping: boolean;
|
|
14
|
+
hit: boolean;
|
|
15
|
+
cacheRead: number;
|
|
16
|
+
input: number;
|
|
17
|
+
output?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface ModelCacheStats {
|
|
20
|
+
schemaVersion: 1;
|
|
21
|
+
provider: string;
|
|
22
|
+
model: string;
|
|
23
|
+
samples: CacheSample[];
|
|
24
|
+
totals: {
|
|
25
|
+
/** Real requests after a wait of at least WAIT_SECONDS, and how many still found their prefix cached. */
|
|
26
|
+
waits: number;
|
|
27
|
+
waitHits: number;
|
|
28
|
+
/** Keepalive pings and the tokens they read (mostly at the cache price). */
|
|
29
|
+
pings: number;
|
|
30
|
+
pingHits: number;
|
|
31
|
+
pingTokens: number;
|
|
32
|
+
/** Output tokens of pings; absent on stats recorded before 0.2.3. A route that ignores the output cap shows here. */
|
|
33
|
+
pingOutputTokens?: number;
|
|
34
|
+
/** Prefix tokens served from cache after a wait, and tokens resent uncached after a wait. */
|
|
35
|
+
keptWarmTokens: number;
|
|
36
|
+
resentTokens: number;
|
|
37
|
+
};
|
|
38
|
+
/** Interval shortened after pings kept missing (never lengthened automatically). */
|
|
39
|
+
learnedIntervalSeconds?: number;
|
|
40
|
+
/** Rule that produced learnedIntervalSeconds; values from older rules are ignored. */
|
|
41
|
+
learnedRule?: number;
|
|
42
|
+
updatedAt: string;
|
|
43
|
+
}
|
|
44
|
+
export interface EffectiveCachePolicy {
|
|
45
|
+
mode: CacheMode;
|
|
46
|
+
intervalSeconds: number;
|
|
47
|
+
modeSource: 'user' | 'pair' | 'role' | CacheDefaults['source'];
|
|
48
|
+
intervalSource: 'user' | 'learned' | CacheDefaults['source'];
|
|
49
|
+
defaults: CacheDefaults;
|
|
50
|
+
}
|
|
51
|
+
/** A request counts as a wait when this long passed since the previous request of the same agent. */
|
|
52
|
+
export declare const WAIT_SECONDS = 120;
|
|
53
|
+
/**
|
|
54
|
+
* Rule 2 (0.2.3): shorten only when most recent pings at this interval missed (3 of the last up to 5).
|
|
55
|
+
* Rule 1 shortened on 2 misses, and providers also drop single prefixes at random: the live log had
|
|
56
|
+
* 4 partial misses in 123 pings, each keeping only the shared 3,968-token system+tools head, while
|
|
57
|
+
* a probe of the same route still hit after 10+ idle minutes. That noise cut a 285 s interval to 214 s.
|
|
58
|
+
*/
|
|
59
|
+
export declare const LEARNING_RULE = 2;
|
|
60
|
+
/** A request reused its prefix when most of its input came from the cache. */
|
|
61
|
+
export declare const cacheHit: (cacheRead: number, input: number) => boolean;
|
|
62
|
+
export declare const clampInterval: (seconds: number) => number;
|
|
63
|
+
export declare class CachePolicy {
|
|
64
|
+
readonly store: SqliteFusionStore;
|
|
65
|
+
constructor(store: SqliteFusionStore);
|
|
66
|
+
setting(provider: string, model: string): ModelCacheSetting | undefined;
|
|
67
|
+
/** Save or clear (null) the user's choice; invalid values are refused, not coerced. */
|
|
68
|
+
save(provider: string, model: string, setting: ModelCacheSetting | null): void;
|
|
69
|
+
stats(provider: string, model: string): ModelCacheStats | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Record a request that followed a wait (or any keepalive ping). Pings that keep missing at the current
|
|
72
|
+
* interval shorten it by a quarter: a too-long interval wastes every ping, a too-short one only costs extra
|
|
73
|
+
* cheap reads, so the rule only ever moves toward safety. Lengthening is left to the user (see suggestion).
|
|
74
|
+
*/
|
|
75
|
+
observe(provider: string, model: string, sample: Omit<CacheSample, 'at'>, currentIntervalSeconds: number): void;
|
|
76
|
+
/**
|
|
77
|
+
* User setting > pair profile (older explicit choice) > learned interval > our own route's billing default >
|
|
78
|
+
* model family default > generic. The Worker defaults to off: it rarely waits long enough to need pings.
|
|
79
|
+
*/
|
|
80
|
+
resolve(provider: string, model: string, role: Role, pairChoice?: boolean | 'auto'): EffectiveCachePolicy;
|
|
81
|
+
/** Suggest a longer interval only on repeated evidence: real waits that still hit well beyond the interval. */
|
|
82
|
+
suggestion(provider: string, model: string, intervalSeconds: number): number | undefined;
|
|
83
|
+
/** Every route the plugin has evidence or a setting for, plus the given routes (the configured pair). */
|
|
84
|
+
routes(extra?: readonly {
|
|
85
|
+
provider: string;
|
|
86
|
+
model: string;
|
|
87
|
+
}[]): {
|
|
88
|
+
provider: string;
|
|
89
|
+
model: string;
|
|
90
|
+
}[];
|
|
91
|
+
}
|
|
92
|
+
type Route = {
|
|
93
|
+
provider: string;
|
|
94
|
+
model: string;
|
|
95
|
+
};
|
|
96
|
+
/** One row of the settings page: what applies, why, what the defaults say, and what was observed. */
|
|
97
|
+
export declare function cacheView(policy: CachePolicy, pair?: {
|
|
98
|
+
lead: Route;
|
|
99
|
+
worker: Route;
|
|
100
|
+
}, pairChoice?: {
|
|
101
|
+
lead?: boolean | 'auto';
|
|
102
|
+
worker?: boolean | 'auto';
|
|
103
|
+
}): {
|
|
104
|
+
provider: string;
|
|
105
|
+
model: string;
|
|
106
|
+
role: Role | undefined;
|
|
107
|
+
mode: CacheMode;
|
|
108
|
+
intervalSeconds: number;
|
|
109
|
+
modeSource: "user" | "role" | "route" | "family" | "generic" | "pair";
|
|
110
|
+
intervalSource: "user" | "route" | "family" | "generic" | "learned";
|
|
111
|
+
setting: ModelCacheSetting;
|
|
112
|
+
defaults: {
|
|
113
|
+
route?: {
|
|
114
|
+
label: string;
|
|
115
|
+
reason: {
|
|
116
|
+
zh: string;
|
|
117
|
+
en: string;
|
|
118
|
+
};
|
|
119
|
+
} | undefined;
|
|
120
|
+
family?: {
|
|
121
|
+
label: string;
|
|
122
|
+
lifetime: {
|
|
123
|
+
zh: string;
|
|
124
|
+
en: string;
|
|
125
|
+
};
|
|
126
|
+
discount: string;
|
|
127
|
+
docs: string;
|
|
128
|
+
} | undefined;
|
|
129
|
+
mode: CacheMode;
|
|
130
|
+
intervalSeconds: number;
|
|
131
|
+
source: "route" | "family" | "generic";
|
|
132
|
+
};
|
|
133
|
+
totals: {
|
|
134
|
+
/** Real requests after a wait of at least WAIT_SECONDS, and how many still found their prefix cached. */
|
|
135
|
+
waits: number;
|
|
136
|
+
waitHits: number;
|
|
137
|
+
/** Keepalive pings and the tokens they read (mostly at the cache price). */
|
|
138
|
+
pings: number;
|
|
139
|
+
pingHits: number;
|
|
140
|
+
pingTokens: number;
|
|
141
|
+
/** Output tokens of pings; absent on stats recorded before 0.2.3. A route that ignores the output cap shows here. */
|
|
142
|
+
pingOutputTokens?: number;
|
|
143
|
+
/** Prefix tokens served from cache after a wait, and tokens resent uncached after a wait. */
|
|
144
|
+
keptWarmTokens: number;
|
|
145
|
+
resentTokens: number;
|
|
146
|
+
} | null;
|
|
147
|
+
learnedIntervalSeconds: number | null;
|
|
148
|
+
suggestion: number | null;
|
|
149
|
+
recent: {
|
|
150
|
+
gapSeconds: number;
|
|
151
|
+
ping: boolean;
|
|
152
|
+
hit: boolean;
|
|
153
|
+
}[];
|
|
154
|
+
}[];
|
|
155
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ArtifactRef, SnapshotId, TaskId } from '../contracts.js';
|
|
2
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
3
|
+
import type { WorkspaceEntry, WorkspaceSnapshot } from './workspace.js';
|
|
4
|
+
export interface ChangeBase {
|
|
5
|
+
schemaVersion: 1;
|
|
6
|
+
snapshot: SnapshotId;
|
|
7
|
+
contents: Record<string, ArtifactRef>;
|
|
8
|
+
/**
|
|
9
|
+
* Paths the Lead widened the scope to only after they had already changed, so their
|
|
10
|
+
* delegation-time bytes are gone. Diffs carry no pre-image for them and the
|
|
11
|
+
* rewritten-test gate cannot compare original lines; the review must say so instead of
|
|
12
|
+
* pretending the file was untouched (`session-daa71a4a`: refusing to record them at all
|
|
13
|
+
* left the task with no admissible report and no admissible widening).
|
|
14
|
+
*/
|
|
15
|
+
unavailable?: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
export declare function captureChangeBase(store: SqliteFusionStore, taskId: TaskId, base: WorkspaceSnapshot, allowed: readonly string[]): ChangeBase;
|
|
18
|
+
/**
|
|
19
|
+
* The same base bytes, for paths the Lead adds to the frozen scope after a report. A file the
|
|
20
|
+
* Worker (or the task's own build command) already changed no longer matches the snapshot, so
|
|
21
|
+
* its delegation-time bytes cannot be recorded: that path is reported as unavailable instead of
|
|
22
|
+
* failing, which would leave the task with no admissible report and no admissible widening.
|
|
23
|
+
*/
|
|
24
|
+
export declare function captureLaterChangeBase(store: SqliteFusionStore, taskId: TaskId, base: WorkspaceSnapshot, allowed: readonly string[]): ChangeBase;
|
|
25
|
+
export interface ChangeDiff {
|
|
26
|
+
path: string;
|
|
27
|
+
status: 'text' | 'binary' | 'type-change' | 'unavailable-base';
|
|
28
|
+
before?: {
|
|
29
|
+
entry: WorkspaceEntry;
|
|
30
|
+
content?: ArtifactRef;
|
|
31
|
+
};
|
|
32
|
+
after?: {
|
|
33
|
+
entry: WorkspaceEntry;
|
|
34
|
+
content: ArtifactRef;
|
|
35
|
+
};
|
|
36
|
+
patch?: ArtifactRef;
|
|
37
|
+
}
|
|
38
|
+
export declare function saveChangeManifest(store: SqliteFusionStore, taskId: TaskId, base: WorkspaceSnapshot, candidate: WorkspaceSnapshot, captured?: ChangeBase): ArtifactRef;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
3
|
+
import type { PhysicalRoute, Role } from '../contracts.js';
|
|
4
|
+
import type { SessionBinding } from './bindings.js';
|
|
5
|
+
interface Owner {
|
|
6
|
+
binding: SessionBinding;
|
|
7
|
+
role: Role;
|
|
8
|
+
}
|
|
9
|
+
/** Publish exact session routes before another plugin estimates or chunks input. */
|
|
10
|
+
export declare function installCompactionRouting(ctx: Context, input: {
|
|
11
|
+
owner(agent: Agent): Owner | undefined;
|
|
12
|
+
route(binding: SessionBinding, role: Role): PhysicalRoute;
|
|
13
|
+
epoch(binding: SessionBinding): number;
|
|
14
|
+
}): () => void;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
3
|
+
import type { GenerateOptions } from '@deepseek-ai/dsh-llm';
|
|
4
|
+
import type { ToolExecution, ToolRunContext } from '@deepseek-ai/dsh-tools';
|
|
5
|
+
import type { FusionEvent, Role, TaskId } from '../contracts.js';
|
|
6
|
+
import { WorkspaceWriteLease } from '../execution/write-lease.js';
|
|
7
|
+
import type { ResolvedProfile } from '../profile/resolve.js';
|
|
8
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
9
|
+
import type { TaskState } from '../task/state.js';
|
|
10
|
+
import type { DeletionBlocker } from '../task/deletion.js';
|
|
11
|
+
import { BindingRepository } from './bindings.js';
|
|
12
|
+
import type { SessionBinding } from './bindings.js';
|
|
13
|
+
import type { CheckDefinition } from './native-checks.js';
|
|
14
|
+
import { NativeFusionScopes } from './native-scopes.js';
|
|
15
|
+
import { NativeModelControl } from './native-model-control.js';
|
|
16
|
+
import { NativeWorkflow } from './native-workflow.js';
|
|
17
|
+
import { NativeRoleSandbox } from './native-role-sandbox.js';
|
|
18
|
+
import { NativeOnDemandContext } from './native-on-demand-context.js';
|
|
19
|
+
import { NativeTaskContext } from './native-task-context.js';
|
|
20
|
+
import { NativeApprovals } from './native-approvals.js';
|
|
21
|
+
import { NativeEffects } from './native-effects.js';
|
|
22
|
+
import { NativeCacheKeepalive } from './native-keepalive.js';
|
|
23
|
+
import type { KeepaliveClock } from './native-keepalive.js';
|
|
24
|
+
import { NativeWorkerTransport } from './native-worker.js';
|
|
25
|
+
import { NativeFusionActivity } from './native-activity.js';
|
|
26
|
+
import { CachePolicy } from './cache-policy.js';
|
|
27
|
+
import type { ChangeBase } from './change-evidence.js';
|
|
28
|
+
export interface CoordinatorOptions {
|
|
29
|
+
profile: ResolvedProfile;
|
|
30
|
+
workerTools: readonly string[];
|
|
31
|
+
/** Must validate existing authorization and durably reserve this actual request. */
|
|
32
|
+
authorizeRequest(agent: Agent, binding: SessionBinding, role: Role, turn: number, step: number): void;
|
|
33
|
+
/** Actual native stream admission, including auxiliary compaction calls. */
|
|
34
|
+
resumeAuthorization?(binding: SessionBinding): string;
|
|
35
|
+
reserveRequest?(request: GenerateOptions, binding: SessionBinding, role: Role): void;
|
|
36
|
+
leaseRoot?: string;
|
|
37
|
+
maxWorkerSteps?: number;
|
|
38
|
+
maxReworkRounds?: number;
|
|
39
|
+
commandMaxSeconds?: number;
|
|
40
|
+
/** Test clock only; production retains the recovered fixed schedule. */
|
|
41
|
+
keepaliveClock?: KeepaliveClock;
|
|
42
|
+
}
|
|
43
|
+
/** At least a sentence that is not a stock stub. */
|
|
44
|
+
export declare function substantiveReview(reason: string): boolean;
|
|
45
|
+
type LooseCheck = {
|
|
46
|
+
command: string;
|
|
47
|
+
id?: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
parser?: CheckDefinition['parser'];
|
|
50
|
+
kind?: CheckDefinition['kind'];
|
|
51
|
+
timeoutSeconds?: number;
|
|
52
|
+
definitionPaths?: readonly string[];
|
|
53
|
+
baseline?: CheckDefinition['baseline'];
|
|
54
|
+
};
|
|
55
|
+
/** Fill the defaults a Lead may omit; an explicit test kind without a parser still fails in freezeChecks. */
|
|
56
|
+
export declare function normalizeChecks(raw: readonly LooseCheck[]): CheckDefinition[];
|
|
57
|
+
/** Consecutive read-only calls allowed before a model must act; the Lead delegates broad reading. */
|
|
58
|
+
export declare const READ_STREAK: Record<Role, number>;
|
|
59
|
+
/** A few lines stay natural for the Lead; anything larger goes to the Sidekick. */
|
|
60
|
+
export declare const LEAD_DIRECT_WRITE: {
|
|
61
|
+
readonly perCall: 30;
|
|
62
|
+
readonly perTask: 80;
|
|
63
|
+
};
|
|
64
|
+
/** Lines a Lead tool call would write; 0 for reads and ordinary commands. */
|
|
65
|
+
export declare function directWriteLines(exec: Readonly<ToolExecution>): number;
|
|
66
|
+
/**
|
|
67
|
+
* The Worker is the cheap model: a real task needs room to explore, run and fix.
|
|
68
|
+
* Stopping it early pushes work back to the expensive Lead or the user.
|
|
69
|
+
*/
|
|
70
|
+
export declare const DEFAULT_POLICY: {
|
|
71
|
+
readonly maxWorkerSteps: 150;
|
|
72
|
+
readonly maxReworkRounds: 3;
|
|
73
|
+
readonly commandMaxSeconds: 600;
|
|
74
|
+
};
|
|
75
|
+
interface DelegateInput {
|
|
76
|
+
goal: string;
|
|
77
|
+
brief: string;
|
|
78
|
+
constraints: string[];
|
|
79
|
+
allowedPaths: string[];
|
|
80
|
+
checks: CheckDefinition[];
|
|
81
|
+
block?: boolean;
|
|
82
|
+
/** Verbatim quotes of the user's hard requirements; frozen as user-provenance constraints. */
|
|
83
|
+
requirements?: string[];
|
|
84
|
+
}
|
|
85
|
+
/** Whitespace-insensitive, otherwise exact: a requirement must be the user's own words. */
|
|
86
|
+
export declare const normalizeQuote: (text: string) => string;
|
|
87
|
+
/** Literal code spans (`like this`) a requirement asks for; a candidate that omits them gets flagged. */
|
|
88
|
+
export declare const literalSpans: (text: string) => string[];
|
|
89
|
+
export interface RewrittenTest {
|
|
90
|
+
path: string;
|
|
91
|
+
/** Original lines no longer present in the file. */
|
|
92
|
+
removedLines?: number;
|
|
93
|
+
deleted?: boolean;
|
|
94
|
+
/** Widened into scope after the change: no original bytes exist to compare against. */
|
|
95
|
+
unavailableBase?: boolean;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Existing test files whose original lines were removed or changed (pure additions are not listed). A Worker
|
|
99
|
+
* that rewrites an old test to fit its change hides a regression the maintainers' test would catch
|
|
100
|
+
* (round 4, canvasapi): the Lead must look at these before accepting.
|
|
101
|
+
*/
|
|
102
|
+
export declare function rewrittenTests(store: SqliteFusionStore, taskId: TaskId, root: string, changeBase: ChangeBase | undefined, changes: readonly string[]): RewrittenTest[];
|
|
103
|
+
/** Rework rounds after which a still-failing work order unlocks Lead takeover (enforced-v3). */
|
|
104
|
+
export declare const ESCALATE_AFTER_REWORKS = 2;
|
|
105
|
+
/** Lead takeover submissions allowed per escalated work order. */
|
|
106
|
+
export declare const MAX_LEAD_SUBMISSIONS = 3;
|
|
107
|
+
/** Native AgentLoop owns work; optional auxiliary calls use the public LLM service. */
|
|
108
|
+
export declare class FusionCoordinator {
|
|
109
|
+
#private;
|
|
110
|
+
readonly ctx: Context;
|
|
111
|
+
readonly store: SqliteFusionStore;
|
|
112
|
+
readonly options: CoordinatorOptions;
|
|
113
|
+
readonly bindings: BindingRepository;
|
|
114
|
+
readonly scopes: NativeFusionScopes;
|
|
115
|
+
readonly transport: NativeWorkerTransport;
|
|
116
|
+
readonly activity: NativeFusionActivity;
|
|
117
|
+
readonly leases: WorkspaceWriteLease;
|
|
118
|
+
readonly taskContext: NativeTaskContext;
|
|
119
|
+
readonly onDemand: NativeOnDemandContext;
|
|
120
|
+
readonly approvals: NativeApprovals;
|
|
121
|
+
readonly effects: NativeEffects;
|
|
122
|
+
readonly keepalive: NativeCacheKeepalive;
|
|
123
|
+
/** Per-model cache keepalive settings, evidence and defaults (shared with the settings API). */
|
|
124
|
+
readonly cachePolicy: CachePolicy;
|
|
125
|
+
readonly modelControl: NativeModelControl;
|
|
126
|
+
readonly workflow: NativeWorkflow;
|
|
127
|
+
readonly roleSandbox: NativeRoleSandbox;
|
|
128
|
+
constructor(ctx: Context, store: SqliteFusionStore, options: CoordinatorOptions);
|
|
129
|
+
state(id: TaskId): TaskState;
|
|
130
|
+
/**
|
|
131
|
+
* Why a task still owns live work in this Host process, or `undefined` when it
|
|
132
|
+
* owns none. This answers the deletion question that persisted state cannot:
|
|
133
|
+
* `control.mode` and `phase` only ever record what a running process last
|
|
134
|
+
* appended, so a task whose process was replaced keeps `mode: 'running'`
|
|
135
|
+
* forever. The registries below are the truth about what runs *now*.
|
|
136
|
+
*
|
|
137
|
+
* Read-only and side-effect free: it may be called from the delete route.
|
|
138
|
+
*/
|
|
139
|
+
liveWork(id: TaskId): DeletionBlocker | undefined;
|
|
140
|
+
append<T extends FusionEvent['type']>(id: TaskId, type: T, payload: Extract<FusionEvent, {
|
|
141
|
+
type: T;
|
|
142
|
+
}>['payload']): TaskState;
|
|
143
|
+
owner(agent: Agent): {
|
|
144
|
+
binding: SessionBinding;
|
|
145
|
+
role: Role;
|
|
146
|
+
} | undefined;
|
|
147
|
+
select(agent: Agent, resolved?: ResolvedProfile): Promise<void>;
|
|
148
|
+
/** Only at idle selection or native running reservation, before prompt assembly. */
|
|
149
|
+
selectBeforeAssembly(agent: Agent, resolved: ResolvedProfile): void;
|
|
150
|
+
clear(agent: Agent): Promise<void>;
|
|
151
|
+
wait(agent: Agent, exec: ToolRunContext): Promise<string>;
|
|
152
|
+
delegate(agent: Agent, args: DelegateInput, exec: ToolRunContext, mode?: 'explore' | 'implement' | 'text'): Promise<string>;
|
|
153
|
+
rework(agent: Agent, feedback: string, exec: ToolRunContext, block?: boolean, checks?: readonly CheckDefinition[], addAllowedPaths?: readonly string[]): Promise<string>;
|
|
154
|
+
review(agent: Agent, decision: 'accept' | 'rework' | 'needs-decision', reason: string, exec: ToolRunContext, verdicts?: readonly {
|
|
155
|
+
index: number;
|
|
156
|
+
met: boolean;
|
|
157
|
+
evidence: string;
|
|
158
|
+
}[]): string;
|
|
159
|
+
pause(agent: Agent): Promise<void>;
|
|
160
|
+
resume(agent: Agent, authorizationId: string): Promise<void>;
|
|
161
|
+
/** Human command only. Never exposed as an LLM tool or triggered by a dead PID alone. */
|
|
162
|
+
reconcile(agent: Agent, inspection: {
|
|
163
|
+
commandId: string;
|
|
164
|
+
note: string;
|
|
165
|
+
effectsStopped?: boolean;
|
|
166
|
+
}): Promise<void>;
|
|
167
|
+
close(): Promise<void>;
|
|
168
|
+
}
|
|
169
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Lossless text decoding; binary artifacts stay available as explicit base64. */
|
|
2
|
+
export declare function evidenceText(bytes: Uint8Array): string | undefined;
|
|
3
|
+
/** Offsets count UTF-16 code units of text, or characters of base64. */
|
|
4
|
+
export declare function evidencePage(bytes: Uint8Array, offset?: number, limit?: number): {
|
|
5
|
+
bytes: number;
|
|
6
|
+
encoding: string;
|
|
7
|
+
offsetUnit: string;
|
|
8
|
+
offset: number;
|
|
9
|
+
totalCharacters: number;
|
|
10
|
+
text: string;
|
|
11
|
+
truncated: boolean;
|
|
12
|
+
nextOffset: number | null;
|
|
13
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
2
|
+
import type { TaskState } from '../task/state.js';
|
|
3
|
+
import type { NativeUsageRecord } from './native-usage.js';
|
|
4
|
+
import { type Count } from '../usage/ledger.js';
|
|
5
|
+
export interface TaskSummary {
|
|
6
|
+
id: string;
|
|
7
|
+
sessionId: string;
|
|
8
|
+
seq: number;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
updatedAt: string;
|
|
11
|
+
title: string;
|
|
12
|
+
phase: string;
|
|
13
|
+
verification: string;
|
|
14
|
+
mode: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function taskSummary(state: TaskState, createdAt: string, updatedAt: string): TaskSummary;
|
|
17
|
+
export interface UsageSummary {
|
|
18
|
+
id: string;
|
|
19
|
+
taskId: string;
|
|
20
|
+
role: string;
|
|
21
|
+
provider: string;
|
|
22
|
+
model: string;
|
|
23
|
+
purpose: string;
|
|
24
|
+
startedAt: string;
|
|
25
|
+
outcome: string;
|
|
26
|
+
authority: 'none' | 'provisional' | 'final';
|
|
27
|
+
input: Count;
|
|
28
|
+
output: Count;
|
|
29
|
+
reasoning: Count;
|
|
30
|
+
totalOutput: Count;
|
|
31
|
+
cacheRead: Count;
|
|
32
|
+
}
|
|
33
|
+
export declare function usageSummary(row: NativeUsageRecord): UsageSummary;
|
|
34
|
+
/** Once at plugin startup; GET never writes, starts agents, or scans full task/usage snapshots. */
|
|
35
|
+
export declare function backfillHistory(store: SqliteFusionStore): void;
|
|
36
|
+
export interface HistoryTotals {
|
|
37
|
+
calls: number;
|
|
38
|
+
final: number;
|
|
39
|
+
provisional: number;
|
|
40
|
+
unreported: number;
|
|
41
|
+
input: {
|
|
42
|
+
known: number;
|
|
43
|
+
reported: number;
|
|
44
|
+
};
|
|
45
|
+
output: {
|
|
46
|
+
known: number;
|
|
47
|
+
reported: number;
|
|
48
|
+
};
|
|
49
|
+
reasoning: {
|
|
50
|
+
known: number;
|
|
51
|
+
reported: number;
|
|
52
|
+
};
|
|
53
|
+
totalOutput: {
|
|
54
|
+
known: number;
|
|
55
|
+
reported: number;
|
|
56
|
+
};
|
|
57
|
+
cacheRead: {
|
|
58
|
+
known: number;
|
|
59
|
+
reported: number;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** How often the Host unlocked Lead takeover (enforced-v3), by reason. */
|
|
63
|
+
export interface TakeoverTotals {
|
|
64
|
+
total: number;
|
|
65
|
+
tasks: number;
|
|
66
|
+
reasons: Record<string, number>;
|
|
67
|
+
}
|
|
68
|
+
export interface HistoryView {
|
|
69
|
+
observedAt: string;
|
|
70
|
+
totalTasks: number;
|
|
71
|
+
tasks: (TaskSummary & {
|
|
72
|
+
usage: HistoryTotals;
|
|
73
|
+
takeovers: number;
|
|
74
|
+
})[];
|
|
75
|
+
nextCursor: string | null;
|
|
76
|
+
takeovers: TakeoverTotals;
|
|
77
|
+
totals: HistoryTotals;
|
|
78
|
+
groups: ({
|
|
79
|
+
role: string;
|
|
80
|
+
provider: string;
|
|
81
|
+
model: string;
|
|
82
|
+
purpose: string;
|
|
83
|
+
} & HistoryTotals)[];
|
|
84
|
+
actualBilledUsd: null;
|
|
85
|
+
savingsPercent: null;
|
|
86
|
+
upstreamHttpCalls: null;
|
|
87
|
+
}
|
|
88
|
+
export declare function readHistory(store: SqliteFusionStore, cursor?: string, limit?: number): HistoryView;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
export declare function trustedRequest(req: IncomingMessage): boolean;
|
|
3
|
+
export declare function json(res: ServerResponse, status: number, body: unknown): void;
|
|
4
|
+
export declare function readJson(req: IncomingMessage): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
/**
|
|
3
|
+
* Output limits come only from the public model metadata DSH discloses for the route (context window and
|
|
4
|
+
* the adapter's default max tokens). No route or model names are special-cased: route names differ between
|
|
5
|
+
* installations, and a guessed cap would be wrong for someone else's setup.
|
|
6
|
+
*/
|
|
7
|
+
export interface ModelOutputLimits {
|
|
8
|
+
contextWindow: number;
|
|
9
|
+
defaultMaxTokens?: number;
|
|
10
|
+
testedOutputCap?: number;
|
|
11
|
+
}
|
|
12
|
+
/** Public model metadata only; resolving limits does not start a model turn. */
|
|
13
|
+
export declare function resolveModelOutputLimits(ctx: Context, provider: string, model: string): Promise<ModelOutputLimits>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Session } from '@deepseek-ai/dsh-session';
|
|
3
|
+
import type { FusionActivityPage } from '../activity.js';
|
|
4
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
5
|
+
/** Paginated read-only data for a plugin-owned tool view; no runtime activation. */
|
|
6
|
+
export declare function readFusionActivity(store: SqliteFusionStore, parentId: string, callId: string, after?: number): FusionActivityPage;
|
|
7
|
+
/** Old conversations remain readable through the public, non-activating history
|
|
8
|
+
* API. Correlate accepted message ids, never timing guesses or model narration.
|
|
9
|
+
* This fallback neither rewrites the old log nor creates a replacement Worker.
|
|
10
|
+
*/
|
|
11
|
+
export declare function readHistoricalFusionActivity(ctx: Context, store: SqliteFusionStore, parentId: string, callId: string, after?: number): Promise<FusionActivityPage>;
|
|
12
|
+
/** Copies actual Worker tool events into plugin-owned presentation storage only.
|
|
13
|
+
* Model history still contains solely the Lead's native messages and reports.
|
|
14
|
+
* Stored source coordinates make replay/HMR idempotent without executing tools.
|
|
15
|
+
*/
|
|
16
|
+
export declare class NativeFusionActivity {
|
|
17
|
+
#private;
|
|
18
|
+
readonly ctx: Context;
|
|
19
|
+
readonly store: SqliteFusionStore;
|
|
20
|
+
readonly errors: Map<string, string>;
|
|
21
|
+
constructor(ctx: Context, store: SqliteFusionStore);
|
|
22
|
+
/** Called before each native delivery. No inference, dispatch or approval. */
|
|
23
|
+
link(parent: Session, childId: string, taskId: string, callId: string): void;
|
|
24
|
+
flush(): Promise<void>;
|
|
25
|
+
close(): Promise<void>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
3
|
+
import type { LogicalApproval, Role, TaskId } from '../contracts.js';
|
|
4
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
5
|
+
import type { TaskState } from '../task/state.js';
|
|
6
|
+
import type { SessionBinding } from './bindings.js';
|
|
7
|
+
type Owner = {
|
|
8
|
+
binding: SessionBinding;
|
|
9
|
+
role: Role;
|
|
10
|
+
};
|
|
11
|
+
interface Callbacks {
|
|
12
|
+
owner(agent: Agent): Owner | undefined;
|
|
13
|
+
state(id: TaskId): TaskState;
|
|
14
|
+
pending(id: TaskId, approval: LogicalApproval): void;
|
|
15
|
+
answered(id: TaskId, approvalId: string, state: 'approved' | 'rejected' | 'withdrawn'): void;
|
|
16
|
+
failed(agent: Agent, error: unknown): void;
|
|
17
|
+
}
|
|
18
|
+
/** Observe native decisions; never answer on the user's behalf or replay a grant. */
|
|
19
|
+
export declare class NativeApprovals {
|
|
20
|
+
#private;
|
|
21
|
+
readonly ctx: Context;
|
|
22
|
+
readonly store: SqliteFusionStore;
|
|
23
|
+
readonly callbacks: Callbacks;
|
|
24
|
+
constructor(ctx: Context, store: SqliteFusionStore, callbacks: Callbacks);
|
|
25
|
+
install(): () => void;
|
|
26
|
+
/** Caller must first stop/release both native Agents and inspect uncertain effects. */
|
|
27
|
+
reconcile(taskId: TaskId, evidence: string): void;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { GenerateOptions } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import type { Digest, Role, TaskId } from '../contracts.js';
|
|
3
|
+
export interface AuxiliaryRequest {
|
|
4
|
+
purpose: 'cache-keepalive';
|
|
5
|
+
taskId: TaskId;
|
|
6
|
+
sessionId: string;
|
|
7
|
+
profileDigest: Digest;
|
|
8
|
+
role: Role;
|
|
9
|
+
seriesId: string;
|
|
10
|
+
iteration: number;
|
|
11
|
+
}
|
|
12
|
+
/** Plugin-local identity: do not widen or misuse the Host's purpose enum. */
|
|
13
|
+
export declare class NativeAuxiliaryRequests {
|
|
14
|
+
#private;
|
|
15
|
+
tag(request: GenerateOptions, metadata: AuxiliaryRequest): void;
|
|
16
|
+
get(request: GenerateOptions): Readonly<AuxiliaryRequest> | undefined;
|
|
17
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
3
|
+
import type { PhysicalRoute, Role } from '../contracts.js';
|
|
4
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
5
|
+
import type { SessionBinding } from './bindings.js';
|
|
6
|
+
/** Explicit bounded authorization when the native provider exposes no reliable money meter. */
|
|
7
|
+
export interface NativeSpendingAuthorization {
|
|
8
|
+
schemaVersion: 1;
|
|
9
|
+
kind: 'native-fusion-requests';
|
|
10
|
+
approved: true;
|
|
11
|
+
authorizationId: string;
|
|
12
|
+
approvedBy: string;
|
|
13
|
+
expiresAt: string;
|
|
14
|
+
routes: readonly PhysicalRoute[];
|
|
15
|
+
maxNativeRequests: number;
|
|
16
|
+
maxReservedOutputTokens: number;
|
|
17
|
+
/** This cannot be represented as a hard dollar cap. */
|
|
18
|
+
costPolicy: 'unknown-cost-acknowledged';
|
|
19
|
+
}
|
|
20
|
+
export declare function nativeAuthorization(raw: unknown): NativeSpendingAuthorization;
|
|
21
|
+
/** Called only by explicit human settings actions (save or limits), never by a model tool. */
|
|
22
|
+
export declare function authorizeConfiguredPair(store: SqliteFusionStore, routes: readonly PhysicalRoute[], limits: unknown): NativeSpendingAuthorization;
|
|
23
|
+
export declare class NativeRequestBudget {
|
|
24
|
+
readonly store: SqliteFusionStore;
|
|
25
|
+
readonly authorizationFile?: string | undefined;
|
|
26
|
+
constructor(store: SqliteFusionStore, authorizationFile?: string | undefined);
|
|
27
|
+
check(routes: readonly PhysicalRoute[]): NativeSpendingAuthorization;
|
|
28
|
+
install(ctx: Context, owner: (agent: Agent) => {
|
|
29
|
+
binding: SessionBinding;
|
|
30
|
+
role: Role;
|
|
31
|
+
} | undefined, onBlocked?: (binding: SessionBinding, error: unknown) => void): () => void;
|
|
32
|
+
reserve(route: PhysicalRoute, maxOutputTokens: number): void;
|
|
33
|
+
}
|