world-model-optimizer 0.2.0__py3-none-any.whl
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.
- llm_waterfall/LICENSE +21 -0
- llm_waterfall/__init__.py +53 -0
- llm_waterfall/adapters/__init__.py +36 -0
- llm_waterfall/adapters/anthropic.py +105 -0
- llm_waterfall/adapters/aws_mantle.py +47 -0
- llm_waterfall/adapters/azure_openai.py +71 -0
- llm_waterfall/adapters/base.py +51 -0
- llm_waterfall/adapters/bedrock.py +309 -0
- llm_waterfall/adapters/openai.py +130 -0
- llm_waterfall/classify.py +184 -0
- llm_waterfall/pricing.py +110 -0
- llm_waterfall/py.typed +0 -0
- llm_waterfall/types.py +295 -0
- llm_waterfall/waterfall.py +255 -0
- wmo/__init__.py +38 -0
- wmo/agents/__init__.py +7 -0
- wmo/agents/default.py +29 -0
- wmo/agents/meta.py +55 -0
- wmo/agents/optimizer.py +55 -0
- wmo/agents/project.py +928 -0
- wmo/cli/__init__.py +5 -0
- wmo/cli/agent_session.py +1123 -0
- wmo/cli/app.py +2489 -0
- wmo/cli/e2b_cmds.py +212 -0
- wmo/cli/eval_closed_loop.py +207 -0
- wmo/cli/harness_app.py +1147 -0
- wmo/cli/harness_distill.py +659 -0
- wmo/cli/hosted_session.py +880 -0
- wmo/cli/ingest_cmd.py +165 -0
- wmo/cli/model_roles.py +82 -0
- wmo/cli/platform_cmds.py +372 -0
- wmo/cli/route_app.py +274 -0
- wmo/cli/session_state.py +243 -0
- wmo/cli/ui.py +1107 -0
- wmo/cli/workspace_sync.py +504 -0
- wmo/config/__init__.py +60 -0
- wmo/config/card.py +129 -0
- wmo/config/config.py +367 -0
- wmo/config/dotenv.py +67 -0
- wmo/config/settings.py +128 -0
- wmo/config/store.py +177 -0
- wmo/conftest.py +19 -0
- wmo/connect/__init__.py +88 -0
- wmo/connect/apps.py +78 -0
- wmo/connect/brave.py +284 -0
- wmo/connect/connector.py +79 -0
- wmo/connect/credentials.py +164 -0
- wmo/connect/github.py +321 -0
- wmo/connect/google.py +627 -0
- wmo/connect/notion.py +790 -0
- wmo/connect/oauth.py +461 -0
- wmo/connect/slack.py +555 -0
- wmo/connect/store.py +199 -0
- wmo/connect/types.py +156 -0
- wmo/core/__init__.py +21 -0
- wmo/core/parsing.py +281 -0
- wmo/core/render.py +271 -0
- wmo/core/text.py +40 -0
- wmo/core/types.py +116 -0
- wmo/distill/__init__.py +14 -0
- wmo/distill/agents.py +140 -0
- wmo/distill/config.py +1006 -0
- wmo/distill/cost.py +437 -0
- wmo/distill/data.py +921 -0
- wmo/distill/deadlines.py +254 -0
- wmo/distill/fake_tinker.py +734 -0
- wmo/distill/gate.py +122 -0
- wmo/distill/loop.py +3499 -0
- wmo/distill/renderers.py +399 -0
- wmo/distill/rendering.py +620 -0
- wmo/distill/rollouts.py +726 -0
- wmo/distill/samples.py +195 -0
- wmo/distill/store.py +829 -0
- wmo/distill/teacher.py +714 -0
- wmo/distill/tokens.py +535 -0
- wmo/distill/tracking.py +552 -0
- wmo/distill/tripwire.py +411 -0
- wmo/distill/xtoken/byte_offsets.py +152 -0
- wmo/distill/xtoken/chunks.py +457 -0
- wmo/distill/xtoken/prompt_logprobs.py +475 -0
- wmo/distill/xtoken/teacher_render.py +346 -0
- wmo/engine/__init__.py +28 -0
- wmo/engine/autoconfig.py +367 -0
- wmo/engine/build.py +346 -0
- wmo/engine/demo.py +77 -0
- wmo/engine/eval_suites.py +245 -0
- wmo/engine/grounding.py +491 -0
- wmo/engine/knowledge.py +291 -0
- wmo/engine/loader.py +36 -0
- wmo/engine/play.py +92 -0
- wmo/engine/prompts.py +99 -0
- wmo/engine/replay.py +443 -0
- wmo/engine/reporting.py +58 -0
- wmo/engine/workspace.py +468 -0
- wmo/engine/world_model.py +568 -0
- wmo/env/__init__.py +22 -0
- wmo/env/base.py +121 -0
- wmo/env/closed_loop.py +229 -0
- wmo/env/episode.py +107 -0
- wmo/env/llm_agent.py +93 -0
- wmo/env/scenarios.py +73 -0
- wmo/evals/__init__.py +52 -0
- wmo/evals/agreement.py +110 -0
- wmo/evals/base.py +45 -0
- wmo/evals/closed_loop.py +480 -0
- wmo/evals/failover.py +96 -0
- wmo/evals/gold.py +127 -0
- wmo/evals/grid.py +394 -0
- wmo/evals/grid_plot.py +205 -0
- wmo/evals/harbor/__init__.py +27 -0
- wmo/evals/harbor/agent.py +573 -0
- wmo/evals/harbor/ctrf.py +171 -0
- wmo/evals/harbor/e2b_environment.py +587 -0
- wmo/evals/harbor/e2b_template_policy.py +144 -0
- wmo/evals/harbor/scorer.py +875 -0
- wmo/evals/harbor/tasks.py +140 -0
- wmo/evals/open_loop.py +194 -0
- wmo/evals/tasks.py +53 -0
- wmo/harness/__init__.py +51 -0
- wmo/harness/code_runtime.py +288 -0
- wmo/harness/create.py +1191 -0
- wmo/harness/delta.py +220 -0
- wmo/harness/doc.py +556 -0
- wmo/harness/e2b_ledger.py +342 -0
- wmo/harness/e2b_reap.py +476 -0
- wmo/harness/e2b_sandbox.py +350 -0
- wmo/harness/environment.py +35 -0
- wmo/harness/live_session.py +543 -0
- wmo/harness/mutate.py +343 -0
- wmo/harness/pi_e2b.py +1710 -0
- wmo/harness/pi_entry/entry.ts +268 -0
- wmo/harness/pi_entry/runner_frames.ts +92 -0
- wmo/harness/pi_entry/runner_live.ts +587 -0
- wmo/harness/pi_entry/runner_service.ts +270 -0
- wmo/harness/pi_entry/runner_stdio.ts +374 -0
- wmo/harness/pi_entry/runner_termination.ts +142 -0
- wmo/harness/pi_local.py +262 -0
- wmo/harness/pi_runtime.py +495 -0
- wmo/harness/pi_vendor.py +65 -0
- wmo/harness/population.py +509 -0
- wmo/harness/project_proposer.py +569 -0
- wmo/harness/proposer.py +977 -0
- wmo/harness/runner_link.py +619 -0
- wmo/harness/runtime.py +389 -0
- wmo/harness/scoring.py +247 -0
- wmo/harness/skills.py +116 -0
- wmo/harness/source_tree.py +319 -0
- wmo/harness/store.py +176 -0
- wmo/harness/tools.py +105 -0
- wmo/harness/vendor/manifest.sha256 +58 -0
- wmo/harness/vendor/pi-agent/CHANGELOG.md +556 -0
- wmo/harness/vendor/pi-agent/LICENSE +21 -0
- wmo/harness/vendor/pi-agent/README.md +488 -0
- wmo/harness/vendor/pi-agent/VENDOR.md +39 -0
- wmo/harness/vendor/pi-agent/docs/agent-harness.md +486 -0
- wmo/harness/vendor/pi-agent/docs/durable-harness.md +212 -0
- wmo/harness/vendor/pi-agent/docs/hooks.md +445 -0
- wmo/harness/vendor/pi-agent/docs/models.md +966 -0
- wmo/harness/vendor/pi-agent/docs/observability.md +376 -0
- wmo/harness/vendor/pi-agent/package.json +60 -0
- wmo/harness/vendor/pi-agent/src/agent-loop.ts +748 -0
- wmo/harness/vendor/pi-agent/src/agent.ts +575 -0
- wmo/harness/vendor/pi-agent/src/harness/agent-harness.ts +1029 -0
- wmo/harness/vendor/pi-agent/src/harness/compaction/branch-summarization.ts +261 -0
- wmo/harness/vendor/pi-agent/src/harness/compaction/compaction.ts +747 -0
- wmo/harness/vendor/pi-agent/src/harness/compaction/utils.ts +144 -0
- wmo/harness/vendor/pi-agent/src/harness/env/nodejs.ts +550 -0
- wmo/harness/vendor/pi-agent/src/harness/messages.ts +164 -0
- wmo/harness/vendor/pi-agent/src/harness/prompt-templates.ts +267 -0
- wmo/harness/vendor/pi-agent/src/harness/session/jsonl-repo.ts +177 -0
- wmo/harness/vendor/pi-agent/src/harness/session/jsonl-storage.ts +293 -0
- wmo/harness/vendor/pi-agent/src/harness/session/memory-repo.ts +50 -0
- wmo/harness/vendor/pi-agent/src/harness/session/memory-storage.ts +131 -0
- wmo/harness/vendor/pi-agent/src/harness/session/repo-utils.ts +51 -0
- wmo/harness/vendor/pi-agent/src/harness/session/session.ts +267 -0
- wmo/harness/vendor/pi-agent/src/harness/session/uuid.ts +54 -0
- wmo/harness/vendor/pi-agent/src/harness/skills.ts +375 -0
- wmo/harness/vendor/pi-agent/src/harness/system-prompt.ts +34 -0
- wmo/harness/vendor/pi-agent/src/harness/types.ts +836 -0
- wmo/harness/vendor/pi-agent/src/harness/utils/shell-output.ts +135 -0
- wmo/harness/vendor/pi-agent/src/harness/utils/truncate.ts +344 -0
- wmo/harness/vendor/pi-agent/src/index.ts +44 -0
- wmo/harness/vendor/pi-agent/src/node.ts +2 -0
- wmo/harness/vendor/pi-agent/src/proxy.ts +367 -0
- wmo/harness/vendor/pi-agent/src/types.ts +428 -0
- wmo/harness/vendor/pi-agent/test/agent-loop.test.ts +1351 -0
- wmo/harness/vendor/pi-agent/test/agent.test.ts +699 -0
- wmo/harness/vendor/pi-agent/test/e2e.test.ts +404 -0
- wmo/harness/vendor/pi-agent/test/harness/agent-harness-stream.test.ts +213 -0
- wmo/harness/vendor/pi-agent/test/harness/agent-harness.test.ts +608 -0
- wmo/harness/vendor/pi-agent/test/harness/compaction.test.ts +655 -0
- wmo/harness/vendor/pi-agent/test/harness/nodejs-env.test.ts +321 -0
- wmo/harness/vendor/pi-agent/test/harness/prompt-templates.test.ts +90 -0
- wmo/harness/vendor/pi-agent/test/harness/repo.test.ts +68 -0
- wmo/harness/vendor/pi-agent/test/harness/resource-formatting.test.ts +24 -0
- wmo/harness/vendor/pi-agent/test/harness/session-test-utils.ts +55 -0
- wmo/harness/vendor/pi-agent/test/harness/session-uuid.test.ts +50 -0
- wmo/harness/vendor/pi-agent/test/harness/session.test.ts +156 -0
- wmo/harness/vendor/pi-agent/test/harness/skills.test.ts +116 -0
- wmo/harness/vendor/pi-agent/test/harness/storage.test.ts +299 -0
- wmo/harness/vendor/pi-agent/test/harness/system-prompt.test.ts +66 -0
- wmo/harness/vendor/pi-agent/test/harness/truncate.test.ts +169 -0
- wmo/harness/vendor/pi-agent/test/scratch/simple.ts +72 -0
- wmo/harness/vendor/pi-agent/test/utils/calculate.ts +32 -0
- wmo/harness/vendor/pi-agent/test/utils/get-current-time.ts +46 -0
- wmo/harness/vendor/pi-agent/tsconfig.build.json +13 -0
- wmo/harness/vendor/pi-agent/vitest.config.ts +19 -0
- wmo/harness/vendor/pi-agent/vitest.harness.config.ts +28 -0
- wmo/harness/vendor/vendor_pi.sh +59 -0
- wmo/harness/workspace_patch.py +270 -0
- wmo/ingest/__init__.py +47 -0
- wmo/ingest/adapter.py +72 -0
- wmo/ingest/base.py +114 -0
- wmo/ingest/braintrust.py +339 -0
- wmo/ingest/detect.py +126 -0
- wmo/ingest/langfuse.py +291 -0
- wmo/ingest/langsmith.py +444 -0
- wmo/ingest/mastra.py +330 -0
- wmo/ingest/messages.py +170 -0
- wmo/ingest/normalize.py +679 -0
- wmo/ingest/otel_genai.py +69 -0
- wmo/ingest/otel_writer.py +100 -0
- wmo/ingest/phoenix.py +150 -0
- wmo/ingest/postgres.py +246 -0
- wmo/ingest/posthog.py +320 -0
- wmo/ingest/quality.py +28 -0
- wmo/ingest/stream.py +209 -0
- wmo/ingest/testdata/sample_otlp.json +60 -0
- wmo/ingest/testdata/sample_spans.jsonl +3 -0
- wmo/optimize/__init__.py +25 -0
- wmo/optimize/base.py +143 -0
- wmo/optimize/gepa.py +806 -0
- wmo/optimize/judge.py +262 -0
- wmo/optimize/judge_quality.py +359 -0
- wmo/optimize/knn.py +468 -0
- wmo/optimize/numeric.py +152 -0
- wmo/optimize/outcomes.py +103 -0
- wmo/optimize/policy.py +669 -0
- wmo/optimize/report.py +231 -0
- wmo/optimize/reward.py +129 -0
- wmo/optimize/routing.py +373 -0
- wmo/platform/__init__.py +6 -0
- wmo/platform/auth.py +115 -0
- wmo/platform/client.py +551 -0
- wmo/platform/credentials.py +126 -0
- wmo/platform/transfer.py +158 -0
- wmo/providers/__init__.py +40 -0
- wmo/providers/_bedrock_chat.py +155 -0
- wmo/providers/_openai_common.py +182 -0
- wmo/providers/_responses_common.py +472 -0
- wmo/providers/anthropic.py +134 -0
- wmo/providers/azure_openai.py +296 -0
- wmo/providers/base.py +300 -0
- wmo/providers/bedrock.py +312 -0
- wmo/providers/models.py +205 -0
- wmo/providers/openai.py +143 -0
- wmo/providers/openai_responses.py +240 -0
- wmo/providers/pool.py +170 -0
- wmo/providers/registry.py +73 -0
- wmo/providers/retry.py +151 -0
- wmo/providers/tinker.py +936 -0
- wmo/providers/waterfall.py +336 -0
- wmo/research/__init__.py +81 -0
- wmo/research/ablation.py +133 -0
- wmo/research/concurrency_plot.py +523 -0
- wmo/research/concurrency_run.py +240 -0
- wmo/research/concurrency_scaling.py +270 -0
- wmo/research/gepa_scaling.py +274 -0
- wmo/research/pipeline.py +198 -0
- wmo/research/scaling_split.py +82 -0
- wmo/research/scenario_fidelity.py +198 -0
- wmo/research/scenario_recovery.py +92 -0
- wmo/research/seed_stability.py +90 -0
- wmo/research/trace_scaling.py +348 -0
- wmo/retrieval/__init__.py +6 -0
- wmo/retrieval/embedders.py +105 -0
- wmo/retrieval/leakfree.py +52 -0
- wmo/retrieval/retriever.py +173 -0
- wmo/scenarios/__init__.py +58 -0
- wmo/scenarios/builder.py +152 -0
- wmo/scenarios/mining/__init__.py +27 -0
- wmo/scenarios/mining/clustering.py +171 -0
- wmo/scenarios/mining/facets.py +226 -0
- wmo/scenarios/mining/selection.py +220 -0
- wmo/scenarios/synthesis/__init__.py +6 -0
- wmo/scenarios/synthesis/scenario_set.py +63 -0
- wmo/scenarios/synthesis/synthesizer.py +85 -0
- wmo/scenarios/verification/__init__.py +17 -0
- wmo/scenarios/verification/judge.py +97 -0
- wmo/scenarios/verification/verify.py +135 -0
- wmo/serving/__init__.py +5 -0
- wmo/serving/builds.py +451 -0
- wmo/serving/chat.py +878 -0
- wmo/serving/endpoint_config.py +64 -0
- wmo/serving/savings.py +250 -0
- wmo/serving/server.py +553 -0
- wmo/serving/traces_source.py +206 -0
- wmo/telemetry.py +213 -0
- wmo/tracking/__init__.py +36 -0
- wmo/tracking/clock.py +24 -0
- wmo/tracking/metered.py +125 -0
- wmo/tracking/pricing.py +99 -0
- wmo/tracking/store.py +31 -0
- wmo/tracking/tracker.py +149 -0
- world_model_optimizer-0.2.0.dist-info/METADATA +203 -0
- world_model_optimizer-0.2.0.dist-info/RECORD +308 -0
- world_model_optimizer-0.2.0.dist-info/WHEEL +4 -0
- world_model_optimizer-0.2.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import type { Model, Models } from "@earendil-works/pi-ai";
|
|
2
|
+
|
|
3
|
+
import type { AgentMessage } from "../../types.ts";
|
|
4
|
+
import {
|
|
5
|
+
convertToLlm,
|
|
6
|
+
createBranchSummaryMessage,
|
|
7
|
+
createCompactionSummaryMessage,
|
|
8
|
+
createCustomMessage,
|
|
9
|
+
} from "../messages.ts";
|
|
10
|
+
import type { BranchSummaryResult, Session, SessionTreeEntry } from "../types.ts";
|
|
11
|
+
import { BranchSummaryError, err, ok, type Result, SessionError } from "../types.ts";
|
|
12
|
+
import { estimateTokens, SUMMARIZATION_SYSTEM_PROMPT } from "./compaction.ts";
|
|
13
|
+
import {
|
|
14
|
+
computeFileLists,
|
|
15
|
+
createFileOps,
|
|
16
|
+
extractFileOpsFromMessage,
|
|
17
|
+
type FileOperations,
|
|
18
|
+
formatFileOperations,
|
|
19
|
+
serializeConversation,
|
|
20
|
+
} from "./utils.ts";
|
|
21
|
+
|
|
22
|
+
/** File-operation details stored on generated branch summary entries. */
|
|
23
|
+
export interface BranchSummaryDetails {
|
|
24
|
+
/** Files read while exploring the summarized branch. */
|
|
25
|
+
readFiles: string[];
|
|
26
|
+
/** Files modified while exploring the summarized branch. */
|
|
27
|
+
modifiedFiles: string[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type { FileOperations } from "./utils.ts";
|
|
31
|
+
|
|
32
|
+
/** Prepared branch content for summarization. */
|
|
33
|
+
export interface BranchPreparation {
|
|
34
|
+
/** Messages selected for the branch summary. */
|
|
35
|
+
messages: AgentMessage[];
|
|
36
|
+
/** File operations extracted from the branch. */
|
|
37
|
+
fileOps: FileOperations;
|
|
38
|
+
/** Estimated token count for selected messages. */
|
|
39
|
+
totalTokens: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Entries selected for branch summarization. */
|
|
43
|
+
export interface CollectEntriesResult {
|
|
44
|
+
/** Entries to summarize in chronological order. */
|
|
45
|
+
entries: SessionTreeEntry[];
|
|
46
|
+
/** Deepest common ancestor between the previous leaf and target entry. */
|
|
47
|
+
commonAncestorId: string | null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Options for generating a branch summary. */
|
|
51
|
+
export interface GenerateBranchSummaryOptions {
|
|
52
|
+
/** Provider collection the summarization request goes through; owns auth resolution. */
|
|
53
|
+
models: Models;
|
|
54
|
+
/** Model used for summarization. */
|
|
55
|
+
model: Model<any>;
|
|
56
|
+
/** Abort signal for the summarization request. */
|
|
57
|
+
signal: AbortSignal;
|
|
58
|
+
/** Optional instructions appended to or replacing the default prompt. */
|
|
59
|
+
customInstructions?: string;
|
|
60
|
+
/** Replace the default prompt with custom instructions instead of appending them. */
|
|
61
|
+
replaceInstructions?: boolean;
|
|
62
|
+
/** Tokens reserved for prompt and model output. Defaults to 16384. */
|
|
63
|
+
reserveTokens?: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Collect entries that should be summarized before navigating to a different session tree entry. */
|
|
67
|
+
export async function collectEntriesForBranchSummary(
|
|
68
|
+
session: Session,
|
|
69
|
+
oldLeafId: string | null,
|
|
70
|
+
targetId: string,
|
|
71
|
+
): Promise<CollectEntriesResult> {
|
|
72
|
+
if (!oldLeafId) {
|
|
73
|
+
return { entries: [], commonAncestorId: null };
|
|
74
|
+
}
|
|
75
|
+
const oldPath = new Set((await session.getBranch(oldLeafId)).map((e) => e.id));
|
|
76
|
+
const targetPath = await session.getBranch(targetId);
|
|
77
|
+
let commonAncestorId: string | null = null;
|
|
78
|
+
for (let i = targetPath.length - 1; i >= 0; i--) {
|
|
79
|
+
if (oldPath.has(targetPath[i].id)) {
|
|
80
|
+
commonAncestorId = targetPath[i].id;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const entries: SessionTreeEntry[] = [];
|
|
85
|
+
let current: string | null = oldLeafId;
|
|
86
|
+
|
|
87
|
+
while (current && current !== commonAncestorId) {
|
|
88
|
+
const entry = await session.getEntry(current);
|
|
89
|
+
if (!entry) throw new SessionError("invalid_session", `Entry ${current} not found`);
|
|
90
|
+
entries.push(entry as SessionTreeEntry);
|
|
91
|
+
current = entry.parentId;
|
|
92
|
+
}
|
|
93
|
+
entries.reverse();
|
|
94
|
+
|
|
95
|
+
return { entries, commonAncestorId };
|
|
96
|
+
}
|
|
97
|
+
function getMessageFromEntry(entry: SessionTreeEntry): AgentMessage | undefined {
|
|
98
|
+
switch (entry.type) {
|
|
99
|
+
case "message":
|
|
100
|
+
if (entry.message.role === "toolResult") return undefined;
|
|
101
|
+
return entry.message;
|
|
102
|
+
|
|
103
|
+
case "custom_message":
|
|
104
|
+
return createCustomMessage(entry.customType, entry.content, entry.display, entry.details, entry.timestamp);
|
|
105
|
+
|
|
106
|
+
case "branch_summary":
|
|
107
|
+
return createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp);
|
|
108
|
+
|
|
109
|
+
case "compaction":
|
|
110
|
+
return createCompactionSummaryMessage(entry.summary, entry.tokensBefore, entry.timestamp);
|
|
111
|
+
case "thinking_level_change":
|
|
112
|
+
case "model_change":
|
|
113
|
+
case "active_tools_change":
|
|
114
|
+
case "custom":
|
|
115
|
+
case "label":
|
|
116
|
+
case "session_info":
|
|
117
|
+
case "leaf":
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Prepare branch entries for summarization within an optional token budget. */
|
|
123
|
+
export function prepareBranchEntries(entries: SessionTreeEntry[], tokenBudget: number = 0): BranchPreparation {
|
|
124
|
+
const messages: AgentMessage[] = [];
|
|
125
|
+
const fileOps = createFileOps();
|
|
126
|
+
let totalTokens = 0;
|
|
127
|
+
for (const entry of entries) {
|
|
128
|
+
if (entry.type === "branch_summary" && !entry.fromHook && entry.details) {
|
|
129
|
+
const details = entry.details as BranchSummaryDetails;
|
|
130
|
+
if (Array.isArray(details.readFiles)) {
|
|
131
|
+
for (const f of details.readFiles) fileOps.read.add(f);
|
|
132
|
+
}
|
|
133
|
+
if (Array.isArray(details.modifiedFiles)) {
|
|
134
|
+
for (const f of details.modifiedFiles) {
|
|
135
|
+
fileOps.edited.add(f);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
141
|
+
const entry = entries[i];
|
|
142
|
+
const message = getMessageFromEntry(entry);
|
|
143
|
+
if (!message) continue;
|
|
144
|
+
extractFileOpsFromMessage(message, fileOps);
|
|
145
|
+
|
|
146
|
+
const tokens = estimateTokens(message);
|
|
147
|
+
if (tokenBudget > 0 && totalTokens + tokens > tokenBudget) {
|
|
148
|
+
if (entry.type === "compaction" || entry.type === "branch_summary") {
|
|
149
|
+
if (totalTokens < tokenBudget * 0.9) {
|
|
150
|
+
messages.unshift(message);
|
|
151
|
+
totalTokens += tokens;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
messages.unshift(message);
|
|
158
|
+
totalTokens += tokens;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return { messages, fileOps, totalTokens };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const BRANCH_SUMMARY_PREAMBLE = `The user explored a different conversation branch before returning here.
|
|
165
|
+
Summary of that exploration:
|
|
166
|
+
|
|
167
|
+
`;
|
|
168
|
+
|
|
169
|
+
const BRANCH_SUMMARY_PROMPT = `Create a structured summary of this conversation branch for context when returning later.
|
|
170
|
+
|
|
171
|
+
Use this EXACT format:
|
|
172
|
+
|
|
173
|
+
## Goal
|
|
174
|
+
[What was the user trying to accomplish in this branch?]
|
|
175
|
+
|
|
176
|
+
## Constraints & Preferences
|
|
177
|
+
- [Any constraints, preferences, or requirements mentioned]
|
|
178
|
+
- [Or "(none)" if none were mentioned]
|
|
179
|
+
|
|
180
|
+
## Progress
|
|
181
|
+
### Done
|
|
182
|
+
- [x] [Completed tasks/changes]
|
|
183
|
+
|
|
184
|
+
### In Progress
|
|
185
|
+
- [ ] [Work that was started but not finished]
|
|
186
|
+
|
|
187
|
+
### Blocked
|
|
188
|
+
- [Issues preventing progress, if any]
|
|
189
|
+
|
|
190
|
+
## Key Decisions
|
|
191
|
+
- **[Decision]**: [Brief rationale]
|
|
192
|
+
|
|
193
|
+
## Next Steps
|
|
194
|
+
1. [What should happen next to continue this work]
|
|
195
|
+
|
|
196
|
+
Keep each section concise. Preserve exact file paths, function names, and error messages.`;
|
|
197
|
+
|
|
198
|
+
/** Generate a summary for abandoned branch entries. */
|
|
199
|
+
export async function generateBranchSummary(
|
|
200
|
+
entries: SessionTreeEntry[],
|
|
201
|
+
options: GenerateBranchSummaryOptions,
|
|
202
|
+
): Promise<Result<BranchSummaryResult, BranchSummaryError>> {
|
|
203
|
+
const { models, model, signal, customInstructions, replaceInstructions, reserveTokens = 16384 } = options;
|
|
204
|
+
const contextWindow = model.contextWindow || 128000;
|
|
205
|
+
const tokenBudget = contextWindow - reserveTokens;
|
|
206
|
+
|
|
207
|
+
const { messages, fileOps } = prepareBranchEntries(entries, tokenBudget);
|
|
208
|
+
|
|
209
|
+
if (messages.length === 0) {
|
|
210
|
+
return ok({ summary: "No content to summarize", readFiles: [], modifiedFiles: [] });
|
|
211
|
+
}
|
|
212
|
+
const llmMessages = convertToLlm(messages);
|
|
213
|
+
const conversationText = serializeConversation(llmMessages);
|
|
214
|
+
let instructions: string;
|
|
215
|
+
if (replaceInstructions && customInstructions) {
|
|
216
|
+
instructions = customInstructions;
|
|
217
|
+
} else if (customInstructions) {
|
|
218
|
+
instructions = `${BRANCH_SUMMARY_PROMPT}\n\nAdditional focus: ${customInstructions}`;
|
|
219
|
+
} else {
|
|
220
|
+
instructions = BRANCH_SUMMARY_PROMPT;
|
|
221
|
+
}
|
|
222
|
+
const promptText = `<conversation>\n${conversationText}\n</conversation>\n\n${instructions}`;
|
|
223
|
+
|
|
224
|
+
const summarizationMessages = [
|
|
225
|
+
{
|
|
226
|
+
role: "user" as const,
|
|
227
|
+
content: [{ type: "text" as const, text: promptText }],
|
|
228
|
+
timestamp: Date.now(),
|
|
229
|
+
},
|
|
230
|
+
];
|
|
231
|
+
const response = await models.completeSimple(
|
|
232
|
+
model,
|
|
233
|
+
{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages },
|
|
234
|
+
{ signal, maxTokens: 2048 },
|
|
235
|
+
);
|
|
236
|
+
if (response.stopReason === "aborted") {
|
|
237
|
+
return err(new BranchSummaryError("aborted", response.errorMessage || "Branch summary aborted"));
|
|
238
|
+
}
|
|
239
|
+
if (response.stopReason === "error") {
|
|
240
|
+
return err(
|
|
241
|
+
new BranchSummaryError(
|
|
242
|
+
"summarization_failed",
|
|
243
|
+
`Branch summary failed: ${response.errorMessage || "Unknown error"}`,
|
|
244
|
+
),
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
let summary = response.content
|
|
249
|
+
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
|
250
|
+
.map((c) => c.text)
|
|
251
|
+
.join("\n");
|
|
252
|
+
summary = BRANCH_SUMMARY_PREAMBLE + summary;
|
|
253
|
+
const { readFiles, modifiedFiles } = computeFileLists(fileOps);
|
|
254
|
+
summary += formatFileOperations(readFiles, modifiedFiles);
|
|
255
|
+
|
|
256
|
+
return ok({
|
|
257
|
+
summary: summary || "No summary generated",
|
|
258
|
+
readFiles,
|
|
259
|
+
modifiedFiles,
|
|
260
|
+
});
|
|
261
|
+
}
|