@danypops/papyrus 0.29.0 → 0.29.1
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.
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
} from "../../src/constants.ts";
|
|
6
6
|
import type { Artifact } from "../../src/domain/artifact.ts";
|
|
7
7
|
import { ruleInjectionPreview } from "./rules.ts";
|
|
8
|
+
import { playbookInjectionPreview } from "./playbook-bridge.ts";
|
|
8
9
|
|
|
9
10
|
export interface ContextPayloadSize {
|
|
10
11
|
characters: number;
|
|
@@ -18,6 +19,7 @@ export interface PapyrusContextInjectionObservation {
|
|
|
18
19
|
producerId: string;
|
|
19
20
|
before: ContextPayloadSize;
|
|
20
21
|
rules: ContextPayloadSize & { count: number };
|
|
22
|
+
playbooks: ContextPayloadSize & { count: number };
|
|
21
23
|
tasks: ContextPayloadSize;
|
|
22
24
|
injected: ContextPayloadSize;
|
|
23
25
|
after: ContextPayloadSize;
|
|
@@ -30,6 +32,7 @@ export interface PapyrusContextInjectionObservation {
|
|
|
30
32
|
export interface BuildContextInjectionInput {
|
|
31
33
|
basePrompt: string;
|
|
32
34
|
rules: Array<Pick<Artifact, "title" | "body" | "extra">>;
|
|
35
|
+
playbooks: Array<Pick<Artifact, "title" | "extra">>;
|
|
33
36
|
taskSummary: string | null;
|
|
34
37
|
observedAt: number;
|
|
35
38
|
sequence: number;
|
|
@@ -46,13 +49,16 @@ function size(value: string): ContextPayloadSize {
|
|
|
46
49
|
export function buildContextInjection(input: BuildContextInjectionInput): {
|
|
47
50
|
prompt: string;
|
|
48
51
|
ruleBlock: string;
|
|
52
|
+
playbookBlock: string;
|
|
49
53
|
taskBlock: string;
|
|
50
54
|
observation: PapyrusContextInjectionObservation;
|
|
51
55
|
} {
|
|
52
56
|
const ruleContent = input.rules.map(ruleInjectionPreview).join("\n");
|
|
53
57
|
const ruleBlock = ruleContent ? `\n\n## Active rules (Papyrus)\n\n${ruleContent}\n` : "";
|
|
58
|
+
const playbookContent = input.playbooks.map(playbookInjectionPreview).join("\n");
|
|
59
|
+
const playbookBlock = playbookContent ? `\n\n## Available playbooks (Papyrus)\n\n${playbookContent}\n` : "";
|
|
54
60
|
const taskBlock = input.taskSummary ? `\n\n## Open tasks (Papyrus)\n\n${input.taskSummary}\n` : "";
|
|
55
|
-
const injected = `${ruleBlock}${taskBlock}`;
|
|
61
|
+
const injected = `${ruleBlock}${playbookBlock}${taskBlock}`;
|
|
56
62
|
const prompt = `${input.basePrompt}${injected}`;
|
|
57
63
|
const fingerprint = createHash("sha256").update(injected).digest("hex");
|
|
58
64
|
const injectedSize = size(injected);
|
|
@@ -60,6 +66,7 @@ export function buildContextInjection(input: BuildContextInjectionInput): {
|
|
|
60
66
|
return {
|
|
61
67
|
prompt,
|
|
62
68
|
ruleBlock,
|
|
69
|
+
playbookBlock,
|
|
63
70
|
taskBlock,
|
|
64
71
|
observation: {
|
|
65
72
|
schema: PAPYRUS_CONTEXT_INJECTION_SCHEMA,
|
|
@@ -68,6 +75,7 @@ export function buildContextInjection(input: BuildContextInjectionInput): {
|
|
|
68
75
|
producerId: input.producerId,
|
|
69
76
|
before: size(input.basePrompt),
|
|
70
77
|
rules: { ...size(ruleBlock), count: input.rules.length },
|
|
78
|
+
playbooks: { ...size(playbookBlock), count: input.playbooks.length },
|
|
71
79
|
tasks: size(taskBlock),
|
|
72
80
|
injected: injectedSize,
|
|
73
81
|
after: afterSize,
|
package/extension/src/index.ts
CHANGED
|
@@ -23,7 +23,7 @@ import { formatMetadata } from "./artifact-format.ts";
|
|
|
23
23
|
import { callService } from "./service-client.ts";
|
|
24
24
|
import { registerDomainTools } from "./domain-tools.ts";
|
|
25
25
|
import { isLiveAskPending } from "./discuss-ask-view.ts";
|
|
26
|
-
import { registerPlaybookBridge } from "./playbook-bridge.ts";
|
|
26
|
+
import { PLAYBOOK_BRIDGE_MAX_PLAYBOOKS, registerPlaybookBridge } from "./playbook-bridge.ts";
|
|
27
27
|
import type { TaskGraph, TaskStatus } from "../../src/task-service.ts";
|
|
28
28
|
import { ActiveTaskContinuation, automaticPauseReason, shouldResumeFocusOnHumanInput, type ActiveTaskMarker } from "./active-task-continuation.ts";
|
|
29
29
|
import { buildTaskWidgetProjection, type TaskWidgetProjection } from "./task-widget.ts";
|
|
@@ -626,13 +626,15 @@ export default async function (pi: ExtensionAPI) {
|
|
|
626
626
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
627
627
|
try {
|
|
628
628
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
629
|
-
const [rules, summary] = await Promise.all([
|
|
629
|
+
const [rules, playbooks, summary] = await Promise.all([
|
|
630
630
|
callService<Record<string, unknown>, Array<Pick<Artifact, "title" | "body" | "extra">>>("rules.injectable", { project_root: ctx.cwd, session_id: sessionId }),
|
|
631
|
+
callService<Record<string, unknown>, Array<Pick<Artifact, "title" | "extra">>>("playbooks.list", { status: "active", limit: PLAYBOOK_BRIDGE_MAX_PLAYBOOKS }),
|
|
631
632
|
callService<Record<string, unknown>, string | null>("tasks.context", { project_root: ctx.cwd, session_id: sessionId }),
|
|
632
633
|
]);
|
|
633
634
|
const injection = buildContextInjection({
|
|
634
635
|
basePrompt: event.systemPrompt ?? "",
|
|
635
636
|
rules,
|
|
637
|
+
playbooks,
|
|
636
638
|
taskSummary: summary,
|
|
637
639
|
observedAt: Date.now(),
|
|
638
640
|
sequence: ++contextInjectionSequence,
|
|
@@ -21,7 +21,7 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
|
21
21
|
import type { Artifact } from "../../src/domain/artifact.ts";
|
|
22
22
|
import { callService } from "./service-client.ts";
|
|
23
23
|
|
|
24
|
-
const PLAYBOOK_BRIDGE_MAX_PLAYBOOKS = 100;
|
|
24
|
+
export const PLAYBOOK_BRIDGE_MAX_PLAYBOOKS = 100;
|
|
25
25
|
|
|
26
26
|
function slugify(title: string): string {
|
|
27
27
|
const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
@@ -37,6 +37,17 @@ export function playbookCommandName(title: string): string {
|
|
|
37
37
|
return `playbook:${slugify(title)}`;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* One line per active Playbook for context injection -- the passive, every-turn surfacing that
|
|
42
|
+
* gives the model the same "this exists and might match my task" awareness Pi's own Skill catalog
|
|
43
|
+
* gives real Skills, without a file-based bridge. See buildContextInjection (rules and open tasks
|
|
44
|
+
* already work this way).
|
|
45
|
+
*/
|
|
46
|
+
export function playbookInjectionPreview(playbook: Pick<Artifact, "title" | "extra">): string {
|
|
47
|
+
const trigger = typeof playbook.extra["trigger"] === "string" ? playbook.extra["trigger"] : "manual invocation";
|
|
48
|
+
return `• ${playbook.title} (when: ${trigger})`;
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
/** Exported for direct testing without a real ExtensionAPI: what would be registered right now. */
|
|
41
52
|
export async function planPlaybookCommandRegistrations(): Promise<Array<{ name: string; id: string; title: string; trigger: string }>> {
|
|
42
53
|
const playbooks = await activePlaybooks();
|
package/package.json
CHANGED