osborn 0.9.137 → 0.9.139
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/pipeline-direct-llm.js +40 -15
- package/package.json +1 -1
|
@@ -25,7 +25,7 @@ function buildSessionTail(sessionId, workingDir) {
|
|
|
25
25
|
return '';
|
|
26
26
|
if (!sessionId)
|
|
27
27
|
return '';
|
|
28
|
-
const maxLines = parseInt(process.env.OSBORN_SESSION_TAIL_COUNT || '
|
|
28
|
+
const maxLines = parseInt(process.env.OSBORN_SESSION_TAIL_COUNT || '1500', 10);
|
|
29
29
|
try {
|
|
30
30
|
const indexPath = getIndexPath(sessionId, workingDir);
|
|
31
31
|
if (!indexPath)
|
|
@@ -63,14 +63,30 @@ export class PipelineDirectLLM extends llm.LLM {
|
|
|
63
63
|
#turnAbort = null;
|
|
64
64
|
#indexWatcher = null;
|
|
65
65
|
#indexBuilding = false;
|
|
66
|
+
// Set to true when PostCompact fires — cleared after injecting the tail once
|
|
67
|
+
// on the next real user turn (seam-only injection, never per-turn).
|
|
68
|
+
#postCompactionTailPending = false;
|
|
66
69
|
// True while the in-flight turn is a [MEETING —] chunk — the tts_say gate in
|
|
67
70
|
// index.ts reads this to skip browser session.say() (meeting audio goes via
|
|
68
71
|
// /canvas, not the laptop speakers → no same-room feedback). Set per chat().
|
|
69
72
|
suppressMeetingTTS = false;
|
|
70
73
|
constructor(opts) {
|
|
71
74
|
super();
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
// Chain the onCompactionEvent callback so we can set #postCompactionTailPending
|
|
76
|
+
// when compaction completes, without breaking the existing UI-notification path.
|
|
77
|
+
const upstreamCompactionEvent = opts.onCompactionEvent;
|
|
78
|
+
const chainedOpts = {
|
|
79
|
+
...opts,
|
|
80
|
+
onCompactionEvent: (event) => {
|
|
81
|
+
if (event.type === 'compaction_complete') {
|
|
82
|
+
this.#postCompactionTailPending = true;
|
|
83
|
+
console.log('[SEAM] compaction complete → will inject session_tail on next turn');
|
|
84
|
+
}
|
|
85
|
+
upstreamCompactionEvent?.(event);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
this.#claudeLLM = new ClaudeLLM(chainedOpts);
|
|
89
|
+
this.#opts = chainedOpts;
|
|
74
90
|
}
|
|
75
91
|
/** Stop the index watcher (call on disconnect/session switch) */
|
|
76
92
|
stopIndexWatcher() {
|
|
@@ -133,16 +149,25 @@ export class PipelineDirectLLM extends llm.LLM {
|
|
|
133
149
|
}
|
|
134
150
|
}
|
|
135
151
|
console.log(`📥 [pipeline] chat() call #${callN} (${userText.length} chars): "${userText}"`);
|
|
136
|
-
// ── SESSION TAIL injection
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
152
|
+
// ── SESSION TAIL injection (seam-only) ───────────────────────────────────
|
|
153
|
+
// Inject the tail ONCE on the first real user turn after a compaction
|
|
154
|
+
// completes. Never injected on every turn (avoids catastrophic accumulation
|
|
155
|
+
// in the SDK persistent subprocess history). Meeting chunks are not real
|
|
156
|
+
// user turns and never get the tail.
|
|
157
|
+
let sessionTailBlock = '';
|
|
158
|
+
if (this.#postCompactionTailPending && !userText.startsWith('[MEETING') && userText.trim()) {
|
|
159
|
+
sessionTailBlock = buildSessionTail(this.#claudeLLM.sessionId, this.#opts.workingDirectory || process.cwd());
|
|
160
|
+
if (sessionTailBlock) {
|
|
161
|
+
const tailLines = sessionTailBlock.split('\n').length - 2;
|
|
162
|
+
const tailChars = sessionTailBlock.length;
|
|
163
|
+
console.log(`[SEAM] injecting post-compaction session_tail: ${tailLines} lines, ~${tailChars} chars`);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
console.log('[SEAM] post-compaction turn but session_tail empty/disabled');
|
|
167
|
+
}
|
|
168
|
+
// Always clear the flag after the first real turn, whether or not the
|
|
169
|
+
// index file had content (avoids re-trying on an empty index).
|
|
170
|
+
this.#postCompactionTailPending = false;
|
|
146
171
|
}
|
|
147
172
|
// Always check the pending playback context — it can carry two independent
|
|
148
173
|
// signals: (a) an actual interruption (spokenText + recentMessages) when the
|
|
@@ -227,7 +252,7 @@ export class PipelineDirectLLM extends llm.LLM {
|
|
|
227
252
|
// when text is non-empty.
|
|
228
253
|
enrichedMessage = userText;
|
|
229
254
|
}
|
|
230
|
-
// Modify the last user message in chatCtx
|
|
255
|
+
// Modify the last user message in chatCtx
|
|
231
256
|
const finalMessage = sessionTailBlock
|
|
232
257
|
? sessionTailBlock + '\n\n' + enrichedMessage
|
|
233
258
|
: enrichedMessage;
|
|
@@ -240,7 +265,7 @@ export class PipelineDirectLLM extends llm.LLM {
|
|
|
240
265
|
}
|
|
241
266
|
}
|
|
242
267
|
else if (sessionTailBlock && userText.trim()) {
|
|
243
|
-
// No interrupt context — inject session tail
|
|
268
|
+
// No interrupt context — inject post-compaction session tail into the user message
|
|
244
269
|
for (let i = chatCtx.items.length - 1; i >= 0; i--) {
|
|
245
270
|
const item = chatCtx.items[i];
|
|
246
271
|
if (item.type === 'message' && item.role === 'user') {
|