billion-context-omp 0.2.3 → 0.2.4

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.
@@ -43,8 +43,11 @@ export declare function buildSummaryPrompt(prompts: Prompts): string;
43
43
  * deliberately NOT used here: fold blocks only replay from in-stream
44
44
  * compress tool calls, which the truncation removes. `previousSummary` (an
45
45
  * earlier compaction's summary) is folded in so iterative compactions never
46
- * drop it. Returns null on any failure so the caller falls back to Pi's
47
- * native compaction. */
46
+ * drop it. On a failed attempt the LLM call is
47
+ * retried ONCE (stochastic formatting failures recover on a fresh call);
48
+ * returns null only when the retry also fails — the caller then CANCELS the
49
+ * compaction (no native fallback: ACP owns compression, host-default
50
+ * summaries are the failure mode this hook exists to prevent). */
48
51
  export declare function summarizeMessages(ctx: ExtensionContext, messages: AgentMessage[], prompts: Prompts, configuredModel?: string | null, opts?: {
49
52
  previousSummary?: string;
50
53
  customInstructions?: string;
@@ -58,11 +61,9 @@ export declare function summarizeMessages(ctx: ExtensionContext, messages: Agent
58
61
  summary: string;
59
62
  model: string;
60
63
  } | null>;
61
- /** Generate a summary for a message range using the compression model. Shared
62
- * entry point for the `/compact` handler. Returns null when no model is
63
- * usable, the slice is empty, the model is unauthenticated, or the response
64
- * is unparseable — the caller then returns `undefined` so Pi falls back to
65
- * its native compaction. */
64
+ /** Generate a summary for a message range using the compression model.
65
+ * Currently unused by the extension (kept as the shared range-summary
66
+ * surface); null = hard failure, caller decides. */
66
67
  export declare function summarizeRange(ctx: ExtensionContext, messages: CoreMessage[], state: CompressionState, startRef: string, endRef: string, prompts: Prompts, configuredModel?: string | null): Promise<{
67
68
  summary: string;
68
69
  model: string;
package/dist/index.js CHANGED
@@ -4558,7 +4558,7 @@ async function statusReport(runtime, ctx) {
4558
4558
  const coveredIds = collectCoveredMessageIds(state);
4559
4559
  const sentTokens = estimateTokens(coreMessages, coveredIds) + systemPromptTokens;
4560
4560
  const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount: sentTokens });
4561
- const versionStr = "0.2.3" ? `billion-context-omp@${"0.2.3"}` : void 0;
4561
+ const versionStr = "0.2.4" ? `billion-context-omp@${"0.2.4"}` : void 0;
4562
4562
  return buildStatusPanel({
4563
4563
  version: versionStr,
4564
4564
  tokenCount: sessionTokens,
@@ -4807,7 +4807,7 @@ import { join as join3 } from "path";
4807
4807
  import { complete } from "@oh-my-pi/pi-ai";
4808
4808
  import { CONFIG_DIR_NAME as CONFIG_DIR_NAME2 } from "@oh-my-pi/pi-utils";
4809
4809
  var TIMEOUT_MS = 6e4;
4810
- var MAX_OUTPUT_TOKENS = 3e3;
4810
+ var MAX_OUTPUT_TOKENS = 8e3;
4811
4811
  var MAX_SLICE_CHARS = 15e4;
4812
4812
  var MAX_MSG_CHARS = 4e3;
4813
4813
  function readCompressModel() {
@@ -4857,9 +4857,10 @@ function parseSummary(text) {
4857
4857
  try {
4858
4858
  const obj = JSON.parse(cleaned);
4859
4859
  if (typeof obj.summary === "string" && obj.summary.length > 0) return obj.summary;
4860
+ return null;
4860
4861
  } catch {
4861
4862
  }
4862
- return null;
4863
+ return cleaned.length >= 50 ? cleaned : null;
4863
4864
  }
4864
4865
  function buildSummaryPrompt(prompts) {
4865
4866
  return prompts.compressPhilosophy.trim() + "\n\n" + prompts.howToCompressRules.trim() + '\n\nCompress the message range provided below into ONE dense, self-contained technical summary following the rules above. Output ONLY a JSON object: {"summary": "..."} where the value is the full summary as a single string.';
@@ -4896,14 +4897,32 @@ User instructions for this compaction: ${custom}`;
4896
4897
  const userText = `ENTIRE conversation to compress (${slice.length} messages, ~${tokens} tokens). Compress it:
4897
4898
 
4898
4899
  ` + formatSlice(slice, opts?.messageRefs ? { ...createInitialState(), messageRefs: opts.messageRefs } : createInitialState());
4899
- const response = await run(
4900
- model,
4901
- { systemPrompt: [instructions], messages: [{ role: "user", content: [{ type: "text", text: userText }], timestamp: Date.now() }] },
4902
- { apiKey: auth.apiKey, headers: auth.headers, maxTokens: MAX_OUTPUT_TOKENS, signal: ac.signal }
4903
- );
4904
- const summary = parseSummary(
4905
- response.content.filter((c) => c.type === "text").map((c) => c.text).join("\n")
4906
- );
4900
+ const attempt = async () => {
4901
+ const response = await run(
4902
+ model,
4903
+ { systemPrompt: [instructions], messages: [{ role: "user", content: [{ type: "text", text: userText }], timestamp: Date.now() }] },
4904
+ { apiKey: auth.apiKey, headers: auth.headers, maxTokens: MAX_OUTPUT_TOKENS, signal: ac.signal }
4905
+ );
4906
+ return parseSummary(
4907
+ response.content.filter((c) => c.type === "text").map((c) => c.text).join("\n")
4908
+ );
4909
+ };
4910
+ let summary = null;
4911
+ try {
4912
+ summary = await attempt();
4913
+ } catch (e) {
4914
+ if (opts?.signal?.aborted || ac.signal.aborted) throw e;
4915
+ logWarn("summarize-messages", { event: "attempt-failed", model: label, error: String(e) });
4916
+ }
4917
+ if (!summary) {
4918
+ try {
4919
+ summary = await attempt();
4920
+ if (summary) logInfo("summarize-messages", { event: "recovered-on-retry", model: label, messages: slice.length });
4921
+ } catch (e) {
4922
+ if (opts?.signal?.aborted || ac.signal.aborted) throw e;
4923
+ logWarn("summarize-messages", { event: "retry-failed", model: label, error: String(e) });
4924
+ }
4925
+ }
4907
4926
  if (!summary) {
4908
4927
  logWarn("summarize-messages", { event: "unparseable-summary", model: label, messages: slice.length });
4909
4928
  return null;
@@ -5266,7 +5285,7 @@ async function checkForUpdate(autoUpdate, notify) {
5266
5285
  const data = await res.json();
5267
5286
  const latest = data.version;
5268
5287
  if (!latest) return;
5269
- const current = runtimeVersion ?? "0.2.3";
5288
+ const current = runtimeVersion ?? "0.2.4";
5270
5289
  const hasUpdate = isNewer(latest, current);
5271
5290
  debug.event("update-check", {
5272
5291
  current,
@@ -5555,8 +5574,8 @@ function wireCompactionDisable(pi, runtime) {
5555
5574
  messageRefs: slot.state.messageRefs
5556
5575
  });
5557
5576
  if (!result) {
5558
- ctx.ui?.notify?.("ACP: compression fell back to Pi native compaction", "warning");
5559
- return void 0;
5577
+ ctx.ui?.notify?.("ACP: /compact aborted \u2014 summary generation failed after retry (details in ~/.omp/acp-omp.log)", "error");
5578
+ return { cancel: true };
5560
5579
  }
5561
5580
  logInfo("compact", {
5562
5581
  sid,
@@ -5583,9 +5602,9 @@ function wireCompactionDisable(pi, runtime) {
5583
5602
  function wireSessionLifecycle(pi, runtime) {
5584
5603
  pi.on("session_start", async (_event, ctx) => {
5585
5604
  const sid = ctx.sessionManager.getSessionId();
5586
- logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.2.3" : null });
5605
+ logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.2.4" : null });
5587
5606
  const selfPath = import.meta.url;
5588
- const conflict = stampAndDetect(selfPath, true ? "0.2.3" : null);
5607
+ const conflict = stampAndDetect(selfPath, true ? "0.2.4" : null);
5589
5608
  if (conflict) {
5590
5609
  logWarn("instance", { event: "dual-instance", self: selfPath, other: conflict.path, otherPid: conflict.pid, otherVersion: conflict.version });
5591
5610
  try {