paseo-plugin-zcode-provider 0.4.1 → 0.4.3
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 +2 -1
- package/package.json +1 -1
- package/server/build-info.ts +1 -1
- package/server/presentation.ts +7 -1
- package/server/provider.ts +17 -8
- package/server/session.ts +34 -1
package/README.md
CHANGED
|
@@ -81,12 +81,13 @@ The source baseline is `3c5b227649371507ddc4eb46ac5133afe6db1cab` (ZCode 3.16.2,
|
|
|
81
81
|
- Models and reasoning options come from ZCode. Editing modes are `build`, `edit`, `guarded` and `yolo`; `settings.plan_mode` is independent. `guarded` (ZCode's Autonomous mode, Server 3.15.1 or later) runs tools without approval but asks once, each time, before a command that ZCode's safety rules consider risky; it is not offered on older runtimes.
|
|
82
82
|
- Text, thoughts, tools, subagent progress, usage and history use V4 snapshots and deltas. Tool output is marked when ZCode truncates it. Usage is cumulative; repeated snapshots do not add it again.
|
|
83
83
|
- Text submitted during generation uses native guidance. Attachments use the native queue. Paseo reports one run across these native turns and completes it only after all accepted input has been consumed and foreground work has ended.
|
|
84
|
+
- Paseo sends every message typed in the app during a run as a steer that asks to clear pending permissions. The plugin queues it first, then declines pending permissions, questions and Plan approvals with their deny action until ZCode reads the message, including requests opened in the meantime. Requests that appear after it is read are left to the user. Declining a Plan approval in Plan mode ends ZCode's turn; the message then starts the next native turn in the same Paseo run (ADR 22).
|
|
84
85
|
- Acceptance is reported once, after the native acknowledgement. Unknown delivery results are never automatically resent. Stop identifies the current native execution, disables automatic queue execution and removes pending input. A new explicit run enables the queue again.
|
|
85
86
|
- As in ZCode Desktop, successful hooks are not shown. A finished hook invocation appears once, as a notification, only when a hook was blocked, failed, timed out or was cancelled; context compaction also appears once, when it ends. Paseo appends every notification it receives, so progress is not reported.
|
|
86
87
|
- Native permission IDs, option values, questions and Plan approval retain their meanings. Question auto-resolution is disabled for each owned Server. Workspace hook trust is reviewed through the official CLI; it is not represented as “allow once.”
|
|
87
88
|
- Each session owns its Server process and environment. Metadata requests use temporary Servers. Closing stdin gives ZCode time to clean up before process termination.
|
|
88
89
|
|
|
89
|
-
The plugin uses ZCode's own skills, MCP configuration and tools. Browser Use and Computer Use cannot run in the plugin's ZCode, even when ZCode Desktop has them enabled: the Computer Use helper accepts only the signed Desktop app, and only Desktop provides browsers. ZCode's Visualize (interactive views in the conversation) renders only in Desktop. The plugin therefore hides all three from the model (ADR 19, ADR 21); Desktop is not affected. Generic rewind, independent Paseo child agents, hook-review UI and Goal/Workflow controls are outside this migration. `prompt.output_schema`, custom system prompts and `persist:false` are unsupported. MCP `alwaysLoad` is unsupported; stdio MCP commands must be absolute paths. Provider options are unsupported: in Paseo 0.11 and later, `agents.providers.zcode.options` in Paseo's `config.json` makes sessions fail with `INVALID_CONFIGURATION`, and the `command` and `env` overrides there are not applied. Paseo does not show context usage reported before the first turn, and the plugin adds no substitute display; Coding Plan quota appears in Paseo 0.11's Usage screen (see [Coding Plan usage](#coding-plan-usage)).
|
|
90
|
+
The plugin uses ZCode's own skills, MCP configuration and tools. Browser Use and Computer Use cannot run in the plugin's ZCode, even when ZCode Desktop has them enabled: the Computer Use helper accepts only the signed Desktop app, and only Desktop provides browsers. ZCode's Visualize (interactive views in the conversation) renders only in Desktop. The plugin therefore hides all three from the model (ADR 19, ADR 21); Desktop is not affected. Generic rewind, independent Paseo child agents, hook-review UI and Goal/Workflow controls are outside this migration. `prompt.output_schema`, custom system prompts and `persist:false` are unsupported. A system prompt makes session creation fail with `INVALID_CONFIGURATION` and a message explaining why, including one appended by Paseo's Orchestration → System prompt setting or by another plugin that adds one to new agents. MCP `alwaysLoad` is unsupported; stdio MCP commands must be absolute paths. Provider options are unsupported: in Paseo 0.11 and later, `agents.providers.zcode.options` in Paseo's `config.json` makes sessions fail with `INVALID_CONFIGURATION`, and the `command` and `env` overrides there are not applied. Paseo does not show context usage reported before the first turn, and the plugin adds no substitute display; Coding Plan quota appears in Paseo 0.11's Usage screen (see [Coding Plan usage](#coding-plan-usage)).
|
|
90
91
|
|
|
91
92
|
## Persistence
|
|
92
93
|
|
package/package.json
CHANGED
package/server/build-info.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated from package.json by npm prepare / prebuild.
|
|
2
|
-
export const PROVIDER_VERSION = "0.4.
|
|
2
|
+
export const PROVIDER_VERSION = "0.4.3";
|
package/server/presentation.ts
CHANGED
|
@@ -233,6 +233,8 @@ export function usage(state: ConversationSnapshot): ProviderUsage {
|
|
|
233
233
|
export interface PresentedInteraction {
|
|
234
234
|
request: ProviderPermissionRequest;
|
|
235
235
|
answer(response: ProviderPermissionResponse): Record<string, unknown>;
|
|
236
|
+
/** Native answer of the first deny action, without interrupting. */
|
|
237
|
+
decline: Record<string, unknown>;
|
|
236
238
|
}
|
|
237
239
|
export function presentInteraction(
|
|
238
240
|
interaction: PendingInteraction,
|
|
@@ -262,7 +264,8 @@ export function presentInteraction(
|
|
|
262
264
|
variant: behavior === "allow" ? "primary" : "danger",
|
|
263
265
|
};
|
|
264
266
|
});
|
|
265
|
-
|
|
267
|
+
const deny = actions.find((a) => a.behavior === "deny");
|
|
268
|
+
if (!deny)
|
|
266
269
|
throw new AdapterError(
|
|
267
270
|
"NATIVE_PROTOCOL_ERROR",
|
|
268
271
|
"ZCode permission has no deny option",
|
|
@@ -299,6 +302,7 @@ export function presentInteraction(
|
|
|
299
302
|
);
|
|
300
303
|
return { optionId: action.id };
|
|
301
304
|
},
|
|
305
|
+
decline: { optionId: deny.id },
|
|
302
306
|
};
|
|
303
307
|
}
|
|
304
308
|
if (p.sensitive)
|
|
@@ -414,6 +418,7 @@ export function presentInteraction(
|
|
|
414
418
|
},
|
|
415
419
|
};
|
|
416
420
|
},
|
|
421
|
+
decline: { action: "decline" },
|
|
417
422
|
};
|
|
418
423
|
}
|
|
419
424
|
return {
|
|
@@ -445,6 +450,7 @@ export function presentInteraction(
|
|
|
445
450
|
content: answerContent(record(response.updatedInput?.answers)),
|
|
446
451
|
};
|
|
447
452
|
},
|
|
453
|
+
decline: { action: "decline" },
|
|
448
454
|
};
|
|
449
455
|
}
|
|
450
456
|
|
package/server/provider.ts
CHANGED
|
@@ -220,7 +220,9 @@ export class ZCodeConnection implements ProviderConnection {
|
|
|
220
220
|
if (input.type === "session.prompt") {
|
|
221
221
|
const promptEntry = entry ?? this.sessions.get(input.sessionId);
|
|
222
222
|
if (promptEntry?.messages.get(input.prompt.clientMessageId)) return;
|
|
223
|
-
|
|
223
|
+
// The input was not admitted. Paseo's interrupt-and-replace fallback
|
|
224
|
+
// for an unavailable steer resends it with the same ID.
|
|
225
|
+
promptEntry?.messages.delete(input.prompt.clientMessageId);
|
|
224
226
|
this.emit({
|
|
225
227
|
type: "session.prompt_result",
|
|
226
228
|
sessionId: input.sessionId,
|
|
@@ -374,11 +376,6 @@ export class ZCodeConnection implements ProviderConnection {
|
|
|
374
376
|
switch (input.type) {
|
|
375
377
|
case "session.prompt": {
|
|
376
378
|
const prompt = input.prompt.input;
|
|
377
|
-
if (input.prompt.clearPendingPermissions)
|
|
378
|
-
throw new AdapterError(
|
|
379
|
-
"INTERACTION_UNSUPPORTED",
|
|
380
|
-
"Steering does not resolve pending ZCode permissions",
|
|
381
|
-
);
|
|
382
379
|
if (input.prompt.delivery === "steer" && !entry.native.hasActiveTurn())
|
|
383
380
|
throw new AdapterError(
|
|
384
381
|
"SESSION_BUSY",
|
|
@@ -439,6 +436,7 @@ export class ZCodeConnection implements ProviderConnection {
|
|
|
439
436
|
{
|
|
440
437
|
clientMessageId: input.prompt.clientMessageId,
|
|
441
438
|
delivery: input.prompt.delivery,
|
|
439
|
+
clearPendingPermissions: input.prompt.clearPendingPermissions,
|
|
442
440
|
beforeSend: async () => {
|
|
443
441
|
if (!entry.submitted) {
|
|
444
442
|
await this.persistenceStore.save(
|
|
@@ -497,7 +495,7 @@ export class ZCodeConnection implements ProviderConnection {
|
|
|
497
495
|
if (config.systemPrompt?.trim())
|
|
498
496
|
throw new AdapterError(
|
|
499
497
|
"INVALID_CONFIGURATION",
|
|
500
|
-
"
|
|
498
|
+
"ZCode does not support custom system prompts. Remove any added by Paseo's System prompt setting (Orchestration) or by another plugin.",
|
|
501
499
|
);
|
|
502
500
|
if (!config.persist)
|
|
503
501
|
throw new AdapterError(
|
|
@@ -814,12 +812,23 @@ function publicError(error: unknown): ProviderError {
|
|
|
814
812
|
PERSISTENCE_WRITE_FAILED:
|
|
815
813
|
"ZCode resume information could not be saved. The prompt was not sent.",
|
|
816
814
|
};
|
|
815
|
+
// diagnosticError keeps the thrown error as the cause. Only a configuration
|
|
816
|
+
// reason the plugin raised itself is shown; wrapped native or unexpected
|
|
817
|
+
// failures keep the generic text.
|
|
818
|
+
const configurationReason =
|
|
819
|
+
error instanceof AdapterError &&
|
|
820
|
+
error.code === "INVALID_CONFIGURATION" &&
|
|
821
|
+
error.cause instanceof AdapterError
|
|
822
|
+
? error.message
|
|
823
|
+
: undefined;
|
|
817
824
|
return {
|
|
818
825
|
diagnostic: formatDiagnostic(error),
|
|
819
826
|
code: error instanceof AdapterError ? error.code : "INVALID_CONFIGURATION",
|
|
820
827
|
message:
|
|
821
828
|
error instanceof AdapterError
|
|
822
|
-
? (messages[error.code] ??
|
|
829
|
+
? (messages[error.code] ??
|
|
830
|
+
configurationReason ??
|
|
831
|
+
`ZCode operation failed (${error.code})`)
|
|
823
832
|
: "Invalid ZCode provider request",
|
|
824
833
|
};
|
|
825
834
|
}
|
package/server/session.ts
CHANGED
|
@@ -55,6 +55,8 @@ interface Admission {
|
|
|
55
55
|
accepted: boolean;
|
|
56
56
|
consumed: boolean;
|
|
57
57
|
productTurnId?: string;
|
|
58
|
+
/** Paseo's clearPendingPermissions: decline interactions until consumed. */
|
|
59
|
+
releasesInteractions?: boolean;
|
|
58
60
|
}
|
|
59
61
|
interface Run {
|
|
60
62
|
id: string;
|
|
@@ -286,6 +288,7 @@ export class ZCodeSession {
|
|
|
286
288
|
});
|
|
287
289
|
}
|
|
288
290
|
}
|
|
291
|
+
this.releaseInteractions();
|
|
289
292
|
if (
|
|
290
293
|
this.state.workspaceHookAdmission ||
|
|
291
294
|
this.state.pendingInteractions.some(
|
|
@@ -323,6 +326,29 @@ export class ZCodeSession {
|
|
|
323
326
|
}
|
|
324
327
|
this.maybeComplete();
|
|
325
328
|
}
|
|
329
|
+
/**
|
|
330
|
+
* ZCode reads a steer only after every tool call of the model step settles,
|
|
331
|
+
* so a parked turn never reads it. While an accepted steer that asked to clear
|
|
332
|
+
* permissions is unread, decline each pending interaction, including requests
|
|
333
|
+
* opened after an earlier decline.
|
|
334
|
+
*/
|
|
335
|
+
private releaseInteractions(): void {
|
|
336
|
+
const run = this.active;
|
|
337
|
+
if (
|
|
338
|
+
!run ||
|
|
339
|
+
run.cancelled ||
|
|
340
|
+
![...run.inputs.values()].some(
|
|
341
|
+
(i) => i.releasesInteractions && i.accepted && !i.consumed,
|
|
342
|
+
)
|
|
343
|
+
)
|
|
344
|
+
return;
|
|
345
|
+
for (const [id, interaction] of this.pending) {
|
|
346
|
+
if (this.answering.has(id)) continue;
|
|
347
|
+
this.resolveInteraction(id, interaction.decline).catch((error) =>
|
|
348
|
+
this.runtimeFailed(diagnosticError(error, this.bridge.diagnostic)),
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
326
352
|
private maybeComplete(): void {
|
|
327
353
|
const run = this.active;
|
|
328
354
|
if (
|
|
@@ -537,6 +563,7 @@ export class ZCodeSession {
|
|
|
537
563
|
options?: {
|
|
538
564
|
clientMessageId: string;
|
|
539
565
|
delivery?: "auto" | "steer";
|
|
566
|
+
clearPendingPermissions?: boolean;
|
|
540
567
|
beforeSend?: () => Promise<void>;
|
|
541
568
|
},
|
|
542
569
|
): Promise<{ turnId: string }> {
|
|
@@ -634,6 +661,7 @@ export class ZCodeSession {
|
|
|
634
661
|
);
|
|
635
662
|
this.assertOpen();
|
|
636
663
|
input.accepted = true;
|
|
664
|
+
input.releasesInteractions = options?.clearPendingPermissions === true;
|
|
637
665
|
if (options?.clientMessageId)
|
|
638
666
|
this.emit({
|
|
639
667
|
type: "prompt_accepted",
|
|
@@ -701,7 +729,12 @@ export class ZCodeSession {
|
|
|
701
729
|
"SESSION_NOT_FOUND",
|
|
702
730
|
"ZCode interaction is no longer pending",
|
|
703
731
|
);
|
|
704
|
-
|
|
732
|
+
await this.resolveInteraction(id, pending.answer(response));
|
|
733
|
+
}
|
|
734
|
+
private async resolveInteraction(
|
|
735
|
+
id: string,
|
|
736
|
+
answer: Record<string, unknown>,
|
|
737
|
+
): Promise<void> {
|
|
705
738
|
this.answering.add(id);
|
|
706
739
|
try {
|
|
707
740
|
await this.control("resolveInteraction", { interactionId: id, answer });
|