@gotgenes/pi-permission-system 38.0.0 → 38.0.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.
- package/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/handlers/before-agent-start.ts +17 -8
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [38.0.1](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v38.0.0...pi-permission-system-v38.0.1) (2026-10-02)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **pi-permission-system:** tolerate a non-Pi before_agent_start payload ([#860](https://github.com/gotgenes/pi-packages/issues/860)) ([33f6a24](https://github.com/gotgenes/pi-packages/commit/33f6a24c820f23d43a56c9377245e804c2fd8ba2)), closes [#860](https://github.com/gotgenes/pi-packages/issues/860)
|
|
14
|
+
|
|
8
15
|
## [38.0.0](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v37.0.0...pi-permission-system-v38.0.0) (2026-10-02)
|
|
9
16
|
|
|
10
17
|
|
package/package.json
CHANGED
|
@@ -22,8 +22,8 @@ import type { TurnPreparation } from "./session-turn-prep";
|
|
|
22
22
|
|
|
23
23
|
/** Minimal subset of BeforeAgentStartEvent used by this handler. */
|
|
24
24
|
interface BeforeAgentStartPayload {
|
|
25
|
-
/**
|
|
26
|
-
readonly systemPrompt: string;
|
|
25
|
+
/** Pi renders a string; a host may supply ordered prompt fragments instead. */
|
|
26
|
+
readonly systemPrompt: string | readonly string[];
|
|
27
27
|
/**
|
|
28
28
|
* The mutable parts Pi renders the prompt from; later handlers, and Pi
|
|
29
29
|
* itself, see what this handler writes here. `customPrompt` says whether Pi
|
|
@@ -32,7 +32,7 @@ interface BeforeAgentStartPayload {
|
|
|
32
32
|
* renders from, and `sections` is where it is stated. `skills` is the
|
|
33
33
|
* catalogue Pi renders, which policy narrows.
|
|
34
34
|
*/
|
|
35
|
-
systemPromptOptions
|
|
35
|
+
systemPromptOptions?: Pick<
|
|
36
36
|
NormalizedBuildSystemPromptOptions,
|
|
37
37
|
"customPrompt" | "toolSnippets" | "promptGuidelines" | "sections" | "skills"
|
|
38
38
|
>;
|
|
@@ -56,10 +56,12 @@ export function shouldExposeTool(
|
|
|
56
56
|
/**
|
|
57
57
|
* Handles the `before_agent_start` event: tool filtering + prompt sanitization.
|
|
58
58
|
*
|
|
59
|
-
*
|
|
59
|
+
* When provided, prompt changes are stated through `event.systemPromptOptions`,
|
|
60
60
|
* never as a returned `systemPrompt`: a returned prompt is frozen for the run,
|
|
61
61
|
* so the sections an extension later in the chain adds (Pi's own
|
|
62
62
|
* `<mcp_servers>` among them) would never reach the provider (#999).
|
|
63
|
+
* Without those options, only tool filtering and skill path resolution run;
|
|
64
|
+
* there is no mutable section or skill catalogue to narrow.
|
|
63
65
|
*
|
|
64
66
|
* Narrowing the active set is enough for a prompt Pi wrote: Pi renders its
|
|
65
67
|
* `<tools>` and `<rules>` from the reconciled active set. A subagent child's
|
|
@@ -97,7 +99,12 @@ export class AgentPrepHandler {
|
|
|
97
99
|
): Promise<BeforeAgentStartEventResult> {
|
|
98
100
|
this.turnPrep.prepare(ctx);
|
|
99
101
|
|
|
100
|
-
|
|
102
|
+
// Normalize once at the boundary, before either prompt consumer reads it.
|
|
103
|
+
const systemPrompt =
|
|
104
|
+
typeof event.systemPrompt === "string"
|
|
105
|
+
? event.systemPrompt
|
|
106
|
+
: event.systemPrompt.join("\n");
|
|
107
|
+
const agentName = this.session.resolveAgentName(ctx, systemPrompt);
|
|
101
108
|
const registered = readRegisteredTools(this.toolRegistry.getAll());
|
|
102
109
|
const surface = this.session.resolveExposedTools(
|
|
103
110
|
this.observeToolSurface(registered),
|
|
@@ -118,7 +125,7 @@ export class AgentPrepHandler {
|
|
|
118
125
|
}
|
|
119
126
|
|
|
120
127
|
const options = event.systemPromptOptions;
|
|
121
|
-
if (this.isSubagentUnderCustomPrompt(event, ctx)) {
|
|
128
|
+
if (options && this.isSubagentUnderCustomPrompt(event, ctx)) {
|
|
122
129
|
const sections = renderToolSurfaceSections({
|
|
123
130
|
allowedTools,
|
|
124
131
|
toolSnippets: options.toolSnippets,
|
|
@@ -134,12 +141,14 @@ export class AgentPrepHandler {
|
|
|
134
141
|
// read before the skill list is narrowed.
|
|
135
142
|
this.session.setActiveSkillEntries(
|
|
136
143
|
visibleSkillPromptEntries(
|
|
137
|
-
|
|
144
|
+
systemPrompt,
|
|
138
145
|
this.resolver,
|
|
139
146
|
agentName,
|
|
140
147
|
this.session.getPathNormalizer(),
|
|
141
148
|
),
|
|
142
149
|
);
|
|
150
|
+
if (!options) return {};
|
|
151
|
+
|
|
143
152
|
// Denials are judged on the list Pi renders `<skills>` from, not on the
|
|
144
153
|
// rendered prompt: that prompt predates this turn's tool changes, and on
|
|
145
154
|
// the turn `read`/`bash` return from a full denial it lists no catalogue.
|
|
@@ -181,5 +190,5 @@ export class AgentPrepHandler {
|
|
|
181
190
|
* test, so an empty string reads here the way it reads there: as none.
|
|
182
191
|
*/
|
|
183
192
|
function hasCustomPrompt(event: BeforeAgentStartPayload): boolean {
|
|
184
|
-
return Boolean(event.systemPromptOptions
|
|
193
|
+
return Boolean(event.systemPromptOptions?.customPrompt);
|
|
185
194
|
}
|