@d3ara1n/pi-scout 0.1.0 → 0.1.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/package.json +1 -1
- package/src/index.ts +4 -4
- package/src/scout-prompt.ts +22 -11
- package/src/side-agent.ts +3 -5
- package/src/types.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@d3ara1n/pi-scout",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Per-turn side agent decision framework for pi — uses a cheap model to select skills and route models before each conversation turn",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"keywords": [
|
package/src/index.ts
CHANGED
|
@@ -198,21 +198,21 @@ export default function scoutExtension(pi: ExtensionAPI) {
|
|
|
198
198
|
? (rolesApi.findRoleByModel(`${currentModel.provider}/${currentModel.id}`) ?? "unknown")
|
|
199
199
|
: "unknown";
|
|
200
200
|
|
|
201
|
-
// 3.
|
|
202
|
-
const scoutSystemPrompt = buildScoutSystemPrompt(config);
|
|
201
|
+
// 3. Build roles list
|
|
203
202
|
const visibleRoles = rolesApi.getVisibleRoles();
|
|
204
203
|
const rolesList = Object.entries(visibleRoles)
|
|
205
204
|
.map(([name, cfg]: [string, any]) => `- ${name}: ${cfg.description ?? "(no description)"}${cfg.model ? ` (model: ${cfg.model})` : " (current model)"}`)
|
|
206
205
|
.join("\n");
|
|
206
|
+
|
|
207
|
+
// 4. Call side agent
|
|
208
|
+
const scoutSystemPrompt = buildScoutSystemPrompt(config, skillsList, rolesList);
|
|
207
209
|
const decision = await callSideAgent(
|
|
208
210
|
sideResolved.model,
|
|
209
211
|
sideResolved.apiKey,
|
|
210
212
|
sideResolved.headers,
|
|
211
213
|
scoutSystemPrompt,
|
|
212
214
|
event.prompt,
|
|
213
|
-
skillsList,
|
|
214
215
|
currentRole,
|
|
215
|
-
rolesList,
|
|
216
216
|
);
|
|
217
217
|
|
|
218
218
|
lastDecision = decision;
|
package/src/scout-prompt.ts
CHANGED
|
@@ -6,31 +6,34 @@ import type { ScoutConfig } from "./types.ts";
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Build the user message for the side agent.
|
|
9
|
+
* Only contains per-turn variable content — stable data lives in the system prompt
|
|
10
|
+
* so it can be prompt-cached across turns.
|
|
9
11
|
*/
|
|
10
12
|
export function buildScoutUserMessage(
|
|
11
13
|
userPrompt: string,
|
|
12
|
-
skillsList: string,
|
|
13
14
|
currentRole: string,
|
|
14
|
-
rolesList: string,
|
|
15
15
|
): string {
|
|
16
16
|
return [
|
|
17
|
-
`User prompt:`,
|
|
18
|
-
userPrompt,
|
|
19
|
-
``,
|
|
20
|
-
`Available skills:`,
|
|
21
|
-
skillsList || "(none)",
|
|
22
|
-
``,
|
|
23
17
|
`Current role: ${currentRole}`,
|
|
24
18
|
``,
|
|
25
|
-
`
|
|
26
|
-
|
|
19
|
+
`User prompt:`,
|
|
20
|
+
userPrompt,
|
|
27
21
|
].join("\n");
|
|
28
22
|
}
|
|
29
23
|
|
|
30
24
|
/**
|
|
31
25
|
* Build the system prompt for the side agent.
|
|
26
|
+
*
|
|
27
|
+
* Stable per-session data (skills, roles) is embedded here rather than in the
|
|
28
|
+
* user message so that the entire system prompt forms a large, cacheable prefix.
|
|
29
|
+
* This is critical for Anthropic which requires a 1024-token minimum for
|
|
30
|
+
* prompt caching to activate.
|
|
32
31
|
*/
|
|
33
|
-
export function buildScoutSystemPrompt(
|
|
32
|
+
export function buildScoutSystemPrompt(
|
|
33
|
+
config: ScoutConfig,
|
|
34
|
+
skillsList: string,
|
|
35
|
+
rolesList: string,
|
|
36
|
+
): string {
|
|
34
37
|
const parts: string[] = [];
|
|
35
38
|
|
|
36
39
|
parts.push(`You are a scout. Analyze the user's request and decide which skills and model role to use.`);
|
|
@@ -59,5 +62,13 @@ export function buildScoutSystemPrompt(config: ScoutConfig): string {
|
|
|
59
62
|
parts.push(`- IMPORTANT: skill routing is disabled. Always return skills: [].`);
|
|
60
63
|
}
|
|
61
64
|
|
|
65
|
+
parts.push(``);
|
|
66
|
+
parts.push(`## Available Skills`);
|
|
67
|
+
parts.push(skillsList || "(none)");
|
|
68
|
+
|
|
69
|
+
parts.push(``);
|
|
70
|
+
parts.push(`## Available Roles`);
|
|
71
|
+
parts.push(rolesList);
|
|
72
|
+
|
|
62
73
|
return parts.join("\n");
|
|
63
74
|
}
|
package/src/side-agent.ts
CHANGED
|
@@ -21,9 +21,8 @@ interface SideAgentContext {
|
|
|
21
21
|
* @param sideModel - The Model instance to use (from pi-model-roles "side" role)
|
|
22
22
|
* @param apiKey - API key for the side model
|
|
23
23
|
* @param headers - Custom headers for the side model
|
|
24
|
-
* @param systemPrompt - Scout system prompt
|
|
24
|
+
* @param systemPrompt - Scout system prompt (includes skills/roles for cache friendliness)
|
|
25
25
|
* @param userPrompt - The user's original prompt text
|
|
26
|
-
* @param skillsList - Formatted list of available skills for the prompt
|
|
27
26
|
* @param currentRole - Current active role name
|
|
28
27
|
* @returns Parsed ScoutDecision, or a safe fallback on error
|
|
29
28
|
*/
|
|
@@ -33,9 +32,7 @@ export async function callSideAgent(
|
|
|
33
32
|
headers: Record<string, string> | undefined,
|
|
34
33
|
systemPrompt: string,
|
|
35
34
|
userPrompt: string,
|
|
36
|
-
skillsList: string,
|
|
37
35
|
currentRole: string,
|
|
38
|
-
rolesList: string,
|
|
39
36
|
): Promise<ScoutDecision> {
|
|
40
37
|
const fallback: ScoutDecision = { skills: [], role: null, reasoning: "side agent error" };
|
|
41
38
|
|
|
@@ -44,13 +41,14 @@ export async function callSideAgent(
|
|
|
44
41
|
messages: [
|
|
45
42
|
{
|
|
46
43
|
role: "user",
|
|
47
|
-
content: buildScoutUserMessage(userPrompt,
|
|
44
|
+
content: buildScoutUserMessage(userPrompt, currentRole),
|
|
48
45
|
},
|
|
49
46
|
],
|
|
50
47
|
};
|
|
51
48
|
|
|
52
49
|
const options: Record<string, any> = {
|
|
53
50
|
maxTokens: 256,
|
|
51
|
+
cacheRetention: "short",
|
|
54
52
|
};
|
|
55
53
|
|
|
56
54
|
if (apiKey) options.apiKey = apiKey;
|