praana 0.5.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/LICENSE +21 -0
- package/README.md +124 -0
- package/bin/praana.js +17 -0
- package/bin/pran.js +17 -0
- package/dist/app-banner.d.ts +11 -0
- package/dist/app-banner.js +161 -0
- package/dist/app-controller.d.ts +44 -0
- package/dist/app-controller.js +143 -0
- package/dist/app-identity.d.ts +18 -0
- package/dist/app-identity.js +52 -0
- package/dist/auto-compact.d.ts +16 -0
- package/dist/auto-compact.js +101 -0
- package/dist/cli-args.d.ts +14 -0
- package/dist/cli-args.js +69 -0
- package/dist/compile-classic.d.ts +21 -0
- package/dist/compile-classic.js +106 -0
- package/dist/compiler.d.ts +75 -0
- package/dist/compiler.js +406 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +433 -0
- package/dist/context-engine/activity-log.d.ts +9 -0
- package/dist/context-engine/activity-log.js +109 -0
- package/dist/context-engine/artifact-store.d.ts +32 -0
- package/dist/context-engine/artifact-store.js +272 -0
- package/dist/context-engine/bm25.d.ts +3 -0
- package/dist/context-engine/bm25.js +32 -0
- package/dist/context-engine/checkpoint.d.ts +34 -0
- package/dist/context-engine/checkpoint.js +430 -0
- package/dist/context-engine/classify.d.ts +3 -0
- package/dist/context-engine/classify.js +60 -0
- package/dist/context-engine/db.d.ts +73 -0
- package/dist/context-engine/db.js +505 -0
- package/dist/context-engine/distiller.d.ts +30 -0
- package/dist/context-engine/distiller.js +67 -0
- package/dist/context-engine/engine-compiler.d.ts +23 -0
- package/dist/context-engine/engine-compiler.js +297 -0
- package/dist/context-engine/error-tracker.d.ts +21 -0
- package/dist/context-engine/error-tracker.js +74 -0
- package/dist/context-engine/event-lineage.d.ts +26 -0
- package/dist/context-engine/event-lineage.js +120 -0
- package/dist/context-engine/extraction.d.ts +26 -0
- package/dist/context-engine/extraction.js +83 -0
- package/dist/context-engine/index.d.ts +82 -0
- package/dist/context-engine/index.js +238 -0
- package/dist/context-engine/scoring.d.ts +13 -0
- package/dist/context-engine/scoring.js +47 -0
- package/dist/context-engine/state-snapshot.d.ts +8 -0
- package/dist/context-engine/state-snapshot.js +50 -0
- package/dist/context-engine/summarize.d.ts +6 -0
- package/dist/context-engine/summarize.js +32 -0
- package/dist/context-engine/telemetry.d.ts +25 -0
- package/dist/context-engine/telemetry.js +64 -0
- package/dist/context-engine/turn-digest.d.ts +50 -0
- package/dist/context-engine/turn-digest.js +250 -0
- package/dist/context-engine/turn-ledger.d.ts +18 -0
- package/dist/context-engine/turn-ledger.js +184 -0
- package/dist/context-engine/turn-recorder.d.ts +24 -0
- package/dist/context-engine/turn-recorder.js +88 -0
- package/dist/context-engine/types.d.ts +201 -0
- package/dist/context-engine/types.js +4 -0
- package/dist/context-pressure.d.ts +19 -0
- package/dist/context-pressure.js +36 -0
- package/dist/distillers/generic.d.ts +14 -0
- package/dist/distillers/generic.js +93 -0
- package/dist/distillers/git-diff.d.ts +8 -0
- package/dist/distillers/git-diff.js +119 -0
- package/dist/distillers/index.d.ts +2 -0
- package/dist/distillers/index.js +16 -0
- package/dist/distillers/npm-test.d.ts +8 -0
- package/dist/distillers/npm-test.js +50 -0
- package/dist/distillers/rg-results.d.ts +8 -0
- package/dist/distillers/rg-results.js +28 -0
- package/dist/distillers/tsc-errors.d.ts +8 -0
- package/dist/distillers/tsc-errors.js +52 -0
- package/dist/event-log.d.ts +56 -0
- package/dist/event-log.js +214 -0
- package/dist/llm.d.ts +29 -0
- package/dist/llm.js +155 -0
- package/dist/logger.d.ts +94 -0
- package/dist/logger.js +287 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +54 -0
- package/dist/memory/confidence.d.ts +7 -0
- package/dist/memory/confidence.js +37 -0
- package/dist/memory/consolidation.d.ts +26 -0
- package/dist/memory/consolidation.js +166 -0
- package/dist/memory/db.d.ts +40 -0
- package/dist/memory/db.js +283 -0
- package/dist/memory/dedup.d.ts +6 -0
- package/dist/memory/dedup.js +50 -0
- package/dist/memory/embedder-factory.d.ts +3 -0
- package/dist/memory/embedder-factory.js +81 -0
- package/dist/memory/embeddings.d.ts +15 -0
- package/dist/memory/embeddings.js +67 -0
- package/dist/memory/index.d.ts +9 -0
- package/dist/memory/index.js +11 -0
- package/dist/memory/ollama-summarizer.d.ts +19 -0
- package/dist/memory/ollama-summarizer.js +72 -0
- package/dist/memory/openai-summarizer.d.ts +21 -0
- package/dist/memory/openai-summarizer.js +51 -0
- package/dist/memory/store.d.ts +61 -0
- package/dist/memory/store.js +502 -0
- package/dist/memory/summarizer-factory.d.ts +3 -0
- package/dist/memory/summarizer-factory.js +69 -0
- package/dist/memory/summarizer.d.ts +4 -0
- package/dist/memory/summarizer.js +112 -0
- package/dist/memory/types.d.ts +87 -0
- package/dist/memory/types.js +17 -0
- package/dist/model-context.d.ts +15 -0
- package/dist/model-context.js +212 -0
- package/dist/project-detector.d.ts +37 -0
- package/dist/project-detector.js +604 -0
- package/dist/render.d.ts +15 -0
- package/dist/render.js +46 -0
- package/dist/session.d.ts +118 -0
- package/dist/session.js +809 -0
- package/dist/skills/index.d.ts +69 -0
- package/dist/skills/index.js +885 -0
- package/dist/skills/types.d.ts +93 -0
- package/dist/skills/types.js +8 -0
- package/dist/slash-commands.d.ts +14 -0
- package/dist/slash-commands.js +301 -0
- package/dist/state-graph.d.ts +38 -0
- package/dist/state-graph.js +255 -0
- package/dist/status-bar.d.ts +54 -0
- package/dist/status-bar.js +184 -0
- package/dist/thinking-display.d.ts +21 -0
- package/dist/thinking-display.js +37 -0
- package/dist/tool-summary.d.ts +4 -0
- package/dist/tool-summary.js +67 -0
- package/dist/tools/index.d.ts +925 -0
- package/dist/tools/index.js +86 -0
- package/dist/tools/knowledge.d.ts +140 -0
- package/dist/tools/knowledge.js +260 -0
- package/dist/tools/memory.d.ts +39 -0
- package/dist/tools/memory.js +300 -0
- package/dist/tools/search-code.d.ts +134 -0
- package/dist/tools/search-code.js +390 -0
- package/dist/tools/system.d.ts +16 -0
- package/dist/tools/system.js +499 -0
- package/dist/tools/tool-def.d.ts +6 -0
- package/dist/tools/tool-def.js +3 -0
- package/dist/turn-control.d.ts +51 -0
- package/dist/turn-control.js +210 -0
- package/dist/turn.d.ts +20 -0
- package/dist/turn.js +624 -0
- package/dist/types.d.ts +233 -0
- package/dist/types.js +4 -0
- package/dist/ui/readline-ui.d.ts +2 -0
- package/dist/ui/readline-ui.js +176 -0
- package/dist/ui/tui/app.d.ts +13 -0
- package/dist/ui/tui/app.js +270 -0
- package/dist/ui/tui/busy-indicator.d.ts +2 -0
- package/dist/ui/tui/busy-indicator.js +13 -0
- package/dist/ui/tui/components/gutter-rule.d.ts +5 -0
- package/dist/ui/tui/components/gutter-rule.js +9 -0
- package/dist/ui/tui/components/inline-tool-row.d.ts +10 -0
- package/dist/ui/tui/components/inline-tool-row.js +8 -0
- package/dist/ui/tui/components/prompt-input.d.ts +20 -0
- package/dist/ui/tui/components/prompt-input.js +120 -0
- package/dist/ui/tui/components/system-line.d.ts +5 -0
- package/dist/ui/tui/components/system-line.js +6 -0
- package/dist/ui/tui/components/thinking-block.d.ts +11 -0
- package/dist/ui/tui/components/thinking-block.js +31 -0
- package/dist/ui/tui/components/toast-line.d.ts +4 -0
- package/dist/ui/tui/components/toast-line.js +8 -0
- package/dist/ui/tui/components/tool-result-line.d.ts +5 -0
- package/dist/ui/tui/components/tool-result-line.js +6 -0
- package/dist/ui/tui/components/turn-footer.d.ts +5 -0
- package/dist/ui/tui/components/turn-footer.js +7 -0
- package/dist/ui/tui/components/user-block.d.ts +6 -0
- package/dist/ui/tui/components/user-block.js +6 -0
- package/dist/ui/tui/logo-banner.d.ts +5 -0
- package/dist/ui/tui/logo-banner.js +8 -0
- package/dist/ui/tui/markdown-render.d.ts +16 -0
- package/dist/ui/tui/markdown-render.js +218 -0
- package/dist/ui/tui/palette.d.ts +12 -0
- package/dist/ui/tui/palette.js +13 -0
- package/dist/ui/tui/reasoning-summary.d.ts +12 -0
- package/dist/ui/tui/reasoning-summary.js +27 -0
- package/dist/ui/tui/reducer.d.ts +92 -0
- package/dist/ui/tui/reducer.js +260 -0
- package/dist/ui/tui/run.d.ts +3 -0
- package/dist/ui/tui/run.js +40 -0
- package/dist/ui/tui/sink.d.ts +4 -0
- package/dist/ui/tui/sink.js +89 -0
- package/dist/ui/tui/status-bar-view.d.ts +5 -0
- package/dist/ui/tui/status-bar-view.js +44 -0
- package/dist/ui/tui/terminal-height.d.ts +12 -0
- package/dist/ui/tui/terminal-height.js +20 -0
- package/dist/ui/tui/terminal-width.d.ts +2 -0
- package/dist/ui/tui/terminal-width.js +5 -0
- package/dist/ui/tui/tool-display.d.ts +23 -0
- package/dist/ui/tui/tool-display.js +217 -0
- package/dist/ui/tui/transcript-line.d.ts +12 -0
- package/dist/ui/tui/transcript-line.js +43 -0
- package/dist/ui/tui/transcript-replay.d.ts +12 -0
- package/dist/ui/tui/transcript-replay.js +117 -0
- package/dist/ui-events.d.ts +39 -0
- package/dist/ui-events.js +33 -0
- package/dist/ui.d.ts +77 -0
- package/dist/ui.js +179 -0
- package/package.json +73 -0
- package/praana.config.example.toml +231 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { computeContextPressureRatio, resolveCompactionConfig, shouldTriggerAutoCompact, } from "./context-pressure.js";
|
|
2
|
+
import { getAppLogger } from "./logger.js";
|
|
3
|
+
export function eventsToSessionEvents(events) {
|
|
4
|
+
const out = [];
|
|
5
|
+
for (const ev of events) {
|
|
6
|
+
switch (ev.kind) {
|
|
7
|
+
case "user_message":
|
|
8
|
+
out.push({
|
|
9
|
+
type: "user_message",
|
|
10
|
+
timestamp: ev.timestamp,
|
|
11
|
+
content: String(ev.payload.text ?? ""),
|
|
12
|
+
});
|
|
13
|
+
break;
|
|
14
|
+
case "agent_message":
|
|
15
|
+
out.push({
|
|
16
|
+
type: "agent_message",
|
|
17
|
+
timestamp: ev.timestamp,
|
|
18
|
+
content: String(ev.payload.text ?? ""),
|
|
19
|
+
});
|
|
20
|
+
break;
|
|
21
|
+
case "tool_call":
|
|
22
|
+
out.push({
|
|
23
|
+
type: "tool_use",
|
|
24
|
+
timestamp: ev.timestamp,
|
|
25
|
+
tool_name: String(ev.payload.tool ?? "unknown"),
|
|
26
|
+
args: ev.payload.args ?? {},
|
|
27
|
+
});
|
|
28
|
+
break;
|
|
29
|
+
case "tool_result":
|
|
30
|
+
out.push({
|
|
31
|
+
type: "tool_result",
|
|
32
|
+
timestamp: ev.timestamp,
|
|
33
|
+
tool_name: String(ev.payload.tool ?? "unknown"),
|
|
34
|
+
result: ev.payload.result,
|
|
35
|
+
});
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
function selectableHistoryEvents(events) {
|
|
44
|
+
return events.filter((e) => e.kind !== "context_action" && e.kind !== "system_note");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Classic-mode compaction: summarise oldest transcript events into Cognitive Memory
|
|
48
|
+
* and mark them compressed so they leave the compiled prompt.
|
|
49
|
+
*/
|
|
50
|
+
export async function maybeAutoCompactClassic(session, promptTokens, modelId) {
|
|
51
|
+
const reserved = session.config.compiler.reserved_output_tokens ?? 0;
|
|
52
|
+
const contextWindow = session.getContextWindowTokens(modelId);
|
|
53
|
+
const pressureRatio = computeContextPressureRatio(promptTokens, contextWindow, reserved);
|
|
54
|
+
const { trigger, armed } = shouldTriggerAutoCompact(pressureRatio, session.config.compiler, session.isCompactionArmed());
|
|
55
|
+
session.setCompactionArmed(armed);
|
|
56
|
+
if (!trigger) {
|
|
57
|
+
return { compacted: false, eventsCompacted: 0, factsStored: 0, pressureRatio };
|
|
58
|
+
}
|
|
59
|
+
if (!session.memoryEnabled || !session.memoryStore) {
|
|
60
|
+
return { compacted: false, eventsCompacted: 0, factsStored: 0, pressureRatio };
|
|
61
|
+
}
|
|
62
|
+
const { compactChunkFraction } = resolveCompactionConfig(session.config.compiler);
|
|
63
|
+
const all = session.eventLog.readAllUncompressed();
|
|
64
|
+
const filtered = selectableHistoryEvents(all);
|
|
65
|
+
if (filtered.length < 4) {
|
|
66
|
+
return { compacted: false, eventsCompacted: 0, factsStored: 0, pressureRatio };
|
|
67
|
+
}
|
|
68
|
+
const chunkSize = Math.max(2, Math.floor(filtered.length * compactChunkFraction));
|
|
69
|
+
const toCompress = filtered.slice(0, chunkSize);
|
|
70
|
+
if (toCompress.length === 0) {
|
|
71
|
+
return { compacted: false, eventsCompacted: 0, factsStored: 0, pressureRatio };
|
|
72
|
+
}
|
|
73
|
+
const sessionEvents = eventsToSessionEvents(toCompress);
|
|
74
|
+
const factsStored = await session.memoryStore.compressTurns(sessionEvents);
|
|
75
|
+
session.eventLog.markEventsAsCompressed(toCompress.map((e) => e.event_id));
|
|
76
|
+
session.eventLog.append({
|
|
77
|
+
kind: "system_note",
|
|
78
|
+
actor: "kernel",
|
|
79
|
+
payload: {
|
|
80
|
+
type: "history_compacted",
|
|
81
|
+
eventsCompacted: toCompress.length,
|
|
82
|
+
factsStored,
|
|
83
|
+
pressureRatio: Number(pressureRatio.toFixed(3)),
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
if (session.debug) {
|
|
87
|
+
getAppLogger().child("session").debug(`${toCompress.length} event(s) → ${factsStored} memory fact(s) (pressure ${(pressureRatio * 100).toFixed(0)}%)`, { details: { events: toCompress.length, factsStored, pressureRatio } });
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
compacted: true,
|
|
91
|
+
eventsCompacted: toCompress.length,
|
|
92
|
+
factsStored,
|
|
93
|
+
pressureRatio,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export function formatCompactionBanner(result) {
|
|
97
|
+
if (!result.compacted)
|
|
98
|
+
return null;
|
|
99
|
+
return (`Auto-compacted ${result.eventsCompacted} older turn(s) into ` +
|
|
100
|
+
`${result.factsStored} memory fact(s) (${(result.pressureRatio * 100).toFixed(0)}% context)`);
|
|
101
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { UiMode, UiScreenMode } from "./types.js";
|
|
2
|
+
export interface CliArgs {
|
|
3
|
+
sessionId: string | null;
|
|
4
|
+
resumeMode: boolean;
|
|
5
|
+
debug: boolean;
|
|
6
|
+
incognito: boolean;
|
|
7
|
+
configPath: string | undefined;
|
|
8
|
+
showHelp: boolean;
|
|
9
|
+
uiMode: UiMode | undefined;
|
|
10
|
+
screenMode: UiScreenMode | undefined;
|
|
11
|
+
}
|
|
12
|
+
export declare function parseCliArgs(args: string[]): CliArgs;
|
|
13
|
+
export declare function resolveUiMode(configMode: UiMode, cliMode: UiMode | undefined, isInteractive: boolean): UiMode;
|
|
14
|
+
export declare function resolveScreenMode(configScreen: UiScreenMode, cliScreen: UiScreenMode | undefined): UiScreenMode;
|
package/dist/cli-args.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export function parseCliArgs(args) {
|
|
2
|
+
let sessionId = null;
|
|
3
|
+
let resumeMode = false;
|
|
4
|
+
let debug = false;
|
|
5
|
+
let incognito = false;
|
|
6
|
+
let configPath;
|
|
7
|
+
let showHelp = false;
|
|
8
|
+
let uiMode;
|
|
9
|
+
let screenMode;
|
|
10
|
+
for (let i = 0; i < args.length; i++) {
|
|
11
|
+
if (args[i] === "--help" || args[i] === "-h") {
|
|
12
|
+
showHelp = true;
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (args[i] === "--debug" || args[i] === "-d") {
|
|
16
|
+
debug = true;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (args[i] === "--incognito" || args[i] === "-I") {
|
|
20
|
+
incognito = true;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if ((args[i] === "--config" || args[i] === "-c") && args[i + 1]) {
|
|
24
|
+
configPath = args[i + 1];
|
|
25
|
+
i++;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (args[i] === "--ui" && args[i + 1]) {
|
|
29
|
+
const mode = args[i + 1].toLowerCase();
|
|
30
|
+
if (mode === "tui" || mode === "readline") {
|
|
31
|
+
uiMode = mode;
|
|
32
|
+
}
|
|
33
|
+
i++;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (args[i] === "--screen" && args[i + 1]) {
|
|
37
|
+
const screen = args[i + 1].toLowerCase();
|
|
38
|
+
if (screen === "preserve" || screen === "alternate") {
|
|
39
|
+
screenMode = screen;
|
|
40
|
+
}
|
|
41
|
+
i++;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (args[i] === "resume" && args[i + 1]) {
|
|
45
|
+
resumeMode = true;
|
|
46
|
+
sessionId = args[i + 1];
|
|
47
|
+
i++;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
sessionId,
|
|
52
|
+
resumeMode,
|
|
53
|
+
debug,
|
|
54
|
+
incognito,
|
|
55
|
+
configPath,
|
|
56
|
+
showHelp,
|
|
57
|
+
uiMode,
|
|
58
|
+
screenMode,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export function resolveUiMode(configMode, cliMode, isInteractive) {
|
|
62
|
+
const mode = cliMode ?? configMode;
|
|
63
|
+
if (mode === "tui" && !isInteractive)
|
|
64
|
+
return "readline";
|
|
65
|
+
return mode;
|
|
66
|
+
}
|
|
67
|
+
export function resolveScreenMode(configScreen, cliScreen) {
|
|
68
|
+
return cliScreen ?? configScreen;
|
|
69
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Event } from "./types.js";
|
|
2
|
+
import type { CompileMetrics } from "./compiler.js";
|
|
3
|
+
export interface ClassicCompileInput {
|
|
4
|
+
cwd: string;
|
|
5
|
+
sessionId: string;
|
|
6
|
+
toolSchemas: string[];
|
|
7
|
+
agentsContext?: string | null;
|
|
8
|
+
projectContext?: string | null;
|
|
9
|
+
skillsCatalog?: string | null;
|
|
10
|
+
memoryDigest?: string | null;
|
|
11
|
+
events: Event[];
|
|
12
|
+
userInput?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function buildClassicSystemFrame(cwd: string, sessionId: string, toolSchemas: string[], agentsContext?: string | null, projectContext?: string | null): string;
|
|
15
|
+
/** Drop the trailing user_message when it duplicates the current turn input. */
|
|
16
|
+
export declare function excludeCurrentUserInputFromEvents(events: Event[], userInput?: string): Event[];
|
|
17
|
+
export declare function buildFullConversationHistory(events: Event[]): string;
|
|
18
|
+
export declare function compileClassicWithMetrics(input: ClassicCompileInput): {
|
|
19
|
+
prompt: string;
|
|
20
|
+
metrics: CompileMetrics;
|
|
21
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { buildCrossSessionMemory } from "./compiler.js";
|
|
2
|
+
function estTokens(text) {
|
|
3
|
+
return Math.ceil(text.length / 4);
|
|
4
|
+
}
|
|
5
|
+
export function buildClassicSystemFrame(cwd, sessionId, toolSchemas, agentsContext, projectContext) {
|
|
6
|
+
const lines = [
|
|
7
|
+
"# System",
|
|
8
|
+
"",
|
|
9
|
+
"You are PRAANA, a coding agent with persistent memory.",
|
|
10
|
+
`Working directory: ${cwd}`,
|
|
11
|
+
`Session ID: ${sessionId}`,
|
|
12
|
+
];
|
|
13
|
+
if (agentsContext?.trim()) {
|
|
14
|
+
lines.push("", "## Project Context", "", agentsContext.trim());
|
|
15
|
+
}
|
|
16
|
+
if (projectContext?.trim()) {
|
|
17
|
+
lines.push("", "## Project Stack", "", projectContext.trim());
|
|
18
|
+
}
|
|
19
|
+
lines.push("", "## Available Tools", "", ...toolSchemas.map((t) => `- ${t}`), "", "Use tools when needed to accomplish the user's request. Respond concisely.", "", "## Skills", "", "Skills are listed below by name and path. Use read_file on a SKILL.md path when a skill is relevant.", "", "## Memory", "", "Use recall() for cross-session memory. Use search_session_log() to search this session's event log.", "Session event log file: ~/.praana/sessions/<session_id>/events.jsonl", "", "## Tool Safety", "", "RULE: Never call write_file, edit_file, or use shell commands with file write side-effects (e.g. `echo > file`, `sed -i`, `tee`) unless the user's message in THIS turn explicitly requests changes. Describing what you would change does not count. If unsure, ask first.");
|
|
20
|
+
return lines.join("\n");
|
|
21
|
+
}
|
|
22
|
+
/** Drop the trailing user_message when it duplicates the current turn input. */
|
|
23
|
+
export function excludeCurrentUserInputFromEvents(events, userInput) {
|
|
24
|
+
if (!userInput?.trim() || events.length === 0)
|
|
25
|
+
return events;
|
|
26
|
+
const last = events[events.length - 1];
|
|
27
|
+
if (last.kind === "user_message" &&
|
|
28
|
+
last.payload.text === userInput) {
|
|
29
|
+
return events.slice(0, -1);
|
|
30
|
+
}
|
|
31
|
+
return events;
|
|
32
|
+
}
|
|
33
|
+
export function buildFullConversationHistory(events) {
|
|
34
|
+
if (events.length === 0) {
|
|
35
|
+
return "# Conversation History\n\n(no prior turns)";
|
|
36
|
+
}
|
|
37
|
+
const lines = ["# Conversation History"];
|
|
38
|
+
const filtered = events.filter((event) => event.kind !== "context_action" && event.kind !== "system_note");
|
|
39
|
+
let lastToolName;
|
|
40
|
+
for (const event of filtered) {
|
|
41
|
+
switch (event.kind) {
|
|
42
|
+
case "user_message":
|
|
43
|
+
lines.push(`User: ${event.payload.text ?? ""}`);
|
|
44
|
+
break;
|
|
45
|
+
case "agent_message":
|
|
46
|
+
lines.push(`PRAANA: ${event.payload.text ?? ""}`);
|
|
47
|
+
break;
|
|
48
|
+
case "tool_call":
|
|
49
|
+
lastToolName = event.payload.tool;
|
|
50
|
+
lines.push(`Tool call: ${lastToolName ?? "unknown"}(${JSON.stringify(event.payload.args ?? {})})`);
|
|
51
|
+
break;
|
|
52
|
+
case "tool_result": {
|
|
53
|
+
const result = event.payload.result;
|
|
54
|
+
const resultStr = typeof result === "string" ? result : JSON.stringify(result ?? null);
|
|
55
|
+
const toolName = event.payload.tool ?? lastToolName ?? "unknown";
|
|
56
|
+
lines.push(`Result (${toolName}): ${resultStr}`);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return lines.join("\n");
|
|
62
|
+
}
|
|
63
|
+
export function compileClassicWithMetrics(input) {
|
|
64
|
+
const sections = [];
|
|
65
|
+
const frame = buildClassicSystemFrame(input.cwd, input.sessionId, input.toolSchemas, input.agentsContext, input.projectContext);
|
|
66
|
+
sections.push(frame);
|
|
67
|
+
let skillsSection = "";
|
|
68
|
+
if (input.skillsCatalog?.trim()) {
|
|
69
|
+
skillsSection = input.skillsCatalog.trim();
|
|
70
|
+
sections.push(skillsSection);
|
|
71
|
+
}
|
|
72
|
+
let crossSection = "";
|
|
73
|
+
if (input.memoryDigest?.trim()) {
|
|
74
|
+
crossSection = buildCrossSessionMemory(input.memoryDigest);
|
|
75
|
+
sections.push(crossSection);
|
|
76
|
+
}
|
|
77
|
+
const history = buildFullConversationHistory(excludeCurrentUserInputFromEvents(input.events, input.userInput));
|
|
78
|
+
sections.push(history);
|
|
79
|
+
let currentSection = "";
|
|
80
|
+
if (input.userInput) {
|
|
81
|
+
currentSection = `## Current Input\n\nUser: ${input.userInput}`;
|
|
82
|
+
sections.push(currentSection);
|
|
83
|
+
}
|
|
84
|
+
const fullPrompt = sections.join("\n\n");
|
|
85
|
+
return {
|
|
86
|
+
prompt: fullPrompt,
|
|
87
|
+
metrics: {
|
|
88
|
+
totalTokens: estTokens(fullPrompt),
|
|
89
|
+
systemFrameTokens: estTokens(frame),
|
|
90
|
+
agentsContextTokens: input.agentsContext ? estTokens(input.agentsContext) : 0,
|
|
91
|
+
skillsCatalogTokens: skillsSection ? estTokens(skillsSection) : 0,
|
|
92
|
+
checkpointTokens: 0,
|
|
93
|
+
crossSessionTokens: crossSection ? estTokens(crossSection) : 0,
|
|
94
|
+
activeStateTokens: 0,
|
|
95
|
+
peripheralStubsTokens: 0,
|
|
96
|
+
recentTurnsTokens: estTokens(history),
|
|
97
|
+
currentInputTokens: estTokens(currentSection),
|
|
98
|
+
activeObjectCount: 0,
|
|
99
|
+
peripheralObjectCount: 0,
|
|
100
|
+
recentTurnsTruncated: false,
|
|
101
|
+
memoryTruncated: false,
|
|
102
|
+
agentsContextTruncated: false,
|
|
103
|
+
skillsTruncated: false,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Event } from "./types.js";
|
|
2
|
+
import type { StateGraph } from "./state-graph.js";
|
|
3
|
+
export interface CompileInput {
|
|
4
|
+
stateGraph: StateGraph;
|
|
5
|
+
memoryDigest: string | null;
|
|
6
|
+
recentEvents: Event[];
|
|
7
|
+
userInput?: string;
|
|
8
|
+
toolSchemas: string[];
|
|
9
|
+
cwd: string;
|
|
10
|
+
sessionId: string;
|
|
11
|
+
tokenBudget: number;
|
|
12
|
+
recentTurnsTokenBudget?: number;
|
|
13
|
+
agentsContext?: string | null;
|
|
14
|
+
skillsPromptSection?: string | null;
|
|
15
|
+
checkpointSection?: string | null;
|
|
16
|
+
memoriesBudgetRatio?: number;
|
|
17
|
+
agentsBudgetRatio?: number;
|
|
18
|
+
skillsSectionBudgetRatio?: number;
|
|
19
|
+
reservedOutputTokens?: number;
|
|
20
|
+
}
|
|
21
|
+
/** Token-estimate metrics per section, emitted for eval / observability. */
|
|
22
|
+
export interface CompileMetrics {
|
|
23
|
+
totalTokens: number;
|
|
24
|
+
systemFrameTokens: number;
|
|
25
|
+
agentsContextTokens: number;
|
|
26
|
+
skillsCatalogTokens: number;
|
|
27
|
+
checkpointTokens: number;
|
|
28
|
+
crossSessionTokens: number;
|
|
29
|
+
activeStateTokens: number;
|
|
30
|
+
peripheralStubsTokens: number;
|
|
31
|
+
recentTurnsTokens: number;
|
|
32
|
+
currentInputTokens: number;
|
|
33
|
+
activeObjectCount: number;
|
|
34
|
+
peripheralObjectCount: number;
|
|
35
|
+
/** If true, some recent turns were truncated due to budget. */
|
|
36
|
+
recentTurnsTruncated: boolean;
|
|
37
|
+
/** If true, cross-session memory was trimmed to section ceiling. */
|
|
38
|
+
memoryTruncated: boolean;
|
|
39
|
+
/** If true, project context was degraded to fit agents budget. */
|
|
40
|
+
agentsContextTruncated: boolean;
|
|
41
|
+
/** If true, skills section was trimmed to section ceiling. */
|
|
42
|
+
skillsTruncated: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** Build a deterministic prompt from structured state. */
|
|
45
|
+
export declare function compile(input: CompileInput): string;
|
|
46
|
+
/** Compile with detailed token metrics per section. */
|
|
47
|
+
export declare function compileWithMetrics(input: CompileInput): {
|
|
48
|
+
prompt: string;
|
|
49
|
+
metrics: CompileMetrics;
|
|
50
|
+
};
|
|
51
|
+
export declare function buildSystemFrame(cwd: string, sessionId: string, toolSchemas: string[], stateSummary?: string, agentsContext?: string | null): string;
|
|
52
|
+
export declare function buildCrossSessionMemory(digest: string): string;
|
|
53
|
+
export declare function buildActiveState(stateGraph: StateGraph): string;
|
|
54
|
+
export declare function buildPeripheralStubs(stateGraph: StateGraph): string | null;
|
|
55
|
+
/**
|
|
56
|
+
* Calculate token savings: compare compact peripheral stubs vs.
|
|
57
|
+
* rendering the same objects in full active form.
|
|
58
|
+
* Returns { compactTokens, fullTokens, savedTokens, savingsRatio }.
|
|
59
|
+
*/
|
|
60
|
+
export declare function calculateTokenSavings(stateGraph: StateGraph): {
|
|
61
|
+
compactTokens: number;
|
|
62
|
+
fullTokens: number;
|
|
63
|
+
savedTokens: number;
|
|
64
|
+
savingsRatio: number;
|
|
65
|
+
};
|
|
66
|
+
/** Build a brief summary of working memory state for the system prompt */
|
|
67
|
+
export declare function buildStateSummary(stateGraph: StateGraph): string;
|
|
68
|
+
export declare function trimSectionToTokenBudget(text: string, maxTokens: number, truncationNote?: string): {
|
|
69
|
+
text: string;
|
|
70
|
+
truncated: boolean;
|
|
71
|
+
};
|
|
72
|
+
export declare function trimAgentsContext(agentsContext: string | null | undefined, maxTokens: number): {
|
|
73
|
+
text: string | null;
|
|
74
|
+
truncated: boolean;
|
|
75
|
+
};
|