@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.
@@ -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
+ }
@@ -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: subagent tools are declared to the model (model-only exposure).
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
- - auto (default): codemode presentation while the \`codemode\` tool is active, direct otherwise.
31
- - direct: subagent tools are declared to the model (model-only, not callable from scripts).
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 active 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.`,
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 = "auto";
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
- // Register the profile for the given effective mode. Only own tools that are really active stay
120
- // script-callable (`deferred`); inactive own tools are `model-only` and never callable. Re-registering
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
- // In the direct profile there is no script path, so the pointer would be unreachable.
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 ?? "auto";
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 {