pi-sage 0.2.14 → 0.2.15
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.
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { CallerContext } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export type InputSource = "interactive" | "rpc" | "extension";
|
|
4
|
+
export type InteractiveOrRpcSource = "interactive" | "rpc";
|
|
5
|
+
|
|
6
|
+
export function isKnownInputSource(value: string): value is InputSource {
|
|
7
|
+
return value === "interactive" || value === "rpc" || value === "extension";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function updateLastInteractiveOrRpcSource(
|
|
11
|
+
previous: InteractiveOrRpcSource | undefined,
|
|
12
|
+
source: string
|
|
13
|
+
): InteractiveOrRpcSource | undefined {
|
|
14
|
+
if (source === "interactive" || source === "rpc") {
|
|
15
|
+
return source;
|
|
16
|
+
}
|
|
17
|
+
return previous;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function buildCallerContextFromSignals(input: {
|
|
21
|
+
lastInteractiveOrRpcSource: InteractiveOrRpcSource | undefined;
|
|
22
|
+
unknownSourceSeen: boolean;
|
|
23
|
+
hasUI: boolean;
|
|
24
|
+
roleHint?: string;
|
|
25
|
+
isCI?: boolean;
|
|
26
|
+
isSubagent?: boolean;
|
|
27
|
+
}): CallerContext | null {
|
|
28
|
+
const { lastInteractiveOrRpcSource, unknownSourceSeen, hasUI, roleHint, isCI, isSubagent } = input;
|
|
29
|
+
if (unknownSourceSeen) return null;
|
|
30
|
+
if (!lastInteractiveOrRpcSource) return null;
|
|
31
|
+
|
|
32
|
+
const normalizedRole = roleHint?.trim().toLowerCase();
|
|
33
|
+
const isRpcSource = lastInteractiveOrRpcSource === "rpc";
|
|
34
|
+
const interactive = hasUI && lastInteractiveOrRpcSource === "interactive";
|
|
35
|
+
const isInteractiveSupervisor = interactive && normalizedRole === "supervisor";
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
session: {
|
|
39
|
+
interactive
|
|
40
|
+
},
|
|
41
|
+
agent: {
|
|
42
|
+
role: normalizedRole ?? "primary",
|
|
43
|
+
isSubagent: Boolean(isSubagent),
|
|
44
|
+
isRpcOrchestrated: isRpcSource || Boolean(normalizedRole && normalizedRole !== "primary" && !isInteractiveSupervisor)
|
|
45
|
+
},
|
|
46
|
+
runtime: {
|
|
47
|
+
mode: isCI ? "ci" : hasUI ? (isRpcSource ? "rpc" : "interactive") : "non-interactive"
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -7,6 +7,12 @@ import {
|
|
|
7
7
|
isHardCostCapExceeded,
|
|
8
8
|
makeBlockedResult
|
|
9
9
|
} from "./policy.js";
|
|
10
|
+
import {
|
|
11
|
+
buildCallerContextFromSignals,
|
|
12
|
+
isKnownInputSource,
|
|
13
|
+
updateLastInteractiveOrRpcSource,
|
|
14
|
+
type InteractiveOrRpcSource
|
|
15
|
+
} from "./caller-context.js";
|
|
10
16
|
import {
|
|
11
17
|
isSageRunnerPolicyError,
|
|
12
18
|
runSageSingleShot,
|
|
@@ -34,8 +40,6 @@ import type {
|
|
|
34
40
|
ToolProfile
|
|
35
41
|
} from "./types.js";
|
|
36
42
|
|
|
37
|
-
type InputSource = "interactive" | "rpc" | "extension";
|
|
38
|
-
|
|
39
43
|
type ModelLike = {
|
|
40
44
|
provider: string;
|
|
41
45
|
id: string;
|
|
@@ -74,12 +78,22 @@ export default function registerSageExtension(pi: ExtensionAPI): void {
|
|
|
74
78
|
sessionCostTotal: 0
|
|
75
79
|
};
|
|
76
80
|
|
|
77
|
-
let
|
|
81
|
+
let lastInteractiveOrRpcSource: InteractiveOrRpcSource | undefined;
|
|
82
|
+
let unknownInputSourceSeen = false;
|
|
78
83
|
|
|
79
84
|
pi.on("input", (event) => {
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
const source = String(event.source ?? "");
|
|
86
|
+
|
|
87
|
+
if (!isKnownInputSource(source)) {
|
|
88
|
+
unknownInputSourceSeen = true;
|
|
89
|
+
return { action: "continue" };
|
|
82
90
|
}
|
|
91
|
+
|
|
92
|
+
lastInteractiveOrRpcSource = updateLastInteractiveOrRpcSource(lastInteractiveOrRpcSource, source);
|
|
93
|
+
if (source === "interactive" || source === "rpc") {
|
|
94
|
+
unknownInputSourceSeen = false;
|
|
95
|
+
}
|
|
96
|
+
|
|
83
97
|
return { action: "continue" };
|
|
84
98
|
});
|
|
85
99
|
|
|
@@ -166,7 +180,7 @@ export default function registerSageExtension(pi: ExtensionAPI): void {
|
|
|
166
180
|
});
|
|
167
181
|
}
|
|
168
182
|
|
|
169
|
-
const callerContext = buildCallerContext(
|
|
183
|
+
const callerContext = buildCallerContext(lastInteractiveOrRpcSource, unknownInputSourceSeen, ctx.hasUI);
|
|
170
184
|
const eligibility = isEligibleCaller(callerContext);
|
|
171
185
|
if (!eligibility.ok) {
|
|
172
186
|
return makeBlockedResult({
|
|
@@ -389,28 +403,19 @@ async function runSageWithFallback(
|
|
|
389
403
|
}
|
|
390
404
|
}
|
|
391
405
|
|
|
392
|
-
function buildCallerContext(
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
agent: {
|
|
406
|
-
role: roleHint ?? "primary",
|
|
407
|
-
isSubagent,
|
|
408
|
-
isRpcOrchestrated: isRpcSource || Boolean(roleHint && roleHint !== "primary" && !isInteractiveSupervisor)
|
|
409
|
-
},
|
|
410
|
-
runtime: {
|
|
411
|
-
mode: process.env.CI ? "ci" : hasUI ? (isRpcSource ? "rpc" : "interactive") : "non-interactive"
|
|
412
|
-
}
|
|
413
|
-
};
|
|
406
|
+
function buildCallerContext(
|
|
407
|
+
lastInteractiveOrRpcSource: InteractiveOrRpcSource | undefined,
|
|
408
|
+
unknownInputSourceSeen: boolean,
|
|
409
|
+
hasUI: boolean
|
|
410
|
+
): CallerContext | null {
|
|
411
|
+
return buildCallerContextFromSignals({
|
|
412
|
+
lastInteractiveOrRpcSource,
|
|
413
|
+
unknownSourceSeen: unknownInputSourceSeen,
|
|
414
|
+
hasUI,
|
|
415
|
+
roleHint: getRoleHint(),
|
|
416
|
+
isCI: Boolean(process.env.CI),
|
|
417
|
+
isSubagent: process.env.PI_SAGE_SUBAGENT === "1"
|
|
418
|
+
});
|
|
414
419
|
}
|
|
415
420
|
|
|
416
421
|
function getRoleHint(): string | undefined {
|