@arhen/pi-core-subagent 1.3.63 → 1.3.65
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/README.md +23 -8
- package/package.json +1 -1
- package/src/child.ts +61 -10
- package/src/format.ts +19 -5
- package/src/index.ts +45 -13
- package/src/manager.ts +720 -61
- package/src/notification-state.ts +30 -0
- package/src/presentation.ts +11 -11
- package/src/types.ts +10 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import type { TaskSnapshot } from "./types.ts";
|
|
3
|
+
|
|
4
|
+
export function textFingerprint(text: string): string {
|
|
5
|
+
return createHash("sha256").update(text.trim()).digest("hex");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function matchesFinalText(task: TaskSnapshot, text: string): boolean {
|
|
9
|
+
return textFingerprint(text) === (task.finalTextFingerprint ?? textFingerprint(task.finalText ?? ""));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function artifactFingerprint(task: TaskSnapshot): string | undefined {
|
|
13
|
+
if (!task.changedFiles?.length && !task.diffStat?.trim() && !task.worktreeError) return undefined;
|
|
14
|
+
return textFingerprint(
|
|
15
|
+
JSON.stringify([task.branch, [...(task.changedFiles ?? [])].sort(), task.diffStat, task.worktreeError]),
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function outcomeFingerprint(task: TaskSnapshot): string {
|
|
20
|
+
return textFingerprint(
|
|
21
|
+
JSON.stringify([
|
|
22
|
+
task.startedAt,
|
|
23
|
+
task.status,
|
|
24
|
+
task.toolCalls,
|
|
25
|
+
task.finalTextFingerprint ?? textFingerprint(task.finalText ?? ""),
|
|
26
|
+
task.error,
|
|
27
|
+
artifactFingerprint(task),
|
|
28
|
+
]),
|
|
29
|
+
);
|
|
30
|
+
}
|
package/src/presentation.ts
CHANGED
|
@@ -11,7 +11,7 @@ import type {
|
|
|
11
11
|
/**
|
|
12
12
|
* Presentation preference for the subagent toolset.
|
|
13
13
|
* - auto: native codemode presentation when the codemode tool is active, direct otherwise.
|
|
14
|
-
* - direct:
|
|
14
|
+
* - direct (default): legacy native declarations and active-tool script callability.
|
|
15
15
|
* - codemode: subagent tools are callable from codemode scripts but not declared or listed.
|
|
16
16
|
*/
|
|
17
17
|
export type SubagentMode = "auto" | "direct" | "codemode";
|
|
@@ -27,8 +27,8 @@ export const SUBAGENT_NAMESPACE: ToolNamespace = {
|
|
|
27
27
|
instructions: `Isolated subagents with their own context, session and optional git worktree. Delegate independent review, testing, research or parallel analysis.
|
|
28
28
|
|
|
29
29
|
## Modes
|
|
30
|
-
-
|
|
31
|
-
-
|
|
30
|
+
- direct (default): legacy native tool declarations and active-tool script callability; activating codemode alone does not switch profiles.
|
|
31
|
+
- auto (opt-in): codemode presentation while the \`codemode\` tool is active, direct otherwise.
|
|
32
32
|
- codemode: active tools are callable from scripts but not declared; inactive tools stay model-only and are not callable at all.
|
|
33
33
|
Switch with \`/subagents mode auto|direct|codemode\`. The preference is stored on the session branch and restored on reload, resume and tree navigation.
|
|
34
34
|
|
|
@@ -57,7 +57,7 @@ Object arguments, exactly as validated when issued by the model:
|
|
|
57
57
|
- End each task with a runnable check, e.g. 'Verify: bun test'. A subagent's claim of success is not evidence.
|
|
58
58
|
|
|
59
59
|
## Codemode
|
|
60
|
-
When codemode is
|
|
60
|
+
When the codemode profile is explicitly selected (or selected by opt-in auto), these tools are not declared. Call an active operation as \`tools.<name>(args)\`; spawning uses \`await tools.subagent(args)\`. If its signature is unknown, inspect only \`text(await describeTool('subagent'))\` once and reuse it. For another operation, inspect only its exact name when needed. Broad search and tool-list dumps are unnecessary for these known names; this namespace is the optional full reference. Inactive tools remain unavailable. Arguments are validated exactly like model-issued calls.`,
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
/** Adds the script-call path to the upfront rules, but only in the codemode profile. */
|
|
@@ -96,7 +96,7 @@ export interface Presentation {
|
|
|
96
96
|
*/
|
|
97
97
|
export function createPresentation(pi: ExtensionAPI, definitions: readonly AnyToolDefinition[]): Presentation {
|
|
98
98
|
const ownNames = (): string[] => definitions.map((definition) => definition.name);
|
|
99
|
-
let preference: SubagentMode = "
|
|
99
|
+
let preference: SubagentMode = "direct";
|
|
100
100
|
let applied: EffectiveMode | undefined;
|
|
101
101
|
let appliedOwn = new Set<string>();
|
|
102
102
|
|
|
@@ -116,8 +116,8 @@ export function createPresentation(pi: ExtensionAPI, definitions: readonly AnyTo
|
|
|
116
116
|
return hidden.length > 0 ? { hiddenDeclarations: hidden } : undefined;
|
|
117
117
|
};
|
|
118
118
|
|
|
119
|
-
//
|
|
120
|
-
//
|
|
119
|
+
// Opted-in codemode defers only active own tools; inactive tools stay model-only. Legacy direct
|
|
120
|
+
// callability follows native activation. Re-registering
|
|
121
121
|
// must not reactivate a tool the user deactivated, so `defaultActive: false` replaces the native
|
|
122
122
|
// default once the initial registration has made the tools available by default.
|
|
123
123
|
const register = (mode: EffectiveMode, ownActive: ReadonlySet<string>, initial = false): void => {
|
|
@@ -125,18 +125,18 @@ export function createPresentation(pi: ExtensionAPI, definitions: readonly AnyTo
|
|
|
125
125
|
applied = mode;
|
|
126
126
|
for (const definition of definitions) {
|
|
127
127
|
const scriptCallable = mode === "codemode" && ownActive.has(definition.name);
|
|
128
|
-
const exposure: ToolExposure = scriptCallable ? "deferred" : "model-only";
|
|
128
|
+
const exposure: ToolExposure = scriptCallable ? "deferred" : mode === "direct" ? "direct" : "model-only";
|
|
129
129
|
const promptGuidelines = [...(definition.promptGuidelines ?? [])];
|
|
130
130
|
if (scriptCallable && !promptGuidelines.includes(CODEMODE_DISCOVERY_GUIDELINE))
|
|
131
131
|
promptGuidelines.push(CODEMODE_DISCOVERY_GUIDELINE);
|
|
132
|
-
//
|
|
132
|
+
// Legacy direct tools stay ungrouped; the namespace reference only belongs to the opted-in profile.
|
|
133
133
|
const description =
|
|
134
134
|
mode === "direct" ? definition.description.replace(NAMESPACE_REFERENCE, "") : definition.description;
|
|
135
135
|
pi.registerTool({
|
|
136
136
|
...definition,
|
|
137
137
|
description,
|
|
138
138
|
exposure,
|
|
139
|
-
namespace: SUBAGENT_NAMESPACE,
|
|
139
|
+
namespace: mode === "codemode" ? SUBAGENT_NAMESPACE : undefined,
|
|
140
140
|
promptGuidelines,
|
|
141
141
|
prepareLoadout: hideDeclarations,
|
|
142
142
|
...(initial ? {} : { defaultActive: false }),
|
|
@@ -187,7 +187,7 @@ export function createPresentation(pi: ExtensionAPI, definitions: readonly AnyTo
|
|
|
187
187
|
restored = candidate.data.mode;
|
|
188
188
|
}
|
|
189
189
|
// Branch-sensitive state: a branch without an entry uses the package default again.
|
|
190
|
-
preference = restored ?? "
|
|
190
|
+
preference = restored ?? "direct";
|
|
191
191
|
},
|
|
192
192
|
sync() {
|
|
193
193
|
const own = new Set(ownNames());
|
package/src/types.ts
CHANGED
|
@@ -30,7 +30,16 @@ export interface TaskSnapshot {
|
|
|
30
30
|
toolCalls: number;
|
|
31
31
|
lastActivity?: string;
|
|
32
32
|
finalText?: string;
|
|
33
|
+
finalTextFingerprint?: string;
|
|
33
34
|
notifiedParent?: boolean;
|
|
35
|
+
finalParentReport?: {
|
|
36
|
+
body: string;
|
|
37
|
+
message: string;
|
|
38
|
+
toolCalls: number;
|
|
39
|
+
fingerprint?: string;
|
|
40
|
+
artifacts?: string;
|
|
41
|
+
delivery: "pending" | "message" | "parked" | "lost" | "awaited";
|
|
42
|
+
};
|
|
34
43
|
error?: string;
|
|
35
44
|
model?: string;
|
|
36
45
|
provider?: string;
|
|
@@ -62,6 +71,7 @@ export interface RunSnapshot {
|
|
|
62
71
|
tasks: TaskSnapshot[];
|
|
63
72
|
aggregateUsage: UsageStats;
|
|
64
73
|
awaited?: boolean;
|
|
74
|
+
completionAwaited?: boolean;
|
|
65
75
|
}
|
|
66
76
|
|
|
67
77
|
export interface RunDetails {
|