@volter/supercode-frontend-vscode 0.1.33 → 0.1.34
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/README.md +11 -0
- package/dist/extension.js +29 -6
- package/dist/view.d.ts +5 -9
- package/dist/view.js +4 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -373,3 +373,14 @@ routing: stock code broadcasts changes to all input states of a provider. The
|
|
|
373
373
|
Volter overlay guards this fix with a native regression test. The former legacy
|
|
374
374
|
option-notification queue is no longer required. The narrow reveal/focus bridge
|
|
375
375
|
remains because the native model catalogue and participant identity are provider-wide.
|
|
376
|
+
|
|
377
|
+
### Native approval cards
|
|
378
|
+
|
|
379
|
+
A host advertising `volter.chat.inTurnApprovalCapability` version 1 presents
|
|
380
|
+
actual approval requests in its native confirmation card. The original offered
|
|
381
|
+
labels, order and response payloads are preserved. Clicking answers the pending
|
|
382
|
+
request inside the current turn through `supercode.frontend.respondInTurnApproval`;
|
|
383
|
+
it never submits a new chat prompt. The host guards the addressed conversation,
|
|
384
|
+
disables the choices during dispatch and retires them only after an acknowledged
|
|
385
|
+
response or an already-resolved result. Hosts without this capability retain
|
|
386
|
+
stable command buttons. Other request kinds retain their existing presentation.
|
package/dist/extension.js
CHANGED
|
@@ -184,6 +184,7 @@ class SupercodeFrontends {
|
|
|
184
184
|
this.#changed.dispose();
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
|
+
let nativeInTurnApprovalCards = false;
|
|
187
188
|
function writeProjected(stream, projected, granted, state) {
|
|
188
189
|
for (const candidate of projected) {
|
|
189
190
|
const parts = resolveParts([candidate], granted);
|
|
@@ -235,6 +236,12 @@ function writePart(stream, part, state) {
|
|
|
235
236
|
return;
|
|
236
237
|
}
|
|
237
238
|
case 'answers':
|
|
239
|
+
if (part.approval && nativeInTurnApprovalCards && part.answers.length > 0) {
|
|
240
|
+
stream.confirmation(part.title, part.message, {
|
|
241
|
+
kind: 'supercode.inTurnApproval', version: 1, answers: part.answers,
|
|
242
|
+
}, part.answers.map(answer => answer.label));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
238
245
|
// Stable API on purpose: a command button runs INSIDE the live turn,
|
|
239
246
|
// which is when a supercode approval is raised. See `view.ts`.
|
|
240
247
|
stream.markdown(`\n\n**${part.title}**\n\n${part.message}\n\n`);
|
|
@@ -300,6 +307,20 @@ export async function activate(context) {
|
|
|
300
307
|
// description, so this is the grant, not the request.
|
|
301
308
|
const granted = grantedProposals(context.extension.packageJSON);
|
|
302
309
|
log.info(`Volter Harness: proposals requested ${REQUESTED_PROPOSALS.join(', ')}; granted ${granted.size ? [...granted].join(', ') : 'none (stable chat parts only)'}`);
|
|
310
|
+
// Explicit workbench support is required: stock confirmation clicks send
|
|
311
|
+
// a new prompt. A missing capability keeps the stable in-turn buttons.
|
|
312
|
+
if (granted.has('chatParticipantAdditions')) {
|
|
313
|
+
try {
|
|
314
|
+
const commands = await vscode.commands.getCommands(true);
|
|
315
|
+
if (commands.includes('volter.chat.inTurnApprovalCapability')) {
|
|
316
|
+
const capability = await vscode.commands.executeCommand('volter.chat.inTurnApprovalCapability');
|
|
317
|
+
nativeInTurnApprovalCards = capability?.version === 1;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
log.warn(`Native in-turn approval cards unavailable: ${String(error)}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
303
324
|
const controls = await ChatHostControls.fromEnvironment();
|
|
304
325
|
const offerChatGPT = await chatGPTAvailable();
|
|
305
326
|
let signingInWithChatGPT;
|
|
@@ -1059,34 +1080,36 @@ export async function activate(context) {
|
|
|
1059
1080
|
*/
|
|
1060
1081
|
async function answerRequest(answer) {
|
|
1061
1082
|
if (!answer || typeof answer.requestId !== 'number')
|
|
1062
|
-
return;
|
|
1083
|
+
return { status: 'unavailable' };
|
|
1063
1084
|
const connection = frontends.get(answer.connectionId);
|
|
1064
1085
|
if (!connection) {
|
|
1065
1086
|
void vscode.window.showWarningMessage('Volter Harness is no longer attached to that runtime.');
|
|
1066
|
-
return;
|
|
1087
|
+
return { status: 'unavailable' };
|
|
1067
1088
|
}
|
|
1068
1089
|
const request = connection.session.pendingRequests.get(answer.requestId);
|
|
1069
1090
|
if (!request) {
|
|
1070
1091
|
void vscode.window.showInformationMessage(`Volter Harness: request #${answer.requestId} is already resolved.`);
|
|
1071
|
-
return;
|
|
1092
|
+
return { status: 'resolved' };
|
|
1072
1093
|
}
|
|
1073
1094
|
let response = answer.response;
|
|
1074
1095
|
try {
|
|
1075
1096
|
if (answer.promptForContent) {
|
|
1076
1097
|
const content = await requestContent(request);
|
|
1077
1098
|
if (content === undefined)
|
|
1078
|
-
return;
|
|
1099
|
+
return { status: 'cancelled' };
|
|
1079
1100
|
response = { ...response, content };
|
|
1080
1101
|
}
|
|
1081
1102
|
await connection.session.respond(response);
|
|
1082
1103
|
void vscode.window.setStatusBarMessage(`Volter Harness: ${resolutionSentence(response, request, answer.requestId)}`, 4000);
|
|
1104
|
+
return { status: 'responded' };
|
|
1083
1105
|
}
|
|
1084
1106
|
catch (error) {
|
|
1085
1107
|
if (error instanceof RequestNotPendingError) {
|
|
1086
1108
|
void vscode.window.showInformationMessage(`Volter Harness: request #${answer.requestId} is already resolved.`);
|
|
1087
|
-
return;
|
|
1109
|
+
return { status: 'resolved' };
|
|
1088
1110
|
}
|
|
1089
1111
|
void vscode.window.showErrorMessage(`Volter Harness could not answer request #${answer.requestId}: ${String(error?.message ?? error)}`);
|
|
1112
|
+
return { status: 'failed' };
|
|
1090
1113
|
}
|
|
1091
1114
|
}
|
|
1092
1115
|
const secretKey = (baseUrl) => `supercode.frontend.token:${baseUrl}`;
|
|
@@ -1132,7 +1155,7 @@ export async function activate(context) {
|
|
|
1132
1155
|
// The one door an answer button uses. It answers the runtime's pending
|
|
1133
1156
|
// request through `frontend.v2.respond` and narrates itself, because a
|
|
1134
1157
|
// click whose effect is invisible is a click nobody can trust.
|
|
1135
|
-
vscode.commands.registerCommand('supercode.frontend.respond', (answer) => answerRequest(answer)), vscode.commands.registerCommand('supercode.frontend.status', async (inspect) => {
|
|
1158
|
+
vscode.commands.registerCommand('supercode.frontend.respond', async (answer) => { await answerRequest(answer); }), vscode.commands.registerCommand('supercode.frontend.respondInTurnApproval', (answer) => answerRequest(answer)), vscode.commands.registerCommand('supercode.frontend.status', async (inspect) => {
|
|
1136
1159
|
if (controls)
|
|
1137
1160
|
await controls.refresh();
|
|
1138
1161
|
if (inspect === true)
|
package/dist/view.d.ts
CHANGED
|
@@ -15,15 +15,10 @@ export declare const VSCODE_CHAT_LIMITS: Readonly<{
|
|
|
15
15
|
/**
|
|
16
16
|
* What one answer button sends back to the runtime.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* crates/harness/src/server.rs blocks the agent loop until it is answered — so
|
|
23
|
-
* the editor refuses that second request and the click does nothing. An
|
|
24
|
-
* answer is therefore a COMMAND button: it runs inside the live turn, it is
|
|
25
|
-
* stable API (no proposal), and each button carries its own answer instead of
|
|
26
|
-
* the one payload a confirmation splits across accepted/rejected.
|
|
18
|
+
* Stock confirmations send a new chat request and cannot answer a running
|
|
19
|
+
* harness turn. Hosts advertising the versioned in-turn approval capability
|
|
20
|
+
* reuse their native confirmation card while dispatching this exact answer.
|
|
21
|
+
* Other hosts retain stable command buttons inside the running turn.
|
|
27
22
|
*/
|
|
28
23
|
export interface ChatAnswer {
|
|
29
24
|
connectionId: string;
|
|
@@ -67,6 +62,7 @@ export type ChatPart = {
|
|
|
67
62
|
resultText?: string;
|
|
68
63
|
} | {
|
|
69
64
|
part: 'answers';
|
|
65
|
+
approval: boolean;
|
|
70
66
|
title: string;
|
|
71
67
|
message: string;
|
|
72
68
|
answers: ChatAnswer[];
|
package/dist/view.js
CHANGED
|
@@ -389,25 +389,9 @@ export function projectEvent(event, context) {
|
|
|
389
389
|
const title = request.kind === 'approval'
|
|
390
390
|
? 'Approval required'
|
|
391
391
|
: subject ? `Approve ${subject}` : `Assistant request #${request.id}`;
|
|
392
|
-
//
|
|
393
|
-
//
|
|
394
|
-
//
|
|
395
|
-
// `ChatResponseConfirmationPart` retires its own buttons on click, but
|
|
396
|
-
// the click answers by sending a NEW chat request, and a supercode
|
|
397
|
-
// approval is raised while the turn still runs (`decide_approval`
|
|
398
|
-
// blocks the agent loop) — the editor refuses that request, so the
|
|
399
|
-
// click does nothing and the runtime waits forever.
|
|
400
|
-
// `stream.questionCarousel` resolves inside the running turn and the
|
|
401
|
-
// widget retires itself — the right shape on paper. Observed: the
|
|
402
|
-
// widget renders with its options, Submit retires it, and the
|
|
403
|
-
// promise never delivers an answer this frontend can read, so the
|
|
404
|
-
// runtime is left blocked. A preferred path that silently swallows
|
|
405
|
-
// the answer is worse than a plain one that works.
|
|
406
|
-
// A command button runs inside the live turn and carries its own answer,
|
|
407
|
-
// so the runtime's offered answers remain usable. It cannot be withdrawn
|
|
408
|
-
// once pushed (`chatCommandContentPart` enables on `!isStale` and has no
|
|
409
|
-
// used-state), so `supercode.frontend.respond` refuses a request that is
|
|
410
|
-
// no longer pending and SAYS so instead of sending a stale answer.
|
|
392
|
+
// The host capability decides whether these original answers can use
|
|
393
|
+
// a native in-turn confirmation card. Stock confirmation clicks start a
|
|
394
|
+
// new chat request, so stable command buttons remain the fallback.
|
|
411
395
|
if (context.canRespond === false || (request.payload && typeof request.payload === 'object' && !Array.isArray(request.payload) && request.payload.observe_only === true)) {
|
|
412
396
|
return [stable({
|
|
413
397
|
part: 'markdown',
|
|
@@ -416,6 +400,7 @@ export function projectEvent(event, context) {
|
|
|
416
400
|
}
|
|
417
401
|
return [stable({
|
|
418
402
|
part: 'answers',
|
|
403
|
+
approval: request.kind === 'approval',
|
|
419
404
|
title: clamp(title, VSCODE_CHAT_LIMITS.titleCharacters),
|
|
420
405
|
message: summary,
|
|
421
406
|
answers,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-frontend-vscode",
|
|
3
3
|
"displayName": "Volter Harness",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.34",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "VS Code chat-view frontend for an existing Volter Harness SDK runtime",
|
|
7
7
|
"publisher": "volter-ai-dev",
|