@alisio/core 0.8.0 → 0.10.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/analysis/data/engine-client.d.ts +2 -0
- package/dist/analysis/data/engine-client.js +11 -4
- package/dist/application.d.ts +11 -1
- package/dist/application.js +46 -0
- package/dist/changelog/data.js +42 -0
- package/dist/commands/builtins.js +6 -0
- package/dist/commands/catalog.d.ts +4 -2
- package/dist/commands/catalog.js +23 -1
- package/dist/config.d.ts +31 -0
- package/dist/config.js +31 -1
- package/dist/context/elide.d.ts +50 -0
- package/dist/context/elide.js +222 -0
- package/dist/context/format.d.ts +21 -0
- package/dist/context/format.js +81 -0
- package/dist/context/governance.d.ts +58 -0
- package/dist/context/governance.js +96 -0
- package/dist/context/invariants.d.ts +88 -0
- package/dist/context/invariants.js +141 -0
- package/dist/context/inventory.d.ts +22 -0
- package/dist/context/inventory.js +178 -0
- package/dist/context/report.d.ts +35 -0
- package/dist/context/report.js +120 -0
- package/dist/context/sources.d.ts +20 -0
- package/dist/context/sources.js +41 -0
- package/dist/context/types.d.ts +43 -0
- package/dist/context/types.js +5 -0
- package/dist/context/usage.d.ts +96 -0
- package/dist/context/usage.js +264 -0
- package/dist/context/util.d.ts +22 -0
- package/dist/context/util.js +36 -0
- package/dist/core/compaction.d.ts +7 -2
- package/dist/core/compaction.js +9 -3
- package/dist/core/contracts.d.ts +8 -0
- package/dist/core/runner.d.ts +67 -0
- package/dist/core/runner.js +272 -10
- package/dist/eval/compare.d.ts +1 -1
- package/dist/eval/compare.js +18 -1
- package/dist/eval/engine.js +31 -1
- package/dist/eval/report.js +44 -1
- package/dist/forge/javascript/hosts/process-host.d.ts +1 -1
- package/dist/forge/javascript/hosts/process-host.js +4 -1
- package/dist/forge/python/wasm-node.d.ts +1 -1
- package/dist/forge/python/wasm-node.js +4 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.js +8 -2
- package/dist/plugins/host.d.ts +5 -0
- package/dist/plugins/host.js +15 -1
- package/dist/plugins/install.d.ts +50 -2
- package/dist/plugins/install.js +102 -12
- package/dist/plugins/local-install.d.ts +33 -0
- package/dist/plugins/local-install.js +121 -0
- package/dist/plugins/npm-runner.d.ts +30 -0
- package/dist/plugins/npm-runner.js +66 -0
- package/dist/plugins/tarball.d.ts +39 -0
- package/dist/plugins/tarball.js +277 -0
- package/dist/plugins/version-compat.d.ts +20 -0
- package/dist/plugins/version-compat.js +154 -0
- package/package.json +2 -2
|
@@ -7,6 +7,8 @@ export declare class DataError extends Error {
|
|
|
7
7
|
}
|
|
8
8
|
/** The engine script on disk (`<root>/analysis/engine/data-engine-<hash>.mjs`). */
|
|
9
9
|
export declare function ensureEngineScript(root: string): Promise<string>;
|
|
10
|
+
/** The whitelisted environment of an engine child, from `parent`. */
|
|
11
|
+
export declare function engineChildEnv(parent?: NodeJS.ProcessEnv): Record<string, string>;
|
|
10
12
|
export interface DataEngineOptions {
|
|
11
13
|
/** State folder (`<root>/analysis/engine/…` holds the script). */
|
|
12
14
|
root: string;
|
|
@@ -57,7 +57,17 @@ const ENV_KEYS = [
|
|
|
57
57
|
"SYSTEMROOT",
|
|
58
58
|
"WINDIR",
|
|
59
59
|
"LANG",
|
|
60
|
+
// Set by hosts that run on the Electron binary (the desktop app): without it the worker, which is
|
|
61
|
+
// spawned from `process.execPath`, would start another GUI instance instead of plain Node.
|
|
62
|
+
"ELECTRON_RUN_AS_NODE",
|
|
60
63
|
];
|
|
64
|
+
/** The whitelisted environment of an engine child, from `parent`. */
|
|
65
|
+
export function engineChildEnv(parent = process.env) {
|
|
66
|
+
return {
|
|
67
|
+
...Object.fromEntries(ENV_KEYS.flatMap((k) => (parent[k] ? [[k, parent[k]]] : []))),
|
|
68
|
+
BUN_BE_BUN: "1",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
61
71
|
/** One engine child process and its pending request. */
|
|
62
72
|
class EngineProcess {
|
|
63
73
|
child;
|
|
@@ -74,10 +84,7 @@ class EngineProcess {
|
|
|
74
84
|
: [`--max-old-space-size=${memoryMb}`, "--disable-warning=ExperimentalWarning"]),
|
|
75
85
|
script,
|
|
76
86
|
], {
|
|
77
|
-
env:
|
|
78
|
-
...Object.fromEntries(ENV_KEYS.flatMap((k) => (process.env[k] ? [[k, process.env[k]]] : []))),
|
|
79
|
-
BUN_BE_BUN: "1",
|
|
80
|
-
},
|
|
87
|
+
env: engineChildEnv(),
|
|
81
88
|
stdio: ["pipe", "pipe", "pipe"],
|
|
82
89
|
windowsHide: true,
|
|
83
90
|
});
|
package/dist/application.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AvailableProviderModel, ModelInfo, ModelProvider, Plugin, PluginCategory, ProviderConfigurationValue, ResolvedProviderModel, RunEvent } from "@alisio/sdk";
|
|
1
|
+
import type { AvailableProviderModel, ContextReport, ModelInfo, ModelProvider, Plugin, PluginCategory, ProviderConfigurationValue, ResolvedProviderModel, RunEvent } from "@alisio/sdk";
|
|
2
2
|
import { AgentDefinitionService } from "./agents/service.ts";
|
|
3
3
|
import { CapabilityGrants } from "./analysis/capabilities.ts";
|
|
4
4
|
import { DatasetService } from "./analysis/data/datasets.ts";
|
|
@@ -148,6 +148,11 @@ export interface PluginCatalogEntry {
|
|
|
148
148
|
enabled: boolean;
|
|
149
149
|
manageable: boolean;
|
|
150
150
|
diagnostic?: string;
|
|
151
|
+
/**
|
|
152
|
+
* The npm package name an external plugin was loaded from. Never a path: the catalog stays
|
|
153
|
+
* path-safe, so file and directory plugins carry no `spec`.
|
|
154
|
+
*/
|
|
155
|
+
spec?: string;
|
|
151
156
|
}
|
|
152
157
|
export interface ConfiguredProviderCatalog {
|
|
153
158
|
profile: string;
|
|
@@ -350,6 +355,11 @@ export declare function createApplication(options?: AppOptions): Promise<{
|
|
|
350
355
|
basis: "window" | "unknown";
|
|
351
356
|
compactionAt: number;
|
|
352
357
|
};
|
|
358
|
+
/**
|
|
359
|
+
* The Context Governor's explanation of a session (spec 012 phase 5): the one `ContextReport`
|
|
360
|
+
* that `/context`, the web panel and the HTTP route render. Read only.
|
|
361
|
+
*/
|
|
362
|
+
contextReport: (sessionId: string) => ContextReport;
|
|
353
363
|
loadModels: (signal: AbortSignal) => Promise<ModelInfo[]>;
|
|
354
364
|
/** Creates a provider for validation/model discovery without changing the active provider. */
|
|
355
365
|
probeProvider(id: string, profile: Record<string, import("@alisio/sdk").ProviderConfigurationValue>, credentials: Record<string, string>, signal: AbortSignal): Promise<ModelInfo[]>;
|
package/dist/application.js
CHANGED
|
@@ -15,6 +15,9 @@ import { TaskJanitor } from "./background/janitor.js";
|
|
|
15
15
|
import { subagentTasks } from "./background/mirror.js";
|
|
16
16
|
import { BackgroundTasks } from "./background/service.js";
|
|
17
17
|
import { configFile, configHome, loadConfigWithProvenance, overridesSavedProviderProfile, setConfigValue, setGlobalMcpAllow, setMcpServerEnabled, setProjectPluginEnabled, setProjectSkillEnabled, stateHome, } from "./config.js";
|
|
18
|
+
import { CONTEXT_POLICY_VERSION } from "./context/elide.js";
|
|
19
|
+
import { buildContextReport } from "./context/report.js";
|
|
20
|
+
import { createInvariantSources } from "./context/sources.js";
|
|
18
21
|
import { completeText } from "./core/compaction.js";
|
|
19
22
|
import { HumanWaits } from "./core/human-wait.js";
|
|
20
23
|
import { DEFAULT_MAX_OUTPUT_TOKENS } from "./core/output-limit.js";
|
|
@@ -31,6 +34,7 @@ import { GoalService } from "./goal/service.js";
|
|
|
31
34
|
import { GoalStore } from "./goal/store.js";
|
|
32
35
|
import { HerdrBridge } from "./integrations/herdr.js";
|
|
33
36
|
import { McpConnector } from "./mcp/connector.js";
|
|
37
|
+
import { currentPlan } from "./plan/state.js";
|
|
34
38
|
import { discoverPlugins, PluginHost } from "./plugins/host.js";
|
|
35
39
|
import { ProofVerifierRegistry } from "./proof/plugin-verifiers.js";
|
|
36
40
|
import { ProofRecorder } from "./proof/recorder.js";
|
|
@@ -328,6 +332,7 @@ export async function createApplication(options = {}) {
|
|
|
328
332
|
status: enabled ? "active" : "inactive",
|
|
329
333
|
enabled,
|
|
330
334
|
manageable: entry.manageable,
|
|
335
|
+
...(isPathSpec(entry.spec) ? {} : { spec: entry.spec }),
|
|
331
336
|
});
|
|
332
337
|
runtimePluginEnabled.set(candidate.plugin.id, enabled);
|
|
333
338
|
}
|
|
@@ -345,6 +350,7 @@ export async function createApplication(options = {}) {
|
|
|
345
350
|
enabled: true,
|
|
346
351
|
manageable: entry.manageable,
|
|
347
352
|
diagnostic: "Activation failed; registrations were rolled back",
|
|
353
|
+
...(isPathSpec(entry.spec) ? {} : { spec: entry.spec }),
|
|
348
354
|
});
|
|
349
355
|
continue;
|
|
350
356
|
}
|
|
@@ -360,6 +366,7 @@ export async function createApplication(options = {}) {
|
|
|
360
366
|
enabled: true,
|
|
361
367
|
manageable: false,
|
|
362
368
|
diagnostic: "Load failed; no path or credential details are shown here",
|
|
369
|
+
...(isPathSpec(entry.spec) ? {} : { spec: entry.spec }),
|
|
363
370
|
});
|
|
364
371
|
}
|
|
365
372
|
}
|
|
@@ -982,6 +989,25 @@ export async function createApplication(options = {}) {
|
|
|
982
989
|
policy: runtimePolicy,
|
|
983
990
|
...config.limits,
|
|
984
991
|
compaction: config.compaction,
|
|
992
|
+
contextGovernor: {
|
|
993
|
+
mode: config.context.governor,
|
|
994
|
+
...config.context.elide,
|
|
995
|
+
policyVersion: config.context.policyVersion ?? CONTEXT_POLICY_VERSION,
|
|
996
|
+
invariantMaxChars: config.context.invariants.maxChars,
|
|
997
|
+
},
|
|
998
|
+
invariantSources: createInvariantSources({
|
|
999
|
+
goal: (sessionId) => goals.get(sessionId),
|
|
1000
|
+
plan: (sessionId) => currentPlan(store, sessionId),
|
|
1001
|
+
criteria: (sessionId) => new ProofStore(store.db).criteria(sessionId),
|
|
1002
|
+
...(analysisEnabled
|
|
1003
|
+
? {
|
|
1004
|
+
capabilities: {
|
|
1005
|
+
granted: (capability, sessionId) => capabilityGrants.granted(capability, sessionId),
|
|
1006
|
+
},
|
|
1007
|
+
}
|
|
1008
|
+
: {}),
|
|
1009
|
+
externalDirectories: () => pathAccess.approvedDirectories().length,
|
|
1010
|
+
}),
|
|
985
1011
|
extensions: plugins,
|
|
986
1012
|
contextWindow,
|
|
987
1013
|
modelOutputLimit: declaredOutputLimit,
|
|
@@ -1586,6 +1612,26 @@ export async function createApplication(options = {}) {
|
|
|
1586
1612
|
contextWindow,
|
|
1587
1613
|
/** Effective context budget + compaction point shared by the runner and the TUI bar. */
|
|
1588
1614
|
contextBudget: (model) => runner.contextBudget(model),
|
|
1615
|
+
/**
|
|
1616
|
+
* The Context Governor's explanation of a session (spec 012 phase 5): the one `ContextReport`
|
|
1617
|
+
* that `/context`, the web panel and the HTTP route render. Read only.
|
|
1618
|
+
*/
|
|
1619
|
+
contextReport: (sessionId) => {
|
|
1620
|
+
const inputs = runner.contextInputs(sessionId);
|
|
1621
|
+
return buildContextReport({
|
|
1622
|
+
sessionId,
|
|
1623
|
+
governor: inputs?.governor ?? {
|
|
1624
|
+
mode: "off",
|
|
1625
|
+
minAgeTurns: 0,
|
|
1626
|
+
epochMessages: 0,
|
|
1627
|
+
policyVersion: CONTEXT_POLICY_VERSION,
|
|
1628
|
+
},
|
|
1629
|
+
messages: inputs?.messages ?? [],
|
|
1630
|
+
...(inputs ? { invariants: inputs.invariants } : {}),
|
|
1631
|
+
...(inputs?.ledger ? { ledger: inputs.ledger } : {}),
|
|
1632
|
+
...(inputs?.governance ? { governance: inputs.governance } : {}),
|
|
1633
|
+
});
|
|
1634
|
+
},
|
|
1589
1635
|
loadModels,
|
|
1590
1636
|
/** Creates a provider for validation/model discovery without changing the active provider. */
|
|
1591
1637
|
async probeProvider(id, profile, credentials, signal) {
|
package/dist/changelog/data.js
CHANGED
|
@@ -2,6 +2,48 @@
|
|
|
2
2
|
export const CHANGELOG_DATA = {
|
|
3
3
|
schema: 1,
|
|
4
4
|
entries: [
|
|
5
|
+
{
|
|
6
|
+
version: "0.10.0",
|
|
7
|
+
date: "2026-11-07",
|
|
8
|
+
sections: [
|
|
9
|
+
{
|
|
10
|
+
title: "Added",
|
|
11
|
+
items: [
|
|
12
|
+
"Settings → Plugins → **Plugin catalog**: browse the published plugins with search, category and tag filters and pages of 10, and install one with a click. The catalog is cached for 24 hours and only downloaded again when it changed; **Check for updates** checks now.",
|
|
13
|
+
"**Install from file**: install a private plugin from a `.tgz` made with `npm pack` or `pnpm pack`. The file is validated first (an Alisio plugin, its SDK range, install scripts), the install shows its progress step by step, and temporary files are removed. The package is kept under `~/.config/alisio/plugins/local-packages`, so the original file can be moved or deleted.",
|
|
14
|
+
"**Installed plugins**: uninstall a plugin, see when a catalog plugin has a newer version, and update one or all of them. Installing a plugin that is already there updates it in place.",
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
title: "Improved",
|
|
19
|
+
items: [
|
|
20
|
+
"When `npm` is missing, installing a plugin says so clearly instead of failing with a spawn error. Alisio Desktop bundles its own `npm`, so plugins install without Node.js on the system.",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
version: "0.9.0",
|
|
27
|
+
date: "2026-11-07",
|
|
28
|
+
sections: [
|
|
29
|
+
{
|
|
30
|
+
title: "Added",
|
|
31
|
+
items: [
|
|
32
|
+
"Alisio Desktop: install Alisio like any other program on Windows, macOS or Linux, with no terminal and no Node.js. Download it from the documentation home page or the `desktop-v0.9.0` GitHub release. The desktop app shares its sessions and settings with the CLI.",
|
|
33
|
+
"Context Governor (experimental, off by default): `context.governor` (`off`, `shadow`, `on`). In `on` mode, tool results made redundant by a later one (superseded reads, repeated identical `bg_output` polls, duplicate searches) are replaced by a one-line stub in the request, and your instructions, the live goal, the approved plan, Proof criteria and session grants survive compaction verbatim. `shadow` only measures and sends exactly what `off` sends.",
|
|
34
|
+
"`/context`, a **Context** tab in the web UI and `GET /api/sessions/:sid/context/report`: what the next request carries and what the governor elides, with counts and token estimates only.",
|
|
35
|
+
"`/stats` shows a Context Governor section, and the web trajectory shows each governed request.",
|
|
36
|
+
"Reliability Lab: the `long-context-stress` suite, and runs record the provider's cached input tokens (`cachedInputTokens`), with a cached-input ratio in reports and `eval compare`.",
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
title: "Improved",
|
|
41
|
+
items: [
|
|
42
|
+
"Alisio now presents itself as an assistant for everyday work (`alisio --help`, the web UI About text and the documentation); programming remains fully supported as an advanced use.",
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
},
|
|
5
47
|
{
|
|
6
48
|
version: "0.8.0",
|
|
7
49
|
date: "2026-10-14",
|
|
@@ -158,6 +158,12 @@ export const BUILTIN_COMMANDS = [
|
|
|
158
158
|
surfaces: INTERACTIVE,
|
|
159
159
|
execution: "surface",
|
|
160
160
|
},
|
|
161
|
+
{
|
|
162
|
+
name: "context",
|
|
163
|
+
description: "Show what the next request carries and what the Context Governor elides",
|
|
164
|
+
surfaces: ALL,
|
|
165
|
+
execution: "core",
|
|
166
|
+
},
|
|
161
167
|
{
|
|
162
168
|
name: "decisions",
|
|
163
169
|
description: "Show Decision Intelligence status, provider health and session metrics",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* The catalog reads its sources live from the host on each call, so plugin/template/skill
|
|
5
5
|
* changes show up without rebuilding it.
|
|
6
6
|
*/
|
|
7
|
-
import { type CommandDescriptor, type ToolDefinition } from "@alisio/sdk";
|
|
7
|
+
import { type CommandDescriptor, type ContextReport, type ToolDefinition } from "@alisio/sdk";
|
|
8
8
|
import type { PluginCatalogEntry } from "../application.ts";
|
|
9
9
|
import type { SessionStore } from "../core/contracts.ts";
|
|
10
10
|
import type { AgentRunner } from "../core/runner.ts";
|
|
@@ -26,7 +26,9 @@ type PluginCommandHandler = (args: string, context?: {
|
|
|
26
26
|
export interface CommandHost {
|
|
27
27
|
workspace: string;
|
|
28
28
|
store: SessionStore;
|
|
29
|
-
runner: Pick<AgentRunner, "policy" | "approvals" | "compact" | "setModel"
|
|
29
|
+
runner: Pick<AgentRunner, "policy" | "approvals" | "compact" | "setModel"> & Partial<Pick<AgentRunner, "governance" | "contextUsage">>;
|
|
30
|
+
/** The Context Governor's report of a session (`/context`); `createApplication` provides it. */
|
|
31
|
+
contextReport?(sessionId: string): ContextReport;
|
|
30
32
|
registry: {
|
|
31
33
|
list(): ToolDefinition[];
|
|
32
34
|
};
|
package/dist/commands/catalog.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { summarizeDecisionEvents, } from "@alisio/sdk";
|
|
8
8
|
import { agentCatalogFromState, agentCommandDescriptors, resolveActiveAgent, } from "../agents/active.js";
|
|
9
|
+
import { formatContextGovernorStatsSection, formatContextReport } from "../context/format.js";
|
|
10
|
+
import { governedEventData } from "../context/governance.js";
|
|
9
11
|
import { formatDecisionStatsSection, formatDecisionsReport, } from "../decisions/index.js";
|
|
10
12
|
import { formatSideQuestion, SIDE_QUESTION_DESCRIPTION, SIDE_QUESTION_USAGE, } from "../sessions/side-questions.js";
|
|
11
13
|
import { BUILTIN_COMMANDS } from "./builtins.js";
|
|
@@ -174,6 +176,12 @@ const HANDLERS = {
|
|
|
174
176
|
output: sum.output + (r.usage?.output ?? 0),
|
|
175
177
|
}), { input: 0, output: 0 });
|
|
176
178
|
const decisionSection = formatDecisionStatsSection(summarizeDecisionEvents(decisionEvents(host, ctx.sessionId)));
|
|
179
|
+
const governance = host.runner?.governance?.(session.id);
|
|
180
|
+
const usage = host.runner?.contextUsage?.(session.id);
|
|
181
|
+
const governorSection = formatContextGovernorStatsSection({
|
|
182
|
+
...(governance ? { governance } : {}),
|
|
183
|
+
...(usage ? { usage } : {}),
|
|
184
|
+
});
|
|
177
185
|
return {
|
|
178
186
|
text: [
|
|
179
187
|
"**Session statistics**",
|
|
@@ -184,10 +192,24 @@ const HANDLERS = {
|
|
|
184
192
|
`- Runs: ${runs.length}`,
|
|
185
193
|
`- Tokens: in ${tokens.input} · out ${tokens.output}`,
|
|
186
194
|
...(decisionSection ? ["", decisionSection] : []),
|
|
195
|
+
...(governorSection ? ["", governorSection] : []),
|
|
187
196
|
].join("\n"),
|
|
188
|
-
data: {
|
|
197
|
+
data: {
|
|
198
|
+
session,
|
|
199
|
+
runs: runs.length,
|
|
200
|
+
tokens,
|
|
201
|
+
...(governorSection
|
|
202
|
+
? { contextGovernor: governance ? governedEventData(governance, usage) : { usage } }
|
|
203
|
+
: {}),
|
|
204
|
+
},
|
|
189
205
|
};
|
|
190
206
|
},
|
|
207
|
+
async context(_args, ctx, host) {
|
|
208
|
+
if (!host.contextReport)
|
|
209
|
+
return { text: "The context report is not available in this host.", tone: "notice" };
|
|
210
|
+
const report = host.contextReport(ctx.sessionId);
|
|
211
|
+
return { text: formatContextReport(report), data: report };
|
|
212
|
+
},
|
|
191
213
|
async skills(_args, _ctx, host) {
|
|
192
214
|
const skills = host.skillCatalog?.() ?? [];
|
|
193
215
|
if (!skills.length)
|
package/dist/config.d.ts
CHANGED
|
@@ -161,6 +161,19 @@ export declare const configSchema: z.ZodPipe<z.ZodObject<{
|
|
|
161
161
|
context: z.ZodDefault<z.ZodObject<{
|
|
162
162
|
claudeMdFallback: z.ZodDefault<z.ZodBoolean>;
|
|
163
163
|
maxBytes: z.ZodDefault<z.ZodNumber>;
|
|
164
|
+
governor: z.ZodDefault<z.ZodEnum<{
|
|
165
|
+
off: "off";
|
|
166
|
+
on: "on";
|
|
167
|
+
shadow: "shadow";
|
|
168
|
+
}>>;
|
|
169
|
+
policyVersion: z.ZodOptional<z.ZodNumber>;
|
|
170
|
+
elide: z.ZodDefault<z.ZodObject<{
|
|
171
|
+
minAgeTurns: z.ZodDefault<z.ZodNumber>;
|
|
172
|
+
epochMessages: z.ZodDefault<z.ZodNumber>;
|
|
173
|
+
}, z.core.$strict>>;
|
|
174
|
+
invariants: z.ZodDefault<z.ZodObject<{
|
|
175
|
+
maxChars: z.ZodDefault<z.ZodNumber>;
|
|
176
|
+
}, z.core.$strict>>;
|
|
164
177
|
}, z.core.$strict>>;
|
|
165
178
|
compaction: z.ZodDefault<z.ZodObject<{
|
|
166
179
|
auto: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -351,6 +364,15 @@ export declare const configSchema: z.ZodPipe<z.ZodObject<{
|
|
|
351
364
|
context: {
|
|
352
365
|
claudeMdFallback: boolean;
|
|
353
366
|
maxBytes: number;
|
|
367
|
+
governor: "off" | "on" | "shadow";
|
|
368
|
+
policyVersion?: number | undefined;
|
|
369
|
+
elide: {
|
|
370
|
+
minAgeTurns: number;
|
|
371
|
+
epochMessages: number;
|
|
372
|
+
};
|
|
373
|
+
invariants: {
|
|
374
|
+
maxChars: number;
|
|
375
|
+
};
|
|
354
376
|
};
|
|
355
377
|
compaction: {
|
|
356
378
|
auto: boolean;
|
|
@@ -600,6 +622,15 @@ export declare const configSchema: z.ZodPipe<z.ZodObject<{
|
|
|
600
622
|
context: {
|
|
601
623
|
claudeMdFallback: boolean;
|
|
602
624
|
maxBytes: number;
|
|
625
|
+
governor: "off" | "on" | "shadow";
|
|
626
|
+
policyVersion?: number | undefined;
|
|
627
|
+
elide: {
|
|
628
|
+
minAgeTurns: number;
|
|
629
|
+
epochMessages: number;
|
|
630
|
+
};
|
|
631
|
+
invariants: {
|
|
632
|
+
maxChars: number;
|
|
633
|
+
};
|
|
603
634
|
};
|
|
604
635
|
compaction: {
|
|
605
636
|
auto: boolean;
|
package/dist/config.js
CHANGED
|
@@ -2,6 +2,7 @@ import { chmod, mkdir, open, readFile, realpath, rename, unlink } from "node:fs/
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
+
import { CONTEXT_POLICY_VERSION } from "./context/elide.js";
|
|
5
6
|
import { DEFAULT_DECISIONS_CONFIG } from "./decisions/service.js";
|
|
6
7
|
import { DEFAULT_FORGE_LIMITS, MAX_FORGE_LIMITS } from "./forge/limits.js";
|
|
7
8
|
import { exists, readJson } from "./runtime/fs.js";
|
|
@@ -230,9 +231,38 @@ const configObjectSchema = z
|
|
|
230
231
|
.min(1024)
|
|
231
232
|
.max(1_048_576)
|
|
232
233
|
.default(32 * 1024),
|
|
234
|
+
/**
|
|
235
|
+
* Context Governor (spec 012): `off` changes nothing, `shadow` computes what it would elide
|
|
236
|
+
* without changing what is sent, `on` sends the projected history.
|
|
237
|
+
*/
|
|
238
|
+
governor: z.enum(["off", "shadow", "on"]).default("off"),
|
|
239
|
+
/** Optional pin of the elision rules; unset follows this build's current version. */
|
|
240
|
+
policyVersion: z.number().int().min(1).max(CONTEXT_POLICY_VERSION).optional(),
|
|
241
|
+
elide: z
|
|
242
|
+
.object({
|
|
243
|
+
/** Assistant messages a redundant result must be older than before it is replaced. */
|
|
244
|
+
minAgeTurns: z.number().int().min(1).max(20).default(2),
|
|
245
|
+
/** Projection grows in steps of this many messages (cache-friendly); 0 is eager. */
|
|
246
|
+
epochMessages: z.number().int().min(0).max(1000).default(32),
|
|
247
|
+
})
|
|
248
|
+
.strict()
|
|
249
|
+
.default(() => ({ minAgeTurns: 2, epochMessages: 32 })),
|
|
250
|
+
invariants: z
|
|
251
|
+
.object({
|
|
252
|
+
/** Size cap of the `<invariants>` block sent after a compaction (`on` mode only). */
|
|
253
|
+
maxChars: z.number().int().min(1000).max(20_000).default(4000),
|
|
254
|
+
})
|
|
255
|
+
.strict()
|
|
256
|
+
.default(() => ({ maxChars: 4000 })),
|
|
233
257
|
})
|
|
234
258
|
.strict()
|
|
235
|
-
.default(() => ({
|
|
259
|
+
.default(() => ({
|
|
260
|
+
claudeMdFallback: false,
|
|
261
|
+
maxBytes: 32 * 1024,
|
|
262
|
+
governor: "off",
|
|
263
|
+
elide: { minAgeTurns: 2, epochMessages: 32 },
|
|
264
|
+
invariants: { maxChars: 4000 },
|
|
265
|
+
})),
|
|
236
266
|
compaction: z
|
|
237
267
|
.object({
|
|
238
268
|
auto: z.boolean().default(true),
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Message } from "@alisio/sdk";
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic elision by substitution (spec 012 phase 2). Pure functions over `Message[]`: they
|
|
4
|
+
* never touch the persisted transcript, only compute what a request MAY send instead.
|
|
5
|
+
*/
|
|
6
|
+
/** Version of the elision rules. Bump it whenever a rule or a stub format changes. */
|
|
7
|
+
export declare const CONTEXT_POLICY_VERSION = 1;
|
|
8
|
+
export type ElisionReason = "superseded_read" | "stale_bg_output" | "duplicate_search";
|
|
9
|
+
export interface Elision {
|
|
10
|
+
/** Index of the elided tool message in the projected history. */
|
|
11
|
+
index: number;
|
|
12
|
+
callId: string;
|
|
13
|
+
/** Inventory id of the tool_result segment (same as `ContextSegment.id`). */
|
|
14
|
+
segmentId: string;
|
|
15
|
+
reason: ElisionReason;
|
|
16
|
+
/** Call id of the EARLIEST later result that justifies the elision (stable under append). */
|
|
17
|
+
witnessCallId: string;
|
|
18
|
+
/** Token ESTIMATE saved (`estimateTokens` of the original text minus that of the stub). */
|
|
19
|
+
tokensSaved: number;
|
|
20
|
+
}
|
|
21
|
+
export interface Projection {
|
|
22
|
+
/** The input array itself when nothing is elided, else a copy with only elided entries replaced. */
|
|
23
|
+
messages: Message[];
|
|
24
|
+
elisions: Elision[];
|
|
25
|
+
/** Estimate of the model-visible text of the history before and after the projection. */
|
|
26
|
+
tokensBefore: number;
|
|
27
|
+
tokensAfter: number;
|
|
28
|
+
/** Messages `[0, boundary)` are eligible; the rest is sent as is until the next epoch. */
|
|
29
|
+
boundary: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Which tool results a later result makes redundant, regardless of age. `witness` is the index of
|
|
33
|
+
* the EARLIEST later result that proves it, so it never changes when messages are appended. Every
|
|
34
|
+
* rule is existential ("some later result exists"), which is what makes the set grow monotonically.
|
|
35
|
+
* Error results are neither candidates nor witnesses.
|
|
36
|
+
*/
|
|
37
|
+
export declare function elisionCandidates(messages: Message[]): Map<number, {
|
|
38
|
+
reason: ElisionReason;
|
|
39
|
+
witness: number;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Projects the history a request would carry: tool results that a later result made redundant are
|
|
43
|
+
* replaced by a one-line stub once they are `minAgeTurns` assistant messages old (counted inside the
|
|
44
|
+
* eligible prefix). With `epochMessages` E > 0 only the prefix `floor(n / E) * E` is eligible, so the
|
|
45
|
+
* projected history grows by appending between epochs and a provider prompt cache stays valid.
|
|
46
|
+
*/
|
|
47
|
+
export declare function projectContext(messages: Message[], o: {
|
|
48
|
+
minAgeTurns: number;
|
|
49
|
+
epochMessages: number;
|
|
50
|
+
}): Projection;
|