cascade-ai 0.20.0 → 0.20.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/bin/cascade.js +0 -0
- package/dist/cli.cjs +3511 -662
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +3509 -661
- package/dist/cli.js.map +1 -1
- package/dist/desktop-core.cjs +6684 -1950
- package/dist/index.cjs +3023 -410
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +955 -10
- package/dist/index.d.ts +955 -10
- package/dist/index.js +2959 -386
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import EventEmitter from 'node:events';
|
|
2
|
+
import { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
2
3
|
import { Server } from 'node:http';
|
|
4
|
+
import { OAuthClientInformationMixed, OAuthTokens, OAuthClientMetadata, OAuthClientInformationFull } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
5
|
+
export { OAuthClientInformationMixed, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
6
|
+
import Database from 'better-sqlite3';
|
|
3
7
|
|
|
4
8
|
type ProviderType = 'anthropic' | 'openai' | 'gemini' | 'azure' | 'openai-compatible' | 'ollama';
|
|
5
9
|
interface ModelInfo {
|
|
@@ -18,6 +22,13 @@ interface ModelInfo {
|
|
|
18
22
|
supportsToolUse?: boolean;
|
|
19
23
|
/** Self-declared or API-sourced specialization categories. */
|
|
20
24
|
specializations?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Canonical base-model id this entry stands for, when `id` isn't itself
|
|
27
|
+
* canonical. Azure deployments are addressed by an arbitrary deployment name
|
|
28
|
+
* (the `id`), but back a real model (e.g. gpt-5) — `baseModelId` carries that
|
|
29
|
+
* real identity so benchmark scoring and live pricing resolve correctly.
|
|
30
|
+
*/
|
|
31
|
+
baseModelId?: string;
|
|
21
32
|
}
|
|
22
33
|
interface ProviderConfig {
|
|
23
34
|
type: ProviderType;
|
|
@@ -104,9 +115,14 @@ interface ImageAttachment {
|
|
|
104
115
|
}
|
|
105
116
|
interface McpServerConfig$1 {
|
|
106
117
|
name: string;
|
|
107
|
-
command
|
|
118
|
+
command?: string;
|
|
108
119
|
args?: string[];
|
|
109
120
|
env?: Record<string, string>;
|
|
121
|
+
url?: string;
|
|
122
|
+
headers?: Record<string, string>;
|
|
123
|
+
/** Path to a JSON store of this server's OAuth state (desktop/CLI). When set,
|
|
124
|
+
* the run attaches an auto-refreshing OAuth token instead of a static header. */
|
|
125
|
+
oauthStore?: string;
|
|
110
126
|
}
|
|
111
127
|
interface ToolDefinition {
|
|
112
128
|
name: string;
|
|
@@ -390,6 +406,8 @@ interface CascadeConfig {
|
|
|
390
406
|
budget: BudgetConfig;
|
|
391
407
|
theme: string;
|
|
392
408
|
workspace: WorkspaceConfig;
|
|
409
|
+
/** Extended context: compact history/input that exceeds the model's window. */
|
|
410
|
+
extendedContext?: ExtendedContextConfig;
|
|
393
411
|
cascadeAuto?: boolean;
|
|
394
412
|
/** Cascade Auto trade-off bias when picking a model. Default: 'balanced'. */
|
|
395
413
|
autoBias?: 'balanced' | 'quality' | 'cost';
|
|
@@ -402,6 +420,12 @@ interface CascadeConfig {
|
|
|
402
420
|
knowledge?: {
|
|
403
421
|
factsExtraction?: boolean;
|
|
404
422
|
};
|
|
423
|
+
/** Workspace code index (Phase 3). Opt-in; registers a `code_search` tool. */
|
|
424
|
+
codeIndex?: {
|
|
425
|
+
enabled?: boolean;
|
|
426
|
+
autoRefresh?: boolean;
|
|
427
|
+
dbPath?: string;
|
|
428
|
+
};
|
|
405
429
|
plugins?: string[];
|
|
406
430
|
localConcurrency?: number;
|
|
407
431
|
localInferenceTimeoutMs?: number;
|
|
@@ -425,6 +449,10 @@ interface CascadeConfig {
|
|
|
425
449
|
enabled?: boolean;
|
|
426
450
|
maxRounds?: number;
|
|
427
451
|
};
|
|
452
|
+
/** Fast answer behaviour. `autoSimple`: pure small talk skips orchestration for a direct single-model reply. Default: true. */
|
|
453
|
+
fastAnswer?: {
|
|
454
|
+
autoSimple?: boolean;
|
|
455
|
+
};
|
|
428
456
|
/** T3 wave execution: 'auto' (sequential for local, parallel for cloud), or force one. Default: 'auto'. */
|
|
429
457
|
t3Execution?: 'auto' | 'parallel' | 'sequential';
|
|
430
458
|
/** T3→T2 reinforcement: let a worker ask its manager to spawn sibling workers. Off by default. */
|
|
@@ -451,6 +479,10 @@ interface CascadeConfig {
|
|
|
451
479
|
*/
|
|
452
480
|
routing?: {
|
|
453
481
|
forceTier?: 'auto' | 'T1' | 'T2' | 'T3';
|
|
482
|
+
/** Override the model-performance stats file (cloud → persistent volume). */
|
|
483
|
+
perfStatsPath?: string;
|
|
484
|
+
/** Read shared scores but don't record this run's outcomes when false. Default true. */
|
|
485
|
+
learnFromOutcomes?: boolean;
|
|
454
486
|
};
|
|
455
487
|
/** Render the TUI in the alternate screen buffer (vim-style). Default: false. */
|
|
456
488
|
altScreen?: boolean;
|
|
@@ -478,6 +510,10 @@ interface BenchmarksConfig {
|
|
|
478
510
|
sourceUrl?: string;
|
|
479
511
|
/** Fetch current per-token prices from OpenRouter (free, no key). Default: true. */
|
|
480
512
|
pricingLive?: boolean;
|
|
513
|
+
/** Where the fetched live snapshot is cached. Cloud → the persistent volume,
|
|
514
|
+
* so live benchmark scores survive redeploys and are shared across requests
|
|
515
|
+
* instead of re-fetched on every fresh Cascade. Defaults to ~/.cascade. */
|
|
516
|
+
cacheFile?: string;
|
|
481
517
|
}
|
|
482
518
|
interface ToolsConfig {
|
|
483
519
|
shellAllowlist: string[];
|
|
@@ -538,11 +574,30 @@ interface MemoryConfig {
|
|
|
538
574
|
maxSessionMessages: number;
|
|
539
575
|
autoSummarizeAt: number;
|
|
540
576
|
retentionDays: number;
|
|
577
|
+
/**
|
|
578
|
+
* Opt-in: after a run completes, distill durable facts from the session into
|
|
579
|
+
* the project knowledge store (undoable per-fact from the Knowledge tab).
|
|
580
|
+
* Off by default — session content stays out of long-term memory unless the
|
|
581
|
+
* user chooses otherwise.
|
|
582
|
+
*/
|
|
583
|
+
rememberSessions?: boolean;
|
|
584
|
+
}
|
|
585
|
+
interface ExtendedContextConfig {
|
|
586
|
+
/** Off by default — when on, oversized history/input is compacted to fit. */
|
|
587
|
+
enabled: boolean;
|
|
588
|
+
/** How far past the model's native window an input may go before it's
|
|
589
|
+
* truncated (via chunk + map-reduce). 2 = up to 2× the window. */
|
|
590
|
+
maxMultiplier: number;
|
|
541
591
|
}
|
|
542
592
|
interface TierLimits {
|
|
543
593
|
t1MaxTokens?: number;
|
|
544
594
|
t2MaxTokens?: number;
|
|
545
595
|
t3MaxTokens?: number;
|
|
596
|
+
/** Per-tier sampling temperature (0–2). Applied only when a call doesn't set
|
|
597
|
+
* its own temperature — deterministic internal calls (temperature: 0) win. */
|
|
598
|
+
t1Temperature?: number;
|
|
599
|
+
t2Temperature?: number;
|
|
600
|
+
t3Temperature?: number;
|
|
546
601
|
}
|
|
547
602
|
interface BudgetConfig {
|
|
548
603
|
dailyBudgetUsd?: number;
|
|
@@ -583,7 +638,7 @@ interface ThemeColors {
|
|
|
583
638
|
t2Color: string;
|
|
584
639
|
t3Color: string;
|
|
585
640
|
}
|
|
586
|
-
type CascadeEventType = 'task:start' | 'task:complete' | 'task:error' | 'tier:status' | 'tier:result' | 'tier:root' | 'stream:token' | 'stream:done' | 'tool:approval-request' | 'tool:approval-response' | 'tool:execute' | 'tool:result' | 'tool:call' | 'cost:update' | 'session:save' | 'escalation' | 'peer:sync' | 'peer:message' | 'plan' | 'log' | 'run:cancelled' | 'budget:warning' | 'budget:exceeded' | 'permission:user-required' | 'mcp:approval-required' | 'plan:approval-required';
|
|
641
|
+
type CascadeEventType = 'task:start' | 'task:complete' | 'task:error' | 'tier:status' | 'tier:result' | 'tier:root' | 'stream:token' | 'stream:done' | 'tool:approval-request' | 'tool:approval-response' | 'tool:execute' | 'tool:result' | 'tool:call' | 'cost:update' | 'session:save' | 'escalation' | 'peer:sync' | 'peer:message' | 'plan' | 'log' | 'run:cancelled' | 'budget:warning' | 'budget:exceeded' | 'permission:user-required' | 'mcp:approval-required' | 'plan:approval-required' | 'context:approval-required' | 'context:compacted';
|
|
587
642
|
interface CascadeEvent<T = unknown> {
|
|
588
643
|
type: CascadeEventType;
|
|
589
644
|
taskId?: string;
|
|
@@ -717,6 +772,36 @@ interface CascadeRunOptions {
|
|
|
717
772
|
* controller.abort();
|
|
718
773
|
*/
|
|
719
774
|
signal?: AbortSignal;
|
|
775
|
+
/**
|
|
776
|
+
* An optional, pre-computed complexity verdict for this run — e.g. from a
|
|
777
|
+
* cheap on-device classifier the caller ran first. When provided (and no tier
|
|
778
|
+
* is manually forced), the orchestrator uses it as the starting verdict and
|
|
779
|
+
* skips its own classifier LLM call, saving that round-trip. The heuristic
|
|
780
|
+
* complexity floors and mid-run escalation still apply, so an under-estimate
|
|
781
|
+
* can't strand genuinely complex work on a cheap tier. Only the first three
|
|
782
|
+
* levels are accepted as a hint; 'Highly Complex' is derived server-side.
|
|
783
|
+
*/
|
|
784
|
+
complexityHint?: Exclude<TaskComplexity, 'Highly Complex'>;
|
|
785
|
+
/**
|
|
786
|
+
* "Fast answer" — bypass the whole T1/T2/T3 orchestration and reply with a
|
|
787
|
+
* single mid-tier model, no tools and no artifact verification. For quick
|
|
788
|
+
* questions and small edits where the multi-agent machinery just adds latency
|
|
789
|
+
* and cost. The reply still streams and is persisted like a normal turn.
|
|
790
|
+
*/
|
|
791
|
+
fastAnswer?: boolean;
|
|
792
|
+
/**
|
|
793
|
+
* The user's ACTUAL message, for routing decisions only, when `prompt` has
|
|
794
|
+
* been augmented by the host (system guidance, memories, documents). The
|
|
795
|
+
* complexity heuristics/classifier and task-type analysis read this instead
|
|
796
|
+
* of the augmented prompt, so a bare "hi" still routes as small talk. The
|
|
797
|
+
* model still receives the full `prompt`. Defaults to `prompt` when unset.
|
|
798
|
+
*/
|
|
799
|
+
routingPrompt?: string;
|
|
800
|
+
/**
|
|
801
|
+
* Optional model id to use for a fast answer (e.g. 'gpt-4o-mini'). When unset,
|
|
802
|
+
* a validated mid-tier model is auto-selected. Ignored unless `fastAnswer`.
|
|
803
|
+
*/
|
|
804
|
+
fastAnswerModel?: string;
|
|
720
805
|
}
|
|
721
806
|
interface CascadeRunResult {
|
|
722
807
|
output: string;
|
|
@@ -738,8 +823,23 @@ interface CascadeRunResult {
|
|
|
738
823
|
declare class ModelSelector {
|
|
739
824
|
private availableProviders;
|
|
740
825
|
private availableModels;
|
|
826
|
+
/**
|
|
827
|
+
* Per-provider set of model ids the provider's own API confirmed it serves
|
|
828
|
+
* (from listModels discovery). When present for a provider, AUTO selection
|
|
829
|
+
* skips that provider's bundled catalog ids that aren't in the set — so a
|
|
830
|
+
* stale/access-gated catalog id is never picked, then 404'd, then failed over.
|
|
831
|
+
* Absent for a provider ⇒ no validation ran ⇒ behave exactly as before.
|
|
832
|
+
*/
|
|
833
|
+
private validatedIds;
|
|
741
834
|
constructor(availableProviders: Set<ProviderType>);
|
|
742
835
|
addDynamicModel(model: ModelInfo): void;
|
|
836
|
+
/** Record the ids a provider's API actually serves (discovery). Empty ⇒ ignored. */
|
|
837
|
+
setValidatedModels(provider: ProviderType, ids: string[]): void;
|
|
838
|
+
/**
|
|
839
|
+
* A model is usable for AUTO selection when its provider is available AND —
|
|
840
|
+
* if that provider was validated — the id is one the provider confirmed.
|
|
841
|
+
*/
|
|
842
|
+
private isUsable;
|
|
743
843
|
/**
|
|
744
844
|
* Permanently drop a model from the available set for this session. Used by
|
|
745
845
|
* the router's 404 / "model not found" self-heal so a dead id is never
|
|
@@ -777,6 +877,11 @@ interface ModelStat {
|
|
|
777
877
|
totalRetries: number;
|
|
778
878
|
totalCostUsd: number;
|
|
779
879
|
sampleCount: number;
|
|
880
|
+
/** Sum of input/context tokens across samples — so we can see whether a
|
|
881
|
+
* model tends to fail on larger contexts and route less to it accordingly. */
|
|
882
|
+
totalContextTokens: number;
|
|
883
|
+
/** Sum of context tokens on the FAILED samples only. */
|
|
884
|
+
failureContextTokens: number;
|
|
780
885
|
}
|
|
781
886
|
interface FeatureStat {
|
|
782
887
|
totalCostUsd: number;
|
|
@@ -786,11 +891,19 @@ declare class ModelPerformanceTracker {
|
|
|
786
891
|
private stats;
|
|
787
892
|
private featureStats;
|
|
788
893
|
private readonly statsFile;
|
|
894
|
+
private readonly readOnly;
|
|
789
895
|
private loaded;
|
|
790
|
-
|
|
896
|
+
/**
|
|
897
|
+
* @param statsFile where stats persist (cloud → the persistent volume).
|
|
898
|
+
* @param options.readOnly consume the shared scores but don't record/save this
|
|
899
|
+
* run's outcomes — the opt-out path for users who declined to contribute.
|
|
900
|
+
*/
|
|
901
|
+
constructor(statsFile?: string, options?: {
|
|
902
|
+
readOnly?: boolean;
|
|
903
|
+
});
|
|
791
904
|
load(): Promise<void>;
|
|
792
905
|
save(): Promise<void>;
|
|
793
|
-
record(modelId: string, taskType: TaskType, outcome: 'success' | 'failure', retries?: number, costUsd?: number): void;
|
|
906
|
+
record(modelId: string, taskType: TaskType, outcome: 'success' | 'failure', retries?: number, costUsd?: number, contextTokens?: number): void;
|
|
794
907
|
recordFeatureCost(featureTag: string, costUsd: number): void;
|
|
795
908
|
/**
|
|
796
909
|
* Record an explicit user rating (good/bad). Counts as 3 automatic samples
|
|
@@ -856,7 +969,7 @@ declare class TaskAnalyzer {
|
|
|
856
969
|
* Record the outcome of a completed run across all tiers that were selected
|
|
857
970
|
* during this session and persist stats to disk.
|
|
858
971
|
*/
|
|
859
|
-
recordRunOutcome(outcome: 'success' | 'failure', costByTier: Record<string, number
|
|
972
|
+
recordRunOutcome(outcome: 'success' | 'failure', costByTier: Record<string, number>, contextTokens?: number): void;
|
|
860
973
|
/**
|
|
861
974
|
* Record an explicit user rating (good/bad) for the last run's selected models.
|
|
862
975
|
* Explicit ratings carry 3× the weight of auto-detected outcomes.
|
|
@@ -1080,6 +1193,12 @@ declare class WorldStateDB {
|
|
|
1080
1193
|
private dbPath;
|
|
1081
1194
|
private encryptionKey;
|
|
1082
1195
|
constructor(workspacePath: string, debugMode?: boolean);
|
|
1196
|
+
/**
|
|
1197
|
+
* Append the CURRENTLY-stored fact for (e, r) to the history ledger before it
|
|
1198
|
+
* is overwritten/deleted, timestamped [its recorded time → now]. No-op when
|
|
1199
|
+
* there is no current row. The value stays encrypted with the same key.
|
|
1200
|
+
*/
|
|
1201
|
+
private archiveCurrentFact;
|
|
1083
1202
|
private initEncryptionKey;
|
|
1084
1203
|
private encrypt;
|
|
1085
1204
|
private decrypt;
|
|
@@ -1117,8 +1236,27 @@ declare class WorldStateDB {
|
|
|
1117
1236
|
* delete — users can prune what the planner remembers about their project.
|
|
1118
1237
|
*/
|
|
1119
1238
|
deleteFact(entity: string, relation: string): boolean;
|
|
1120
|
-
/** Delete every fact. Returns how many were removed. */
|
|
1239
|
+
/** Delete every fact. Returns how many were removed. History is preserved. */
|
|
1121
1240
|
clearFacts(): number;
|
|
1241
|
+
/**
|
|
1242
|
+
* Prior values for one (entity, relation), newest-first — the durable trail of
|
|
1243
|
+
* what this fact used to be before it was overwritten or deleted. Decrypted
|
|
1244
|
+
* here (the ciphertext never leaves this process).
|
|
1245
|
+
*/
|
|
1246
|
+
getFactHistory(entity: string, relation: string): Array<{
|
|
1247
|
+
value: string;
|
|
1248
|
+
sourceWorker: string;
|
|
1249
|
+
validFrom: string;
|
|
1250
|
+
validTo: string;
|
|
1251
|
+
change: string;
|
|
1252
|
+
}>;
|
|
1253
|
+
/**
|
|
1254
|
+
* Restore a historical value for (entity, relation) as the current fact. The
|
|
1255
|
+
* value currently in place (if any) is itself archived first, so restore is
|
|
1256
|
+
* undoable. When `validFrom` is given, restores that exact historical entry;
|
|
1257
|
+
* otherwise restores the most recent one. Returns whether anything was restored.
|
|
1258
|
+
*/
|
|
1259
|
+
restoreFact(entity: string, relation: string, validFrom?: string): boolean;
|
|
1122
1260
|
exportKnowledge(): {
|
|
1123
1261
|
facts: WorldFact[];
|
|
1124
1262
|
worldLog: WorldStateEntry[];
|
|
@@ -1272,6 +1410,15 @@ declare class CascadeRouter extends EventEmitter {
|
|
|
1272
1410
|
refreshLiveData(): Promise<void>;
|
|
1273
1411
|
/** Returns the live-data provider once refreshLiveData has run (UX/insight). */
|
|
1274
1412
|
getLiveData(): LiveDataProvider | undefined;
|
|
1413
|
+
/**
|
|
1414
|
+
* Validate the official cloud providers (anthropic/openai/gemini) against
|
|
1415
|
+
* their own /models list at init time so AUTO selection only picks a model the
|
|
1416
|
+
* key actually serves. This is the fix for "a non-existent catalog model gets
|
|
1417
|
+
* selected, then the run fails over through several models before one works".
|
|
1418
|
+
* Cached per key (TTL) so a per-request router doesn't re-discover; fully
|
|
1419
|
+
* best-effort + time-boxed, so offline/error simply keeps the bundled catalog.
|
|
1420
|
+
*/
|
|
1421
|
+
private validateCloudProviderModels;
|
|
1275
1422
|
/**
|
|
1276
1423
|
* Query each available cloud provider's live model list and register the
|
|
1277
1424
|
* results. Confirms catalog ids still exist and surfaces newly released
|
|
@@ -1322,6 +1469,12 @@ declare class CascadeRouter extends EventEmitter {
|
|
|
1322
1469
|
/** Set (or clear) the current run's abort signal for instant cancellation. */
|
|
1323
1470
|
setRunSignal(signal: AbortSignal | undefined): void;
|
|
1324
1471
|
getSelector(): ModelSelector;
|
|
1472
|
+
/**
|
|
1473
|
+
* The tightest context window (in tokens) across the resolved tier models, or
|
|
1474
|
+
* undefined if none are resolved yet. Extended-context compaction budgets
|
|
1475
|
+
* against this so the compacted context fits whichever tier handles the run.
|
|
1476
|
+
*/
|
|
1477
|
+
getReferenceContextWindow(): number | undefined;
|
|
1325
1478
|
/** Wire the Cascade Auto task analyzer used for per-subtask model routing. */
|
|
1326
1479
|
setTaskAnalyzer(analyzer: TaskAnalyzer): void;
|
|
1327
1480
|
setWorldStateDB(db: WorldStateDB | undefined): void;
|
|
@@ -1399,6 +1552,8 @@ declare class CascadeRouter extends EventEmitter {
|
|
|
1399
1552
|
* Used to populate the desktop model pickers with the user's real models.
|
|
1400
1553
|
*/
|
|
1401
1554
|
getAvailableModels(): ModelInfo[];
|
|
1555
|
+
/** Logs why a configured provider failed its availability probe. */
|
|
1556
|
+
private emitProbeFailure;
|
|
1402
1557
|
private detectAvailableProviders;
|
|
1403
1558
|
private discoverOllamaModels;
|
|
1404
1559
|
/** Returns true when at least one real model was discovered from the endpoint. */
|
|
@@ -1451,9 +1606,11 @@ declare abstract class BaseTool {
|
|
|
1451
1606
|
|
|
1452
1607
|
interface McpServerConfig {
|
|
1453
1608
|
name: string;
|
|
1454
|
-
command
|
|
1609
|
+
command?: string;
|
|
1455
1610
|
args?: string[];
|
|
1456
1611
|
env?: Record<string, string>;
|
|
1612
|
+
url?: string;
|
|
1613
|
+
headers?: Record<string, string>;
|
|
1457
1614
|
}
|
|
1458
1615
|
/**
|
|
1459
1616
|
* Gate called before each MCP server is spawned. Lets the caller (REPL or
|
|
@@ -1487,7 +1644,16 @@ declare class McpClient {
|
|
|
1487
1644
|
private approvalCallback;
|
|
1488
1645
|
private onWarn;
|
|
1489
1646
|
constructor(options?: McpClientOptions);
|
|
1490
|
-
connect(server: McpServerConfig
|
|
1647
|
+
connect(server: McpServerConfig, opts?: {
|
|
1648
|
+
authProvider?: OAuthClientProvider;
|
|
1649
|
+
}): Promise<void>;
|
|
1650
|
+
/**
|
|
1651
|
+
* Connect to a remote MCP server. Tries Streamable HTTP first (the current
|
|
1652
|
+
* transport); if that fails (a legacy server that only speaks SSE), retries
|
|
1653
|
+
* once over SSE. Auth headers ride on every request. Returns the live
|
|
1654
|
+
* transport so the caller can register it.
|
|
1655
|
+
*/
|
|
1656
|
+
private connectRemote;
|
|
1491
1657
|
disconnect(serverName: string): Promise<void>;
|
|
1492
1658
|
disconnectAll(): Promise<void>;
|
|
1493
1659
|
callTool(serverName: string, toolName: string, input: Record<string, unknown>): Promise<string>;
|
|
@@ -1813,13 +1979,14 @@ declare class T1Administrator extends BaseTier {
|
|
|
1813
1979
|
/** One entry in the per-run orchestration decision trail (see /why). */
|
|
1814
1980
|
interface DecisionLogEntry {
|
|
1815
1981
|
at: string;
|
|
1816
|
-
kind: 'complexity' | 'model' | 'failover' | 'escalation';
|
|
1982
|
+
kind: 'complexity' | 'model' | 'failover' | 'escalation' | 'context';
|
|
1817
1983
|
detail: string;
|
|
1818
1984
|
}
|
|
1819
1985
|
declare class Cascade extends EventEmitter {
|
|
1820
1986
|
private router;
|
|
1821
1987
|
private toolRegistry;
|
|
1822
1988
|
private mcpClient;
|
|
1989
|
+
private codeIndex?;
|
|
1823
1990
|
private config;
|
|
1824
1991
|
/** Orchestration decisions for the CURRENT run — cleared on each run(). */
|
|
1825
1992
|
private decisionLog;
|
|
@@ -1855,6 +2022,13 @@ declare class Cascade extends EventEmitter {
|
|
|
1855
2022
|
*/
|
|
1856
2023
|
private pendingMcpApprovals;
|
|
1857
2024
|
private requestMcpApproval;
|
|
2025
|
+
/**
|
|
2026
|
+
* Build the workspace code index and register the `code_search` tool. Uses the
|
|
2027
|
+
* user's own provider key for embeddings (and, if chat-capable, reranking).
|
|
2028
|
+
* The index persists to a per-workspace SQLite file; `autoRefresh` brings it
|
|
2029
|
+
* up to date at init (incremental — only changed files re-embed).
|
|
2030
|
+
*/
|
|
2031
|
+
private initCodeIndex;
|
|
1858
2032
|
private recordDecision;
|
|
1859
2033
|
/**
|
|
1860
2034
|
* The orchestration decision trail for the most recent run: complexity
|
|
@@ -1872,6 +2046,18 @@ declare class Cascade extends EventEmitter {
|
|
|
1872
2046
|
* directly (no re-decompose).
|
|
1873
2047
|
*/
|
|
1874
2048
|
resolvePlanApproval(approved: boolean, note?: string, editedPlan?: TaskPlan): void;
|
|
2049
|
+
private pendingContextApproval?;
|
|
2050
|
+
/** Resolve a pending extended-context confirmation from a UI listener. */
|
|
2051
|
+
resolveContextApproval(approved: boolean): void;
|
|
2052
|
+
private requestContextApproval;
|
|
2053
|
+
/**
|
|
2054
|
+
* Extended context: when enabled, compact an over-budget conversation history
|
|
2055
|
+
* (rolling summary — cheap, automatic) and/or a single oversized input (chunk
|
|
2056
|
+
* + map-reduce — confirm-gated) so the run fits the model's window. Returns a
|
|
2057
|
+
* new options object with the compacted prompt/history; a no-op when disabled,
|
|
2058
|
+
* when nothing overflows, or when the model window isn't known yet.
|
|
2059
|
+
*/
|
|
2060
|
+
private applyExtendedContext;
|
|
1875
2061
|
/**
|
|
1876
2062
|
* Autonomy control (used by the /auto command). 'auto' makes the next run
|
|
1877
2063
|
* hands-off: the plan gate auto-approves and non-dangerous tools auto-approve,
|
|
@@ -1919,6 +2105,22 @@ declare class Cascade extends EventEmitter {
|
|
|
1919
2105
|
private estimatePlanCost;
|
|
1920
2106
|
init(): Promise<void>;
|
|
1921
2107
|
private isCasualGreeting;
|
|
2108
|
+
/**
|
|
2109
|
+
* Pure small talk that a single tool-less model answers best: greetings,
|
|
2110
|
+
* acknowledgements and self-identity questions. Deliberately NARROWER than
|
|
2111
|
+
* looksLikeConversational — "what is X" / "show me Y" / "list Z" need tools
|
|
2112
|
+
* or real lookup and stay on the worker path. Bare confirmations ("yes",
|
|
2113
|
+
* "ok") in an ongoing conversation are task input, not small talk.
|
|
2114
|
+
*/
|
|
2115
|
+
private looksLikeSmallTalk;
|
|
2116
|
+
/**
|
|
2117
|
+
* A terse option/menu selection ("3", "b)", "option 2") replying to an
|
|
2118
|
+
* ongoing conversation. These inherit the prior turn's intent — they are
|
|
2119
|
+
* usually an ACTION choice, so they must not be short-circuited to a
|
|
2120
|
+
* tool-less direct answer, and a context-free on-device hint about them
|
|
2121
|
+
* is noise (the hint classifier never saw the conversation).
|
|
2122
|
+
*/
|
|
2123
|
+
private looksLikeTerseOptionReply;
|
|
1922
2124
|
private looksLikeSimpleArtifactTask;
|
|
1923
2125
|
private looksLikeConversational;
|
|
1924
2126
|
/**
|
|
@@ -1951,8 +2153,31 @@ declare class Cascade extends EventEmitter {
|
|
|
1951
2153
|
private looksLikeModerateBuild;
|
|
1952
2154
|
private static globCache;
|
|
1953
2155
|
private countWorkspaceFiles;
|
|
2156
|
+
/**
|
|
2157
|
+
* Raises a raw complexity verdict (from the classifier LLM or a caller hint)
|
|
2158
|
+
* to the tier the prompt's signals demand. A small model that under-rates
|
|
2159
|
+
* clearly multi-step build work can't strand it below where it belongs:
|
|
2160
|
+
* explicit build+scale signals floor it to Complex (full T1→T2→T3), and a
|
|
2161
|
+
* single-deliverable build floors a "Simple" up to Moderate (one manager).
|
|
2162
|
+
* Conservative on purpose — the source is free to go higher, and a manual
|
|
2163
|
+
* tier override is the escape hatch. Records the decision it makes.
|
|
2164
|
+
*/
|
|
2165
|
+
private floorComplexity;
|
|
1954
2166
|
private determineComplexity;
|
|
1955
2167
|
run(options: CascadeRunOptions): Promise<CascadeRunResult>;
|
|
2168
|
+
/**
|
|
2169
|
+
* Direct single-model reply — the "fast answer" path. No planning, no workers,
|
|
2170
|
+
* no tools, no artifact verification: the user's message (with recent history)
|
|
2171
|
+
* answered by one mid-tier model, streamed as the primary output and shaped
|
|
2172
|
+
* into the normal CascadeRunResult so persistence + the run receipt still work.
|
|
2173
|
+
*/
|
|
2174
|
+
private runFastAnswer;
|
|
2175
|
+
/**
|
|
2176
|
+
* Distill a completed session into durable facts and store them in the
|
|
2177
|
+
* project knowledge graph (opt-in via memory.rememberSessions). Best-effort:
|
|
2178
|
+
* skips trivial exchanges, uses one cheap T3 call, and swallows all errors.
|
|
2179
|
+
*/
|
|
2180
|
+
private rememberSession;
|
|
1956
2181
|
getRouter(): CascadeRouter;
|
|
1957
2182
|
getToolRegistry(): ToolRegistry;
|
|
1958
2183
|
/**
|
|
@@ -2589,6 +2814,519 @@ interface HookResult {
|
|
|
2589
2814
|
error?: string;
|
|
2590
2815
|
}
|
|
2591
2816
|
|
|
2817
|
+
/** The persisted state of one MCP server's OAuth: DCR result, tokens, PKCE verifier. */
|
|
2818
|
+
interface McpOAuthState {
|
|
2819
|
+
clientInformation?: OAuthClientInformationMixed;
|
|
2820
|
+
tokens?: OAuthTokens;
|
|
2821
|
+
codeVerifier?: string;
|
|
2822
|
+
}
|
|
2823
|
+
/** Pluggable persistence for a single server's OAuth state (differs per surface). */
|
|
2824
|
+
interface McpOAuthStore {
|
|
2825
|
+
load(): McpOAuthState | undefined | Promise<McpOAuthState | undefined>;
|
|
2826
|
+
save(state: McpOAuthState): void | Promise<void>;
|
|
2827
|
+
clear?(): void | Promise<void>;
|
|
2828
|
+
}
|
|
2829
|
+
interface McpOAuthProviderOptions {
|
|
2830
|
+
/** Where the authorization server redirects back (our callback / loopback). */
|
|
2831
|
+
redirectUrl: string;
|
|
2832
|
+
store: McpOAuthStore;
|
|
2833
|
+
/** Send the user to the authorization URL (open a browser / hand it to the web). */
|
|
2834
|
+
redirect: (authorizationUrl: URL) => void | Promise<void>;
|
|
2835
|
+
clientName?: string;
|
|
2836
|
+
scope?: string;
|
|
2837
|
+
/** Fixed OAuth `state` (e.g. the cloud pending-flow key). Random if omitted. */
|
|
2838
|
+
state?: string;
|
|
2839
|
+
}
|
|
2840
|
+
/**
|
|
2841
|
+
* Our `OAuthClientProvider`: storage + redirect for the MCP SDK's OAuth client.
|
|
2842
|
+
* The SDK calls these hooks while it runs discovery/DCR/PKCE/refresh for us.
|
|
2843
|
+
*/
|
|
2844
|
+
declare class McpOAuthProvider implements OAuthClientProvider {
|
|
2845
|
+
private readonly opts;
|
|
2846
|
+
private cache;
|
|
2847
|
+
private readonly _state;
|
|
2848
|
+
constructor(opts: McpOAuthProviderOptions);
|
|
2849
|
+
/** The `state` this provider uses — callers validate it on the callback. */
|
|
2850
|
+
get oauthState(): string;
|
|
2851
|
+
private loaded;
|
|
2852
|
+
private persist;
|
|
2853
|
+
get redirectUrl(): string;
|
|
2854
|
+
get clientMetadata(): OAuthClientMetadata;
|
|
2855
|
+
state(): string;
|
|
2856
|
+
clientInformation(): Promise<OAuthClientInformationMixed | undefined>;
|
|
2857
|
+
saveClientInformation(info: OAuthClientInformationFull): Promise<void>;
|
|
2858
|
+
tokens(): Promise<OAuthTokens | undefined>;
|
|
2859
|
+
saveTokens(tokens: OAuthTokens): Promise<void>;
|
|
2860
|
+
redirectToAuthorization(authorizationUrl: URL): Promise<void>;
|
|
2861
|
+
saveCodeVerifier(codeVerifier: string): Promise<void>;
|
|
2862
|
+
codeVerifier(): Promise<string>;
|
|
2863
|
+
invalidateCredentials(scope: 'all' | 'client' | 'tokens' | 'verifier' | 'discovery'): Promise<void>;
|
|
2864
|
+
}
|
|
2865
|
+
/** A 0600 JSON file store for one server's OAuth state (desktop/CLI). */
|
|
2866
|
+
declare class FileMcpOAuthStore implements McpOAuthStore {
|
|
2867
|
+
private readonly filePath;
|
|
2868
|
+
constructor(filePath: string);
|
|
2869
|
+
load(): McpOAuthState | undefined;
|
|
2870
|
+
save(state: McpOAuthState): void;
|
|
2871
|
+
clear(): void;
|
|
2872
|
+
}
|
|
2873
|
+
/**
|
|
2874
|
+
* Build a refresh-only provider over a file store, for a run connecting an
|
|
2875
|
+
* already-authorized OAuth MCP server. Refresh is silent; if the refresh token
|
|
2876
|
+
* is dead the transport would need a browser redirect, which a headless run
|
|
2877
|
+
* can't do — so `redirect` throws a clear "reconnect" message instead.
|
|
2878
|
+
*/
|
|
2879
|
+
declare function fileOAuthProvider(storePath: string): McpOAuthProvider;
|
|
2880
|
+
/** Drive the OAuth flow to the point of a browser redirect (or already-authorized). */
|
|
2881
|
+
declare function beginMcpOAuth(provider: OAuthClientProvider, serverUrl: string): Promise<'AUTHORIZED' | 'REDIRECT'>;
|
|
2882
|
+
/** Complete the flow with the authorization code (saves tokens via the provider). */
|
|
2883
|
+
declare function completeMcpOAuth(provider: OAuthClientProvider, serverUrl: string, authorizationCode: string): Promise<void>;
|
|
2884
|
+
/** The authorization server (issuer) protecting an MCP server, if it advertises one. */
|
|
2885
|
+
declare function discoverMcpAuthServer(serverUrl: string): Promise<string | undefined>;
|
|
2886
|
+
/** Refresh an access token from a stored refresh token + client registration. */
|
|
2887
|
+
declare function refreshMcpToken(input: {
|
|
2888
|
+
authorizationServerUrl: string;
|
|
2889
|
+
clientInformation: OAuthClientInformationMixed;
|
|
2890
|
+
refreshToken: string;
|
|
2891
|
+
}): Promise<OAuthTokens>;
|
|
2892
|
+
interface LoopbackOAuthResult {
|
|
2893
|
+
tokens: OAuthTokens;
|
|
2894
|
+
clientInformation?: OAuthClientInformationMixed;
|
|
2895
|
+
}
|
|
2896
|
+
/**
|
|
2897
|
+
* Run the full OAuth connect for a rich native client: open a one-shot
|
|
2898
|
+
* `127.0.0.1` listener, let the MCP SDK drive discovery/DCR/PKCE, open the
|
|
2899
|
+
* system browser via `openUrl`, catch the code on the loopback, finish the
|
|
2900
|
+
* exchange, and return the tokens (also persisted through `store`).
|
|
2901
|
+
*/
|
|
2902
|
+
declare function connectMcpWithLoopbackOAuth(opts: {
|
|
2903
|
+
serverUrl: string;
|
|
2904
|
+
store: McpOAuthStore;
|
|
2905
|
+
openUrl: (url: string) => void | Promise<void>;
|
|
2906
|
+
clientName?: string;
|
|
2907
|
+
scope?: string;
|
|
2908
|
+
signal?: AbortSignal;
|
|
2909
|
+
timeoutMs?: number;
|
|
2910
|
+
}): Promise<LoopbackOAuthResult>;
|
|
2911
|
+
|
|
2912
|
+
/** A unit of indexed text. `sourceId` groups chunks from one document/file. */
|
|
2913
|
+
interface Chunk {
|
|
2914
|
+
id: string;
|
|
2915
|
+
text: string;
|
|
2916
|
+
sourceId: string;
|
|
2917
|
+
/** Order of this chunk within its source (0-based). */
|
|
2918
|
+
ord: number;
|
|
2919
|
+
meta?: Record<string, unknown>;
|
|
2920
|
+
}
|
|
2921
|
+
/** A chunk with a relevance score (higher = more relevant). */
|
|
2922
|
+
interface ScoredChunk extends Chunk {
|
|
2923
|
+
score: number;
|
|
2924
|
+
}
|
|
2925
|
+
/** Turns text into embedding vectors. Implementations wrap a provider API or a
|
|
2926
|
+
* local model. `model` + `dims` are recorded with every vector so a future
|
|
2927
|
+
* model change forces a clean re-index rather than silent quality rot. */
|
|
2928
|
+
interface Embedder {
|
|
2929
|
+
readonly model: string;
|
|
2930
|
+
/** Vector dimension. 0 until the first embed call resolves it. */
|
|
2931
|
+
readonly dims: number;
|
|
2932
|
+
/** Embed a batch of texts → one vector per input (same order). */
|
|
2933
|
+
embed(texts: string[]): Promise<number[][]>;
|
|
2934
|
+
}
|
|
2935
|
+
interface SearchOptions {
|
|
2936
|
+
namespace: string;
|
|
2937
|
+
k?: number;
|
|
2938
|
+
/** Restrict results to these source ids (e.g. the docs attached to a run). */
|
|
2939
|
+
sourceIds?: string[];
|
|
2940
|
+
}
|
|
2941
|
+
/** Persists chunk vectors and answers the two first-stage queries of hybrid
|
|
2942
|
+
* retrieval. The Phase-1 implementation is SQLite-backed (BLOB vectors +
|
|
2943
|
+
* FTS5), swappable later for a dedicated ANN index behind this interface. */
|
|
2944
|
+
interface VectorStore {
|
|
2945
|
+
upsert(records: Array<{
|
|
2946
|
+
chunk: Chunk;
|
|
2947
|
+
vector: number[];
|
|
2948
|
+
}>, embedModel: string): void;
|
|
2949
|
+
/** True once this source has chunks for the given embed model (skip re-embed). */
|
|
2950
|
+
hasSource(namespace: string, sourceId: string, embedModel: string): boolean;
|
|
2951
|
+
lexicalSearch(query: string, opts: SearchOptions): ScoredChunk[];
|
|
2952
|
+
denseSearch(queryVector: number[], opts: SearchOptions): ScoredChunk[];
|
|
2953
|
+
deleteSource(namespace: string, sourceId: string): void;
|
|
2954
|
+
}
|
|
2955
|
+
|
|
2956
|
+
interface ChunkOptions {
|
|
2957
|
+
/** Target chunk size in characters (~512 tokens by default). */
|
|
2958
|
+
targetChars?: number;
|
|
2959
|
+
/** Overlap carried from the end of one chunk into the next. */
|
|
2960
|
+
overlapChars?: number;
|
|
2961
|
+
/** Drop a trailing chunk smaller than this unless it's the only one. */
|
|
2962
|
+
minChars?: number;
|
|
2963
|
+
}
|
|
2964
|
+
/**
|
|
2965
|
+
* Chunk prose/markdown into overlapping windows. Returns `{ text, ord }` in
|
|
2966
|
+
* document order. Deterministic and dependency-free.
|
|
2967
|
+
*/
|
|
2968
|
+
declare function chunkText(input: string, options?: ChunkOptions): Array<{
|
|
2969
|
+
text: string;
|
|
2970
|
+
ord: number;
|
|
2971
|
+
}>;
|
|
2972
|
+
|
|
2973
|
+
interface OpenAIEmbedderOptions {
|
|
2974
|
+
apiKey?: string;
|
|
2975
|
+
baseURL?: string;
|
|
2976
|
+
model: string;
|
|
2977
|
+
/** Matryoshka truncation for text-embedding-3-* (e.g. 512). Omit for native. */
|
|
2978
|
+
dimensions?: number;
|
|
2979
|
+
}
|
|
2980
|
+
/**
|
|
2981
|
+
* Embedder backed by an OpenAI-compatible `/v1/embeddings` endpoint. Works
|
|
2982
|
+
* against OpenAI, OpenAI-compatible gateways, and Ollama (which exposes the same
|
|
2983
|
+
* route) — so the cloud uses a provider API and desktop/CLI can point at a local
|
|
2984
|
+
* Ollama with no separate runtime.
|
|
2985
|
+
*/
|
|
2986
|
+
declare class OpenAICompatibleEmbedder implements Embedder {
|
|
2987
|
+
readonly model: string;
|
|
2988
|
+
private client;
|
|
2989
|
+
private dimensions;
|
|
2990
|
+
private resolvedDims;
|
|
2991
|
+
constructor(opts: OpenAIEmbedderOptions);
|
|
2992
|
+
get dims(): number;
|
|
2993
|
+
embed(texts: string[]): Promise<number[][]>;
|
|
2994
|
+
}
|
|
2995
|
+
/**
|
|
2996
|
+
* Pick an embeddings-capable provider from the user's configured providers and
|
|
2997
|
+
* build an Embedder, or return null when none can embed (e.g. an Anthropic-only
|
|
2998
|
+
* setup). Prefers a hosted OpenAI/compatible key over a local Ollama.
|
|
2999
|
+
*/
|
|
3000
|
+
declare function embedderFromProviders(providers: ProviderConfig[], opts?: {
|
|
3001
|
+
model?: string;
|
|
3002
|
+
dimensions?: number;
|
|
3003
|
+
}): Embedder | null;
|
|
3004
|
+
|
|
3005
|
+
declare class SqliteVectorStore implements VectorStore {
|
|
3006
|
+
private db;
|
|
3007
|
+
constructor(db: Database.Database);
|
|
3008
|
+
private migrate;
|
|
3009
|
+
upsert(records: Array<{
|
|
3010
|
+
chunk: Chunk;
|
|
3011
|
+
vector: number[];
|
|
3012
|
+
}>, embedModel: string): void;
|
|
3013
|
+
hasSource(namespace: string, sourceId: string, embedModel: string): boolean;
|
|
3014
|
+
deleteSource(namespace: string, sourceId: string): void;
|
|
3015
|
+
lexicalSearch(query: string, opts: SearchOptions): ScoredChunk[];
|
|
3016
|
+
denseSearch(queryVector: number[], opts: SearchOptions): ScoredChunk[];
|
|
3017
|
+
private sourceFilter;
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
interface Reranker {
|
|
3021
|
+
readonly name: string;
|
|
3022
|
+
/** Reorder candidates for a query; return the best `topK`, best-first. */
|
|
3023
|
+
rerank(query: string, candidates: ScoredChunk[], topK: number): Promise<ScoredChunk[]>;
|
|
3024
|
+
}
|
|
3025
|
+
/** A minimal text-completion function (prompt in, text out). */
|
|
3026
|
+
type CompleteFn = (prompt: string) => Promise<string>;
|
|
3027
|
+
/** Parse a model's "3,1,4" answer into 0-based indices, keeping only valid,
|
|
3028
|
+
* in-range, non-duplicate entries. Returns null when nothing parses. */
|
|
3029
|
+
declare function parseRankOrder(reply: string, count: number): number[] | null;
|
|
3030
|
+
declare class LLMReranker implements Reranker {
|
|
3031
|
+
readonly name = "llm-listwise";
|
|
3032
|
+
private complete;
|
|
3033
|
+
/** Cap on candidates sent to the model (keeps the prompt + cost bounded). */
|
|
3034
|
+
private maxCandidates;
|
|
3035
|
+
constructor(opts: {
|
|
3036
|
+
complete: CompleteFn;
|
|
3037
|
+
maxCandidates?: number;
|
|
3038
|
+
});
|
|
3039
|
+
rerank(query: string, candidates: ScoredChunk[], topK: number): Promise<ScoredChunk[]>;
|
|
3040
|
+
}
|
|
3041
|
+
/**
|
|
3042
|
+
* Build a completion function from the user's providers using an OpenAI-
|
|
3043
|
+
* compatible `/chat/completions` endpoint (OpenAI, compatible gateways, Ollama).
|
|
3044
|
+
* Returns null when no such provider is configured (reranking then no-ops and
|
|
3045
|
+
* the fused order stands). Mirrors embedderFromProviders so the same key powers
|
|
3046
|
+
* both stages.
|
|
3047
|
+
*/
|
|
3048
|
+
declare function chatCompleterFromProviders(providers: ProviderConfig[], opts?: {
|
|
3049
|
+
model?: string;
|
|
3050
|
+
}): CompleteFn | null;
|
|
3051
|
+
|
|
3052
|
+
interface RetrieverSearchOptions {
|
|
3053
|
+
namespace: string;
|
|
3054
|
+
/** Final number of chunks to return. */
|
|
3055
|
+
k?: number;
|
|
3056
|
+
/** Restrict to these source ids (e.g. only this run's attached docs). */
|
|
3057
|
+
sourceIds?: string[];
|
|
3058
|
+
/** Candidates to pull from each first stage before fusion. */
|
|
3059
|
+
candidates?: number;
|
|
3060
|
+
/** RRF damping constant (higher = flatter). Standard default is 60. */
|
|
3061
|
+
rrfK?: number;
|
|
3062
|
+
/** Rerank the fused candidates when a reranker is configured (default true). */
|
|
3063
|
+
rerank?: boolean;
|
|
3064
|
+
}
|
|
3065
|
+
/**
|
|
3066
|
+
* Fuse several ranked lists into one by Reciprocal Rank Fusion. Each list
|
|
3067
|
+
* contributes 1/(rrfK + rank) to an item's score; identical items across lists
|
|
3068
|
+
* accumulate. Returns items best-first.
|
|
3069
|
+
*/
|
|
3070
|
+
declare function reciprocalRankFusion(lists: ScoredChunk[][], rrfK?: number): ScoredChunk[];
|
|
3071
|
+
declare class Retriever {
|
|
3072
|
+
private readonly embedder;
|
|
3073
|
+
private readonly store;
|
|
3074
|
+
/** Optional second-stage reranker (Phase 2). When set, search reranks the
|
|
3075
|
+
* fused candidates before returning the top-k. */
|
|
3076
|
+
private readonly reranker?;
|
|
3077
|
+
constructor(embedder: Embedder, store: VectorStore,
|
|
3078
|
+
/** Optional second-stage reranker (Phase 2). When set, search reranks the
|
|
3079
|
+
* fused candidates before returning the top-k. */
|
|
3080
|
+
reranker?: Reranker | undefined);
|
|
3081
|
+
/** Chunk model this retriever embeds with (for cache/version keys). */
|
|
3082
|
+
get embedModel(): string;
|
|
3083
|
+
/** True when this source is already indexed under the current embed model. */
|
|
3084
|
+
isIndexed(namespace: string, sourceId: string): boolean;
|
|
3085
|
+
/**
|
|
3086
|
+
* Embed and store a source's chunks. Skips work when the source is already
|
|
3087
|
+
* indexed under the current embed model (so re-runs don't re-embed). Returns
|
|
3088
|
+
* the number of chunks newly indexed.
|
|
3089
|
+
*/
|
|
3090
|
+
index(namespace: string, sourceId: string, chunks: Array<{
|
|
3091
|
+
text: string;
|
|
3092
|
+
ord: number;
|
|
3093
|
+
}>): Promise<number>;
|
|
3094
|
+
/** Hybrid search: lexical ∪ dense, fused with RRF, then optionally reranked. */
|
|
3095
|
+
search(query: string, opts: RetrieverSearchOptions): Promise<ScoredChunk[]>;
|
|
3096
|
+
}
|
|
3097
|
+
|
|
3098
|
+
type RetrievalMode = 'none' | 'cag' | 'rag' | 'graph' | 'code';
|
|
3099
|
+
interface RetrievalContext {
|
|
3100
|
+
/** Retrievable sources attached to this run (e.g. documents). */
|
|
3101
|
+
sourceCount: number;
|
|
3102
|
+
/** Total characters across those sources. */
|
|
3103
|
+
totalChars: number;
|
|
3104
|
+
/** Below this size, sources are injected in full (cache-augmented). */
|
|
3105
|
+
cagCharBudget: number;
|
|
3106
|
+
/** A single direct model call — no orchestration/retrieval machinery. */
|
|
3107
|
+
fastAnswer?: boolean;
|
|
3108
|
+
}
|
|
3109
|
+
interface RetrievalPlan {
|
|
3110
|
+
mode: RetrievalMode;
|
|
3111
|
+
/** Human-readable rationale (surfaced in notices / decision logs). */
|
|
3112
|
+
reason: string;
|
|
3113
|
+
}
|
|
3114
|
+
/** Rough characters-per-token, the standard ~4:1 approximation for English text. */
|
|
3115
|
+
declare const CHARS_PER_TOKEN = 4;
|
|
3116
|
+
/**
|
|
3117
|
+
* The character budget below which attached documents are injected in full
|
|
3118
|
+
* (CAG) rather than retrieved (RAG) — derived from the model context window
|
|
3119
|
+
* instead of a fixed byte cliff. Reserve most of the window for the system
|
|
3120
|
+
* prompt, conversation history, and the model's own output, and let attached
|
|
3121
|
+
* documents occupy up to `docFraction` of what the window can hold. A larger
|
|
3122
|
+
* window therefore admits larger documents in full; retrieval only kicks in
|
|
3123
|
+
* for corpora that genuinely wouldn't fit. (A 52 KB doc is ~13k tokens — it
|
|
3124
|
+
* fits comfortably in any modern window, so it should never be forced to RAG.)
|
|
3125
|
+
*/
|
|
3126
|
+
declare function cagCharBudget(contextWindowTokens: number, opts?: {
|
|
3127
|
+
docFraction?: number;
|
|
3128
|
+
charsPerToken?: number;
|
|
3129
|
+
}): number;
|
|
3130
|
+
/**
|
|
3131
|
+
* Choose the retrieval mode for a run. Pure and deterministic so it's unit-
|
|
3132
|
+
* testable and reusable across cloud, desktop, and CLI.
|
|
3133
|
+
*/
|
|
3134
|
+
declare function planRetrieval(ctx: RetrievalContext): RetrievalPlan;
|
|
3135
|
+
|
|
3136
|
+
interface CodeChunker {
|
|
3137
|
+
chunk(text: string, opts?: {
|
|
3138
|
+
filename?: string;
|
|
3139
|
+
}): Array<{
|
|
3140
|
+
text: string;
|
|
3141
|
+
ord: number;
|
|
3142
|
+
}>;
|
|
3143
|
+
}
|
|
3144
|
+
interface CodeChunkOptions {
|
|
3145
|
+
targetChars?: number;
|
|
3146
|
+
/** Lines of trailing context carried into the next chunk when a segment is
|
|
3147
|
+
* hard-split (0 for whole-definition segments, which don't need it). */
|
|
3148
|
+
overlapLines?: number;
|
|
3149
|
+
filename?: string;
|
|
3150
|
+
}
|
|
3151
|
+
/**
|
|
3152
|
+
* Chunk source code into definition-aligned, size-bounded pieces. Returns
|
|
3153
|
+
* `{ text, ord }` in file order. Deterministic and dependency-free.
|
|
3154
|
+
*/
|
|
3155
|
+
declare function chunkCode(text: string, opts?: CodeChunkOptions): Array<{
|
|
3156
|
+
text: string;
|
|
3157
|
+
ord: number;
|
|
3158
|
+
}>;
|
|
3159
|
+
/** Default heuristic implementation of the CodeChunker seam. */
|
|
3160
|
+
declare const heuristicCodeChunker: CodeChunker;
|
|
3161
|
+
|
|
3162
|
+
interface FileManifest {
|
|
3163
|
+
/** repo-relative path → content hash (hex). */
|
|
3164
|
+
files: Record<string, string>;
|
|
3165
|
+
/** Fingerprint over the whole (sorted) manifest — equal roots ⇒ no changes. */
|
|
3166
|
+
root: string;
|
|
3167
|
+
}
|
|
3168
|
+
interface ManifestDiff {
|
|
3169
|
+
added: string[];
|
|
3170
|
+
changed: string[];
|
|
3171
|
+
removed: string[];
|
|
3172
|
+
unchanged: string[];
|
|
3173
|
+
}
|
|
3174
|
+
declare function hashContent(content: string | Buffer): string;
|
|
3175
|
+
declare function buildManifest(entries: Array<{
|
|
3176
|
+
path: string;
|
|
3177
|
+
hash: string;
|
|
3178
|
+
}>): FileManifest;
|
|
3179
|
+
declare function diffManifest(oldManifest: FileManifest | null, next: FileManifest): ManifestDiff;
|
|
3180
|
+
|
|
3181
|
+
interface WorkspaceIndexOptions {
|
|
3182
|
+
root: string;
|
|
3183
|
+
/** better-sqlite3 DB hosting vectors + the manifest. */
|
|
3184
|
+
db: Database.Database;
|
|
3185
|
+
embedder: Embedder;
|
|
3186
|
+
reranker?: Reranker;
|
|
3187
|
+
/** Predicate for paths to skip (e.g. CascadeIgnore.isIgnored bound to root). */
|
|
3188
|
+
isIgnored?: (absPath: string) => boolean;
|
|
3189
|
+
namespace?: string;
|
|
3190
|
+
extensions?: string[];
|
|
3191
|
+
maxFileBytes?: number;
|
|
3192
|
+
chunker?: CodeChunker;
|
|
3193
|
+
}
|
|
3194
|
+
interface RefreshResult {
|
|
3195
|
+
filesIndexed: number;
|
|
3196
|
+
filesRemoved: number;
|
|
3197
|
+
filesUnchanged: number;
|
|
3198
|
+
chunks: number;
|
|
3199
|
+
root: string;
|
|
3200
|
+
}
|
|
3201
|
+
declare class WorkspaceIndex {
|
|
3202
|
+
private readonly root;
|
|
3203
|
+
private readonly db;
|
|
3204
|
+
private readonly store;
|
|
3205
|
+
private readonly retriever;
|
|
3206
|
+
private readonly namespace;
|
|
3207
|
+
private readonly extensions;
|
|
3208
|
+
private readonly maxFileBytes;
|
|
3209
|
+
private readonly isIgnored;
|
|
3210
|
+
private readonly chunker;
|
|
3211
|
+
constructor(opts: WorkspaceIndexOptions);
|
|
3212
|
+
private migrate;
|
|
3213
|
+
/** Recursively collect indexable files under root (relative paths). */
|
|
3214
|
+
private collectFiles;
|
|
3215
|
+
private loadStoredManifest;
|
|
3216
|
+
private saveManifest;
|
|
3217
|
+
/**
|
|
3218
|
+
* Scan the workspace and bring the index up to date, re-embedding only files
|
|
3219
|
+
* whose contents changed since the last refresh. Returns what changed.
|
|
3220
|
+
*/
|
|
3221
|
+
refresh(onFile?: (rel: string) => void): Promise<RefreshResult>;
|
|
3222
|
+
/** Hybrid + reranked search over the indexed codebase. */
|
|
3223
|
+
search(query: string, k?: number): Promise<ScoredChunk[]>;
|
|
3224
|
+
}
|
|
3225
|
+
|
|
3226
|
+
/** The slice of world-state this retriever needs — so it's testable in isolation. */
|
|
3227
|
+
interface GraphFactSource {
|
|
3228
|
+
getAllFacts(): WorldFact[];
|
|
3229
|
+
getFactsForEntities(entities: string[]): WorldFact[];
|
|
3230
|
+
}
|
|
3231
|
+
interface GraphSearchOptions {
|
|
3232
|
+
/** How many hops to expand from the seed entities (default 1). */
|
|
3233
|
+
hops?: number;
|
|
3234
|
+
/** Max facts to return. */
|
|
3235
|
+
limit?: number;
|
|
3236
|
+
}
|
|
3237
|
+
interface RankedFact extends WorldFact {
|
|
3238
|
+
/** Query-overlap score (higher = more relevant); 0 for pure hop-neighbors. */
|
|
3239
|
+
score: number;
|
|
3240
|
+
/** Hop distance from a seed entity (0 = seed). */
|
|
3241
|
+
hop: number;
|
|
3242
|
+
}
|
|
3243
|
+
declare class GraphRetriever {
|
|
3244
|
+
private readonly source;
|
|
3245
|
+
constructor(source: GraphFactSource);
|
|
3246
|
+
/**
|
|
3247
|
+
* Retrieve facts relevant to a query, expanding the graph a few hops from the
|
|
3248
|
+
* entities the query mentions. Returns facts ranked by relevance.
|
|
3249
|
+
*/
|
|
3250
|
+
search(query: string, opts?: GraphSearchOptions): RankedFact[];
|
|
3251
|
+
/** Human-readable "- entity relation value" lines for injection into a run. */
|
|
3252
|
+
format(facts: RankedFact[]): string;
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3255
|
+
/**
|
|
3256
|
+
* Lets a worker search the indexed workspace codebase by meaning + keywords and
|
|
3257
|
+
* get back the most relevant passages with their file paths. Backed by the
|
|
3258
|
+
* hybrid + reranked WorkspaceIndex, so it finds code by concept, not just exact
|
|
3259
|
+
* string match.
|
|
3260
|
+
*/
|
|
3261
|
+
declare class CodeSearchTool extends BaseTool {
|
|
3262
|
+
private readonly index;
|
|
3263
|
+
readonly name = "code_search";
|
|
3264
|
+
readonly description = "Search the indexed workspace codebase for code relevant to a query (semantic + keyword). Returns the most relevant snippets with their file paths. Use to find where something is implemented or how an API is used.";
|
|
3265
|
+
readonly inputSchema: {
|
|
3266
|
+
type: string;
|
|
3267
|
+
properties: {
|
|
3268
|
+
query: {
|
|
3269
|
+
type: string;
|
|
3270
|
+
description: string;
|
|
3271
|
+
};
|
|
3272
|
+
k: {
|
|
3273
|
+
type: string;
|
|
3274
|
+
description: string;
|
|
3275
|
+
};
|
|
3276
|
+
};
|
|
3277
|
+
required: string[];
|
|
3278
|
+
};
|
|
3279
|
+
constructor(index: WorkspaceIndex);
|
|
3280
|
+
execute(input: Record<string, unknown>, _options: ToolExecuteOptions): Promise<string>;
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3283
|
+
/**
|
|
3284
|
+
* Lets a worker query the project knowledge graph (world-state) for facts
|
|
3285
|
+
* related to entities in the query, following relationships a couple of hops.
|
|
3286
|
+
* Best for relational / multi-hop questions ("what depends on X?", "which
|
|
3287
|
+
* component owns Y?") that vector search answers poorly.
|
|
3288
|
+
*/
|
|
3289
|
+
declare class GraphSearchTool extends BaseTool {
|
|
3290
|
+
readonly name = "knowledge_graph_search";
|
|
3291
|
+
readonly description = "Search the project knowledge graph (learned entity\u2192relation\u2192value facts) for information related to a query, expanding a couple of hops across relationships. Use for relational or multi-hop questions about the project.";
|
|
3292
|
+
readonly inputSchema: {
|
|
3293
|
+
type: string;
|
|
3294
|
+
properties: {
|
|
3295
|
+
query: {
|
|
3296
|
+
type: string;
|
|
3297
|
+
description: string;
|
|
3298
|
+
};
|
|
3299
|
+
hops: {
|
|
3300
|
+
type: string;
|
|
3301
|
+
description: string;
|
|
3302
|
+
};
|
|
3303
|
+
};
|
|
3304
|
+
required: string[];
|
|
3305
|
+
};
|
|
3306
|
+
private retriever;
|
|
3307
|
+
constructor(source: GraphFactSource);
|
|
3308
|
+
execute(input: Record<string, unknown>, _options: ToolExecuteOptions): Promise<string>;
|
|
3309
|
+
}
|
|
3310
|
+
|
|
3311
|
+
interface DistilledFact {
|
|
3312
|
+
entity: string;
|
|
3313
|
+
relation: string;
|
|
3314
|
+
value: string;
|
|
3315
|
+
}
|
|
3316
|
+
/** A run is worth distilling only if the conversation carried real content. */
|
|
3317
|
+
declare function sessionWorthRemembering(history: ConversationMessage[], latestPrompt: string, output: string): boolean;
|
|
3318
|
+
/**
|
|
3319
|
+
* Build the transcript the distiller reads: recent history + the final turn,
|
|
3320
|
+
* capped so a long session doesn't blow the distiller's budget.
|
|
3321
|
+
*/
|
|
3322
|
+
declare function buildSessionTranscript(history: ConversationMessage[], latestPrompt: string, output: string, maxChars?: number): string;
|
|
3323
|
+
/**
|
|
3324
|
+
* Distill durable facts from a session transcript via one cheap model call.
|
|
3325
|
+
* `generate` returns the model's raw text; parsing is defensive (a JSON array of
|
|
3326
|
+
* triples anywhere in the reply). Never throws — returns [] on any problem.
|
|
3327
|
+
*/
|
|
3328
|
+
declare function distillSessionFacts(transcript: string, generate: (prompt: string) => Promise<string>): Promise<DistilledFact[]>;
|
|
3329
|
+
|
|
2592
3330
|
/** Structured log levels for audit entries */
|
|
2593
3331
|
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
2594
3332
|
/** Extended audit entry with log level */
|
|
@@ -2783,4 +3521,211 @@ declare class CascadeToolError extends Error {
|
|
|
2783
3521
|
declare function preferIpv4Host(url: string | undefined): string | undefined;
|
|
2784
3522
|
declare function nodeHttpFetch(input: string | URL | Request, init?: RequestInit, redirectCount?: number): Promise<Response>;
|
|
2785
3523
|
|
|
2786
|
-
|
|
3524
|
+
/**
|
|
3525
|
+
* Best-effort guess of the canonical base model an Azure deployment backs, from
|
|
3526
|
+
* its (arbitrary) deployment name. Ordered most-specific → least so "gpt-5-mini"
|
|
3527
|
+
* doesn't match the "gpt-5" base. Distinct point releases (gpt-5.5, gpt-5.4,
|
|
3528
|
+
* gpt-5.4-mini) resolve to their OWN base so their real economics + benchmark
|
|
3529
|
+
* scores apply — only unrecognised gpt-5.x fold into the gpt-5 base.
|
|
3530
|
+
* Returns null when the name gives no signal (e.g. "prod-fast") — the caller
|
|
3531
|
+
* then keeps neutral defaults, or the user can set an explicit base model.
|
|
3532
|
+
*/
|
|
3533
|
+
declare function inferAzureBaseModel(deploymentName: string): string | null;
|
|
3534
|
+
/**
|
|
3535
|
+
* The ModelInfo for one configured Azure deployment. On Azure the deployment IS
|
|
3536
|
+
* the model (you address it by deployment name, and which base model backs it is
|
|
3537
|
+
* opaque to the API) — so each `providers[]` entry with a deploymentName becomes
|
|
3538
|
+
* one selectable model.
|
|
3539
|
+
*
|
|
3540
|
+
* Which base model it serves drives correct benchmark scoring + pricing, so we
|
|
3541
|
+
* resolve it: an explicit `cfg.model` (user override) wins, else we infer it from
|
|
3542
|
+
* the deployment name. When resolved to a known catalog model, this deployment
|
|
3543
|
+
* INHERITS that model's real economics (context window, pricing, vision, output
|
|
3544
|
+
* cap) while keeping the deployment name as its callable `id` and carrying the
|
|
3545
|
+
* base identity in `baseModelId`. Unresolved deployments fall back to neutral
|
|
3546
|
+
* GPT-4o-class defaults (an estimate, not $0), exactly as before.
|
|
3547
|
+
*/
|
|
3548
|
+
declare function azureModelForDeployment(cfg: ProviderConfig): ModelInfo | null;
|
|
3549
|
+
|
|
3550
|
+
interface CloudUser {
|
|
3551
|
+
id: string;
|
|
3552
|
+
email: string | null;
|
|
3553
|
+
name: string | null;
|
|
3554
|
+
plan?: string;
|
|
3555
|
+
}
|
|
3556
|
+
interface CloudSession {
|
|
3557
|
+
serverUrl: string;
|
|
3558
|
+
accessToken: string;
|
|
3559
|
+
/** Epoch ms when the access token expires (refresh before this). */
|
|
3560
|
+
accessExpiresAt: number;
|
|
3561
|
+
refreshToken: string;
|
|
3562
|
+
user: CloudUser;
|
|
3563
|
+
}
|
|
3564
|
+
|
|
3565
|
+
interface EncryptedBlob {
|
|
3566
|
+
ciphertext: string;
|
|
3567
|
+
salt: string;
|
|
3568
|
+
iv: string;
|
|
3569
|
+
}
|
|
3570
|
+
declare function encryptJSON(data: unknown, passphrase: string): Promise<EncryptedBlob>;
|
|
3571
|
+
/** Throws (AES-GCM auth-tag check fails) on a wrong passphrase or tampered ciphertext. */
|
|
3572
|
+
declare function decryptJSON<T>(blob: EncryptedBlob, passphrase: string): Promise<T>;
|
|
3573
|
+
|
|
3574
|
+
declare const DEFAULT_CLOUD_URL = "https://app.cascadeai.in";
|
|
3575
|
+
/** Providers the loopback flow can start (must match the server's `/auth/native/:provider`). */
|
|
3576
|
+
type NativeProvider = 'google' | 'github';
|
|
3577
|
+
interface DeviceStart {
|
|
3578
|
+
deviceCode: string;
|
|
3579
|
+
userCode: string;
|
|
3580
|
+
verificationUri: string;
|
|
3581
|
+
expiresIn: number;
|
|
3582
|
+
interval: number;
|
|
3583
|
+
}
|
|
3584
|
+
interface CloudConversation {
|
|
3585
|
+
id: string;
|
|
3586
|
+
title: string;
|
|
3587
|
+
/** Branching: leaf of the currently-selected path (null for an empty chat). */
|
|
3588
|
+
activeLeafId?: string | null;
|
|
3589
|
+
skillId?: string | null;
|
|
3590
|
+
createdAt?: number;
|
|
3591
|
+
updatedAt?: number;
|
|
3592
|
+
}
|
|
3593
|
+
interface CloudMessage {
|
|
3594
|
+
/** Present on messages read from the server; absent on minimal echoes. */
|
|
3595
|
+
id?: string;
|
|
3596
|
+
/** Branching: the message this replies to (null = a root turn). */
|
|
3597
|
+
parentId?: string | null;
|
|
3598
|
+
role: string;
|
|
3599
|
+
content: string;
|
|
3600
|
+
tier?: string | null;
|
|
3601
|
+
model?: string | null;
|
|
3602
|
+
costUsd?: number | null;
|
|
3603
|
+
/** JSON-encoded run-explorer report, or null. */
|
|
3604
|
+
why?: string | null;
|
|
3605
|
+
/** Branching: ids of this message + its siblings, oldest first (for < n/m >). */
|
|
3606
|
+
siblingIds?: string[];
|
|
3607
|
+
}
|
|
3608
|
+
/** A locally-executed turn to persist into the cloud conversation tree. */
|
|
3609
|
+
interface CloudTurnInput {
|
|
3610
|
+
userContent: string;
|
|
3611
|
+
assistant: {
|
|
3612
|
+
content: string;
|
|
3613
|
+
tier?: string | null;
|
|
3614
|
+
model?: string | null;
|
|
3615
|
+
costUsd?: number | null;
|
|
3616
|
+
why?: string | null;
|
|
3617
|
+
};
|
|
3618
|
+
/** Fork a sibling of this edited user turn (server derives the parent). */
|
|
3619
|
+
editOfMessageId?: string;
|
|
3620
|
+
/** Re-answer this user turn (reply saved as a sibling; no new user message). */
|
|
3621
|
+
regenerateFromUserMessageId?: string;
|
|
3622
|
+
}
|
|
3623
|
+
type DevicePollResult = 'pending' | 'slow_down' | 'expired' | {
|
|
3624
|
+
session: CloudSession;
|
|
3625
|
+
};
|
|
3626
|
+
/**
|
|
3627
|
+
* Where the signed-in session persists. The CLI uses the default file store
|
|
3628
|
+
* (`~/.cascade-ai/cloud-session.json`, 0600); the desktop injects a
|
|
3629
|
+
* `safeStorage`-backed one. Kept tiny so any host can implement it.
|
|
3630
|
+
*/
|
|
3631
|
+
interface CloudSessionStore {
|
|
3632
|
+
load(): CloudSession | null;
|
|
3633
|
+
save(session: CloudSession): void;
|
|
3634
|
+
clear(): void;
|
|
3635
|
+
}
|
|
3636
|
+
declare class CloudClient {
|
|
3637
|
+
private readonly serverUrl;
|
|
3638
|
+
private readonly store;
|
|
3639
|
+
constructor(serverUrl: string, dir?: string, store?: CloudSessionStore);
|
|
3640
|
+
/** Build a client from a stored session, or null if not signed in. */
|
|
3641
|
+
static fromSession(dir?: string, store?: CloudSessionStore): CloudClient | null;
|
|
3642
|
+
private url;
|
|
3643
|
+
startDevice(): Promise<DeviceStart>;
|
|
3644
|
+
/** Single poll of the device grant. On approval, persists + returns the session. */
|
|
3645
|
+
pollDevice(deviceCode: string): Promise<DevicePollResult>;
|
|
3646
|
+
/**
|
|
3647
|
+
* Run the full device flow: start it, hand the code to `onCode`, then poll at
|
|
3648
|
+
* the server's interval until approved or expired.
|
|
3649
|
+
*/
|
|
3650
|
+
runDeviceLogin(onCode: (d: DeviceStart) => void, opts?: {
|
|
3651
|
+
signal?: AbortSignal;
|
|
3652
|
+
}): Promise<CloudSession>;
|
|
3653
|
+
/**
|
|
3654
|
+
* Run the loopback flow for a rich native client (the desktop). Opens a
|
|
3655
|
+
* one-shot listener on `http://127.0.0.1:<random>`, sends the user to the
|
|
3656
|
+
* provider in the system browser via `openUrl`, catches the one-time code on
|
|
3657
|
+
* the loopback redirect, and exchanges it (+ the PKCE verifier) for tokens.
|
|
3658
|
+
*
|
|
3659
|
+
* No secret is involved: PKCE S256 proves the client that started the flow is
|
|
3660
|
+
* the one redeeming the code. Storage-agnostic — persists through the same
|
|
3661
|
+
* session store as the device flow, so callers get a ready `CloudSession`.
|
|
3662
|
+
*/
|
|
3663
|
+
runLoopbackLogin(openUrl: (url: string) => void | Promise<void>, opts?: {
|
|
3664
|
+
provider?: NativeProvider;
|
|
3665
|
+
signal?: AbortSignal;
|
|
3666
|
+
timeoutMs?: number;
|
|
3667
|
+
}): Promise<CloudSession>;
|
|
3668
|
+
/** Exchange a fresh token response for a stored session (fetches the user). */
|
|
3669
|
+
private finishLogin;
|
|
3670
|
+
private session;
|
|
3671
|
+
private refresh;
|
|
3672
|
+
private accessToken;
|
|
3673
|
+
/** Authenticated request that refreshes once on a 401 (e.g. server-side revoke). */
|
|
3674
|
+
private authed;
|
|
3675
|
+
private authedGet;
|
|
3676
|
+
private fetchMe;
|
|
3677
|
+
me(): Promise<CloudUser>;
|
|
3678
|
+
listConversations(): Promise<CloudConversation[]>;
|
|
3679
|
+
getMessages(conversationId: string): Promise<CloudMessage[]>;
|
|
3680
|
+
/** Start a new cloud conversation and return it. */
|
|
3681
|
+
createConversation(title?: string): Promise<CloudConversation>;
|
|
3682
|
+
/** Persist a locally-executed turn; returns the new active path (with siblings). */
|
|
3683
|
+
appendTurn(conversationId: string, turn: CloudTurnInput): Promise<CloudMessage[]>;
|
|
3684
|
+
/** Branching: switch the active path to a sibling; returns the new path. */
|
|
3685
|
+
selectBranch(conversationId: string, messageId: string): Promise<CloudMessage[]>;
|
|
3686
|
+
/** Branching: delete a message and its subtree; returns the new path. */
|
|
3687
|
+
deleteMessage(conversationId: string, messageId: string): Promise<CloudMessage[]>;
|
|
3688
|
+
renameConversation(conversationId: string, title: string): Promise<void>;
|
|
3689
|
+
deleteConversation(conversationId: string): Promise<void>;
|
|
3690
|
+
/** Fetch the stored encrypted settings envelope (ciphertext only), or null. */
|
|
3691
|
+
pullSecrets(): Promise<{
|
|
3692
|
+
blob: EncryptedBlob | null;
|
|
3693
|
+
version?: number;
|
|
3694
|
+
updatedAt?: number;
|
|
3695
|
+
}>;
|
|
3696
|
+
/** Store/replace the encrypted settings envelope. The server never decrypts it. */
|
|
3697
|
+
pushSecrets(blob: EncryptedBlob): Promise<{
|
|
3698
|
+
version: number;
|
|
3699
|
+
updatedAt: number;
|
|
3700
|
+
}>;
|
|
3701
|
+
/** Forget the stored envelope on the server. */
|
|
3702
|
+
deleteSecrets(): Promise<void>;
|
|
3703
|
+
logout(): Promise<void>;
|
|
3704
|
+
}
|
|
3705
|
+
|
|
3706
|
+
interface SyncBundle {
|
|
3707
|
+
v: 1;
|
|
3708
|
+
/** LLM provider keys / endpoints. */
|
|
3709
|
+
providers?: ProviderConfig[];
|
|
3710
|
+
/** Web-search backend keys (Brave / Tavily) + SearXNG URL. */
|
|
3711
|
+
webSearch?: WebSearchConfig;
|
|
3712
|
+
/** MCP servers / connectors (headers carry auth). */
|
|
3713
|
+
mcpServers?: McpServerConfig$1[];
|
|
3714
|
+
/** Per-tier model overrides (non-secret). */
|
|
3715
|
+
models?: ModelOverrides;
|
|
3716
|
+
/** Budget caps (non-secret). */
|
|
3717
|
+
budget?: BudgetConfig;
|
|
3718
|
+
/** Assorted non-secret preferences. */
|
|
3719
|
+
prefs?: {
|
|
3720
|
+
autoBias?: 'balanced' | 'quality' | 'cost';
|
|
3721
|
+
cascadeAuto?: boolean;
|
|
3722
|
+
extendedContext?: ExtendedContextConfig;
|
|
3723
|
+
autonomy?: 'manual' | 'auto';
|
|
3724
|
+
};
|
|
3725
|
+
}
|
|
3726
|
+
/** Pluck the portable subset of a config into a bundle (undefined fields omitted). */
|
|
3727
|
+
declare function gatherSyncBundle(config: CascadeConfig): SyncBundle;
|
|
3728
|
+
/** Merge a pulled bundle into a config, returning the updated config to persist. */
|
|
3729
|
+
declare function applySyncBundle(bundle: SyncBundle, config: CascadeConfig): CascadeConfig;
|
|
3730
|
+
|
|
3731
|
+
export { AZURE_BASE_URL_TEMPLATE, type ApprovalRequest, type ApprovalResponse, type AuditEntry, AuditLogger, type BenchmarksConfig, type BudgetConfig, CASCADE_AUDIT_FILE, CASCADE_CONFIG_DIR, CASCADE_CONFIG_FILE, CASCADE_DASHBOARD_SECRET_FILE, CASCADE_DB_FILE, CASCADE_IGNORE_FILE, CASCADE_KEYSTORE_FILE, CASCADE_MD_FILE, CASCADE_VERSION, CHARS_PER_TOKEN, COMPLEXITY_T2_COUNT, Cascade, CascadeCancelledError, type CascadeConfig, type CascadeEvent, type CascadeEventType, CascadeIgnore, type CascadeMessage, CascadeRouter, type CascadeRunOptions, type CascadeRunResult, type CascadeThemeName, CascadeToolError, type Chunk, type ChunkOptions, CloudClient, type CloudConversation, type CloudMessage, type CloudSession, type CloudSessionStore, type CloudTurnInput, type CloudUser, type CodeChunkOptions, type CodeChunker, CodeSearchTool, type CompleteFn, ConfigManager, type ConversationMessage, DEFAULT_API_PORT, DEFAULT_APPROVAL_REQUIRED, DEFAULT_AUTO_SUMMARIZE_AT, DEFAULT_CLOUD_URL, DEFAULT_CONTEXT_LIMIT, DEFAULT_DASHBOARD_PORT, DEFAULT_MAX_SESSION_MESSAGES, DEFAULT_RETENTION_DAYS, DEFAULT_THEME, type DashboardConfig, DashboardServer, type DeviceStart, type DistilledFact, type Embedder, type EncryptedBlob, type EscalationPayload, type ExtendedContextConfig, type FileManifest, FileMcpOAuthStore, GLOBAL_CONFIG_DIR, GLOBAL_CREDENTIALS_FILE, GLOBAL_DB_FILE, GLOBAL_KEYSTORE_FILE, GLOBAL_RUNTIME_DB_FILE, type GenerateOptions, type GenerateResult, type GraphFactSource, GraphRetriever, type GraphSearchOptions, GraphSearchTool, type HookDefinition, type HooksConfig, HooksRunner, type Identity, type ImageAttachment, Keystore, LLMReranker, LM_STUDIO_BASE_URL, type LegacyThemeName, MODELS, type ManifestDiff, McpClient, McpOAuthProvider, type McpOAuthState, type McpOAuthStore, type McpServerConfig$1 as McpServerConfig, type MemoryConfig, MemoryStore, type Message, type MessageContent, type MessagePayload, type MessageStatus, type MessageType, type ModelInfo, type ModelOverrides, type NativeProvider, OLLAMA_BASE_URL, OpenAICompatibleEmbedder, type OpenAIEmbedderOptions, PROVIDER_DISPLAY_NAMES, type PeerMessage, type PeerMessageEvent, type PeerSyncPayload, type PeerSyncType, type PermissionDecision, type PermissionDecisionPayload, type PermissionRequest, type PermissionTrailEntry, type PlanReviewConfig, type ProviderConfig, type ProviderType, type RankedFact, type RefreshResult, type Reranker, type RetrievalContext, type RetrievalMode, type RetrievalPlan, Retriever, type RetrieverSearchOptions, type RuntimeNode, type RuntimeNodeLog, type RuntimeRefreshPayload, type RuntimeScope, type RuntimeSession, type RuntimeSnapshotPayload, type ScheduledTask, type ScoredChunk, type SearchOptions, type Session, type SessionCheckpoint, type SessionMetadata, type SessionSubscriptionPayload, SqliteVectorStore, type StatusUpdate, type StoredMessage, type StreamChunk, type SyncBundle, T1Administrator, type T1ToT2Assignment, T1_MODEL_PRIORITY, T2Manager, type T2Result, type T2ToT3Assignment, T2_MODEL_PRIORITY, type T3Result, type T3ResultPayload, type T3SubtaskSpec, T3Worker, T3_MODEL_PRIORITY, THEME_NAMES, TOOL_NAMES, type TaskComplexity, TaskScheduler, Telemetry, type TelemetryConfig, type Theme, type ThemeColors, type ThemeName, type TierConfig, type TierLimits, type TierRole, type TierStatus, type TokenUsage, type ToolCall, type ToolDefinition, type ToolExecuteOptions, ToolRegistry, type ToolResult, type ToolsConfig, VISION_MODEL_PRIORITY, type VectorStore, type WebSearchConfig, type WebhookConfig, type WorkspaceConfig, WorkspaceIndex, type WorkspaceIndexOptions, applySyncBundle, azureModelForDeployment, beginMcpOAuth, buildManifest, buildSessionTranscript, cagCharBudget, chatCompleterFromProviders, chunkCode, chunkText, completeMcpOAuth, connectMcpWithLoopbackOAuth, createCascade, decryptJSON as decryptSyncBlob, diffManifest, discoverMcpAuthServer, distillSessionFacts, embedderFromProviders, encryptJSON as encryptSyncBlob, fileOAuthProvider, gatherSyncBundle, hashContent, heuristicCodeChunker, inferAzureBaseModel, nodeHttpFetch, parseRankOrder, planRetrieval, preferIpv4Host, reciprocalRankFusion, refreshMcpToken, runCascade, sessionWorthRemembering, streamCascade };
|