@gotgenes/pi-subagents 6.17.1 → 6.18.0
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 +32 -0
- package/docs/architecture/architecture.md +8 -9
- package/docs/plans/0164-reorganize-into-domain-directories.md +409 -0
- package/docs/retro/0164-reorganize-into-domain-directories.md +82 -0
- package/package.json +7 -2
- package/src/{agent-types.ts → config/agent-types.ts} +2 -2
- package/src/{custom-agents.ts → config/custom-agents.ts} +5 -4
- package/src/{default-agents.ts → config/default-agents.ts} +1 -1
- package/src/{invocation-config.ts → config/invocation-config.ts} +1 -1
- package/src/handlers/index.ts +2 -2
- package/src/handlers/lifecycle.ts +2 -1
- package/src/index.ts +27 -26
- package/src/{agent-manager.ts → lifecycle/agent-manager.ts} +17 -14
- package/src/{agent-record.ts → lifecycle/agent-record.ts} +6 -6
- package/src/{agent-runner.ts → lifecycle/agent-runner.ts} +9 -9
- package/src/{parent-snapshot.ts → lifecycle/parent-snapshot.ts} +2 -1
- package/src/{worktree-state.ts → lifecycle/worktree-state.ts} +1 -1
- package/src/{worktree.ts → lifecycle/worktree.ts} +1 -1
- package/src/{notification.ts → observation/notification.ts} +4 -4
- package/src/{record-observer.ts → observation/record-observer.ts} +3 -2
- package/src/{renderer.ts → observation/renderer.ts} +2 -2
- package/src/runtime.ts +2 -2
- package/src/{service-adapter.ts → service/service-adapter.ts} +7 -7
- package/src/{service.ts → service/service.ts} +2 -1
- package/src/{context.ts → session/context.ts} +2 -0
- package/src/{env.ts → session/env.ts} +2 -2
- package/src/{memory.ts → session/memory.ts} +2 -2
- package/src/{model-resolver.ts → session/model-resolver.ts} +2 -1
- package/src/{prompts.ts → session/prompts.ts} +4 -4
- package/src/{session-config.ts → session/session-config.ts} +5 -5
- package/src/{skill-loader.ts → session/skill-loader.ts} +3 -3
- package/src/tools/agent-tool.ts +14 -14
- package/src/tools/background-spawner.ts +8 -8
- package/src/tools/foreground-runner.ts +16 -15
- package/src/tools/get-result-tool.ts +6 -6
- package/src/tools/helpers.ts +4 -4
- package/src/tools/spawn-config.ts +7 -6
- package/src/tools/steer-tool.ts +3 -3
- package/src/types.ts +1 -1
- package/src/ui/agent-activity-tracker.ts +1 -1
- package/src/ui/agent-config-editor.ts +6 -5
- package/src/ui/agent-creation-wizard.ts +5 -5
- package/src/ui/agent-menu.ts +10 -9
- package/src/ui/agent-widget.ts +7 -8
- package/src/ui/conversation-viewer.ts +7 -7
- package/src/ui/display.ts +2 -2
- package/src/ui/ui-observer.ts +2 -1
- package/src/ui/widget-renderer.ts +5 -5
- /package/src/{execution-state.ts → lifecycle/execution-state.ts} +0 -0
- /package/src/{usage.ts → lifecycle/usage.ts} +0 -0
- /package/src/{notification-state.ts → observation/notification-state.ts} +0 -0
- /package/src/{session-dir.ts → session/session-dir.ts} +0 -0
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
6
6
|
import { basename, join } from "node:path";
|
|
7
7
|
import { getAgentDir, parseFrontmatter } from "@earendil-works/pi-coding-agent";
|
|
8
|
-
import { BUILTIN_TOOL_NAMES } from "
|
|
9
|
-
import { debugLog } from "
|
|
10
|
-
import type { AgentConfig, MemoryScope, ThinkingLevel } from "
|
|
8
|
+
import { BUILTIN_TOOL_NAMES } from "#src/config/agent-types";
|
|
9
|
+
import { debugLog } from "#src/debug";
|
|
10
|
+
import type { AgentConfig, MemoryScope, ThinkingLevel } from "#src/types";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Scan for custom agent .md files from multiple locations.
|
|
@@ -51,7 +51,7 @@ function loadFromDir(dir: string, agents: Map<string, AgentConfig>, source: "pro
|
|
|
51
51
|
continue;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
const { frontmatter: fm, body } = parseFrontmatter
|
|
54
|
+
const { frontmatter: fm, body } = parseFrontmatter(content);
|
|
55
55
|
|
|
56
56
|
agents.set(name, {
|
|
57
57
|
name,
|
|
@@ -95,6 +95,7 @@ function nonNegativeInt(val: unknown): number | undefined {
|
|
|
95
95
|
*/
|
|
96
96
|
function parseCsvField(val: unknown): string[] | undefined {
|
|
97
97
|
if (val === undefined || val === null) return undefined;
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string -- val is already narrowed past null/undefined; String() is the intended coercion here
|
|
98
99
|
const s = String(val).trim();
|
|
99
100
|
if (!s || s === "none") return undefined;
|
|
100
101
|
const items = s.split(",").map(t => t.trim()).filter(Boolean);
|
package/src/handlers/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { SessionLifecycleHandler } from "
|
|
2
|
-
export { ToolStartHandler } from "
|
|
1
|
+
export { SessionLifecycleHandler } from "#src/handlers/lifecycle";
|
|
2
|
+
export { ToolStartHandler } from "#src/handlers/tool-start";
|
|
@@ -52,11 +52,12 @@ export class SessionLifecycleHandler {
|
|
|
52
52
|
// 3. Abort all agents — stop running work
|
|
53
53
|
// 4. Dispose notifications — cancel pending nudges/timers
|
|
54
54
|
// 5. Dispose manager — final cleanup
|
|
55
|
-
|
|
55
|
+
handleSessionShutdown(): Promise<void> {
|
|
56
56
|
this.unpublishService();
|
|
57
57
|
this.runtime.clearSessionContext();
|
|
58
58
|
this.manager.abortAll();
|
|
59
59
|
this.disposeNotifications();
|
|
60
60
|
this.manager.dispose();
|
|
61
|
+
return Promise.resolve();
|
|
61
62
|
}
|
|
62
63
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-argument -- Pi SDK types are not fully exported; see upstream Pi SDK for type improvements */
|
|
1
2
|
/**
|
|
2
3
|
* pi-agents — A pi extension providing Claude Code-style autonomous sub-agents.
|
|
3
4
|
*
|
|
@@ -20,35 +21,35 @@ import {
|
|
|
20
21
|
SettingsManager as SdkSettingsManager,
|
|
21
22
|
SessionManager,
|
|
22
23
|
} from "@earendil-works/pi-coding-agent";
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import { type
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import { preloadSkills } from "
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
45
|
-
import {
|
|
46
|
-
import {
|
|
24
|
+
import { AgentTypeRegistry } from "#src/config/agent-types";
|
|
25
|
+
import { loadCustomAgents } from "#src/config/custom-agents";
|
|
26
|
+
import { SessionLifecycleHandler, ToolStartHandler } from "#src/handlers/index";
|
|
27
|
+
import { AgentManager, type AgentManagerObserver } from "#src/lifecycle/agent-manager";
|
|
28
|
+
import { createAgentRunner, getAgentConversation, type RunnerIO, steerAgent } from "#src/lifecycle/agent-runner";
|
|
29
|
+
import { buildParentSnapshot } from "#src/lifecycle/parent-snapshot";
|
|
30
|
+
import { GitWorktreeManager } from "#src/lifecycle/worktree";
|
|
31
|
+
import { buildEventData, type NotificationDetails, NotificationManager } from "#src/observation/notification";
|
|
32
|
+
import { createNotificationRenderer } from "#src/observation/renderer";
|
|
33
|
+
import { createSubagentRuntime } from "#src/runtime";
|
|
34
|
+
import { publishSubagentsService, unpublishSubagentsService } from "#src/service/service";
|
|
35
|
+
import { createSubagentsService } from "#src/service/service-adapter";
|
|
36
|
+
import { detectEnv } from "#src/session/env";
|
|
37
|
+
import { buildMemoryBlock, buildReadOnlyMemoryBlock } from "#src/session/memory";
|
|
38
|
+
import { type ModelRegistry, resolveModel } from "#src/session/model-resolver";
|
|
39
|
+
import { buildAgentPrompt } from "#src/session/prompts";
|
|
40
|
+
import { deriveSubagentSessionDir } from "#src/session/session-dir";
|
|
41
|
+
import { preloadSkills } from "#src/session/skill-loader";
|
|
42
|
+
import { SettingsManager } from "#src/settings";
|
|
43
|
+
import { createAgentTool } from "#src/tools/agent-tool";
|
|
44
|
+
import { createGetResultTool } from "#src/tools/get-result-tool";
|
|
45
|
+
import { getModelLabelFromConfig } from "#src/tools/helpers";
|
|
46
|
+
import { createSteerTool } from "#src/tools/steer-tool";
|
|
47
|
+
import { FsAgentFileOps } from "#src/ui/agent-file-ops";
|
|
48
|
+
import { createAgentsMenuHandler } from "#src/ui/agent-menu";
|
|
47
49
|
import {
|
|
48
50
|
AgentWidget,
|
|
49
51
|
type UICtx,
|
|
50
|
-
} from "
|
|
51
|
-
import { GitWorktreeManager } from "./worktree";
|
|
52
|
+
} from "#src/ui/agent-widget";
|
|
52
53
|
|
|
53
54
|
export default function (pi: ExtensionAPI) {
|
|
54
55
|
// ---- Register custom notification renderer ----
|
|
@@ -9,17 +9,17 @@
|
|
|
9
9
|
import { randomUUID } from "node:crypto";
|
|
10
10
|
import type { Model } from "@earendil-works/pi-ai";
|
|
11
11
|
import type { AgentSession } from "@earendil-works/pi-coding-agent";
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import type {
|
|
18
|
-
import {
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
import type {
|
|
22
|
-
import {
|
|
12
|
+
import { AgentTypeRegistry } from "#src/config/agent-types";
|
|
13
|
+
import { debugLog } from "#src/debug";
|
|
14
|
+
import { AgentRecord } from "#src/lifecycle/agent-record";
|
|
15
|
+
import type { AgentRunner } from "#src/lifecycle/agent-runner";
|
|
16
|
+
import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
|
|
17
|
+
import type { WorktreeManager } from "#src/lifecycle/worktree";
|
|
18
|
+
import { WorktreeState } from "#src/lifecycle/worktree-state";
|
|
19
|
+
import { NotificationState } from "#src/observation/notification-state";
|
|
20
|
+
import { subscribeRecordObserver } from "#src/observation/record-observer";
|
|
21
|
+
import type { RunConfig } from "#src/runtime";
|
|
22
|
+
import type { AgentInvocation, IsolationMode, ShellExec, SubagentType, ThinkingLevel } from "#src/types";
|
|
23
23
|
|
|
24
24
|
export type CompactionInfo = { reason: "manual" | "threshold" | "overflow"; tokensBefore: number };
|
|
25
25
|
|
|
@@ -235,6 +235,7 @@ export class AgentManager {
|
|
|
235
235
|
onSessionCreated: (session) => {
|
|
236
236
|
// Capture the session file path early so it's available for display
|
|
237
237
|
// before the run completes (e.g. in background agent status messages).
|
|
238
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- sessionManager is typed as always present but Pi SDK may not provide it
|
|
238
239
|
const outputFile = session.sessionManager?.getSessionFile?.() ?? undefined;
|
|
239
240
|
// Set the execution-state collaborator — born complete at session creation.
|
|
240
241
|
record.execution = { session, outputFile };
|
|
@@ -282,7 +283,7 @@ export class AgentManager {
|
|
|
282
283
|
}
|
|
283
284
|
return responseText;
|
|
284
285
|
})
|
|
285
|
-
.catch((err) => {
|
|
286
|
+
.catch((err: unknown) => {
|
|
286
287
|
record.markError(err);
|
|
287
288
|
|
|
288
289
|
unsubRecordObserver?.();
|
|
@@ -313,7 +314,7 @@ export class AgentManager {
|
|
|
313
314
|
while (this.queue.length > 0 && this.runningBackground < this._getMaxConcurrent()) {
|
|
314
315
|
const next = this.queue.shift()!;
|
|
315
316
|
const record = this.agents.get(next.id);
|
|
316
|
-
if (
|
|
317
|
+
if (record?.status !== "queued") continue;
|
|
317
318
|
try {
|
|
318
319
|
this.startAgent(next.id, record, next.args);
|
|
319
320
|
} catch (err) {
|
|
@@ -402,6 +403,7 @@ export class AgentManager {
|
|
|
402
403
|
|
|
403
404
|
/** Dispose a record's session and remove it from the map. */
|
|
404
405
|
private removeRecord(id: string, record: AgentRecord): void {
|
|
406
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- dispose may not exist on all session implementations
|
|
405
407
|
record.session?.dispose?.();
|
|
406
408
|
this.agents.delete(id);
|
|
407
409
|
this.pendingSteers.delete(id);
|
|
@@ -464,12 +466,13 @@ export class AgentManager {
|
|
|
464
466
|
async waitForAll(): Promise<void> {
|
|
465
467
|
// Loop because drainQueue respects the concurrency limit — as running
|
|
466
468
|
// agents finish they start queued ones, which need awaiting too.
|
|
469
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- intentional infinite loop with explicit break
|
|
467
470
|
while (true) {
|
|
468
471
|
this.drainQueue();
|
|
469
472
|
const pending = [...this.agents.values()]
|
|
470
473
|
.filter(r => r.status === "running" || r.status === "queued")
|
|
471
474
|
.map(r => r.promise)
|
|
472
|
-
.filter(
|
|
475
|
+
.filter((p): p is Promise<string> => p != null);
|
|
473
476
|
if (pending.length === 0) break;
|
|
474
477
|
await Promise.allSettled(pending);
|
|
475
478
|
}
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import type { AgentSession } from "@earendil-works/pi-coding-agent";
|
|
16
|
-
import type { ExecutionState } from "
|
|
17
|
-
import type {
|
|
18
|
-
import
|
|
19
|
-
import type {
|
|
20
|
-
import {
|
|
21
|
-
import type {
|
|
16
|
+
import type { ExecutionState } from "#src/lifecycle/execution-state";
|
|
17
|
+
import type { LifetimeUsage } from "#src/lifecycle/usage";
|
|
18
|
+
import { addUsage } from "#src/lifecycle/usage";
|
|
19
|
+
import type { WorktreeState } from "#src/lifecycle/worktree-state";
|
|
20
|
+
import type { NotificationState } from "#src/observation/notification-state";
|
|
21
|
+
import type { AgentInvocation, SubagentType } from "#src/types";
|
|
22
22
|
|
|
23
23
|
export type AgentRecordStatus =
|
|
24
24
|
| "queued"
|
|
@@ -8,12 +8,12 @@ import {
|
|
|
8
8
|
type AgentSessionEvent,
|
|
9
9
|
type SettingsManager,
|
|
10
10
|
} from "@earendil-works/pi-coding-agent";
|
|
11
|
-
import type { AgentConfigLookup } from "
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
14
|
-
import type {
|
|
15
|
-
import { type AssemblerIO, assembleSessionConfig } from "
|
|
16
|
-
import type { ShellExec, SubagentType, ThinkingLevel } from "
|
|
11
|
+
import type { AgentConfigLookup } from "#src/config/agent-types";
|
|
12
|
+
import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
|
|
13
|
+
import { extractText } from "#src/session/context";
|
|
14
|
+
import type { EnvInfo } from "#src/session/env";
|
|
15
|
+
import { type AssemblerIO, assembleSessionConfig } from "#src/session/session-config";
|
|
16
|
+
import type { ShellExec, SubagentType, ThinkingLevel } from "#src/types";
|
|
17
17
|
|
|
18
18
|
/** Names of tools registered by this extension that subagents must NOT inherit. */
|
|
19
19
|
const EXCLUDED_TOOL_NAMES = ["Agent", "get_subagent_result", "steer_subagent"];
|
|
@@ -246,7 +246,7 @@ function forwardAbortSignal(
|
|
|
246
246
|
signal?: AbortSignal,
|
|
247
247
|
): () => void {
|
|
248
248
|
if (!signal) return () => {};
|
|
249
|
-
const onAbort = () => session.abort();
|
|
249
|
+
const onAbort = (): void => { void session.abort(); };
|
|
250
250
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
251
251
|
return () => signal.removeEventListener("abort", onAbort);
|
|
252
252
|
}
|
|
@@ -375,12 +375,12 @@ export async function runAgent(
|
|
|
375
375
|
if (maxTurns != null) {
|
|
376
376
|
if (!softLimitReached && turnCount >= maxTurns) {
|
|
377
377
|
softLimitReached = true;
|
|
378
|
-
session.steer(
|
|
378
|
+
void session.steer(
|
|
379
379
|
"You have reached your turn limit. Wrap up immediately — provide your final answer now.",
|
|
380
380
|
);
|
|
381
381
|
} else if (softLimitReached && turnCount >= maxTurns + (options.graceTurns ?? 5)) {
|
|
382
382
|
aborted = true;
|
|
383
|
-
session.abort();
|
|
383
|
+
void session.abort();
|
|
384
384
|
}
|
|
385
385
|
}
|
|
386
386
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
6
|
-
import { buildParentContext } from "
|
|
6
|
+
import { buildParentContext } from "#src/session/context";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Plain data snapshot of the parent session state captured at spawn time.
|
|
@@ -41,6 +41,7 @@ export function buildParentSnapshot(
|
|
|
41
41
|
systemPrompt: ctx.getSystemPrompt(),
|
|
42
42
|
model: ctx.model,
|
|
43
43
|
modelRegistry: ctx.modelRegistry,
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- || intentional: converts empty string to undefined as well as null/undefined
|
|
44
45
|
parentContext: parentContext || undefined,
|
|
45
46
|
};
|
|
46
47
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* cleanupResult is recorded once at completion or error — it is not set at construction.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { WorktreeCleanupResult, WorktreeInfo } from "
|
|
9
|
+
import type { WorktreeCleanupResult, WorktreeInfo } from "#src/lifecycle/worktree";
|
|
10
10
|
|
|
11
11
|
export type { WorktreeCleanupResult, WorktreeInfo };
|
|
12
12
|
|
|
@@ -11,7 +11,7 @@ import { randomUUID } from "node:crypto";
|
|
|
11
11
|
import { existsSync } from "node:fs";
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
13
13
|
import { join } from "node:path";
|
|
14
|
-
import { debugLog } from "
|
|
14
|
+
import { debugLog } from "#src/debug";
|
|
15
15
|
|
|
16
16
|
export interface WorktreeInfo {
|
|
17
17
|
/** Absolute path to the worktree directory. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { debugLog } from "
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
4
|
-
import {
|
|
1
|
+
import { debugLog } from "#src/debug";
|
|
2
|
+
import { getLifetimeTotal, getSessionContextPercent } from "#src/lifecycle/usage";
|
|
3
|
+
import type { AgentRecord } from "#src/types";
|
|
4
|
+
import type { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
|
|
5
5
|
|
|
6
6
|
/** Details attached to custom notification messages for visual rendering. */
|
|
7
7
|
export interface NotificationDetails {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment -- Pi SDK types are not fully exported; see upstream Pi SDK for type improvements */
|
|
1
2
|
/**
|
|
2
3
|
* record-observer.ts — Subscribes to session events and updates AgentRecord stats.
|
|
3
4
|
*
|
|
@@ -5,8 +6,8 @@
|
|
|
5
6
|
* and resume() with a single direct subscription.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
|
-
import type { CompactionInfo } from "
|
|
9
|
-
import type { AgentRecord } from "
|
|
9
|
+
import type { CompactionInfo } from "#src/lifecycle/agent-manager";
|
|
10
|
+
import type { AgentRecord } from "#src/lifecycle/agent-record";
|
|
10
11
|
|
|
11
12
|
/** Narrow session interface — only the subscribe method needed by the observer. */
|
|
12
13
|
interface SubscribableSession {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Text } from "@earendil-works/pi-tui";
|
|
2
|
-
import type { NotificationDetails } from "
|
|
3
|
-
import { formatMs, formatTokens, formatTurns } from "
|
|
2
|
+
import type { NotificationDetails } from "#src/observation/notification";
|
|
3
|
+
import { formatMs, formatTokens, formatTurns } from "#src/ui/display";
|
|
4
4
|
|
|
5
5
|
/** Narrow theme interface — only the methods the renderer actually calls. */
|
|
6
6
|
interface RendererTheme {
|
package/src/runtime.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* Follows the same pattern as pi-permission-system's ExtensionRuntime.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { AgentActivityTracker } from "
|
|
10
|
-
import type { UICtx } from "
|
|
9
|
+
import type { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
|
|
10
|
+
import type { UICtx } from "#src/ui/agent-widget";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Narrow widget interface consumed by SubagentRuntime delegation methods.
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
9
|
-
import type {
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import type {
|
|
13
|
-
import type { AgentRecord } from "
|
|
9
|
+
import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
|
|
10
|
+
import { buildParentSnapshot } from "#src/lifecycle/parent-snapshot";
|
|
11
|
+
import type { SubagentRecord, SubagentsService } from "#src/service/service";
|
|
12
|
+
import type { ModelRegistry } from "#src/session/model-resolver";
|
|
13
|
+
import type { AgentRecord } from "#src/types";
|
|
14
14
|
|
|
15
15
|
/** Narrow interface for the AgentManager — avoids coupling to the concrete class. */
|
|
16
16
|
export interface AgentManagerLike {
|
|
@@ -26,7 +26,7 @@ export interface AgentManagerLike {
|
|
|
26
26
|
/** Create a SubagentsService backed by the given dependencies. */
|
|
27
27
|
export function createSubagentsService(
|
|
28
28
|
manager: AgentManagerLike,
|
|
29
|
-
resolveModel: (input: string, registry: ModelRegistry) => unknown
|
|
29
|
+
resolveModel: (input: string, registry: ModelRegistry) => unknown,
|
|
30
30
|
getCtx: () => { pi: unknown; ctx: unknown } | undefined,
|
|
31
31
|
getModelRegistry: () => ModelRegistry | undefined,
|
|
32
32
|
): SubagentsService {
|
|
@@ -85,7 +85,7 @@ export function createSubagentsService(
|
|
|
85
85
|
|
|
86
86
|
async steer(id: string, message: string): Promise<boolean> {
|
|
87
87
|
const record = manager.getRecord(id);
|
|
88
|
-
if (
|
|
88
|
+
if (record?.status !== "running") {
|
|
89
89
|
return false;
|
|
90
90
|
}
|
|
91
91
|
const session = record.session;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* svc?.spawn("Explore", "Check for stale TODOs");
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type { LifetimeUsage } from "
|
|
12
|
+
import type { LifetimeUsage } from "#src/lifecycle/usage";
|
|
13
13
|
|
|
14
14
|
export type { LifetimeUsage };
|
|
15
15
|
|
|
@@ -100,5 +100,6 @@ export function getSubagentsService(): SubagentsService | undefined {
|
|
|
100
100
|
|
|
101
101
|
/** Remove the SubagentsService from globalThis (call on shutdown/reload). */
|
|
102
102
|
export function unpublishSubagentsService(): void {
|
|
103
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- Symbol-keyed global property; Map.delete() is not applicable
|
|
103
104
|
delete (globalThis as Record<symbol, unknown>)[SERVICE_KEY];
|
|
104
105
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return -- Pi SDK types are not fully exported; see upstream Pi SDK for type improvements */
|
|
1
2
|
/**
|
|
2
3
|
* context.ts — Extract parent conversation context for subagent inheritance.
|
|
3
4
|
*/
|
|
@@ -19,6 +20,7 @@ export function extractText(content: unknown[]): string {
|
|
|
19
20
|
*/
|
|
20
21
|
export function buildParentContext(ctx: ExtensionContext): string {
|
|
21
22
|
const entries = ctx.sessionManager.getBranch();
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- getBranch() may return undefined at runtime despite its type
|
|
22
24
|
if (!entries || entries.length === 0) return "";
|
|
23
25
|
|
|
24
26
|
const parts: string[] = [];
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* env.ts — Detect environment info (git, platform) for subagent system prompts.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { debugLog } from "
|
|
6
|
-
import type { ShellExec } from "
|
|
5
|
+
import { debugLog } from "#src/debug";
|
|
6
|
+
import type { ShellExec } from "#src/types";
|
|
7
7
|
|
|
8
8
|
export interface EnvInfo {
|
|
9
9
|
isGitRepo: boolean;
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
import { existsSync, lstatSync, mkdirSync, readFileSync } from "node:fs";
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
12
|
import { join, } from "node:path";
|
|
13
|
-
import { debugLog } from "
|
|
14
|
-
import type { MemoryScope } from "
|
|
13
|
+
import { debugLog } from "#src/debug";
|
|
14
|
+
import type { MemoryScope } from "#src/types";
|
|
15
15
|
|
|
16
16
|
/** Maximum lines to read from MEMORY.md */
|
|
17
17
|
const MAX_MEMORY_LINES = 200;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-redundant-type-constituents -- Pi SDK types are not fully exported; see upstream Pi SDK for type improvements */
|
|
1
2
|
/**
|
|
2
3
|
* Model resolution: exact match ("provider/modelId") with fuzzy fallback.
|
|
3
4
|
*/
|
|
@@ -16,7 +17,7 @@ export interface ModelRegistry {
|
|
|
16
17
|
|
|
17
18
|
/** Successful model resolution — `model` is the resolved or inherited model instance. */
|
|
18
19
|
export interface ModelResolutionResult {
|
|
19
|
-
|
|
20
|
+
|
|
20
21
|
model: any;
|
|
21
22
|
error?: undefined;
|
|
22
23
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* prompts.ts — System prompt builder for agents.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { EnvInfo } from "
|
|
6
|
-
import type { AgentPromptConfig } from "
|
|
5
|
+
import type { EnvInfo } from "#src/session/env";
|
|
6
|
+
import type { AgentPromptConfig } from "#src/types";
|
|
7
7
|
|
|
8
8
|
/** Extra sections to inject into the system prompt (memory, skills, etc.). */
|
|
9
9
|
export interface PromptExtras {
|
|
@@ -57,7 +57,7 @@ Platform: ${env.platform}`;
|
|
|
57
57
|
extraSections.length > 0 ? "\n\n" + extraSections.join("\n") : "";
|
|
58
58
|
|
|
59
59
|
if (config.promptMode === "append") {
|
|
60
|
-
const identity = parentSystemPrompt
|
|
60
|
+
const identity = parentSystemPrompt ?? genericBase;
|
|
61
61
|
|
|
62
62
|
const bridge = `<sub_agent_context>
|
|
63
63
|
You are operating as a sub-agent invoked to handle a specific task.
|
|
@@ -72,7 +72,7 @@ You are operating as a sub-agent invoked to handle a specific task.
|
|
|
72
72
|
- Be concise but complete
|
|
73
73
|
</sub_agent_context>`;
|
|
74
74
|
|
|
75
|
-
const customSection = config.systemPrompt
|
|
75
|
+
const customSection = config.systemPrompt.trim()
|
|
76
76
|
? `\n\n<agent_instructions>\n${config.systemPrompt}\n</agent_instructions>`
|
|
77
77
|
: "";
|
|
78
78
|
|
|
@@ -14,16 +14,16 @@ import {
|
|
|
14
14
|
type AgentConfigLookup,
|
|
15
15
|
getMemoryToolNames,
|
|
16
16
|
getReadOnlyMemoryToolNames,
|
|
17
|
-
} from "
|
|
18
|
-
import type { EnvInfo } from "
|
|
19
|
-
import type { PromptExtras } from "
|
|
20
|
-
import type { PreloadedSkill } from "
|
|
17
|
+
} from "#src/config/agent-types";
|
|
18
|
+
import type { EnvInfo } from "#src/session/env";
|
|
19
|
+
import type { PromptExtras } from "#src/session/prompts";
|
|
20
|
+
import type { PreloadedSkill } from "#src/session/skill-loader";
|
|
21
21
|
import type {
|
|
22
22
|
AgentPromptConfig,
|
|
23
23
|
MemoryScope,
|
|
24
24
|
SubagentType,
|
|
25
25
|
ThinkingLevel,
|
|
26
|
-
} from "
|
|
26
|
+
} from "#src/types";
|
|
27
27
|
|
|
28
28
|
// ── Public interfaces ────────────────────────────────────────────────────────
|
|
29
29
|
|
|
@@ -23,8 +23,8 @@ import { existsSync, readdirSync } from "node:fs";
|
|
|
23
23
|
import { homedir } from "node:os";
|
|
24
24
|
import { join } from "node:path";
|
|
25
25
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
26
|
-
import { debugLog } from "
|
|
27
|
-
import { isSymlink, isUnsafeName, safeReadFile } from "
|
|
26
|
+
import { debugLog } from "#src/debug";
|
|
27
|
+
import { isSymlink, isUnsafeName, safeReadFile } from "#src/session/memory";
|
|
28
28
|
|
|
29
29
|
export interface PreloadedSkill {
|
|
30
30
|
name: string;
|
|
@@ -69,7 +69,7 @@ function findSkillDirectory(root: string, name: string): string | undefined {
|
|
|
69
69
|
const current = queue.shift();
|
|
70
70
|
if (current === undefined) continue;
|
|
71
71
|
|
|
72
|
-
let entries: Dirent
|
|
72
|
+
let entries: Dirent[];
|
|
73
73
|
try {
|
|
74
74
|
entries = readdirSync(current, { withFileTypes: true });
|
|
75
75
|
} catch (err) {
|
package/src/tools/agent-tool.ts
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-base-to-string, @typescript-eslint/restrict-template-expressions -- Pi SDK types are not fully exported; see upstream Pi SDK for type improvements */
|
|
1
2
|
import type { AgentToolResult } from "@earendil-works/pi-coding-agent";
|
|
2
3
|
import { Text } from "@earendil-works/pi-tui";
|
|
3
4
|
import { Type } from "@sinclair/typebox";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import type { ParentSnapshot } from "
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import { type
|
|
5
|
+
import { AgentTypeRegistry } from "#src/config/agent-types";
|
|
6
|
+
import type { AgentSpawnConfig } from "#src/lifecycle/agent-manager";
|
|
7
|
+
import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
|
|
8
|
+
import { spawnBackground } from "#src/tools/background-spawner";
|
|
9
|
+
import { runForeground } from "#src/tools/foreground-runner";
|
|
10
|
+
import { buildDetails, buildTypeListText, textResult } from "#src/tools/helpers";
|
|
11
|
+
import { type ModelInfo, resolveSpawnConfig } from "#src/tools/spawn-config";
|
|
12
|
+
import type { AgentRecord } from "#src/types";
|
|
13
|
+
import { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
|
|
14
|
+
import { type UICtx } from "#src/ui/agent-widget";
|
|
11
15
|
import {
|
|
12
16
|
type AgentDetails,
|
|
13
17
|
formatMs,
|
|
14
18
|
formatTurns,
|
|
15
19
|
getDisplayName,
|
|
16
20
|
SPINNER,
|
|
17
|
-
} from "
|
|
18
|
-
import { spawnBackground } from "./background-spawner";
|
|
19
|
-
import { runForeground } from "./foreground-runner";
|
|
20
|
-
import { buildDetails, buildTypeListText, textResult } from "./helpers";
|
|
21
|
-
import { type ModelInfo, resolveSpawnConfig } from "./spawn-config";
|
|
21
|
+
} from "#src/ui/display";
|
|
22
22
|
|
|
23
23
|
// ---- Deps interface ----
|
|
24
24
|
|
|
@@ -171,7 +171,7 @@ Guidelines:
|
|
|
171
171
|
const displayName = args.subagent_type
|
|
172
172
|
? getDisplayName(args.subagent_type as string, registry)
|
|
173
173
|
: "Agent";
|
|
174
|
-
const desc = (args.description as string) ?? "";
|
|
174
|
+
const desc = (args.description as string | undefined) ?? "";
|
|
175
175
|
return new Text(
|
|
176
176
|
"▸ " +
|
|
177
177
|
theme.fg("toolTitle", theme.bold(displayName)) +
|
|
@@ -326,7 +326,7 @@ Guidelines:
|
|
|
326
326
|
return textResult(`Failed to resume agent "${params.resume}".`);
|
|
327
327
|
}
|
|
328
328
|
return textResult(
|
|
329
|
-
record.result?.trim()
|
|
329
|
+
record.result?.trim() ?? record.error?.trim() ?? "No output.",
|
|
330
330
|
buildDetails(config.detailBase, record),
|
|
331
331
|
);
|
|
332
332
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { AgentSpawnConfig } from "
|
|
2
|
-
import type { ParentSnapshot } from "
|
|
3
|
-
import type {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import type {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
1
|
+
import type { AgentSpawnConfig } from "#src/lifecycle/agent-manager";
|
|
2
|
+
import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
|
|
3
|
+
import type { AgentActivityAccess } from "#src/tools/agent-tool";
|
|
4
|
+
import { textResult } from "#src/tools/helpers";
|
|
5
|
+
import type { ResolvedSpawnConfig } from "#src/tools/spawn-config";
|
|
6
|
+
import type { AgentRecord } from "#src/types";
|
|
7
|
+
import { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
|
|
8
|
+
import { subscribeUIObserver } from "#src/ui/ui-observer";
|
|
9
9
|
|
|
10
10
|
/** Narrow manager interface for the background spawner. */
|
|
11
11
|
export interface BackgroundManagerDeps {
|