@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,104 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { ToolRunContext } from '@deepseek-ai/dsh-tools';
|
|
3
|
+
import type { ToolEvidence, WorkOrder, WorkerReport } from '../contracts.js';
|
|
4
|
+
import { evaluateReport } from '../evidence/gate.js';
|
|
5
|
+
import type { CheckPlan, PlannedReceipt } from '../evidence/receipts.js';
|
|
6
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
7
|
+
export interface CheckDefinition {
|
|
8
|
+
id: string;
|
|
9
|
+
description: string;
|
|
10
|
+
command: string;
|
|
11
|
+
kind: 'test' | 'static-check';
|
|
12
|
+
parser: TestParser | 'exit-code';
|
|
13
|
+
/** Existing acceptance test files. Their bytes may not change during execution. May be empty for a new project. */
|
|
14
|
+
definitionPaths: readonly string[];
|
|
15
|
+
/** Per-check limit; defaults to the work-order policy. */
|
|
16
|
+
timeoutSeconds?: number;
|
|
17
|
+
/**
|
|
18
|
+
* `no-new-failures`: a broad regression suite measured against the untouched workspace. The Host runs it
|
|
19
|
+
* once before the Worker starts and freezes the failing test ids; the candidate passes when every failure
|
|
20
|
+
* it shows was already failing there. Default: every test must pass.
|
|
21
|
+
*/
|
|
22
|
+
baseline?: 'no-new-failures';
|
|
23
|
+
}
|
|
24
|
+
/** Parsers that name each failing test, which baseline-relative checks need. Mocha's default report spreads a name over several lines. */
|
|
25
|
+
export declare const BASELINE_PARSERS: readonly ["unittest", "pytest", "vitest", "jest", "tap", "go", "cargo"];
|
|
26
|
+
export type BaselineParser = typeof BASELINE_PARSERS[number];
|
|
27
|
+
export declare const TEST_PARSERS: readonly ["unittest", "pytest", "vitest", "jest", "mocha", "tap", "go", "cargo"];
|
|
28
|
+
export type TestParser = typeof TEST_PARSERS[number];
|
|
29
|
+
export declare const MAX_CHECK_SECONDS = 3600;
|
|
30
|
+
export interface FrozenCheck {
|
|
31
|
+
definition: CheckDefinition;
|
|
32
|
+
plan: CheckPlan;
|
|
33
|
+
}
|
|
34
|
+
/** Shell setup failures need a corrected check, rather than an implementation repair. */
|
|
35
|
+
export declare function checkCommandUnavailable(exitCode: number | null, stderr: string, platform?: NodeJS.Platform): boolean;
|
|
36
|
+
export declare function freezeChecks(order: WorkOrder, root: string, definitions: readonly CheckDefinition[]): FrozenCheck[];
|
|
37
|
+
/**
|
|
38
|
+
* Counts passed tests from a runner's summary. A suite passes when nothing failed or errored and at
|
|
39
|
+
* least one test ran; skipped, deselected, pending, ignored and expected-failure tests were not
|
|
40
|
+
* executed and do not veto the result (real projects routinely skip optional-dependency tests; study
|
|
41
|
+
* 2026-09-26: "799 passed, 86 skipped" blocked an otherwise verified acceptance).
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseTestCounts(parser: CheckDefinition['parser'], text: string): PlannedReceipt['counts'];
|
|
44
|
+
/**
|
|
45
|
+
* Passed count and the ids of failing tests, only when the output names every failure the summary counts:
|
|
46
|
+
* a failure without a name, or two failures under one name, would let a candidate trade a frozen failure for
|
|
47
|
+
* a new one. Ids must stay the same across runs, so positions (TAP numbers, durations) are not part of them.
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseTestFailures(parser: CheckDefinition['parser'], text: string): {
|
|
50
|
+
passed: number;
|
|
51
|
+
failedIds: string[];
|
|
52
|
+
} | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Bare program names each simple command segment starts with. Paths are left
|
|
55
|
+
* out because an earlier `cd` in the same command changes where they resolve;
|
|
56
|
+
* anything this cannot parse is simply not probed.
|
|
57
|
+
*/
|
|
58
|
+
export declare function checkPrograms(command: string, platform?: NodeJS.Platform): string[];
|
|
59
|
+
/**
|
|
60
|
+
* Resolves program names the way the native bash tool will: `bash -c` with the
|
|
61
|
+
* Host's own PATH (its subprocess scrub removes only credential-shaped and
|
|
62
|
+
* DSH_* names). Running here instead of through the tool keeps this read-only
|
|
63
|
+
* probe out of the user's approval flow. Returns undefined when inconclusive,
|
|
64
|
+
* for example without bash; the recorded check result is then the fallback.
|
|
65
|
+
*/
|
|
66
|
+
export declare function probeMissingPrograms(root: string, programs: readonly string[]): Promise<{
|
|
67
|
+
missing: string[];
|
|
68
|
+
alternatives: Record<string, string[]>;
|
|
69
|
+
locations: Record<string, string[]>;
|
|
70
|
+
} | undefined>;
|
|
71
|
+
/**
|
|
72
|
+
* Where a program missing from the Host PATH is installed anyway. A desktop app started from the Dock gets only
|
|
73
|
+
* the system PATH, so Homebrew, version-manager and per-user tools are invisible to bash there; naming the
|
|
74
|
+
* absolute path lets the Lead retry once instead of searching.
|
|
75
|
+
*/
|
|
76
|
+
export declare function programLocations(name: string, home?: string): string[];
|
|
77
|
+
/** Trusted producer: commands run through native dispatch/permission and retain the enclosing tool token. */
|
|
78
|
+
interface CheckInput {
|
|
79
|
+
ctx: Context;
|
|
80
|
+
store: SqliteFusionStore;
|
|
81
|
+
exec: ToolRunContext;
|
|
82
|
+
root: string;
|
|
83
|
+
order: WorkOrder;
|
|
84
|
+
nativeTimeout?: boolean;
|
|
85
|
+
authorizeNested(callId: string): () => void;
|
|
86
|
+
uncertain?(evidence: ToolEvidence): void;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Runs every baseline-relative check on the untouched workspace before the Worker starts and freezes the
|
|
90
|
+
* failing test ids into its plan. An unreadable baseline refuses the delegation: guessing would let a
|
|
91
|
+
* candidate hide new failures.
|
|
92
|
+
*/
|
|
93
|
+
export declare function runBaselineChecks(input: CheckInput & {
|
|
94
|
+
checks: readonly FrozenCheck[];
|
|
95
|
+
}): Promise<FrozenCheck[]>;
|
|
96
|
+
export declare function runNativeChecks(input: CheckInput & {
|
|
97
|
+
report: WorkerReport;
|
|
98
|
+
checks: readonly FrozenCheck[];
|
|
99
|
+
}): Promise<{
|
|
100
|
+
report: WorkerReport;
|
|
101
|
+
receipts: PlannedReceipt[];
|
|
102
|
+
verdict: ReturnType<typeof evaluateReport>;
|
|
103
|
+
}>;
|
|
104
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { GenerateOptions } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import type { PairProfile, PhysicalRoute } from '../contracts.js';
|
|
3
|
+
/**
|
|
4
|
+
* Public llm/stream routing for the Host's mutable, one-shot summary envelope.
|
|
5
|
+
* The Host still owns the compaction transaction and records this exact target.
|
|
6
|
+
* Never replace a prepared AgentLoop request or start a nested model call.
|
|
7
|
+
*/
|
|
8
|
+
export declare function routeNativeCompaction(request: GenerateOptions, profile: PairProfile, effectiveRoute?: PhysicalRoute): void;
|
|
@@ -0,0 +1,36 @@
|
|
|
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 { PhysicalRoute, Role, TokenMeasurement } from '../contracts.js';
|
|
5
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
6
|
+
import type { SessionBinding } from './bindings.js';
|
|
7
|
+
import { type NativeTaskContext } from './native-task-context.js';
|
|
8
|
+
import type { NativeAuxiliaryRequests } from './native-auxiliary.js';
|
|
9
|
+
type Owner = {
|
|
10
|
+
binding: SessionBinding;
|
|
11
|
+
role: Role;
|
|
12
|
+
};
|
|
13
|
+
interface ContextCheck {
|
|
14
|
+
route: PhysicalRoute;
|
|
15
|
+
measurement: TokenMeasurement;
|
|
16
|
+
budget: number;
|
|
17
|
+
purpose: GenerateOptions['purpose'] | 'conversation' | 'cache-keepalive';
|
|
18
|
+
logRevision: number;
|
|
19
|
+
nativeBaseline: string;
|
|
20
|
+
minimumRetainedInputTokens: number;
|
|
21
|
+
}
|
|
22
|
+
/** Optional summary routing, then final admission and the Host's single compaction owner. */
|
|
23
|
+
export declare class NativeContextGuard {
|
|
24
|
+
#private;
|
|
25
|
+
readonly ctx: Context;
|
|
26
|
+
readonly store: SqliteFusionStore;
|
|
27
|
+
readonly owner: (agent: Agent) => Owner | undefined;
|
|
28
|
+
readonly blocked: (owner: Owner, reason: string) => void;
|
|
29
|
+
readonly taskContext?: NativeTaskContext | undefined;
|
|
30
|
+
readonly auxiliary?: NativeAuxiliaryRequests | undefined;
|
|
31
|
+
readonly route?: ((binding: SessionBinding, role: Role) => PhysicalRoute) | undefined;
|
|
32
|
+
constructor(ctx: Context, store: SqliteFusionStore, owner: (agent: Agent) => Owner | undefined, blocked: (owner: Owner, reason: string) => void, taskContext?: NativeTaskContext | undefined, auxiliary?: NativeAuxiliaryRequests | undefined, route?: ((binding: SessionBinding, role: Role) => PhysicalRoute) | undefined);
|
|
33
|
+
measure(agent: Agent, owner: Owner, request: GenerateOptions): Promise<ContextCheck>;
|
|
34
|
+
install(admit: (agent: Agent, owner: Owner, request: GenerateOptions) => void, ready: (agent: Agent, request: GenerateOptions) => void): () => void;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
3
|
+
import type { ToolExecution } from '@deepseek-ai/dsh-tools';
|
|
4
|
+
import type { JobView } from '@deepseek-ai/dsh-jobs';
|
|
5
|
+
import type { ArtifactRef, Role, TaskId } from '../contracts.js';
|
|
6
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
7
|
+
import type { SessionBinding } from './bindings.js';
|
|
8
|
+
interface EffectRecord {
|
|
9
|
+
schemaVersion: 1;
|
|
10
|
+
taskId: TaskId;
|
|
11
|
+
agentId: string;
|
|
12
|
+
role: Role;
|
|
13
|
+
callId: string;
|
|
14
|
+
rootCallId: string;
|
|
15
|
+
toolName: string;
|
|
16
|
+
processId: number;
|
|
17
|
+
startedAt: string;
|
|
18
|
+
state: 'dispatch-started' | 'returned' | 'outcome-unknown' | 'inspected';
|
|
19
|
+
arguments: ArtifactRef;
|
|
20
|
+
endedAt?: string;
|
|
21
|
+
nativeIsError?: boolean;
|
|
22
|
+
inspectionEvidence?: string;
|
|
23
|
+
quiescenceBasis?: 'explicit-user-inspection';
|
|
24
|
+
nativeJob?: {
|
|
25
|
+
id: string;
|
|
26
|
+
startedAt: number;
|
|
27
|
+
deadlineAt: number | null;
|
|
28
|
+
status: JobView['status'];
|
|
29
|
+
detail?: string;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** Public native dispatch journal; it never wraps a provider or invents a PID. */
|
|
33
|
+
export declare class NativeEffects {
|
|
34
|
+
#private;
|
|
35
|
+
readonly ctx: Context;
|
|
36
|
+
readonly store: SqliteFusionStore;
|
|
37
|
+
readonly callbacks: {
|
|
38
|
+
owner(agent: Agent): {
|
|
39
|
+
binding: SessionBinding;
|
|
40
|
+
role: Role;
|
|
41
|
+
} | undefined;
|
|
42
|
+
track(exec: Readonly<ToolExecution>): boolean;
|
|
43
|
+
failed(agent: Agent, error: unknown): void;
|
|
44
|
+
backgroundMaxMs?(exec: Readonly<ToolExecution>, binding: SessionBinding): number | null;
|
|
45
|
+
};
|
|
46
|
+
constructor(ctx: Context, store: SqliteFusionStore, callbacks: {
|
|
47
|
+
owner(agent: Agent): {
|
|
48
|
+
binding: SessionBinding;
|
|
49
|
+
role: Role;
|
|
50
|
+
} | undefined;
|
|
51
|
+
track(exec: Readonly<ToolExecution>): boolean;
|
|
52
|
+
failed(agent: Agent, error: unknown): void;
|
|
53
|
+
backgroundMaxMs?(exec: Readonly<ToolExecution>, binding: SessionBinding): number | null;
|
|
54
|
+
});
|
|
55
|
+
install(): () => void;
|
|
56
|
+
backgroundProblem(exec: Readonly<ToolExecution>): string | undefined;
|
|
57
|
+
jobProblem(exec: Readonly<ToolExecution>, taskId: TaskId): string | undefined;
|
|
58
|
+
waitingForJob(agent: Agent): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Whether a tool call this process is running belongs to this task, or a
|
|
61
|
+
* native job it started there is still unsettled. This is the in-process half
|
|
62
|
+
* of the deletion guard: a durable row alone cannot tell a live call from the
|
|
63
|
+
* residue of an interrupted one, because both look like `dispatch-started`.
|
|
64
|
+
*/
|
|
65
|
+
live(taskId: TaskId): boolean;
|
|
66
|
+
onlyBackgroundPending(taskId: TaskId): boolean;
|
|
67
|
+
stopJobs(taskId: TaskId): Promise<void>;
|
|
68
|
+
pending(taskId: TaskId): readonly {
|
|
69
|
+
id: string;
|
|
70
|
+
record: EffectRecord;
|
|
71
|
+
}[];
|
|
72
|
+
assertInspection(taskId: TaskId, effectsStopped: boolean): void;
|
|
73
|
+
inspected(taskId: TaskId, evidence: string, effectsStopped: boolean): void;
|
|
74
|
+
}
|
|
75
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TaskId } from '../contracts.js';
|
|
2
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
3
|
+
/** Coverage uses logical receipt IDs; ordinary evidence uses content digests. */
|
|
4
|
+
export declare function readNativeEvidence(store: SqliteFusionStore, taskId: TaskId, id: string): Uint8Array;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ExplorationReport, ExplorationSource, WorkOrder } from '../contracts.js';
|
|
2
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
3
|
+
import type { WorkspaceSnapshot } from './workspace.js';
|
|
4
|
+
/**
|
|
5
|
+
* Source-backed handoff. Completed reports are checked against the files they cite,
|
|
6
|
+
* not against every other file in a non-git root. blocked and needs-decision reports
|
|
7
|
+
* are always recorded, with drift or a failed whole-tree snapshot named, and are not acceptance.
|
|
8
|
+
*
|
|
9
|
+
* `current` is omitted when snapshotting the tree threw. The failure is stored on a
|
|
10
|
+
* non-completed report. A completed report ignores that unrelated failure and still
|
|
11
|
+
* stands or falls on the cited files alone.
|
|
12
|
+
*/
|
|
13
|
+
export declare function captureExploration(store: SqliteFusionStore, order: WorkOrder, baseline: WorkspaceSnapshot, current: WorkspaceSnapshot | undefined, submitted: Pick<ExplorationReport, 'summary' | 'status' | 'unresolved'>, sources: readonly ExplorationSource[], snapshotFailure?: string): ExplorationReport;
|
|
14
|
+
/** Path of the first cited file whose bytes no longer match the captured digest, if any. */
|
|
15
|
+
export declare function citedEvidenceChanged(root: string, baseline: WorkspaceSnapshot, report: Pick<ExplorationReport, 'sources'>): string | undefined;
|
|
@@ -0,0 +1,82 @@
|
|
|
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 { Role, TaskId } from '../contracts.js';
|
|
5
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
6
|
+
import type { SessionBinding } from './bindings.js';
|
|
7
|
+
import type { CacheMode } from './cache-defaults.js';
|
|
8
|
+
import { NativeAuxiliaryRequests } from './native-auxiliary.js';
|
|
9
|
+
/** R19 recovered schedule. */
|
|
10
|
+
export declare const KEEPALIVE_INTERVAL_MS = 285000;
|
|
11
|
+
/**
|
|
12
|
+
* The line appended after the copied prefix. maxTokens: 1 is not enough on its own: the ChatGPT Codex route
|
|
13
|
+
* rejects an output cap and pi-ai omits it, so a ping that said "continue" made the Lead think and call tools
|
|
14
|
+
* (live log: median 463 output tokens, all ending in tool calls). Measured 2026-10-01 on gpt-6-astra (Codex):
|
|
15
|
+
* "Reply OK" answered "OK" in 5 output tokens, 0 reasoning, no tool calls, 16/16 with tools still offered,
|
|
16
|
+
* full cache hit; "continue" called tools 8/8 and a bare "OK" read as approval and produced a plan.
|
|
17
|
+
* Tool choice and reasoning effort cannot change here: effort is part of OpenAI's cache key (effort "low"
|
|
18
|
+
* missed the cache entirely) and DSH requests carry no tool_choice.
|
|
19
|
+
*/
|
|
20
|
+
export declare const KEEPALIVE_PROMPT = "Reply OK";
|
|
21
|
+
export declare const KEEPALIVE_ATTEMPTS = 11;
|
|
22
|
+
export interface KeepaliveClock {
|
|
23
|
+
now(): number;
|
|
24
|
+
schedule(callback: () => void, delayMs: number): () => void;
|
|
25
|
+
}
|
|
26
|
+
type Owner = {
|
|
27
|
+
binding: SessionBinding;
|
|
28
|
+
role: Role;
|
|
29
|
+
};
|
|
30
|
+
interface Callbacks {
|
|
31
|
+
owner(agent: Agent): Owner | undefined;
|
|
32
|
+
allowed(agent: Agent, owner: Owner): boolean;
|
|
33
|
+
failed(agent: Agent, reason: string): void;
|
|
34
|
+
/** Per-model mode and interval (user setting, learned, defaults); absent: the pair profile and a fixed interval. */
|
|
35
|
+
policy?(owner: Owner, provider: string, model: string): {
|
|
36
|
+
mode: CacheMode;
|
|
37
|
+
intervalMs: number;
|
|
38
|
+
};
|
|
39
|
+
/** Evidence for learning and the settings page: a request after a wait, or a ping. */
|
|
40
|
+
observe?(owner: Owner, provider: string, model: string, sample: {
|
|
41
|
+
gapSeconds: number;
|
|
42
|
+
ping: boolean;
|
|
43
|
+
hit: boolean;
|
|
44
|
+
cacheRead: number;
|
|
45
|
+
input: number;
|
|
46
|
+
output?: number;
|
|
47
|
+
}): void;
|
|
48
|
+
}
|
|
49
|
+
export interface KeepaliveRecord {
|
|
50
|
+
schemaVersion: 1;
|
|
51
|
+
id: string;
|
|
52
|
+
taskId: TaskId;
|
|
53
|
+
sessionId: string;
|
|
54
|
+
role: Role;
|
|
55
|
+
profileDigest: string;
|
|
56
|
+
inputDigest: string;
|
|
57
|
+
createdAt: string;
|
|
58
|
+
updatedAt: string;
|
|
59
|
+
state: 'generating' | 'scheduled' | 'inflight' | 'stopped';
|
|
60
|
+
attempts: number;
|
|
61
|
+
successes: number;
|
|
62
|
+
stopReason?: string;
|
|
63
|
+
}
|
|
64
|
+
/** Retains only plugin-owned requests in memory; never replays timers on restart. */
|
|
65
|
+
/** Explicit per-role choice; unset is automatic for the Lead (armed only on observed cache reads), off for the Worker. */
|
|
66
|
+
export declare function keepalivePolicy(binding: SessionBinding, role: Role): boolean | 'auto';
|
|
67
|
+
export declare class NativeCacheKeepalive {
|
|
68
|
+
#private;
|
|
69
|
+
readonly ctx: Context;
|
|
70
|
+
readonly store: SqliteFusionStore;
|
|
71
|
+
readonly auxiliary: NativeAuxiliaryRequests;
|
|
72
|
+
readonly callbacks: Callbacks;
|
|
73
|
+
readonly clock: KeepaliveClock;
|
|
74
|
+
constructor(ctx: Context, store: SqliteFusionStore, auxiliary: NativeAuxiliaryRequests, callbacks: Callbacks, clock?: KeepaliveClock);
|
|
75
|
+
stopSession(sessionId: string, reason: string): Promise<void>;
|
|
76
|
+
stopTask(taskId: TaskId, reason: string): Promise<void>;
|
|
77
|
+
/** Called again after asynchronous context measurement, before spend admission. */
|
|
78
|
+
assertRequest(agent: Agent, request: GenerateOptions): void;
|
|
79
|
+
install(): void;
|
|
80
|
+
close(): Promise<void>;
|
|
81
|
+
}
|
|
82
|
+
export {};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
3
|
+
import type { LlmFailure, UserMessage } from '@deepseek-ai/dsh-llm';
|
|
4
|
+
import type { PhysicalRoute, Role } from '../contracts.js';
|
|
5
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
6
|
+
import { type SessionBinding } from './bindings.js';
|
|
7
|
+
export interface ModelControl {
|
|
8
|
+
schemaVersion: 1;
|
|
9
|
+
sessionId: string;
|
|
10
|
+
profileDigest: string;
|
|
11
|
+
epoch: number;
|
|
12
|
+
recoveryEpoch?: number;
|
|
13
|
+
/** Lead-cleared recoverable Worker waits for the current task (bounded). */
|
|
14
|
+
leadRecoveries?: {
|
|
15
|
+
taskId: string;
|
|
16
|
+
count: number;
|
|
17
|
+
};
|
|
18
|
+
routes: Record<Role, PhysicalRoute>;
|
|
19
|
+
waits: Partial<Record<Role, {
|
|
20
|
+
taskId: string;
|
|
21
|
+
code: string;
|
|
22
|
+
at: string;
|
|
23
|
+
retryNotBefore?: string;
|
|
24
|
+
quotaResetAt: null;
|
|
25
|
+
}>>;
|
|
26
|
+
operation?: {
|
|
27
|
+
id: string;
|
|
28
|
+
taskId: string;
|
|
29
|
+
state: 'prepared' | 'dispatching' | 'delivered' | 'failed';
|
|
30
|
+
message?: UserMessage;
|
|
31
|
+
error?: string;
|
|
32
|
+
};
|
|
33
|
+
schedule?: {
|
|
34
|
+
id: string;
|
|
35
|
+
taskId: string;
|
|
36
|
+
epoch: number;
|
|
37
|
+
dueAt: string;
|
|
38
|
+
userSeq: number;
|
|
39
|
+
state: 'scheduled' | 'cancelled' | 'fired' | 'failed';
|
|
40
|
+
reason?: string;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export interface ControlView extends ModelControl {
|
|
44
|
+
revision: number;
|
|
45
|
+
}
|
|
46
|
+
export declare function readModelControl(store: SqliteFusionStore, binding: SessionBinding): ControlView | undefined;
|
|
47
|
+
interface Callbacks {
|
|
48
|
+
owner(agent: Agent): {
|
|
49
|
+
binding: SessionBinding;
|
|
50
|
+
role: Role;
|
|
51
|
+
} | undefined;
|
|
52
|
+
resolve(sessionId: string): Promise<Agent>;
|
|
53
|
+
pause(agent: Agent): Promise<void>;
|
|
54
|
+
resume(agent: Agent): Promise<void>;
|
|
55
|
+
settled(binding: SessionBinding): boolean;
|
|
56
|
+
stopAuxiliary(binding: SessionBinding): void;
|
|
57
|
+
}
|
|
58
|
+
/** Durable local controls. No provider polling, synthetic user identity, or silent routing fallback. */
|
|
59
|
+
export declare class NativeModelControl {
|
|
60
|
+
#private;
|
|
61
|
+
readonly ctx: Context;
|
|
62
|
+
readonly store: SqliteFusionStore;
|
|
63
|
+
readonly callbacks: Callbacks;
|
|
64
|
+
constructor(ctx: Context, store: SqliteFusionStore, callbacks: Callbacks);
|
|
65
|
+
reset(binding: SessionBinding): void;
|
|
66
|
+
write(view: ControlView): number;
|
|
67
|
+
route(binding: SessionBinding, role: Role): PhysicalRoute;
|
|
68
|
+
waiting(binding: SessionBinding, role: Role): {
|
|
69
|
+
taskId: string;
|
|
70
|
+
code: string;
|
|
71
|
+
at: string;
|
|
72
|
+
retryNotBefore?: string;
|
|
73
|
+
quotaResetAt: null;
|
|
74
|
+
} | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* Clear a role wait the Lead can resolve itself by sending a new instruction: a missing report or
|
|
77
|
+
* transition (WORKFLOW_INCOMPLETE), a repeated unchanged result (NO_PROGRESS) or an unclassified
|
|
78
|
+
* error (UNKNOWN). At most LEAD_RECOVERIES per task; quota and credential stops are never cleared here.
|
|
79
|
+
*/
|
|
80
|
+
leadRecover(binding: SessionBinding, role: Role): boolean;
|
|
81
|
+
/** The role stalled again after the Lead already redirected it LEAD_RECOVERIES times this task. */
|
|
82
|
+
recoveriesExhausted(binding: SessionBinding, role: Role): boolean;
|
|
83
|
+
blocked(binding: SessionBinding, role: Role): string | undefined;
|
|
84
|
+
reconcileDelivery(agent: Agent, binding: SessionBinding, evidenceId: string): void;
|
|
85
|
+
failure(binding: SessionBinding, role: Role, failure: LlmFailure): void;
|
|
86
|
+
private require;
|
|
87
|
+
private userSeq;
|
|
88
|
+
cancel(binding: SessionBinding, reason?: string): void;
|
|
89
|
+
schedule(sessionId: string, taskId: string, revision: number, dueAt: string): Promise<void>;
|
|
90
|
+
continue(sessionId: string, taskId: string, revision: number, change?: {
|
|
91
|
+
role: Role;
|
|
92
|
+
route: PhysicalRoute;
|
|
93
|
+
}, scheduledId?: string): Promise<void>;
|
|
94
|
+
private runContinue;
|
|
95
|
+
private clearTimer;
|
|
96
|
+
private arm;
|
|
97
|
+
close(): Promise<void>;
|
|
98
|
+
}
|
|
99
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
2
|
+
import type { Role } from '../contracts.js';
|
|
3
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
4
|
+
import type { SessionBinding } from './bindings.js';
|
|
5
|
+
import type { NativeTaskContext } from './native-task-context.js';
|
|
6
|
+
/** No per-step snapshots. Emit a compact pointer only after loss of context. */
|
|
7
|
+
export declare class NativeOnDemandContext {
|
|
8
|
+
#private;
|
|
9
|
+
readonly store: SqliteFusionStore;
|
|
10
|
+
readonly facts: NativeTaskContext;
|
|
11
|
+
constructor(store: SqliteFusionStore, facts: NativeTaskContext);
|
|
12
|
+
private id;
|
|
13
|
+
message(agent: Agent, binding: SessionBinding, role: Role): ({
|
|
14
|
+
content: {
|
|
15
|
+
type: "text";
|
|
16
|
+
text: string;
|
|
17
|
+
}[];
|
|
18
|
+
source: {
|
|
19
|
+
kind: "plugin:dsh-fusion";
|
|
20
|
+
form: "snapshot";
|
|
21
|
+
sections: {
|
|
22
|
+
name: string;
|
|
23
|
+
text: string;
|
|
24
|
+
}[];
|
|
25
|
+
};
|
|
26
|
+
} & Pick<import("@deepseek-ai/dsh-llm").UserMessage, "role" | "id">) | undefined;
|
|
27
|
+
blocked(agent: Agent, binding: SessionBinding): string | undefined;
|
|
28
|
+
read(agent: Agent, binding: SessionBinding, role: Role, offset?: number, limit?: number): {
|
|
29
|
+
bytes: number;
|
|
30
|
+
encoding: string;
|
|
31
|
+
offsetUnit: string;
|
|
32
|
+
offset: number;
|
|
33
|
+
totalCharacters: number;
|
|
34
|
+
text: string;
|
|
35
|
+
truncated: boolean;
|
|
36
|
+
nextOffset: number | null;
|
|
37
|
+
taskId: import("../contracts.js").TaskId;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
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
|
+
/** Auxiliary native calls may carry a session without an active Agent turn. */
|
|
5
|
+
export declare function nativeRequestAgent(ctx: Context, request: GenerateOptions): Agent | undefined;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
2
|
+
import type { ToolExecution } from '@deepseek-ai/dsh-tools';
|
|
3
|
+
import type { ReviewTicket, TaskId } from '../contracts.js';
|
|
4
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
5
|
+
/** Capture before the Lead request starts; later tool callbacks cannot bind to a newer report. */
|
|
6
|
+
export declare function captureNativeReviewRequest(store: SqliteFusionStore, agent: Agent, turn: number, step: number, ticket: ReviewTicket): void;
|
|
7
|
+
export declare function nativeReviewProof(store: SqliteFusionStore, taskId: TaskId, exec: ToolExecution): {
|
|
8
|
+
ticket: Readonly<ReviewTicket>;
|
|
9
|
+
terminalEvidenceRef: string;
|
|
10
|
+
finishReason: 'tool_calls' | 'stop';
|
|
11
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
3
|
+
import type { ToolExecution } from '@deepseek-ai/dsh-tools';
|
|
4
|
+
import type { Role } from '../contracts.js';
|
|
5
|
+
import type { SqliteFusionStore } from '../task/sqlite-store.js';
|
|
6
|
+
import type { SessionBinding } from './bindings.js';
|
|
7
|
+
type Mode = 'read-only' | 'workspace-write' | 'danger-full-access';
|
|
8
|
+
declare module '@deepseek-ai/dsh-session/types' {
|
|
9
|
+
interface SessionEventMap {
|
|
10
|
+
'sandbox/mode': {
|
|
11
|
+
mode: Mode;
|
|
12
|
+
source?: 'delegation';
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export declare const roleSeparated: (binding: SessionBinding) => boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Role separation enforced below the prompt: the Lead's session runs under the
|
|
19
|
+
* Host's own read-only sandbox (bash and filesystem are refused by the OS
|
|
20
|
+
* backend), while the Sidekick keeps the mode the user chose. The plugin never
|
|
21
|
+
* widens a mode: the Sidekick gets exactly the user's mode, and leaving Fusion
|
|
22
|
+
* restores it on the conversation. Only public session events are written.
|
|
23
|
+
*/
|
|
24
|
+
export declare class NativeRoleSandbox {
|
|
25
|
+
#private;
|
|
26
|
+
readonly ctx: Context;
|
|
27
|
+
readonly store: SqliteFusionStore;
|
|
28
|
+
readonly binding: (sessionId: string) => SessionBinding | undefined;
|
|
29
|
+
constructor(ctx: Context, store: SqliteFusionStore, binding: (sessionId: string) => SessionBinding | undefined);
|
|
30
|
+
/**
|
|
31
|
+
* Called before every model request of an enforced-v3 role. `writer` is true only while the Lead holds the
|
|
32
|
+
* write lease through a Host-unlocked takeover; it then runs under the user's own mode, like the Sidekick.
|
|
33
|
+
*/
|
|
34
|
+
ensure(agent: Agent, binding: SessionBinding, role: Role, writer?: boolean): void;
|
|
35
|
+
/**
|
|
36
|
+
* Frozen acceptance checks are plugin-issued and nested in a Lead tool call, so
|
|
37
|
+
* they would inherit the Lead's read-only session. They run under the user's
|
|
38
|
+
* mode; the Lead's own shell stays refused meanwhile because leadShellProblem
|
|
39
|
+
* requires an actual read-only resolution at execution time.
|
|
40
|
+
*/
|
|
41
|
+
whileChecking<T>(agent: Agent, binding: SessionBinding, run: () => Promise<T>): Promise<T>;
|
|
42
|
+
/** A Lead shell is allowed only when the Host will actually run it read-only and without escalation. */
|
|
43
|
+
leadShellProblem(exec: Readonly<ToolExecution>): string | undefined;
|
|
44
|
+
/** Put the user's own mode back when the conversation leaves Fusion. */
|
|
45
|
+
restore(agent: Agent): void;
|
|
46
|
+
/** A mode switch the user makes while Fusion is selected becomes the Sidekick's mode; the Lead stays read-only. */
|
|
47
|
+
install(): () => void;
|
|
48
|
+
}
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
3
|
+
import type { UserMessage } from '@deepseek-ai/dsh-llm';
|
|
4
|
+
import type { ToolExecution } from '@deepseek-ai/dsh-tools';
|
|
5
|
+
import type { PhysicalRoute, Role } from '../contracts.js';
|
|
6
|
+
import type { SessionBinding } from './bindings.js';
|
|
7
|
+
export interface FusionScopeCallbacks {
|
|
8
|
+
route?(binding: SessionBinding, role: Role): PhysicalRoute;
|
|
9
|
+
beforeTurn?(agent: Agent, binding: SessionBinding, role: Role, turn: number): SessionBinding;
|
|
10
|
+
taskContext?(agent: Agent, binding: SessionBinding, role: Role): UserMessage | undefined;
|
|
11
|
+
beforeStep?(agent: Agent, binding: SessionBinding, role: Role): void;
|
|
12
|
+
projectMessage?(agent: Agent, binding: SessionBinding, role: Role, message: UserMessage): UserMessage;
|
|
13
|
+
/** All independent pause, budget, recovery and unknown-effect gates are checked here. */
|
|
14
|
+
canAccess?(agent: Agent, binding: SessionBinding, role: Role): string | undefined;
|
|
15
|
+
/** Shared gates plus limits that apply only to admitting a new generation. */
|
|
16
|
+
prepareRequest?(agent: Agent, binding: SessionBinding, role: Role, signal: AbortSignal): Promise<void>;
|
|
17
|
+
canRequest(agent: Agent, binding: SessionBinding, role: Role): string | undefined;
|
|
18
|
+
canExecute(exec: Readonly<ToolExecution>, binding: SessionBinding, role: Role): string | undefined;
|
|
19
|
+
beforeRequest(agent: Agent, turn: number, step: number, binding: SessionBinding, role: Role): void;
|
|
20
|
+
/** Disclosed context window for this physical model, read when the request is built. */
|
|
21
|
+
modelLimits?(provider: string, model: string): Promise<{
|
|
22
|
+
contextWindow: number;
|
|
23
|
+
defaultMaxTokens?: number;
|
|
24
|
+
testedOutputCap?: number;
|
|
25
|
+
}>;
|
|
26
|
+
/** Read-stage tools, presented natively. Undefined restores the native composition. */
|
|
27
|
+
readOnlyTools?(agent: Agent, binding: SessionBinding, role: Role): readonly string[] | undefined;
|
|
28
|
+
installTools(scope: Context, agent: Agent, binding: SessionBinding, role: Role): readonly (() => void)[];
|
|
29
|
+
}
|
|
30
|
+
/** Physical routing, prompt and tools live in the exact native Agent scope. */
|
|
31
|
+
export declare class NativeFusionScopes {
|
|
32
|
+
#private;
|
|
33
|
+
private readonly callbacks;
|
|
34
|
+
constructor(callbacks: FusionScopeCallbacks);
|
|
35
|
+
get(agent: Agent): {
|
|
36
|
+
binding: SessionBinding;
|
|
37
|
+
role: Role;
|
|
38
|
+
} | undefined;
|
|
39
|
+
assertReady(agent: Agent): void;
|
|
40
|
+
install(agent: Agent, binding: SessionBinding, role: Role): void;
|
|
41
|
+
/** Refresh at the persisted state transition, before native prompt providers run. */
|
|
42
|
+
refreshTools(agent: Agent): void;
|
|
43
|
+
/**
|
|
44
|
+
* Caller owns quiescence and the original session-controller model selection.
|
|
45
|
+
* Removing these listeners reveals that existing selection; it does not mutate
|
|
46
|
+
* a request header or fabricate a replacement global default.
|
|
47
|
+
*/
|
|
48
|
+
detach(agent: Agent): void;
|
|
49
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
3
|
+
import { LlmAdapter } from '@deepseek-ai/dsh-llm';
|
|
4
|
+
import type { GenerateOptions, LlmModelInfo, LlmResolvedModelInfo, ModelModality, StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
5
|
+
import type { PhysicalRoute } from '../contracts.js';
|
|
6
|
+
import { FUSION_MODEL, FUSION_PROVIDER, isFusionSelection } from '../identity.js';
|
|
7
|
+
import type { ResolvedProfile } from '../profile/resolve.js';
|
|
8
|
+
import type { FusionCoordinator } from './coordinator.js';
|
|
9
|
+
export { FUSION_MODEL, FUSION_PROVIDER, isFusionSelection };
|
|
10
|
+
/** Resolves the configured Lead's declared input modalities; undefined means unconfigured or unverifiable. */
|
|
11
|
+
export type LeadInputModalities = () => Promise<readonly ModelModality[] | undefined>;
|
|
12
|
+
/** Catalog-only local adapter; the native request is physically routed before dispatch. */
|
|
13
|
+
export declare class FusionCatalogAdapter extends LlmAdapter {
|
|
14
|
+
private readonly leadInputModalities?;
|
|
15
|
+
constructor(leadInputModalities?: LeadInputModalities | undefined);
|
|
16
|
+
providerInfo(provider: string): {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
};
|
|
20
|
+
listModels(provider: string): Promise<readonly LlmModelInfo[]>;
|
|
21
|
+
resolveModel(provider: string, model: string): Promise<LlmResolvedModelInfo>;
|
|
22
|
+
stream(_options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
23
|
+
}
|
|
24
|
+
/** Public native lifecycle integration. No model-menu replacement or Host patch. */
|
|
25
|
+
export declare function installNativeFusionSelection(ctx: Context, input: {
|
|
26
|
+
coordinator(): FusionCoordinator | undefined;
|
|
27
|
+
profile(): ResolvedProfile | undefined;
|
|
28
|
+
selection(agent: Agent): PhysicalRoute | undefined;
|
|
29
|
+
}): () => void;
|