fix: adjust live VS Code streaming updates
- Handle SSE paths with query strings and trailing slashes correctly - Normalize streamed chunk newlines before SSE block parsing - Apply streaming fixes across chat, session editor, and agent manager panels
This commit is contained in:
@@ -156,7 +156,12 @@ export class AgentManagerPanelProvider {
|
||||
|
||||
const { path, headers } = (payload || {}) as { path?: string; headers?: Record<string, string> };
|
||||
const normalizedPath = typeof path === 'string' && path.trim().length > 0 ? path.trim() : '/event';
|
||||
const shouldInjectActivity = normalizedPath === '/event' || normalizedPath === '/global/event';
|
||||
const normalizedPathname = (() => {
|
||||
const rawPathname = normalizedPath.split('?')[0];
|
||||
if (rawPathname === '/') return '/';
|
||||
return rawPathname.replace(/\/+$/, '');
|
||||
})();
|
||||
const shouldInjectActivity = normalizedPathname === '/event' || normalizedPathname === '/global/event';
|
||||
|
||||
if (!apiBaseUrl) {
|
||||
return {
|
||||
@@ -189,7 +194,7 @@ export class AgentManagerPanelProvider {
|
||||
});
|
||||
|
||||
// Fallback for OpenCode versions without /global/event.
|
||||
if ((!response.ok || !response.body) && normalizedPath === '/global/event') {
|
||||
if ((!response.ok || !response.body) && normalizedPathname === '/global/event') {
|
||||
const fallbackUrl = new URL('event', base).toString();
|
||||
response = await fetch(fallbackUrl, {
|
||||
method: 'GET',
|
||||
@@ -259,7 +264,7 @@ export class AgentManagerPanelProvider {
|
||||
if (!chunk) continue;
|
||||
|
||||
// Reduce webview message pressure by forwarding complete SSE blocks.
|
||||
sseBuffer += shouldInjectActivity ? chunk.replace(/\r\n/g, '\n') : chunk;
|
||||
sseBuffer += chunk.replace(/\r\n/g, '\n');
|
||||
const blocks = sseBuffer.split('\n\n');
|
||||
sseBuffer = blocks.pop() ?? '';
|
||||
if (blocks.length > 0) {
|
||||
@@ -275,7 +280,7 @@ export class AgentManagerPanelProvider {
|
||||
|
||||
const tail = decoder.decode();
|
||||
if (tail) {
|
||||
sseBuffer += shouldInjectActivity ? tail.replace(/\r\n/g, '\n') : tail;
|
||||
sseBuffer += tail.replace(/\r\n/g, '\n');
|
||||
}
|
||||
if (sseBuffer) {
|
||||
if (shouldInjectActivity) {
|
||||
|
||||
@@ -184,7 +184,12 @@ export class ChatViewProvider implements vscode.WebviewViewProvider {
|
||||
|
||||
const { path, headers } = (payload || {}) as { path?: string; headers?: Record<string, string> };
|
||||
const normalizedPath = typeof path === 'string' && path.trim().length > 0 ? path.trim() : '/event';
|
||||
const shouldInjectActivity = normalizedPath === '/event' || normalizedPath === '/global/event';
|
||||
const normalizedPathname = (() => {
|
||||
const rawPathname = normalizedPath.split('?')[0];
|
||||
if (rawPathname === '/') return '/';
|
||||
return rawPathname.replace(/\/+$/, '');
|
||||
})();
|
||||
const shouldInjectActivity = normalizedPathname === '/event' || normalizedPathname === '/global/event';
|
||||
|
||||
if (!apiBaseUrl) {
|
||||
return {
|
||||
@@ -218,7 +223,7 @@ export class ChatViewProvider implements vscode.WebviewViewProvider {
|
||||
|
||||
// Fallback: OpenCode versions without /global/event.
|
||||
// VS Code is single-workspace, so we can wrap /event into { directory, payload }.
|
||||
if ((!response.ok || !response.body) && normalizedPath === '/global/event') {
|
||||
if ((!response.ok || !response.body) && normalizedPathname === '/global/event') {
|
||||
const fallbackUrl = new URL('event', base).toString();
|
||||
response = await fetch(fallbackUrl, {
|
||||
method: 'GET',
|
||||
@@ -290,7 +295,7 @@ export class ChatViewProvider implements vscode.WebviewViewProvider {
|
||||
// Reduce webview message pressure by forwarding complete SSE blocks.
|
||||
// The SDK SSE parser is block-based (\n\n delimited) and can consume
|
||||
// partial chunks, but VS Code's postMessage channel can be a bottleneck.
|
||||
sseBuffer += shouldInjectActivity ? chunk.replace(/\r\n/g, '\n') : chunk;
|
||||
sseBuffer += chunk.replace(/\r\n/g, '\n');
|
||||
const blocks = sseBuffer.split('\n\n');
|
||||
sseBuffer = blocks.pop() ?? '';
|
||||
if (blocks.length > 0) {
|
||||
@@ -306,7 +311,7 @@ export class ChatViewProvider implements vscode.WebviewViewProvider {
|
||||
|
||||
const tail = decoder.decode();
|
||||
if (tail) {
|
||||
sseBuffer += shouldInjectActivity ? tail.replace(/\r\n/g, '\n') : tail;
|
||||
sseBuffer += tail.replace(/\r\n/g, '\n');
|
||||
}
|
||||
if (sseBuffer) {
|
||||
if (shouldInjectActivity) {
|
||||
|
||||
@@ -179,7 +179,12 @@ export class SessionEditorPanelProvider {
|
||||
|
||||
const { path, headers } = (payload || {}) as { path?: string; headers?: Record<string, string> };
|
||||
const normalizedPath = typeof path === 'string' && path.trim().length > 0 ? path.trim() : '/event';
|
||||
const shouldInjectActivity = normalizedPath === '/event' || normalizedPath === '/global/event';
|
||||
const normalizedPathname = (() => {
|
||||
const rawPathname = normalizedPath.split('?')[0];
|
||||
if (rawPathname === '/') return '/';
|
||||
return rawPathname.replace(/\/+$/, '');
|
||||
})();
|
||||
const shouldInjectActivity = normalizedPathname === '/event' || normalizedPathname === '/global/event';
|
||||
|
||||
if (!apiBaseUrl) {
|
||||
return {
|
||||
@@ -213,7 +218,7 @@ export class SessionEditorPanelProvider {
|
||||
|
||||
// Fallback: OpenCode versions without /global/event.
|
||||
// VS Code is single-workspace, so we can wrap /event into { directory, payload }.
|
||||
if ((!response.ok || !response.body) && normalizedPath === '/global/event') {
|
||||
if ((!response.ok || !response.body) && normalizedPathname === '/global/event') {
|
||||
const fallbackUrl = new URL('event', base).toString();
|
||||
response = await fetch(fallbackUrl, {
|
||||
method: 'GET',
|
||||
@@ -282,7 +287,7 @@ export class SessionEditorPanelProvider {
|
||||
const chunk = decoder.decode(value, { stream: true });
|
||||
if (!chunk) continue;
|
||||
|
||||
sseBuffer += shouldInjectActivity ? chunk.replace(/\r\n/g, '\n') : chunk;
|
||||
sseBuffer += chunk.replace(/\r\n/g, '\n');
|
||||
const blocks = sseBuffer.split('\n\n');
|
||||
sseBuffer = blocks.pop() ?? '';
|
||||
if (blocks.length > 0) {
|
||||
@@ -298,7 +303,7 @@ export class SessionEditorPanelProvider {
|
||||
|
||||
const tail = decoder.decode();
|
||||
if (tail) {
|
||||
sseBuffer += shouldInjectActivity ? tail.replace(/\r\n/g, '\n') : tail;
|
||||
sseBuffer += tail.replace(/\r\n/g, '\n');
|
||||
}
|
||||
if (sseBuffer) {
|
||||
if (shouldInjectActivity) {
|
||||
|
||||
Reference in New Issue
Block a user