vibeostheog 0.20.9 → 0.20.11
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/CHANGELOG.md +4 -0
- package/package.json +2 -2
- package/src/index.js +6 -2
- package/src/lib/hooks/chat-transform.js +30 -1
- package/src/lib/pricing.js +3 -4
- package/src/vibeOS-lib/blackbox/pivot-cache.js +23 -3
- package/src/vibeOS-lib/blackbox/vibemax.js +15 -3
- package/src/vibeOS-lib/smart-cache.js +15 -0
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeostheog",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.11",
|
|
4
4
|
"description": "Cost-aware delegation enforcer for OpenCode. Tracks model usage, routes Task subagents to cheaper tiers, surfaces cumulative savings in chat. Includes research audit, reporting framework, project memory, progressive scratchpad decadence, and trinity CLI for brain/medium/cheap slot switching.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"release": "node scripts/release.mjs",
|
|
@@ -89,4 +89,4 @@
|
|
|
89
89
|
"dependencies": {
|
|
90
90
|
"vibeoscore": "file:vibeoscore-1.0.2.tgz"
|
|
91
91
|
}
|
|
92
|
-
}
|
|
92
|
+
}
|
package/src/index.js
CHANGED
|
@@ -164,8 +164,12 @@ async function _seedModelTiersIfMissing(directory) {
|
|
|
164
164
|
const brain = ranked?.brain?.id || fallbackModel;
|
|
165
165
|
const medium = ranked?.medium?.id || brain;
|
|
166
166
|
const cheap = ranked?.cheap?.id || medium || brain;
|
|
167
|
-
if (!brain)
|
|
168
|
-
|
|
167
|
+
if (!brain) {
|
|
168
|
+
brain = "deepseek/deepseek-v4-pro";
|
|
169
|
+
medium = "deepseek/deepseek-v4-flash";
|
|
170
|
+
cheap = "deepseek/deepseek-chat";
|
|
171
|
+
console.error("[vibeOS] no providers detected — using default model tiers (brain=v4-pro, medium=v4-flash, cheap=v4-chat)");
|
|
172
|
+
}
|
|
169
173
|
const tiers = {
|
|
170
174
|
selection: {
|
|
171
175
|
enabled: true,
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync } from "node:fs";
|
|
3
3
|
import { join, basename } from "node:path";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
|
-
import { currentModel, currentProjectFingerprint, currentProjectName, _blackboxEnabled, loadSelection, writeSelection, safeJsonParse, applyDecadence, getSessionScratchpadDir, ensureSessionScratchpadDirs, indexAppend, briefedProjects, getActiveJobForProject, loadTodos, promotedProjectPatterns, detectTechStack, projectFingerprint, TRINITY_OPENCODE_CONFIG, TIERS_FILE, loadGlobalLearning, setCurrentProjectFingerprint, setCurrentProjectName, stableJson, TOOL_NAME_NORMALIZE, } from "../state.js";
|
|
5
|
+
import { currentModel, currentProjectFingerprint, currentProjectName, _blackboxEnabled, loadSelection, writeSelection, safeJsonParse, applyDecadence, getSessionScratchpadDir, ensureSessionScratchpadDirs, indexAppend, briefedProjects, getActiveJobForProject, loadTodos, promotedProjectPatterns, detectTechStack, projectFingerprint, TRINITY_OPENCODE_CONFIG, TIERS_FILE, loadGlobalLearning, setCurrentProjectFingerprint, setCurrentProjectName, stableJson, TOOL_NAME_NORMALIZE, _cacheDb, } from "../state.js";
|
|
6
6
|
import { applySlot, TRINITY_CHEAP, TRINITY_MEDIUM, } from "../pricing.js";
|
|
7
7
|
import { scoreStress, classifyTurnSimple, loadOptimizationMode, saveOptimizationMode, selectOptimizationModeRemote, computeControlVector, getBlackboxTracker, loadBlackboxState as loadBlackboxStateFromCtx, saveBlackboxState as saveBlackboxStateToCtx, extractLastUserText, isLikelyOffTopic, fetchBlackboxEnrichment, estimateContextBudget, buildControlHistoryEntry, } from "../turn-classify.js";
|
|
8
8
|
import { applyBudgetFirstMode, peekBudgetFirstMode } from "../mode-policy.js";
|
|
9
|
+
import { vibemaxPipeline } from "../../vibeOS-lib/blackbox/vibemax.js";
|
|
10
|
+
import { addCacheEntry, extractRecentCacheOutputs } from "../../vibeOS-lib/smart-cache.js";
|
|
9
11
|
import { remoteCall } from "../api-client.js";
|
|
10
12
|
import { loadCredit } from "../credit-api.js";
|
|
11
13
|
import { loadSessionOptMode, loadSessionSlot, writeSessionSlot } from "../selection-manager.js";
|
|
@@ -583,6 +585,33 @@ export const onSystemTransform = async (_input, output) => {
|
|
|
583
585
|
const stressScore = rawStress * (_controlVector?.stress_multiplier ?? 1);
|
|
584
586
|
const credit = loadCredit();
|
|
585
587
|
_turnCountInject++;
|
|
588
|
+
// ── Pivot detection and PIVOT BACK injection ──
|
|
589
|
+
if (latestUserIntent && _blackboxEnabled !== false) {
|
|
590
|
+
try {
|
|
591
|
+
const pivotResult = await vibemaxPipeline({
|
|
592
|
+
user_text: latestUserIntent,
|
|
593
|
+
_pivotContext: {
|
|
594
|
+
files: onSystemTransform._recentFiles || [],
|
|
595
|
+
decisions: onSystemTransform._recentDecisions || [],
|
|
596
|
+
blockers: onSystemTransform._recentBlockers || [],
|
|
597
|
+
toolOutputs: _cacheDb ? extractRecentCacheOutputs(_cacheDb, 10) : [],
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
if (pivotResult?.pivot?.injection) {
|
|
601
|
+
pushSystem(output, pivotResult.pivot.injection);
|
|
602
|
+
// Warm smart cache with workflow tool outputs
|
|
603
|
+
if (pivotResult.pivot.workflowId && pivotResult.pivot.toolOutputs?.length > 0) {
|
|
604
|
+
try {
|
|
605
|
+
for (const entry of pivotResult.pivot.toolOutputs) {
|
|
606
|
+
addCacheEntry(_cacheDb, entry.hash, entry.tool, entry.prompt, entry.sizeBytes || 1024, entry.ageSec || 3600);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
catch { /* cache warming is best-effort */ }
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
catch { /* pivot pipeline is best-effort */ }
|
|
614
|
+
}
|
|
586
615
|
const stressMitigationDirective = rawStress > 0.7
|
|
587
616
|
? "[stress mitigation: CRITICAL] The user's message shows very high stress indicators. " +
|
|
588
617
|
"Stay calm, structured, and thorough. Use proper markdown formatting with code blocks, " +
|
package/src/lib/pricing.js
CHANGED
|
@@ -281,8 +281,7 @@ export function formatUsd(v) {
|
|
|
281
281
|
// ── Free model exceptions ───────────────────────────────────────────
|
|
282
282
|
// Models with negligible per-turn cost (less than 2e-5 USD/turn).
|
|
283
283
|
// These skip enforcement entirely to avoid noise.
|
|
284
|
-
// deepseek-chat is
|
|
285
|
-
// No DeepSeek models are free. Only local models (Ollama) qualify.
|
|
284
|
+
// deepseek-chat is free with a DeepSeek API token — priced at $1e-12 (near-zero).
|
|
286
285
|
const FREE_MODEL_TURN_USD = 1e-10;
|
|
287
286
|
const FREE_MODELS = new Set([]);
|
|
288
287
|
// Approximate USD per typical ~1 K-token turn (blended input+output).
|
|
@@ -302,8 +301,8 @@ const MODEL_USD_PER_TURN = {
|
|
|
302
301
|
// ── DeepSeek (OC platform + OpenRouter) ──────────────────
|
|
303
302
|
"deepseek/deepseek-v4-pro": 0.00057,
|
|
304
303
|
"deepseek/deepseek-v4-flash": 0.000182,
|
|
305
|
-
"deepseek/deepseek-chat": 0.
|
|
306
|
-
"deepseek-chat": 0.
|
|
304
|
+
"deepseek/deepseek-chat": 0.000000000001,
|
|
305
|
+
"deepseek-chat": 0.000000000001,
|
|
307
306
|
"deepseek/deepseek-v3": 0.000182,
|
|
308
307
|
"deepseek/deepseek-r1": 0.00124,
|
|
309
308
|
"deepseek/deepseek-reasoner": 0.000182,
|
|
@@ -87,6 +87,7 @@ export class PivotCache {
|
|
|
87
87
|
access_count: 0,
|
|
88
88
|
useful_sections: ["decisions", "files"],
|
|
89
89
|
skip_sections: [],
|
|
90
|
+
toolOutputs: context.toolOutputs || [],
|
|
90
91
|
};
|
|
91
92
|
this.store.pivots[workflowId] = entry;
|
|
92
93
|
if (!this.pivotSequence.includes(workflowId)) {
|
|
@@ -138,14 +139,33 @@ export class PivotCache {
|
|
|
138
139
|
return "";
|
|
139
140
|
const parts = [];
|
|
140
141
|
const skip = new Set(entry.skip_sections);
|
|
142
|
+
// Intent — what was this workflow about
|
|
143
|
+
const intent = entry.intent || entry.tokens.join(", ") || "";
|
|
144
|
+
if (intent) {
|
|
145
|
+
parts.push(`[PIVOT BACK] Returning to workflow: "${intent}". Context from previous session follows.`);
|
|
146
|
+
}
|
|
147
|
+
// Files — what was being modified
|
|
148
|
+
if (!skip.has("files") && entry.files.length > 0) {
|
|
149
|
+
parts.push(`[files modified] ${entry.files.slice(0, 6).join(", ")}`);
|
|
150
|
+
}
|
|
151
|
+
// Decisions — key choices made
|
|
141
152
|
if (!skip.has("decisions") && entry.decisions.length > 0) {
|
|
142
|
-
|
|
153
|
+
const filtered = entry.decisions.filter(d => d !== "previous workflow captured at pivot point");
|
|
154
|
+
if (filtered.length > 0) {
|
|
155
|
+
parts.push(`[decisions] ${filtered.slice(0, 3).join(" | ")}`);
|
|
156
|
+
}
|
|
143
157
|
}
|
|
144
|
-
|
|
158
|
+
// Blockers — what was blocking progress
|
|
159
|
+
if (!skip.has("blockers") && entry.blockers.length > 0) {
|
|
145
160
|
parts.push(`[blockers] ${entry.blockers.slice(0, 2).join(" | ")}`);
|
|
146
161
|
}
|
|
162
|
+
// Code snippets — relevant context
|
|
147
163
|
if (entry.code_snippets.length > 0 && entry.useful_sections.includes("code") && !skip.has("code")) {
|
|
148
|
-
parts.push(`[code] ${entry.code_snippets.slice(0, 2).join(" | ")}`);
|
|
164
|
+
parts.push(`[code context] ${entry.code_snippets.slice(0, 2).join(" | ")}`);
|
|
165
|
+
}
|
|
166
|
+
// If nothing useful, return a minimal note
|
|
167
|
+
if (parts.length <= 1 && entry.tokens.length > 0) {
|
|
168
|
+
return `[PIVOT BACK] Returning to workflow tagged: ${entry.tokens.join(", ")}. Intent: ${intent}`;
|
|
149
169
|
}
|
|
150
170
|
return parts.join("\n");
|
|
151
171
|
}
|
|
@@ -84,6 +84,7 @@ export function resetVibeMaXPipeline() {
|
|
|
84
84
|
if (pivotCache)
|
|
85
85
|
pivotCache.resetSequence();
|
|
86
86
|
}
|
|
87
|
+
export { getPivotCache };
|
|
87
88
|
export function vibemaxSelectMode(input = {}) {
|
|
88
89
|
const stress = Number(input.stress_multiplier || input.stress || 0);
|
|
89
90
|
const pm = autoSelectMode(input.sub_regime, stress) || fallback(input.sub_regime, input.user_text || input.prompt || "");
|
|
@@ -105,7 +106,13 @@ export function vibemaxSelectMode(input = {}) {
|
|
|
105
106
|
auto_result: null, tier: "medium", thinking: think, tdd: "quality", flow: "strict",
|
|
106
107
|
enforcement: "strict", wbp: cfg.wbp || "normal", c7: "required", kp: cfg.kp || [3, 6],
|
|
107
108
|
tc: 0.3, amode: "plan", cost: 0.3,
|
|
108
|
-
pivot: isPivotBack ? {
|
|
109
|
+
pivot: isPivotBack ? {
|
|
110
|
+
matchedId: pivotBack.matchedId,
|
|
111
|
+
confidence: pivotBack.confidence,
|
|
112
|
+
injection,
|
|
113
|
+
intent: pivotBack.intent,
|
|
114
|
+
toolOutputs: (pc.read(pivotBack.matchedId)?.toolOutputs || []),
|
|
115
|
+
} : null,
|
|
109
116
|
};
|
|
110
117
|
}
|
|
111
118
|
export function vibemaxPipeline(input = {}) {
|
|
@@ -120,8 +127,13 @@ export function vibemaxPipeline(input = {}) {
|
|
|
120
127
|
pc.snapshot(prevId, {
|
|
121
128
|
tokens: [...prevTokens],
|
|
122
129
|
intent: prevMessage.substring(0, 60),
|
|
123
|
-
decisions:
|
|
124
|
-
|
|
130
|
+
decisions: input._pivotContext?.decisions?.length
|
|
131
|
+
? input._pivotContext.decisions
|
|
132
|
+
: [`workflow: ${prevMessage.substring(0, 80)}`],
|
|
133
|
+
files: input._pivotContext?.files || [],
|
|
134
|
+
code_snippets: input._pivotContext?.code_snippets || [],
|
|
135
|
+
blockers: input._pivotContext?.blockers || [],
|
|
136
|
+
toolOutputs: input._pivotContext?.toolOutputs || [],
|
|
125
137
|
});
|
|
126
138
|
}
|
|
127
139
|
const result = vibemaxSelectMode(input);
|
|
@@ -91,6 +91,21 @@ export function compositeSimilarity(a, b) {
|
|
|
91
91
|
cosineSimilarity(a, b) * 0.35 +
|
|
92
92
|
keywordOverlapScore(a, b) * 0.30);
|
|
93
93
|
}
|
|
94
|
+
// ── Cache tool output export for PIVOT snapshot ────────────────────
|
|
95
|
+
export function extractRecentCacheOutputs(db, limit = 10) {
|
|
96
|
+
if (!db?.entries || !Array.isArray(db.entries))
|
|
97
|
+
return [];
|
|
98
|
+
const now = Date.now();
|
|
99
|
+
return db.entries
|
|
100
|
+
.slice(-limit)
|
|
101
|
+
.map(e => ({
|
|
102
|
+
hash: e.hash || "",
|
|
103
|
+
tool: e.tool || "",
|
|
104
|
+
prompt: e.prompt?.slice(0, 120) || "",
|
|
105
|
+
sizeBytes: e.sizeBytes || 1024,
|
|
106
|
+
ageSec: e.at ? Math.round((now - new Date(e.at).getTime()) / 1000) : 3600,
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
94
109
|
// ── Cache database management ───────────────────────────────────────
|
|
95
110
|
export function createCacheDatabase() {
|
|
96
111
|
return { entries: [], stats: {} };
|