@code-yeongyu/senpi 2026.8.21 → 2026.8.22
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 +48 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +5 -4
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/extensions/builtin/permission-system/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/permission-system/index.js +7 -11
- package/dist/core/extensions/builtin/permission-system/index.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +79 -31
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +40 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/extension/session-manager.ts +8 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-kernel.ts +15 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/stream-retry.d.ts +21 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/stream-retry.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/stream-retry.js +36 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/stream-retry.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/types.d.ts +10 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js +166 -26
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/google.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
- package/dist/modes/interactive/split-trailing-assistant-text.d.ts +0 -7
- package/dist/modes/interactive/split-trailing-assistant-text.d.ts.map +0 -1
- package/dist/modes/interactive/split-trailing-assistant-text.js +0 -19
- package/dist/modes/interactive/split-trailing-assistant-text.js.map +0 -1
|
@@ -91,7 +91,6 @@ import { applyKeybindingsFileEdit, seedKeybindingsFile } from "./keybindings-com
|
|
|
91
91
|
import { refreshModelCatalogs } from "./model-catalog-refresh.js";
|
|
92
92
|
import { getModelSearchText } from "./model-search.js";
|
|
93
93
|
import { isRiskyMainModel, RISKY_MAIN_MODEL_WARNING } from "./risky-main-model-warning.js";
|
|
94
|
-
import { splitTrailingAssistantContent } from "./split-trailing-assistant-text.js";
|
|
95
94
|
import { DEFAULT_SMOOTH_FPS, StreamingRevealController } from "./streaming-reveal.js";
|
|
96
95
|
import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, onThemeChange, setRegisteredThemes, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
|
|
97
96
|
import { InteractiveThemeController } from "./theme/theme-controller.js";
|
|
@@ -286,6 +285,17 @@ function formatLoginProviderCompletionDescription(provider) {
|
|
|
286
285
|
const authTypes = provider.authTypes.map(formatAuthSelectorProviderType).join("/");
|
|
287
286
|
return provider.name === provider.id ? authTypes : `${provider.name} · ${authTypes}`;
|
|
288
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* Content the streaming component owns: everything through the FIRST toolCall.
|
|
290
|
+
* Text painted between tool cards lives in persistent per-segment components
|
|
291
|
+
* below the cards (regression 1064), so the head must never reabsorb it.
|
|
292
|
+
*/
|
|
293
|
+
function assistantStreamingHeadMessage(message) {
|
|
294
|
+
const firstToolIndex = message.content.findIndex((block) => block.type === "toolCall");
|
|
295
|
+
if (firstToolIndex === -1)
|
|
296
|
+
return message;
|
|
297
|
+
return { ...message, content: message.content.slice(0, firstToolIndex + 1) };
|
|
298
|
+
}
|
|
289
299
|
/** Coordinates render-only user echoes with AgentSession's canonical input lifecycle. */
|
|
290
300
|
export class OptimisticUserEchoController {
|
|
291
301
|
constructor(render) {
|
|
@@ -308,10 +318,14 @@ export class OptimisticUserEchoController {
|
|
|
308
318
|
const record = this.pending.find((candidate) => candidate.id === id);
|
|
309
319
|
if (!record)
|
|
310
320
|
return;
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
321
|
+
// Only a prompt that actually STARTED keeps its optimistic echo; queued
|
|
322
|
+
// (steer/follow-up) input must render as the pending-queue waiting state,
|
|
323
|
+
// matching upstream pi where user messages appear only at canonical
|
|
324
|
+
// message_start and queued text lives in the pending display.
|
|
325
|
+
if (disposition === "started")
|
|
314
326
|
record.eligibleForCanonicalStart = true;
|
|
327
|
+
else
|
|
328
|
+
this.reject(id);
|
|
315
329
|
},
|
|
316
330
|
};
|
|
317
331
|
}
|
|
@@ -518,7 +532,7 @@ export class InteractiveMode {
|
|
|
518
532
|
this.managedToolStatusStarted = false;
|
|
519
533
|
// Streaming message tracking
|
|
520
534
|
this.streamingComponent = undefined;
|
|
521
|
-
this.
|
|
535
|
+
this.assistantTextSegments = new Map();
|
|
522
536
|
this.streamingMessage = undefined;
|
|
523
537
|
// Tool execution tracking: toolCallId -> component
|
|
524
538
|
this.pendingTools = new Map();
|
|
@@ -1976,6 +1990,7 @@ export class InteractiveMode {
|
|
|
1976
1990
|
this.toolResultReveal.stop();
|
|
1977
1991
|
this.streamingComponent = undefined;
|
|
1978
1992
|
this.streamingMessage = undefined;
|
|
1993
|
+
this.assistantTextSegments.clear();
|
|
1979
1994
|
this.clearPendingTools();
|
|
1980
1995
|
this.clearToolHookStatuses();
|
|
1981
1996
|
this.renderInitialMessages();
|
|
@@ -3470,17 +3485,14 @@ export class InteractiveMode {
|
|
|
3470
3485
|
this.streamingComponent.setExpanded(this.toolOutputExpanded);
|
|
3471
3486
|
this.streamingMessage = event.message;
|
|
3472
3487
|
this.chatContainer.addChild(this.streamingComponent);
|
|
3473
|
-
this.streamingReveal.begin(this.streamingComponent, this.streamingMessage);
|
|
3488
|
+
this.streamingReveal.begin(this.streamingComponent, assistantStreamingHeadMessage(this.streamingMessage));
|
|
3474
3489
|
this.requestStreamingRender();
|
|
3475
3490
|
}
|
|
3476
3491
|
break;
|
|
3477
3492
|
case "message_update":
|
|
3478
3493
|
if (this.streamingComponent && event.message.role === "assistant") {
|
|
3479
3494
|
this.streamingMessage = event.message;
|
|
3480
|
-
|
|
3481
|
-
const { head } = splitTrailingAssistantContent(event.message.content);
|
|
3482
|
-
this.streamingReveal.setTarget({ ...event.message, content: head });
|
|
3483
|
-
}
|
|
3495
|
+
this.streamingReveal.setTarget(assistantStreamingHeadMessage(event.message));
|
|
3484
3496
|
for (const content of this.streamingMessage.content) {
|
|
3485
3497
|
if (content.type === "toolCall") {
|
|
3486
3498
|
let component = this.pendingTools.get(content.id);
|
|
@@ -3525,7 +3537,7 @@ export class InteractiveMode {
|
|
|
3525
3537
|
this.streamingMessage.errorMessage = errorMessage;
|
|
3526
3538
|
}
|
|
3527
3539
|
this.syncTrailingAssistantText(this.streamingMessage);
|
|
3528
|
-
this.
|
|
3540
|
+
this.assistantTextSegments.clear();
|
|
3529
3541
|
this.addContinuityNotice(this.streamingMessage);
|
|
3530
3542
|
if (this.streamingMessage.stopReason === "aborted" || this.streamingMessage.stopReason === "error") {
|
|
3531
3543
|
if (!errorMessage) {
|
|
@@ -3625,6 +3637,7 @@ export class InteractiveMode {
|
|
|
3625
3637
|
this.streamingComponent = undefined;
|
|
3626
3638
|
this.streamingMessage = undefined;
|
|
3627
3639
|
}
|
|
3640
|
+
this.detachAssistantTextSegments();
|
|
3628
3641
|
this.clearPendingTools();
|
|
3629
3642
|
this.ui.requestRender();
|
|
3630
3643
|
break;
|
|
@@ -4109,25 +4122,57 @@ export class InteractiveMode {
|
|
|
4109
4122
|
syncTrailingAssistantText(message) {
|
|
4110
4123
|
if (!this.streamingComponent)
|
|
4111
4124
|
return;
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
this.trailingAssistantComponent = undefined;
|
|
4118
|
-
}
|
|
4125
|
+
this.streamingComponent.updateContent(assistantStreamingHeadMessage(message), true);
|
|
4126
|
+
const content = message.content;
|
|
4127
|
+
const firstToolIndex = content.findIndex((block) => block.type === "toolCall");
|
|
4128
|
+
if (firstToolIndex === -1) {
|
|
4129
|
+
this.detachAssistantTextSegments();
|
|
4119
4130
|
return;
|
|
4120
4131
|
}
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4132
|
+
let index = firstToolIndex + 1;
|
|
4133
|
+
while (index < content.length) {
|
|
4134
|
+
if (content[index]?.type === "toolCall") {
|
|
4135
|
+
index += 1;
|
|
4136
|
+
continue;
|
|
4137
|
+
}
|
|
4138
|
+
const runStart = index;
|
|
4139
|
+
const runBlocks = [];
|
|
4140
|
+
while (index < content.length && content[index]?.type !== "toolCall") {
|
|
4141
|
+
const runBlock = content[index];
|
|
4142
|
+
if (runBlock)
|
|
4143
|
+
runBlocks.push(runBlock);
|
|
4144
|
+
index += 1;
|
|
4145
|
+
}
|
|
4146
|
+
const runMessage = { ...message, content: runBlocks };
|
|
4147
|
+
const existing = this.assistantTextSegments.get(runStart);
|
|
4148
|
+
if (existing) {
|
|
4149
|
+
existing.updateContent(runMessage, true);
|
|
4150
|
+
continue;
|
|
4151
|
+
}
|
|
4152
|
+
const segment = new AssistantMessageComponent(runMessage, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad, this.getMarkdownTransformers());
|
|
4153
|
+
segment.setExpanded(this.toolOutputExpanded);
|
|
4154
|
+
this.assistantTextSegments.set(runStart, segment);
|
|
4155
|
+
const followingToolCall = content.slice(index).find((block) => block.type === "toolCall");
|
|
4156
|
+
const followingToolCallId = followingToolCall?.type === "toolCall" ? followingToolCall.id : undefined;
|
|
4157
|
+
const followingToolComponent = followingToolCallId ? this.pendingTools.get(followingToolCallId) : undefined;
|
|
4158
|
+
const anchorIndex = followingToolComponent ? this.chatContainer.children.indexOf(followingToolComponent) : -1;
|
|
4159
|
+
if (anchorIndex >= 0)
|
|
4160
|
+
this.chatContainer.children.splice(anchorIndex, 0, segment);
|
|
4161
|
+
else
|
|
4162
|
+
this.chatContainer.addChild(segment);
|
|
4163
|
+
}
|
|
4164
|
+
for (const [runStart, segment] of this.assistantTextSegments) {
|
|
4165
|
+
if (runStart >= content.length || content[runStart]?.type === "toolCall") {
|
|
4166
|
+
this.chatContainer.detachChild(segment);
|
|
4167
|
+
this.assistantTextSegments.delete(runStart);
|
|
4168
|
+
}
|
|
4169
|
+
}
|
|
4170
|
+
}
|
|
4171
|
+
detachAssistantTextSegments() {
|
|
4172
|
+
for (const segment of this.assistantTextSegments.values()) {
|
|
4173
|
+
this.chatContainer.detachChild(segment);
|
|
4127
4174
|
}
|
|
4128
|
-
this.
|
|
4129
|
-
this.chatContainer.detachChild(this.trailingAssistantComponent);
|
|
4130
|
-
this.chatContainer.addChild(this.trailingAssistantComponent);
|
|
4175
|
+
this.assistantTextSegments.clear();
|
|
4131
4176
|
}
|
|
4132
4177
|
createToolExecutionComponent(toolName, toolCallId, args) {
|
|
4133
4178
|
if (this.chrome) {
|
|
@@ -4906,12 +4951,12 @@ export class InteractiveMode {
|
|
|
4906
4951
|
return allQueued.length;
|
|
4907
4952
|
}
|
|
4908
4953
|
queueCompactionMessage(text, mode, droppedImageCount = 0) {
|
|
4909
|
-
|
|
4954
|
+
// No optimistic echo here: compaction-queued input is waiting state and must
|
|
4955
|
+
// render only in the pending-messages display until it is actually delivered.
|
|
4910
4956
|
this.compactionQueuedMessages.push({
|
|
4911
4957
|
text,
|
|
4912
4958
|
mode,
|
|
4913
4959
|
enqueueOrder: this.session.reserveQueuedInputOrder(),
|
|
4914
|
-
pendingEchoId,
|
|
4915
4960
|
});
|
|
4916
4961
|
this.getSessionLogger().debug("compaction_queue_enqueue", {
|
|
4917
4962
|
mode,
|
|
@@ -5384,11 +5429,15 @@ export class InteractiveMode {
|
|
|
5384
5429
|
return findExactModelReferenceMatch(searchTerm, [...this.session.modelRuntime.getAvailableSnapshot()]);
|
|
5385
5430
|
}
|
|
5386
5431
|
async selectModelFromUi(model, done) {
|
|
5432
|
+
// The selector overlay is already disposed on Enter, so releasing it only
|
|
5433
|
+
// after setModel resolves leaves a stale frozen frame for the whole provider
|
|
5434
|
+
// auth round trip. Release and repaint first, then apply the switch.
|
|
5435
|
+
done?.();
|
|
5436
|
+
this.ui?.requestRender();
|
|
5387
5437
|
try {
|
|
5388
5438
|
const systemPromptChange = await this.session.setModel(model);
|
|
5389
5439
|
this.footer.invalidate();
|
|
5390
5440
|
this.updateEditorBorderColor();
|
|
5391
|
-
done?.();
|
|
5392
5441
|
const systemPromptStr = systemPromptChange?.systemPromptName
|
|
5393
5442
|
? ` (optimized system prompt applied: ${systemPromptChange.systemPromptName})`
|
|
5394
5443
|
: "";
|
|
@@ -5398,7 +5447,6 @@ export class InteractiveMode {
|
|
|
5398
5447
|
this.checkDaxnutsEasterEgg(model);
|
|
5399
5448
|
}
|
|
5400
5449
|
catch (error) {
|
|
5401
|
-
done?.();
|
|
5402
5450
|
this.showError(error instanceof Error ? error.message : String(error));
|
|
5403
5451
|
}
|
|
5404
5452
|
}
|