cascade-ai 0.13.2 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +708 -47
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +708 -47
- package/dist/cli.js.map +1 -1
- package/dist/desktop-core.cjs +710 -49
- package/dist/index.cjs +708 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +164 -6
- package/dist/index.d.ts +164 -6
- package/dist/index.js +708 -47
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -387,6 +387,10 @@ interface CascadeConfig {
|
|
|
387
387
|
enableToolCreation?: boolean;
|
|
388
388
|
/** Persist runtime-generated tools and reload them on startup (untrusted). Default: true. */
|
|
389
389
|
persistDynamicTools?: boolean;
|
|
390
|
+
/** Project knowledge (world state) settings. */
|
|
391
|
+
knowledge?: {
|
|
392
|
+
factsExtraction?: boolean;
|
|
393
|
+
};
|
|
390
394
|
plugins?: string[];
|
|
391
395
|
localConcurrency?: number;
|
|
392
396
|
localInferenceTimeoutMs?: number;
|
|
@@ -478,6 +482,12 @@ interface ToolsConfig {
|
|
|
478
482
|
mcpTrusted?: string[];
|
|
479
483
|
/** Web search backends — at least one should be configured for best results */
|
|
480
484
|
webSearch?: WebSearchConfig;
|
|
485
|
+
/**
|
|
486
|
+
* Sandbox runtime for LLM-authored dynamic tools. 'isolate' = hard V8 isolate
|
|
487
|
+
* (isolated-vm, capability-confined), 'worker' = node:worker_threads,
|
|
488
|
+
* 'auto' (default) = isolate when available else worker.
|
|
489
|
+
*/
|
|
490
|
+
dynamicToolSandbox?: 'isolate' | 'worker' | 'auto';
|
|
481
491
|
}
|
|
482
492
|
interface HooksConfig {
|
|
483
493
|
preToolUse?: HookDefinition[];
|
|
@@ -818,7 +828,9 @@ declare class TaskAnalyzer {
|
|
|
818
828
|
* Scores tier-eligible models using cost efficiency + historical performance.
|
|
819
829
|
* Falls back to the priority-list default when no candidates have history.
|
|
820
830
|
*/
|
|
821
|
-
selectModel(prompt: string, tier: TierRole, selector: ModelSelector
|
|
831
|
+
selectModel(prompt: string, tier: TierRole, selector: ModelSelector, opts?: {
|
|
832
|
+
requiresToolUse?: boolean;
|
|
833
|
+
}): Promise<ModelInfo | null>;
|
|
822
834
|
/**
|
|
823
835
|
* Record the outcome of a completed run across all tiers that were selected
|
|
824
836
|
* during this session and persist stats to disk.
|
|
@@ -862,6 +874,20 @@ declare class MemoryStore {
|
|
|
862
874
|
addMessage(message: StoredMessage): void;
|
|
863
875
|
getSessionMessages(sessionId: string): StoredMessage[];
|
|
864
876
|
searchMessages(query: string, limit?: number): StoredMessage[];
|
|
877
|
+
/** Full sessions (with messages) for the given ids, or ALL sessions. */
|
|
878
|
+
exportSessions(ids?: string[]): Session[];
|
|
879
|
+
/**
|
|
880
|
+
* Import sessions from a bundle. Returns the created `{id, title}` rows so
|
|
881
|
+
* the caller can mirror them into the runtime session list (the sidebar
|
|
882
|
+
* reads runtime_sessions, not sessions). Malformed entries are skipped.
|
|
883
|
+
*/
|
|
884
|
+
importSessions(sessions: Session[]): Array<{
|
|
885
|
+
id: string;
|
|
886
|
+
title: string;
|
|
887
|
+
}>;
|
|
888
|
+
/** Import identities/personas, deduped by (case-insensitive) name — an
|
|
889
|
+
* existing name is skipped, never replaced. Imports are never the default. */
|
|
890
|
+
importIdentities(identities: Identity[]): number;
|
|
865
891
|
createIdentity(identity: Identity): void;
|
|
866
892
|
updateIdentity(id: string, updates: Partial<Identity>): void;
|
|
867
893
|
getIdentity(id: string): Identity | null;
|
|
@@ -884,6 +910,15 @@ declare class MemoryStore {
|
|
|
884
910
|
getCacheAge(): number;
|
|
885
911
|
saveModelProfile(modelId: string, provider: ProviderType, specializations: string[]): void;
|
|
886
912
|
getModelProfile(modelId: string, provider: ProviderType): ModelInfo | undefined;
|
|
913
|
+
/**
|
|
914
|
+
* Persist a probed capability verdict (currently: native tool support) into
|
|
915
|
+
* the model's cached profile, merging with whatever is already recorded.
|
|
916
|
+
* Read back via getModelProfile — so a model is probed once ever, not once
|
|
917
|
+
* per run.
|
|
918
|
+
*/
|
|
919
|
+
saveModelCapability(modelId: string, provider: ProviderType, caps: {
|
|
920
|
+
supportsToolUse?: boolean;
|
|
921
|
+
}): void;
|
|
887
922
|
getProfiledModelIds(): string[];
|
|
888
923
|
private toolResultCache;
|
|
889
924
|
private static CACHEABLE_TOOLS;
|
|
@@ -923,6 +958,16 @@ interface PriceEntry {
|
|
|
923
958
|
input: number;
|
|
924
959
|
output: number;
|
|
925
960
|
}
|
|
961
|
+
/**
|
|
962
|
+
* Per-model capability facts from the same OpenRouter catalog the pricing fetch
|
|
963
|
+
* already downloads: context window, native tool support, and input modalities.
|
|
964
|
+
* Previously discarded — provider listModels() stubs guessed/hardcoded these.
|
|
965
|
+
*/
|
|
966
|
+
interface CapabilityEntry {
|
|
967
|
+
contextWindow?: number;
|
|
968
|
+
supportsTools?: boolean;
|
|
969
|
+
inputModalities?: string[];
|
|
970
|
+
}
|
|
926
971
|
interface LiveDataOptions {
|
|
927
972
|
/** Master switch for live quality fetch. Default: true. */
|
|
928
973
|
live?: boolean;
|
|
@@ -938,6 +983,7 @@ interface LiveDataOptions {
|
|
|
938
983
|
declare class LiveDataProvider {
|
|
939
984
|
private snapshot;
|
|
940
985
|
private prices;
|
|
986
|
+
private capabilities;
|
|
941
987
|
private source;
|
|
942
988
|
private fetchedAt;
|
|
943
989
|
private loaded;
|
|
@@ -953,7 +999,13 @@ declare class LiveDataProvider {
|
|
|
953
999
|
refresh(force?: boolean): Promise<void>;
|
|
954
1000
|
private doRefresh;
|
|
955
1001
|
private fetchSnapshot;
|
|
956
|
-
|
|
1002
|
+
/**
|
|
1003
|
+
* One fetch of the OpenRouter catalog yields BOTH pricing and capability
|
|
1004
|
+
* facts (context window, native tool support, input modalities) — the
|
|
1005
|
+
* capability fields used to be discarded while providers guessed/hardcoded
|
|
1006
|
+
* them in their listModels() stubs.
|
|
1007
|
+
*/
|
|
1008
|
+
private fetchCatalog;
|
|
957
1009
|
private saveCache;
|
|
958
1010
|
/** Quality profile for a model family, or null when we have no live/cached data. */
|
|
959
1011
|
getQualityProfile(family: string): BenchmarkProfile | null;
|
|
@@ -964,10 +1016,20 @@ declare class LiveDataProvider {
|
|
|
964
1016
|
* leaving the original untouched (so the shared catalog is never mutated).
|
|
965
1017
|
*/
|
|
966
1018
|
applyLivePricing(models: ModelInfo[]): ModelInfo[];
|
|
1019
|
+
/** Current capability facts for a model id, or null when unknown. */
|
|
1020
|
+
getCapability(modelId: string): CapabilityEntry | null;
|
|
1021
|
+
/**
|
|
1022
|
+
* Returns capability-corrected copies of each model (originals untouched):
|
|
1023
|
+
* real context windows replace the providers' hardcoded guesses, native
|
|
1024
|
+
* tool support replaces the assume-by-provider default, and vision is set
|
|
1025
|
+
* from the declared input modalities.
|
|
1026
|
+
*/
|
|
1027
|
+
applyLiveCapabilities(models: ModelInfo[]): ModelInfo[];
|
|
967
1028
|
/** Where the active quality data came from — for /why and `cascade models`. */
|
|
968
1029
|
getDataSource(): DataSource;
|
|
969
1030
|
getGeneratedAt(): string | null;
|
|
970
1031
|
hasLivePricing(): boolean;
|
|
1032
|
+
hasCapabilities(): boolean;
|
|
971
1033
|
}
|
|
972
1034
|
|
|
973
1035
|
interface WorldStateEntry {
|
|
@@ -976,6 +1038,19 @@ interface WorldStateEntry {
|
|
|
976
1038
|
summary: string;
|
|
977
1039
|
workerId: string;
|
|
978
1040
|
}
|
|
1041
|
+
/**
|
|
1042
|
+
* A single queryable fact in the project knowledge graph (world-state v2):
|
|
1043
|
+
* an `(entity, relation) → value` triple with provenance. Facts are upserted on
|
|
1044
|
+
* `(entity, relation)`, so a newer observation supersedes an older one instead of
|
|
1045
|
+
* appending — T1/T2 query relevant facts by entity rather than replaying the log.
|
|
1046
|
+
*/
|
|
1047
|
+
interface WorldFact {
|
|
1048
|
+
entity: string;
|
|
1049
|
+
relation: string;
|
|
1050
|
+
value: string;
|
|
1051
|
+
sourceWorker: string;
|
|
1052
|
+
timestamp: string;
|
|
1053
|
+
}
|
|
979
1054
|
declare class WorldStateDB {
|
|
980
1055
|
private workspacePath;
|
|
981
1056
|
private debugMode;
|
|
@@ -990,6 +1065,58 @@ declare class WorldStateDB {
|
|
|
990
1065
|
addEntry(workerId: string, summary: string): string;
|
|
991
1066
|
getAllEntries(): WorldStateEntry[];
|
|
992
1067
|
getFormattedState(): string;
|
|
1068
|
+
/**
|
|
1069
|
+
* Upsert a fact. `(entity, relation)` is normalized so casing/whitespace don't
|
|
1070
|
+
* fragment the key; an existing pair is superseded (value + provenance updated)
|
|
1071
|
+
* rather than duplicated. Empty entity/relation/value are ignored.
|
|
1072
|
+
*/
|
|
1073
|
+
upsertFact(entity: string, relation: string, value: string, sourceWorker: string, timestamp?: string): void;
|
|
1074
|
+
private rowToFact;
|
|
1075
|
+
/** All facts whose entity matches one of the (normalized) query entities. */
|
|
1076
|
+
getFactsForEntities(entities: string[]): WorldFact[];
|
|
1077
|
+
/** Every fact (used for tests / debug / whole-graph views). */
|
|
1078
|
+
getAllFacts(): WorldFact[];
|
|
1079
|
+
/**
|
|
1080
|
+
* A compact, human/LLM-readable fact block for T1/T2 planning. When `entities`
|
|
1081
|
+
* is given, only facts about those entities are included; otherwise all facts.
|
|
1082
|
+
* Returns '' when there are none so callers can fall back to the linear log.
|
|
1083
|
+
*/
|
|
1084
|
+
getFormattedFacts(entities?: string[]): string;
|
|
1085
|
+
/**
|
|
1086
|
+
* A compact knowledge block for T1/T2 planning. When `prompt` is given, facts
|
|
1087
|
+
* whose entity/relation/value mention a prompt token are preferred (relevance
|
|
1088
|
+
* filter); otherwise, or when nothing matches, all facts are used (capped at
|
|
1089
|
+
* `limit`). Returns '' when there are no facts, so the caller can fall back to
|
|
1090
|
+
* the raw linear log — this replaces replaying the whole log during planning.
|
|
1091
|
+
*/
|
|
1092
|
+
getFormattedKnowledge(prompt?: string, limit?: number): string;
|
|
1093
|
+
exportKnowledge(): {
|
|
1094
|
+
facts: WorldFact[];
|
|
1095
|
+
worldLog: WorldStateEntry[];
|
|
1096
|
+
};
|
|
1097
|
+
/**
|
|
1098
|
+
* Merge imported knowledge. Facts upsert on (entity, relation) with
|
|
1099
|
+
* newer-timestamp-wins (a local fact newer than the imported one is kept);
|
|
1100
|
+
* log entries append with fresh ids, skipping exact duplicates
|
|
1101
|
+
* (worker + timestamp + summary). Returns counts of what actually landed.
|
|
1102
|
+
*/
|
|
1103
|
+
importKnowledge(data: {
|
|
1104
|
+
facts?: Array<{
|
|
1105
|
+
entity?: string;
|
|
1106
|
+
relation?: string;
|
|
1107
|
+
value?: string;
|
|
1108
|
+
sourceWorker?: string;
|
|
1109
|
+
timestamp?: string;
|
|
1110
|
+
}>;
|
|
1111
|
+
worldLog?: Array<{
|
|
1112
|
+
workerId?: string;
|
|
1113
|
+
summary?: string;
|
|
1114
|
+
timestamp?: string;
|
|
1115
|
+
}>;
|
|
1116
|
+
}): {
|
|
1117
|
+
facts: number;
|
|
1118
|
+
logEntries: number;
|
|
1119
|
+
};
|
|
993
1120
|
private dumpDebugIfNeeded;
|
|
994
1121
|
close(): void;
|
|
995
1122
|
}
|
|
@@ -1095,6 +1222,18 @@ declare class CascadeRouter extends EventEmitter {
|
|
|
1095
1222
|
* No-op if store is not provided.
|
|
1096
1223
|
*/
|
|
1097
1224
|
profileModels(store: MemoryStore): Promise<void>;
|
|
1225
|
+
/**
|
|
1226
|
+
* One-time native tool-call probe for local/compat models with NO capability
|
|
1227
|
+
* metadata. llama.cpp / LM Studio "/models" endpoints return ids only, so
|
|
1228
|
+
* `supportsToolUse` stays undefined and the T3 tool gate ASSUMES native
|
|
1229
|
+
* support — wrong for many local builds, which then fumble tool-format
|
|
1230
|
+
* output. Each unknown model is probed once with a trivial tool; the verdict
|
|
1231
|
+
* persists in the MemoryStore's model_cache (via the previously-dormant
|
|
1232
|
+
* getModelProfile read-back), so a model is probed once EVER, not per run.
|
|
1233
|
+
* Cloud providers are never probed — their metadata is authoritative.
|
|
1234
|
+
*/
|
|
1235
|
+
probeLocalToolSupport(store: MemoryStore): Promise<void>;
|
|
1236
|
+
private probeNativeToolCall;
|
|
1098
1237
|
/**
|
|
1099
1238
|
* Cascade Auto live data: discover/validate real model ids from each cloud
|
|
1100
1239
|
* provider, then fetch current public quality scores + per-token prices and
|
|
@@ -1111,8 +1250,10 @@ declare class CascadeRouter extends EventEmitter {
|
|
|
1111
1250
|
*/
|
|
1112
1251
|
private discoverProviderModels;
|
|
1113
1252
|
/**
|
|
1114
|
-
* Replace available models with live-priced
|
|
1115
|
-
*
|
|
1253
|
+
* Replace available models with live-priced AND capability-corrected copies
|
|
1254
|
+
* (real context windows, native tool support, vision from modalities), then
|
|
1255
|
+
* refresh the already resolved tier models so shared-tier cost accounting and
|
|
1256
|
+
* the tool-use gate both see current data.
|
|
1116
1257
|
*/
|
|
1117
1258
|
private applyLivePricing;
|
|
1118
1259
|
generate(tier: TierRole, options: GenerateOptions, onChunk?: (chunk: StreamChunk) => void, requireVision?: boolean): Promise<GenerateResult>;
|
|
@@ -1127,6 +1268,10 @@ declare class CascadeRouter extends EventEmitter {
|
|
|
1127
1268
|
enabled: boolean;
|
|
1128
1269
|
maxPerSection: number;
|
|
1129
1270
|
};
|
|
1271
|
+
/** Project-knowledge settings (config.knowledge). Facts extraction on by default. */
|
|
1272
|
+
getKnowledgeConfig(): {
|
|
1273
|
+
factsExtraction: boolean;
|
|
1274
|
+
};
|
|
1130
1275
|
/**
|
|
1131
1276
|
* Resolved T3 wave execution mode. 'auto' becomes 'sequential' when the T3
|
|
1132
1277
|
* tier resolves to a LOCAL model (the single-GPU queue serializes anyway, so
|
|
@@ -1169,7 +1314,9 @@ declare class CascadeRouter extends EventEmitter {
|
|
|
1169
1314
|
* null when Cascade Auto is off (callers then use the shared tier model).
|
|
1170
1315
|
* Pure heuristic — no extra LLM call.
|
|
1171
1316
|
*/
|
|
1172
|
-
selectModelForSubtask(tier: TierRole, text: string
|
|
1317
|
+
selectModelForSubtask(tier: TierRole, text: string, opts?: {
|
|
1318
|
+
requiresToolUse?: boolean;
|
|
1319
|
+
}): Promise<ModelInfo | null>;
|
|
1173
1320
|
getStats(): RouterStats;
|
|
1174
1321
|
/**
|
|
1175
1322
|
* What did delegation save? Compares actual spend against the
|
|
@@ -1468,6 +1615,7 @@ declare class PermissionEscalator extends EventEmitter {
|
|
|
1468
1615
|
cancelAllPending(): void;
|
|
1469
1616
|
}
|
|
1470
1617
|
|
|
1618
|
+
type SandboxMode = 'isolate' | 'worker' | 'auto';
|
|
1471
1619
|
interface GeneratedToolSpec {
|
|
1472
1620
|
name: string;
|
|
1473
1621
|
description: string;
|
|
@@ -1489,12 +1637,14 @@ declare class ToolCreator {
|
|
|
1489
1637
|
private workspacePath?;
|
|
1490
1638
|
/** When false, persisted tools are neither loaded nor written. */
|
|
1491
1639
|
private persistEnabled;
|
|
1640
|
+
/** Sandbox runtime for generated tools; passed to each DynamicTool. */
|
|
1641
|
+
private sandboxMode;
|
|
1492
1642
|
private logger?;
|
|
1493
1643
|
/** name → spec, for persistence, broadcast, and re-registration. */
|
|
1494
1644
|
private specs;
|
|
1495
1645
|
/** capability fingerprint → tool name, so the same need isn't re-generated. */
|
|
1496
1646
|
private capabilityIndex;
|
|
1497
|
-
constructor(router: CascadeRouter, registry: ToolRegistry, workspacePath?: string, persistEnabled?: boolean);
|
|
1647
|
+
constructor(router: CascadeRouter, registry: ToolRegistry, workspacePath?: string, persistEnabled?: boolean, sandboxMode?: SandboxMode);
|
|
1498
1648
|
setPermissionEscalator(escalator: PermissionEscalator): void;
|
|
1499
1649
|
/** Route diagnostics through the host (Cascade) so they survive the Ink TUI. */
|
|
1500
1650
|
setLogger(fn: (msg: string) => void): void;
|
|
@@ -2011,6 +2161,14 @@ declare class T3Worker extends BaseTier {
|
|
|
2011
2161
|
*/
|
|
2012
2162
|
private reflectAndImprove;
|
|
2013
2163
|
private selfTest;
|
|
2164
|
+
/**
|
|
2165
|
+
* world-state v2: distill a completed subtask's output into durable
|
|
2166
|
+
* `(entity, relation, value)` facts and upsert them into the knowledge graph.
|
|
2167
|
+
* A bounded, cheap T3-tier call; entirely best-effort — any failure is swallowed
|
|
2168
|
+
* so it never blocks or fails the subtask. Respects the subtask's privacy tier
|
|
2169
|
+
* (a local-only subtask extracts on a local model too, never leaking to cloud).
|
|
2170
|
+
*/
|
|
2171
|
+
private extractAndStoreFacts;
|
|
2014
2172
|
private correctOutput;
|
|
2015
2173
|
private buildSystemPrompt;
|
|
2016
2174
|
private buildInitialPrompt;
|
package/dist/index.d.ts
CHANGED
|
@@ -387,6 +387,10 @@ interface CascadeConfig {
|
|
|
387
387
|
enableToolCreation?: boolean;
|
|
388
388
|
/** Persist runtime-generated tools and reload them on startup (untrusted). Default: true. */
|
|
389
389
|
persistDynamicTools?: boolean;
|
|
390
|
+
/** Project knowledge (world state) settings. */
|
|
391
|
+
knowledge?: {
|
|
392
|
+
factsExtraction?: boolean;
|
|
393
|
+
};
|
|
390
394
|
plugins?: string[];
|
|
391
395
|
localConcurrency?: number;
|
|
392
396
|
localInferenceTimeoutMs?: number;
|
|
@@ -478,6 +482,12 @@ interface ToolsConfig {
|
|
|
478
482
|
mcpTrusted?: string[];
|
|
479
483
|
/** Web search backends — at least one should be configured for best results */
|
|
480
484
|
webSearch?: WebSearchConfig;
|
|
485
|
+
/**
|
|
486
|
+
* Sandbox runtime for LLM-authored dynamic tools. 'isolate' = hard V8 isolate
|
|
487
|
+
* (isolated-vm, capability-confined), 'worker' = node:worker_threads,
|
|
488
|
+
* 'auto' (default) = isolate when available else worker.
|
|
489
|
+
*/
|
|
490
|
+
dynamicToolSandbox?: 'isolate' | 'worker' | 'auto';
|
|
481
491
|
}
|
|
482
492
|
interface HooksConfig {
|
|
483
493
|
preToolUse?: HookDefinition[];
|
|
@@ -818,7 +828,9 @@ declare class TaskAnalyzer {
|
|
|
818
828
|
* Scores tier-eligible models using cost efficiency + historical performance.
|
|
819
829
|
* Falls back to the priority-list default when no candidates have history.
|
|
820
830
|
*/
|
|
821
|
-
selectModel(prompt: string, tier: TierRole, selector: ModelSelector
|
|
831
|
+
selectModel(prompt: string, tier: TierRole, selector: ModelSelector, opts?: {
|
|
832
|
+
requiresToolUse?: boolean;
|
|
833
|
+
}): Promise<ModelInfo | null>;
|
|
822
834
|
/**
|
|
823
835
|
* Record the outcome of a completed run across all tiers that were selected
|
|
824
836
|
* during this session and persist stats to disk.
|
|
@@ -862,6 +874,20 @@ declare class MemoryStore {
|
|
|
862
874
|
addMessage(message: StoredMessage): void;
|
|
863
875
|
getSessionMessages(sessionId: string): StoredMessage[];
|
|
864
876
|
searchMessages(query: string, limit?: number): StoredMessage[];
|
|
877
|
+
/** Full sessions (with messages) for the given ids, or ALL sessions. */
|
|
878
|
+
exportSessions(ids?: string[]): Session[];
|
|
879
|
+
/**
|
|
880
|
+
* Import sessions from a bundle. Returns the created `{id, title}` rows so
|
|
881
|
+
* the caller can mirror them into the runtime session list (the sidebar
|
|
882
|
+
* reads runtime_sessions, not sessions). Malformed entries are skipped.
|
|
883
|
+
*/
|
|
884
|
+
importSessions(sessions: Session[]): Array<{
|
|
885
|
+
id: string;
|
|
886
|
+
title: string;
|
|
887
|
+
}>;
|
|
888
|
+
/** Import identities/personas, deduped by (case-insensitive) name — an
|
|
889
|
+
* existing name is skipped, never replaced. Imports are never the default. */
|
|
890
|
+
importIdentities(identities: Identity[]): number;
|
|
865
891
|
createIdentity(identity: Identity): void;
|
|
866
892
|
updateIdentity(id: string, updates: Partial<Identity>): void;
|
|
867
893
|
getIdentity(id: string): Identity | null;
|
|
@@ -884,6 +910,15 @@ declare class MemoryStore {
|
|
|
884
910
|
getCacheAge(): number;
|
|
885
911
|
saveModelProfile(modelId: string, provider: ProviderType, specializations: string[]): void;
|
|
886
912
|
getModelProfile(modelId: string, provider: ProviderType): ModelInfo | undefined;
|
|
913
|
+
/**
|
|
914
|
+
* Persist a probed capability verdict (currently: native tool support) into
|
|
915
|
+
* the model's cached profile, merging with whatever is already recorded.
|
|
916
|
+
* Read back via getModelProfile — so a model is probed once ever, not once
|
|
917
|
+
* per run.
|
|
918
|
+
*/
|
|
919
|
+
saveModelCapability(modelId: string, provider: ProviderType, caps: {
|
|
920
|
+
supportsToolUse?: boolean;
|
|
921
|
+
}): void;
|
|
887
922
|
getProfiledModelIds(): string[];
|
|
888
923
|
private toolResultCache;
|
|
889
924
|
private static CACHEABLE_TOOLS;
|
|
@@ -923,6 +958,16 @@ interface PriceEntry {
|
|
|
923
958
|
input: number;
|
|
924
959
|
output: number;
|
|
925
960
|
}
|
|
961
|
+
/**
|
|
962
|
+
* Per-model capability facts from the same OpenRouter catalog the pricing fetch
|
|
963
|
+
* already downloads: context window, native tool support, and input modalities.
|
|
964
|
+
* Previously discarded — provider listModels() stubs guessed/hardcoded these.
|
|
965
|
+
*/
|
|
966
|
+
interface CapabilityEntry {
|
|
967
|
+
contextWindow?: number;
|
|
968
|
+
supportsTools?: boolean;
|
|
969
|
+
inputModalities?: string[];
|
|
970
|
+
}
|
|
926
971
|
interface LiveDataOptions {
|
|
927
972
|
/** Master switch for live quality fetch. Default: true. */
|
|
928
973
|
live?: boolean;
|
|
@@ -938,6 +983,7 @@ interface LiveDataOptions {
|
|
|
938
983
|
declare class LiveDataProvider {
|
|
939
984
|
private snapshot;
|
|
940
985
|
private prices;
|
|
986
|
+
private capabilities;
|
|
941
987
|
private source;
|
|
942
988
|
private fetchedAt;
|
|
943
989
|
private loaded;
|
|
@@ -953,7 +999,13 @@ declare class LiveDataProvider {
|
|
|
953
999
|
refresh(force?: boolean): Promise<void>;
|
|
954
1000
|
private doRefresh;
|
|
955
1001
|
private fetchSnapshot;
|
|
956
|
-
|
|
1002
|
+
/**
|
|
1003
|
+
* One fetch of the OpenRouter catalog yields BOTH pricing and capability
|
|
1004
|
+
* facts (context window, native tool support, input modalities) — the
|
|
1005
|
+
* capability fields used to be discarded while providers guessed/hardcoded
|
|
1006
|
+
* them in their listModels() stubs.
|
|
1007
|
+
*/
|
|
1008
|
+
private fetchCatalog;
|
|
957
1009
|
private saveCache;
|
|
958
1010
|
/** Quality profile for a model family, or null when we have no live/cached data. */
|
|
959
1011
|
getQualityProfile(family: string): BenchmarkProfile | null;
|
|
@@ -964,10 +1016,20 @@ declare class LiveDataProvider {
|
|
|
964
1016
|
* leaving the original untouched (so the shared catalog is never mutated).
|
|
965
1017
|
*/
|
|
966
1018
|
applyLivePricing(models: ModelInfo[]): ModelInfo[];
|
|
1019
|
+
/** Current capability facts for a model id, or null when unknown. */
|
|
1020
|
+
getCapability(modelId: string): CapabilityEntry | null;
|
|
1021
|
+
/**
|
|
1022
|
+
* Returns capability-corrected copies of each model (originals untouched):
|
|
1023
|
+
* real context windows replace the providers' hardcoded guesses, native
|
|
1024
|
+
* tool support replaces the assume-by-provider default, and vision is set
|
|
1025
|
+
* from the declared input modalities.
|
|
1026
|
+
*/
|
|
1027
|
+
applyLiveCapabilities(models: ModelInfo[]): ModelInfo[];
|
|
967
1028
|
/** Where the active quality data came from — for /why and `cascade models`. */
|
|
968
1029
|
getDataSource(): DataSource;
|
|
969
1030
|
getGeneratedAt(): string | null;
|
|
970
1031
|
hasLivePricing(): boolean;
|
|
1032
|
+
hasCapabilities(): boolean;
|
|
971
1033
|
}
|
|
972
1034
|
|
|
973
1035
|
interface WorldStateEntry {
|
|
@@ -976,6 +1038,19 @@ interface WorldStateEntry {
|
|
|
976
1038
|
summary: string;
|
|
977
1039
|
workerId: string;
|
|
978
1040
|
}
|
|
1041
|
+
/**
|
|
1042
|
+
* A single queryable fact in the project knowledge graph (world-state v2):
|
|
1043
|
+
* an `(entity, relation) → value` triple with provenance. Facts are upserted on
|
|
1044
|
+
* `(entity, relation)`, so a newer observation supersedes an older one instead of
|
|
1045
|
+
* appending — T1/T2 query relevant facts by entity rather than replaying the log.
|
|
1046
|
+
*/
|
|
1047
|
+
interface WorldFact {
|
|
1048
|
+
entity: string;
|
|
1049
|
+
relation: string;
|
|
1050
|
+
value: string;
|
|
1051
|
+
sourceWorker: string;
|
|
1052
|
+
timestamp: string;
|
|
1053
|
+
}
|
|
979
1054
|
declare class WorldStateDB {
|
|
980
1055
|
private workspacePath;
|
|
981
1056
|
private debugMode;
|
|
@@ -990,6 +1065,58 @@ declare class WorldStateDB {
|
|
|
990
1065
|
addEntry(workerId: string, summary: string): string;
|
|
991
1066
|
getAllEntries(): WorldStateEntry[];
|
|
992
1067
|
getFormattedState(): string;
|
|
1068
|
+
/**
|
|
1069
|
+
* Upsert a fact. `(entity, relation)` is normalized so casing/whitespace don't
|
|
1070
|
+
* fragment the key; an existing pair is superseded (value + provenance updated)
|
|
1071
|
+
* rather than duplicated. Empty entity/relation/value are ignored.
|
|
1072
|
+
*/
|
|
1073
|
+
upsertFact(entity: string, relation: string, value: string, sourceWorker: string, timestamp?: string): void;
|
|
1074
|
+
private rowToFact;
|
|
1075
|
+
/** All facts whose entity matches one of the (normalized) query entities. */
|
|
1076
|
+
getFactsForEntities(entities: string[]): WorldFact[];
|
|
1077
|
+
/** Every fact (used for tests / debug / whole-graph views). */
|
|
1078
|
+
getAllFacts(): WorldFact[];
|
|
1079
|
+
/**
|
|
1080
|
+
* A compact, human/LLM-readable fact block for T1/T2 planning. When `entities`
|
|
1081
|
+
* is given, only facts about those entities are included; otherwise all facts.
|
|
1082
|
+
* Returns '' when there are none so callers can fall back to the linear log.
|
|
1083
|
+
*/
|
|
1084
|
+
getFormattedFacts(entities?: string[]): string;
|
|
1085
|
+
/**
|
|
1086
|
+
* A compact knowledge block for T1/T2 planning. When `prompt` is given, facts
|
|
1087
|
+
* whose entity/relation/value mention a prompt token are preferred (relevance
|
|
1088
|
+
* filter); otherwise, or when nothing matches, all facts are used (capped at
|
|
1089
|
+
* `limit`). Returns '' when there are no facts, so the caller can fall back to
|
|
1090
|
+
* the raw linear log — this replaces replaying the whole log during planning.
|
|
1091
|
+
*/
|
|
1092
|
+
getFormattedKnowledge(prompt?: string, limit?: number): string;
|
|
1093
|
+
exportKnowledge(): {
|
|
1094
|
+
facts: WorldFact[];
|
|
1095
|
+
worldLog: WorldStateEntry[];
|
|
1096
|
+
};
|
|
1097
|
+
/**
|
|
1098
|
+
* Merge imported knowledge. Facts upsert on (entity, relation) with
|
|
1099
|
+
* newer-timestamp-wins (a local fact newer than the imported one is kept);
|
|
1100
|
+
* log entries append with fresh ids, skipping exact duplicates
|
|
1101
|
+
* (worker + timestamp + summary). Returns counts of what actually landed.
|
|
1102
|
+
*/
|
|
1103
|
+
importKnowledge(data: {
|
|
1104
|
+
facts?: Array<{
|
|
1105
|
+
entity?: string;
|
|
1106
|
+
relation?: string;
|
|
1107
|
+
value?: string;
|
|
1108
|
+
sourceWorker?: string;
|
|
1109
|
+
timestamp?: string;
|
|
1110
|
+
}>;
|
|
1111
|
+
worldLog?: Array<{
|
|
1112
|
+
workerId?: string;
|
|
1113
|
+
summary?: string;
|
|
1114
|
+
timestamp?: string;
|
|
1115
|
+
}>;
|
|
1116
|
+
}): {
|
|
1117
|
+
facts: number;
|
|
1118
|
+
logEntries: number;
|
|
1119
|
+
};
|
|
993
1120
|
private dumpDebugIfNeeded;
|
|
994
1121
|
close(): void;
|
|
995
1122
|
}
|
|
@@ -1095,6 +1222,18 @@ declare class CascadeRouter extends EventEmitter {
|
|
|
1095
1222
|
* No-op if store is not provided.
|
|
1096
1223
|
*/
|
|
1097
1224
|
profileModels(store: MemoryStore): Promise<void>;
|
|
1225
|
+
/**
|
|
1226
|
+
* One-time native tool-call probe for local/compat models with NO capability
|
|
1227
|
+
* metadata. llama.cpp / LM Studio "/models" endpoints return ids only, so
|
|
1228
|
+
* `supportsToolUse` stays undefined and the T3 tool gate ASSUMES native
|
|
1229
|
+
* support — wrong for many local builds, which then fumble tool-format
|
|
1230
|
+
* output. Each unknown model is probed once with a trivial tool; the verdict
|
|
1231
|
+
* persists in the MemoryStore's model_cache (via the previously-dormant
|
|
1232
|
+
* getModelProfile read-back), so a model is probed once EVER, not per run.
|
|
1233
|
+
* Cloud providers are never probed — their metadata is authoritative.
|
|
1234
|
+
*/
|
|
1235
|
+
probeLocalToolSupport(store: MemoryStore): Promise<void>;
|
|
1236
|
+
private probeNativeToolCall;
|
|
1098
1237
|
/**
|
|
1099
1238
|
* Cascade Auto live data: discover/validate real model ids from each cloud
|
|
1100
1239
|
* provider, then fetch current public quality scores + per-token prices and
|
|
@@ -1111,8 +1250,10 @@ declare class CascadeRouter extends EventEmitter {
|
|
|
1111
1250
|
*/
|
|
1112
1251
|
private discoverProviderModels;
|
|
1113
1252
|
/**
|
|
1114
|
-
* Replace available models with live-priced
|
|
1115
|
-
*
|
|
1253
|
+
* Replace available models with live-priced AND capability-corrected copies
|
|
1254
|
+
* (real context windows, native tool support, vision from modalities), then
|
|
1255
|
+
* refresh the already resolved tier models so shared-tier cost accounting and
|
|
1256
|
+
* the tool-use gate both see current data.
|
|
1116
1257
|
*/
|
|
1117
1258
|
private applyLivePricing;
|
|
1118
1259
|
generate(tier: TierRole, options: GenerateOptions, onChunk?: (chunk: StreamChunk) => void, requireVision?: boolean): Promise<GenerateResult>;
|
|
@@ -1127,6 +1268,10 @@ declare class CascadeRouter extends EventEmitter {
|
|
|
1127
1268
|
enabled: boolean;
|
|
1128
1269
|
maxPerSection: number;
|
|
1129
1270
|
};
|
|
1271
|
+
/** Project-knowledge settings (config.knowledge). Facts extraction on by default. */
|
|
1272
|
+
getKnowledgeConfig(): {
|
|
1273
|
+
factsExtraction: boolean;
|
|
1274
|
+
};
|
|
1130
1275
|
/**
|
|
1131
1276
|
* Resolved T3 wave execution mode. 'auto' becomes 'sequential' when the T3
|
|
1132
1277
|
* tier resolves to a LOCAL model (the single-GPU queue serializes anyway, so
|
|
@@ -1169,7 +1314,9 @@ declare class CascadeRouter extends EventEmitter {
|
|
|
1169
1314
|
* null when Cascade Auto is off (callers then use the shared tier model).
|
|
1170
1315
|
* Pure heuristic — no extra LLM call.
|
|
1171
1316
|
*/
|
|
1172
|
-
selectModelForSubtask(tier: TierRole, text: string
|
|
1317
|
+
selectModelForSubtask(tier: TierRole, text: string, opts?: {
|
|
1318
|
+
requiresToolUse?: boolean;
|
|
1319
|
+
}): Promise<ModelInfo | null>;
|
|
1173
1320
|
getStats(): RouterStats;
|
|
1174
1321
|
/**
|
|
1175
1322
|
* What did delegation save? Compares actual spend against the
|
|
@@ -1468,6 +1615,7 @@ declare class PermissionEscalator extends EventEmitter {
|
|
|
1468
1615
|
cancelAllPending(): void;
|
|
1469
1616
|
}
|
|
1470
1617
|
|
|
1618
|
+
type SandboxMode = 'isolate' | 'worker' | 'auto';
|
|
1471
1619
|
interface GeneratedToolSpec {
|
|
1472
1620
|
name: string;
|
|
1473
1621
|
description: string;
|
|
@@ -1489,12 +1637,14 @@ declare class ToolCreator {
|
|
|
1489
1637
|
private workspacePath?;
|
|
1490
1638
|
/** When false, persisted tools are neither loaded nor written. */
|
|
1491
1639
|
private persistEnabled;
|
|
1640
|
+
/** Sandbox runtime for generated tools; passed to each DynamicTool. */
|
|
1641
|
+
private sandboxMode;
|
|
1492
1642
|
private logger?;
|
|
1493
1643
|
/** name → spec, for persistence, broadcast, and re-registration. */
|
|
1494
1644
|
private specs;
|
|
1495
1645
|
/** capability fingerprint → tool name, so the same need isn't re-generated. */
|
|
1496
1646
|
private capabilityIndex;
|
|
1497
|
-
constructor(router: CascadeRouter, registry: ToolRegistry, workspacePath?: string, persistEnabled?: boolean);
|
|
1647
|
+
constructor(router: CascadeRouter, registry: ToolRegistry, workspacePath?: string, persistEnabled?: boolean, sandboxMode?: SandboxMode);
|
|
1498
1648
|
setPermissionEscalator(escalator: PermissionEscalator): void;
|
|
1499
1649
|
/** Route diagnostics through the host (Cascade) so they survive the Ink TUI. */
|
|
1500
1650
|
setLogger(fn: (msg: string) => void): void;
|
|
@@ -2011,6 +2161,14 @@ declare class T3Worker extends BaseTier {
|
|
|
2011
2161
|
*/
|
|
2012
2162
|
private reflectAndImprove;
|
|
2013
2163
|
private selfTest;
|
|
2164
|
+
/**
|
|
2165
|
+
* world-state v2: distill a completed subtask's output into durable
|
|
2166
|
+
* `(entity, relation, value)` facts and upsert them into the knowledge graph.
|
|
2167
|
+
* A bounded, cheap T3-tier call; entirely best-effort — any failure is swallowed
|
|
2168
|
+
* so it never blocks or fails the subtask. Respects the subtask's privacy tier
|
|
2169
|
+
* (a local-only subtask extracts on a local model too, never leaking to cloud).
|
|
2170
|
+
*/
|
|
2171
|
+
private extractAndStoreFacts;
|
|
2014
2172
|
private correctOutput;
|
|
2015
2173
|
private buildSystemPrompt;
|
|
2016
2174
|
private buildInitialPrompt;
|