mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-21 00:05:49 +02:00
Match Pi native question schemas to accepted method fields
This commit is contained in:
1 parent
926104e4d6
commit
a97649f283
3 files changed
+45
-5
No files matched your search
@@ -36,6 +36,15 @@ Cleanup passes. Both failed corrected local attempts remain failed; the memory
|
||||
case is not qualified. No byte assertion, timeout, model or permission boundary
|
||||
is relaxed. Production remains held; no merge or release is authorized.
|
||||
|
||||
The corrected Linux native-questions attempt delivers the first three typed
|
||||
answers, then its editor call fails with `Pi question has unsupported fields`.
|
||||
The original schema advertises fields that the selected method cannot accept.
|
||||
The schema correction separates the four method contracts while retaining
|
||||
strict handler validation. All 37 Pi extension tests pass. A credential-free
|
||||
calibration proves that the installed old schema accepts an editor placeholder
|
||||
that its handler rejects, while the corrected schema rejects that input before
|
||||
execution. This correction also requires fresh runtime artifact qualification.
|
||||
|
||||
## Frozen target
|
||||
|
||||
- Pi: `@earendil-works/pi-coding-agent@1.0.0`.
|
||||
|
||||
@@ -4,6 +4,7 @@ import { mkdtemp, mkdir, realpath, rename, rm, symlink, writeFile } from "node:f
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import Ajv from "ajv";
|
||||
import {
|
||||
checkPiNativeTool, installPiRuntimeExtension, piMcpRequest, readPiRuntimeConfiguration,
|
||||
PI_NATIVE_QUESTION_TOOL, PI_PERMISSION_TITLE_PREFIX, type PiExtensionApi, type PiRuntimeConfiguration, type PiToolDefinition,
|
||||
@@ -30,6 +31,26 @@ function harness() {
|
||||
}
|
||||
|
||||
describe("owned Pi runtime extension", () => {
|
||||
it("advertises only the fields each native question method accepts", async () => {
|
||||
const { config } = await workspace(); const h = harness();
|
||||
await installPiRuntimeExtension(h.api, config);
|
||||
const validate = new Ajv().compile(h.nativeTools[0]!.parameters);
|
||||
const questions = [
|
||||
{ method: "select", title: "Color", options: [{ id: "blue", label: "Blue" }] },
|
||||
{ method: "confirm", title: "Preference", message: "Prefer dark mode?" },
|
||||
{ method: "input", title: "Name", placeholder: "Name" },
|
||||
{ method: "editor", title: "Draft", prefill: "Old draft" },
|
||||
];
|
||||
for (const question of questions) expect(validate(question)).toBe(true);
|
||||
for (const question of [
|
||||
{ ...questions[3], placeholder: "Name" },
|
||||
{ ...questions[2], prefill: "Old draft" },
|
||||
{ ...questions[1], options: [] },
|
||||
{ method: "select", title: "Color" },
|
||||
{ method: "confirm", title: "Preference" },
|
||||
]) expect(validate(question)).toBe(false);
|
||||
});
|
||||
|
||||
it("stops Pi 1 cache warming even when native economics recommend a paid refresh", async () => {
|
||||
const { config } = await workspace(); const h = harness();
|
||||
await installPiRuntimeExtension(h.api, config);
|
||||
|
||||
@@ -374,11 +374,21 @@ export async function installPiRuntimeExtension(
|
||||
pi.registerTool({
|
||||
name: PI_NATIVE_QUESTION_TOOL, label: "Ask a native question",
|
||||
description: "Ask the human a native Pi select, confirm, input, or editor question. Select is single-choice and returns the supplied stable option ID. This cannot approve tools or a Paperclip Plan. For durable task questions or Plan approval use the assigned Paperclip semantic tools. Cancellation is not an answer; confirm false means No or dismissal.",
|
||||
parameters: { type: "object", additionalProperties: false, required: ["method", "title"], properties: {
|
||||
method: { type: "string", enum: ["select", "confirm", "input", "editor"] }, title: { type: "string", maxLength: PI_QUESTION_LABEL_MAX_LENGTH },
|
||||
options: { type: "array", minItems: 1, maxItems: 128, items: { type: "object", additionalProperties: false, required: ["id", "label"], properties: { id: { type: "string", pattern: "^[A-Za-z0-9_-]{1,128}$" }, label: { type: "string", maxLength: PI_QUESTION_LABEL_MAX_LENGTH } } } },
|
||||
message: { type: "string", maxLength: 16384 }, placeholder: { type: "string", maxLength: 16384 }, prefill: { type: "string", maxLength: 16384 },
|
||||
} },
|
||||
parameters: { type: "object", anyOf: [
|
||||
{ type: "object", additionalProperties: false, required: ["method", "title", "options"], properties: {
|
||||
method: { const: "select" }, title: { type: "string", maxLength: PI_QUESTION_LABEL_MAX_LENGTH },
|
||||
options: { type: "array", minItems: 1, maxItems: 128, items: { type: "object", additionalProperties: false, required: ["id", "label"], properties: { id: { type: "string", pattern: "^[A-Za-z0-9_-]{1,128}$" }, label: { type: "string", maxLength: PI_QUESTION_LABEL_MAX_LENGTH } } } },
|
||||
} },
|
||||
{ type: "object", additionalProperties: false, required: ["method", "title", "message"], properties: {
|
||||
method: { const: "confirm" }, title: { type: "string", maxLength: PI_QUESTION_LABEL_MAX_LENGTH }, message: { type: "string", maxLength: 16384 },
|
||||
} },
|
||||
{ type: "object", additionalProperties: false, required: ["method", "title"], properties: {
|
||||
method: { const: "input" }, title: { type: "string", maxLength: PI_QUESTION_LABEL_MAX_LENGTH }, placeholder: { type: "string", maxLength: 16384 },
|
||||
} },
|
||||
{ type: "object", additionalProperties: false, required: ["method", "title"], properties: {
|
||||
method: { const: "editor" }, title: { type: "string", maxLength: PI_QUESTION_LABEL_MAX_LENGTH }, prefill: { type: "string", maxLength: 16384 },
|
||||
} },
|
||||
] },
|
||||
async execute(callId, args, signal, _onUpdate, context) {
|
||||
const id = identities.bind(callId, PI_NATIVE_QUESTION_TOOL, args);
|
||||
const previous = questions.get(id); if (previous) return previous;
|
||||
|
||||
Reference in new issue
Block a user