@codex-infinity/pi-infinity 0.64.2 → 0.65.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/CHANGELOG.md +57 -34
- package/README.md +5 -3
- package/dist/cli/args.d.ts +7 -4
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +37 -15
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +51 -102
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +103 -138
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +86 -0
- package/dist/core/agent-session-services.d.ts.map +1 -0
- package/dist/core/agent-session-services.js +116 -0
- package/dist/core/agent-session-services.js.map +1 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/index.d.ts +2 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/types.d.ts +10 -13
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +10 -0
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/index.d.ts +3 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +4 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +3 -14
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/package-manager.d.ts +20 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +32 -0
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +21 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +2 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +202 -456
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +20 -0
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +3 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +56 -29
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts +2 -2
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +4 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +1 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +2 -2
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +23 -15
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/package-manager-cli.d.ts +4 -0
- package/dist/package-manager-cli.d.ts.map +1 -0
- package/dist/package-manager-cli.js +234 -0
- package/dist/package-manager-cli.js.map +1 -0
- package/docs/extensions.md +34 -26
- package/docs/sdk.md +109 -46
- package/docs/settings.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
- package/examples/extensions/hello.ts +18 -17
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/13-session-runtime.ts +30 -12
- package/examples/sdk/README.md +2 -0
- package/package.json +4 -4
|
@@ -1,134 +1,83 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import {
|
|
4
|
-
import type {
|
|
5
|
-
import { ModelRegistry } from "./model-registry.js";
|
|
6
|
-
import { type DefaultResourceLoaderOptions, type ResourceLoader } from "./resource-loader.js";
|
|
7
|
-
import { type CreateAgentSessionResult } from "./sdk.js";
|
|
1
|
+
import type { AgentSession } from "./agent-session.js";
|
|
2
|
+
import type { AgentSessionRuntimeDiagnostic, AgentSessionServices } from "./agent-session-services.js";
|
|
3
|
+
import type { SessionStartEvent } from "./extensions/index.js";
|
|
4
|
+
import type { CreateAgentSessionResult } from "./sdk.js";
|
|
8
5
|
import { SessionManager } from "./session-manager.js";
|
|
9
|
-
import { SettingsManager } from "./settings-manager.js";
|
|
10
|
-
import type { Tool } from "./tools/index.js";
|
|
11
6
|
/**
|
|
12
|
-
*
|
|
7
|
+
* Result returned by runtime creation.
|
|
13
8
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* or in settings, not here.
|
|
9
|
+
* The caller gets the created session, its cwd-bound services, and all
|
|
10
|
+
* diagnostics collected during setup.
|
|
17
11
|
*/
|
|
18
|
-
export interface
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/** Optional shared auth storage. If omitted, file-backed storage under agentDir is used. */
|
|
22
|
-
authStorage?: AuthStorage;
|
|
23
|
-
/** Initial model for the first created session runtime. */
|
|
24
|
-
model?: Model<any>;
|
|
25
|
-
/** Initial thinking level for the first created session runtime. */
|
|
26
|
-
thinkingLevel?: ThinkingLevel;
|
|
27
|
-
/** Optional scoped model list for model cycling and selection. */
|
|
28
|
-
scopedModels?: Array<{
|
|
29
|
-
model: Model<any>;
|
|
30
|
-
thinkingLevel?: ThinkingLevel;
|
|
31
|
-
}>;
|
|
32
|
-
/** Built-in tool set override. */
|
|
33
|
-
tools?: Tool[];
|
|
34
|
-
/** Additional custom tools registered directly through the SDK. */
|
|
35
|
-
customTools?: ToolDefinition[];
|
|
36
|
-
/**
|
|
37
|
-
* Resource loader input used for each created runtime.
|
|
38
|
-
*
|
|
39
|
-
* Pass either a factory that creates a fully custom ResourceLoader for the
|
|
40
|
-
* target cwd, or DefaultResourceLoader options without cwd/agentDir/
|
|
41
|
-
* settingsManager, which are supplied by the runtime.
|
|
42
|
-
*/
|
|
43
|
-
resourceLoader?: ((cwd: string, agentDir: string) => Promise<ResourceLoader>) | Omit<DefaultResourceLoaderOptions, "cwd" | "agentDir" | "settingsManager">;
|
|
12
|
+
export interface CreateAgentSessionRuntimeResult extends CreateAgentSessionResult {
|
|
13
|
+
services: AgentSessionServices;
|
|
14
|
+
diagnostics: AgentSessionRuntimeDiagnostic[];
|
|
44
15
|
}
|
|
45
|
-
/** Options for creating one concrete runtime instance. */
|
|
46
|
-
export interface CreateAgentSessionRuntimeOptions {
|
|
47
|
-
/** Working directory for this runtime instance. */
|
|
48
|
-
cwd: string;
|
|
49
|
-
/** Optional preselected session manager. If omitted, normal session resolution applies. */
|
|
50
|
-
sessionManager?: SessionManager;
|
|
51
|
-
/** Optional session_start metadata to emit when the runtime binds extensions. */
|
|
52
|
-
sessionStartEvent?: SessionStartEvent;
|
|
53
|
-
}
|
|
54
|
-
type AgentSessionRuntime = CreateAgentSessionResult & {
|
|
55
|
-
cwd: string;
|
|
56
|
-
agentDir: string;
|
|
57
|
-
authStorage: AuthStorage;
|
|
58
|
-
modelRegistry: ModelRegistry;
|
|
59
|
-
settingsManager: SettingsManager;
|
|
60
|
-
resourceLoader: ResourceLoader;
|
|
61
|
-
sessionManager: SessionManager;
|
|
62
|
-
};
|
|
63
16
|
/**
|
|
64
|
-
*
|
|
65
|
-
* services it depends on.
|
|
17
|
+
* Creates a full runtime for a target cwd and session manager.
|
|
66
18
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* directories.
|
|
19
|
+
* The factory closes over process-global fixed inputs, recreates cwd-bound
|
|
20
|
+
* services for the effective cwd, resolves session options against those
|
|
21
|
+
* services, and finally creates the AgentSession.
|
|
71
22
|
*/
|
|
72
|
-
export
|
|
23
|
+
export type CreateAgentSessionRuntimeFactory = (options: {
|
|
24
|
+
cwd: string;
|
|
25
|
+
agentDir: string;
|
|
26
|
+
sessionManager: SessionManager;
|
|
27
|
+
sessionStartEvent?: SessionStartEvent;
|
|
28
|
+
}) => Promise<CreateAgentSessionRuntimeResult>;
|
|
73
29
|
/**
|
|
74
|
-
*
|
|
30
|
+
* Owns the current AgentSession plus its cwd-bound services.
|
|
75
31
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
32
|
+
* Session replacement methods tear down the current runtime first, then create
|
|
33
|
+
* and apply the next runtime. If creation fails, the error is propagated to the
|
|
34
|
+
* caller. The caller is responsible for user-facing error handling.
|
|
79
35
|
*/
|
|
80
|
-
export declare class
|
|
81
|
-
private
|
|
82
|
-
private
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
36
|
+
export declare class AgentSessionRuntime {
|
|
37
|
+
private _session;
|
|
38
|
+
private _services;
|
|
39
|
+
private readonly createRuntime;
|
|
40
|
+
private _diagnostics;
|
|
41
|
+
private _modelFallbackMessage?;
|
|
42
|
+
constructor(_session: AgentSession, _services: AgentSessionServices, createRuntime: CreateAgentSessionRuntimeFactory, _diagnostics?: AgentSessionRuntimeDiagnostic[], _modelFallbackMessage?: string | undefined);
|
|
43
|
+
get services(): AgentSessionServices;
|
|
44
|
+
get session(): AgentSession;
|
|
45
|
+
get cwd(): string;
|
|
46
|
+
get diagnostics(): readonly AgentSessionRuntimeDiagnostic[];
|
|
47
|
+
get modelFallbackMessage(): string | undefined;
|
|
86
48
|
private emitBeforeSwitch;
|
|
87
49
|
private emitBeforeFork;
|
|
88
|
-
private
|
|
89
|
-
|
|
90
|
-
* Replace the active runtime with one opened from an existing session file.
|
|
91
|
-
*
|
|
92
|
-
* Emits `session_before_switch` before replacement and returns
|
|
93
|
-
* `{ cancelled: true }` if an extension vetoes the switch.
|
|
94
|
-
*/
|
|
50
|
+
private teardownCurrent;
|
|
51
|
+
private apply;
|
|
95
52
|
switchSession(sessionPath: string): Promise<{
|
|
96
53
|
cancelled: boolean;
|
|
97
54
|
}>;
|
|
98
|
-
/**
|
|
99
|
-
* Replace the active runtime with a fresh session in the current cwd.
|
|
100
|
-
*
|
|
101
|
-
* `setup` runs after replacement against the new session manager, which lets
|
|
102
|
-
* callers seed entries before normal use begins.
|
|
103
|
-
*/
|
|
104
55
|
newSession(options?: {
|
|
105
|
-
/** Optional parent session path recorded in the new session header. */
|
|
106
56
|
parentSession?: string;
|
|
107
|
-
/** Optional callback for seeding the new session manager after replacement. */
|
|
108
57
|
setup?: (sessionManager: SessionManager) => Promise<void>;
|
|
109
58
|
}): Promise<{
|
|
110
59
|
cancelled: boolean;
|
|
111
60
|
}>;
|
|
112
|
-
/**
|
|
113
|
-
* Replace the active runtime with a fork rooted at the given user-message
|
|
114
|
-
* entry.
|
|
115
|
-
*
|
|
116
|
-
* Returns the selected user text so UIs can restore it into the editor after
|
|
117
|
-
* the fork completes.
|
|
118
|
-
*/
|
|
119
61
|
fork(entryId: string): Promise<{
|
|
120
62
|
cancelled: boolean;
|
|
121
63
|
selectedText?: string;
|
|
122
64
|
}>;
|
|
123
|
-
/**
|
|
124
|
-
* Import a JSONL session file into the current session directory and replace
|
|
125
|
-
* the active runtime with the imported session.
|
|
126
|
-
*/
|
|
127
65
|
importFromJsonl(inputPath: string): Promise<{
|
|
128
66
|
cancelled: boolean;
|
|
129
67
|
}>;
|
|
130
|
-
/** Emit session shutdown for the active runtime and dispose it permanently. */
|
|
131
68
|
dispose(): Promise<void>;
|
|
132
69
|
}
|
|
133
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Create the initial runtime from a runtime factory and initial session target.
|
|
72
|
+
*
|
|
73
|
+
* The same factory is stored on the returned AgentSessionRuntime and reused for
|
|
74
|
+
* later /new, /resume, /fork, and import flows.
|
|
75
|
+
*/
|
|
76
|
+
export declare function createAgentSessionRuntime(createRuntime: CreateAgentSessionRuntimeFactory, options: {
|
|
77
|
+
cwd: string;
|
|
78
|
+
agentDir: string;
|
|
79
|
+
sessionManager: SessionManager;
|
|
80
|
+
sessionStartEvent?: SessionStartEvent;
|
|
81
|
+
}): Promise<AgentSessionRuntime>;
|
|
82
|
+
export { type AgentSessionRuntimeDiagnostic, type AgentSessionServices, type CreateAgentSessionFromServicesOptions, type CreateAgentSessionServicesOptions, createAgentSessionFromServices, createAgentSessionServices, } from "./agent-session-services.js";
|
|
134
83
|
//# sourceMappingURL=agent-session-runtime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-session-runtime.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { copyFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { basename, join, resolve } from \"node:path\";\nimport type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport type { Model } from \"@mariozechner/pi-ai\";\nimport { getAgentDir } from \"../config.js\";\nimport { AuthStorage } from \"./auth-storage.js\";\nimport type { SessionStartEvent, ToolDefinition } from \"./extensions/index.js\";\nimport { emitSessionShutdownEvent } from \"./extensions/runner.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { DefaultResourceLoader, type DefaultResourceLoaderOptions, type ResourceLoader } from \"./resource-loader.js\";\nimport { type CreateAgentSessionResult, createAgentSession } from \"./sdk.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { SettingsManager } from \"./settings-manager.js\";\nimport type { Tool } from \"./tools/index.js\";\n\n/**\n * Stable bootstrap inputs reused whenever the active runtime is replaced.\n *\n * Use this for process-level wiring that should survive `/new`, `/resume`,\n * `/fork`, and import flows. Session-local state belongs in the session file\n * or in settings, not here.\n */\nexport interface AgentSessionRuntimeBootstrap {\n\t/** Agent directory used for auth, models, settings, sessions, and resource discovery. */\n\tagentDir?: string;\n\t/** Optional shared auth storage. If omitted, file-backed storage under agentDir is used. */\n\tauthStorage?: AuthStorage;\n\t/** Initial model for the first created session runtime. */\n\tmodel?: Model<any>;\n\t/** Initial thinking level for the first created session runtime. */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Optional scoped model list for model cycling and selection. */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\t/** Built-in tool set override. */\n\ttools?: Tool[];\n\t/** Additional custom tools registered directly through the SDK. */\n\tcustomTools?: ToolDefinition[];\n\t/**\n\t * Resource loader input used for each created runtime.\n\t *\n\t * Pass either a factory that creates a fully custom ResourceLoader for the\n\t * target cwd, or DefaultResourceLoader options without cwd/agentDir/\n\t * settingsManager, which are supplied by the runtime.\n\t */\n\tresourceLoader?:\n\t\t| ((cwd: string, agentDir: string) => Promise<ResourceLoader>)\n\t\t| Omit<DefaultResourceLoaderOptions, \"cwd\" | \"agentDir\" | \"settingsManager\">;\n}\n\n/** Options for creating one concrete runtime instance. */\nexport interface CreateAgentSessionRuntimeOptions {\n\t/** Working directory for this runtime instance. */\n\tcwd: string;\n\t/** Optional preselected session manager. If omitted, normal session resolution applies. */\n\tsessionManager?: SessionManager;\n\t/** Optional session_start metadata to emit when the runtime binds extensions. */\n\tsessionStartEvent?: SessionStartEvent;\n}\n\ntype AgentSessionRuntime = CreateAgentSessionResult & {\n\tcwd: string;\n\tagentDir: string;\n\tauthStorage: AuthStorage;\n\tmodelRegistry: ModelRegistry;\n\tsettingsManager: SettingsManager;\n\tresourceLoader: ResourceLoader;\n\tsessionManager: SessionManager;\n};\n\n/**\n * Create one runtime instance containing an AgentSession plus the cwd-bound\n * services it depends on.\n *\n * Most SDK callers should keep the returned value wrapped in an\n * AgentSessionRuntimeHost instead of holding it directly. The host owns\n * replacing the runtime when switching sessions across files or working\n * directories.\n */\nexport async function createAgentSessionRuntime(\n\tbootstrap: AgentSessionRuntimeBootstrap,\n\toptions: CreateAgentSessionRuntimeOptions,\n): Promise<AgentSessionRuntime> {\n\tconst cwd = options.cwd;\n\tconst agentDir = bootstrap.agentDir ?? getAgentDir();\n\tconst authStorage = bootstrap.authStorage ?? AuthStorage.create(join(agentDir, \"auth.json\"));\n\tconst settingsManager = SettingsManager.create(cwd, agentDir);\n\tconst modelRegistry = ModelRegistry.create(authStorage, join(agentDir, \"models.json\"));\n\tconst resourceLoader =\n\t\ttypeof bootstrap.resourceLoader === \"function\"\n\t\t\t? await bootstrap.resourceLoader(cwd, agentDir)\n\t\t\t: new DefaultResourceLoader({\n\t\t\t\t\t...(bootstrap.resourceLoader ?? {}),\n\t\t\t\t\tcwd,\n\t\t\t\t\tagentDir,\n\t\t\t\t\tsettingsManager,\n\t\t\t\t});\n\tawait resourceLoader.reload();\n\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tfor (const { name, config } of extensionsResult.runtime.pendingProviderRegistrations) {\n\t\tmodelRegistry.registerProvider(name, config);\n\t}\n\textensionsResult.runtime.pendingProviderRegistrations = [];\n\n\tconst created = await createAgentSession({\n\t\tcwd,\n\t\tagentDir,\n\t\tauthStorage,\n\t\tmodelRegistry,\n\t\tsettingsManager,\n\t\tresourceLoader,\n\t\tsessionManager: options.sessionManager,\n\t\tmodel: bootstrap.model,\n\t\tthinkingLevel: bootstrap.thinkingLevel,\n\t\tscopedModels: bootstrap.scopedModels,\n\t\ttools: bootstrap.tools,\n\t\tcustomTools: bootstrap.customTools,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n\n\treturn {\n\t\t...created,\n\t\tcwd,\n\t\tagentDir,\n\t\tauthStorage,\n\t\tmodelRegistry,\n\t\tsettingsManager,\n\t\tresourceLoader,\n\t\tsessionManager: created.session.sessionManager,\n\t};\n}\n\nfunction extractUserMessageText(content: string | Array<{ type: string; text?: string }>): string {\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\n\treturn content\n\t\t.filter((part): part is { type: \"text\"; text: string } => part.type === \"text\" && typeof part.text === \"string\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\");\n}\n\n/**\n * Stable wrapper around a replaceable AgentSession runtime.\n *\n * Use this when your application needs `/new`, `/resume`, `/fork`, or import\n * behavior. After replacement, read `session` again and rebind any\n * session-local subscriptions or extension bindings.\n */\nexport class AgentSessionRuntimeHost {\n\tconstructor(\n\t\tprivate readonly bootstrap: AgentSessionRuntimeBootstrap,\n\t\tprivate runtime: AgentSessionRuntime,\n\t) {}\n\n\t/** The currently active session instance. Re-read this after runtime replacement. */\n\tget session() {\n\t\treturn this.runtime.session;\n\t}\n\n\tprivate async emitBeforeSwitch(\n\t\treason: \"new\" | \"resume\",\n\t\ttargetSessionFile?: string,\n\t): Promise<{ cancelled: boolean }> {\n\t\tconst runner = this.runtime.session.extensionRunner;\n\t\tif (!runner?.hasHandlers(\"session_before_switch\")) {\n\t\t\treturn { cancelled: false };\n\t\t}\n\n\t\tconst result = await runner.emit({\n\t\t\ttype: \"session_before_switch\",\n\t\t\treason,\n\t\t\ttargetSessionFile,\n\t\t});\n\t\treturn { cancelled: result?.cancel === true };\n\t}\n\n\tprivate async emitBeforeFork(entryId: string): Promise<{ cancelled: boolean }> {\n\t\tconst runner = this.runtime.session.extensionRunner;\n\t\tif (!runner?.hasHandlers(\"session_before_fork\")) {\n\t\t\treturn { cancelled: false };\n\t\t}\n\n\t\tconst result = await runner.emit({\n\t\t\ttype: \"session_before_fork\",\n\t\t\tentryId,\n\t\t});\n\t\treturn { cancelled: result?.cancel === true };\n\t}\n\n\tprivate async replace(options: CreateAgentSessionRuntimeOptions): Promise<void> {\n\t\tconst nextRuntime = await createAgentSessionRuntime(this.bootstrap, options);\n\t\tawait emitSessionShutdownEvent(this.runtime.session.extensionRunner);\n\t\tthis.runtime.session.dispose();\n\t\tif (process.cwd() !== nextRuntime.cwd) {\n\t\t\tprocess.chdir(nextRuntime.cwd);\n\t\t}\n\t\tthis.runtime = nextRuntime;\n\t}\n\n\t/**\n\t * Replace the active runtime with one opened from an existing session file.\n\t *\n\t * Emits `session_before_switch` before replacement and returns\n\t * `{ cancelled: true }` if an extension vetoes the switch.\n\t */\n\tasync switchSession(sessionPath: string): Promise<{ cancelled: boolean }> {\n\t\tconst beforeResult = await this.emitBeforeSwitch(\"resume\", sessionPath);\n\t\tif (beforeResult.cancelled) {\n\t\t\treturn beforeResult;\n\t\t}\n\n\t\tconst previousSessionFile = this.runtime.session.sessionFile;\n\t\tconst sessionManager = SessionManager.open(sessionPath);\n\t\tawait this.replace({\n\t\t\tcwd: sessionManager.getCwd(),\n\t\t\tsessionManager,\n\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"resume\", previousSessionFile },\n\t\t});\n\t\treturn { cancelled: false };\n\t}\n\n\t/**\n\t * Replace the active runtime with a fresh session in the current cwd.\n\t *\n\t * `setup` runs after replacement against the new session manager, which lets\n\t * callers seed entries before normal use begins.\n\t */\n\tasync newSession(options?: {\n\t\t/** Optional parent session path recorded in the new session header. */\n\t\tparentSession?: string;\n\t\t/** Optional callback for seeding the new session manager after replacement. */\n\t\tsetup?: (sessionManager: SessionManager) => Promise<void>;\n\t}): Promise<{ cancelled: boolean }> {\n\t\tconst beforeResult = await this.emitBeforeSwitch(\"new\");\n\t\tif (beforeResult.cancelled) {\n\t\t\treturn beforeResult;\n\t\t}\n\n\t\tconst previousSessionFile = this.runtime.session.sessionFile;\n\t\tconst sessionDir = this.runtime.sessionManager.getSessionDir();\n\t\tconst sessionManager = SessionManager.create(this.runtime.cwd, sessionDir);\n\t\tif (options?.parentSession) {\n\t\t\tsessionManager.newSession({ parentSession: options.parentSession });\n\t\t}\n\t\tawait this.replace({\n\t\t\tcwd: this.runtime.cwd,\n\t\t\tsessionManager,\n\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"new\", previousSessionFile },\n\t\t});\n\t\tif (options?.setup) {\n\t\t\tawait options.setup(this.runtime.sessionManager);\n\t\t\tthis.runtime.session.agent.state.messages = this.runtime.sessionManager.buildSessionContext().messages;\n\t\t}\n\t\treturn { cancelled: false };\n\t}\n\n\t/**\n\t * Replace the active runtime with a fork rooted at the given user-message\n\t * entry.\n\t *\n\t * Returns the selected user text so UIs can restore it into the editor after\n\t * the fork completes.\n\t */\n\tasync fork(entryId: string): Promise<{ cancelled: boolean; selectedText?: string }> {\n\t\tconst beforeResult = await this.emitBeforeFork(entryId);\n\t\tif (beforeResult.cancelled) {\n\t\t\treturn { cancelled: true };\n\t\t}\n\n\t\tconst selectedEntry = this.runtime.sessionManager.getEntry(entryId);\n\t\tif (!selectedEntry || selectedEntry.type !== \"message\" || selectedEntry.message.role !== \"user\") {\n\t\t\tthrow new Error(\"Invalid entry ID for forking\");\n\t\t}\n\n\t\tconst previousSessionFile = this.runtime.session.sessionFile;\n\t\tconst selectedText = extractUserMessageText(selectedEntry.message.content);\n\t\tif (this.runtime.sessionManager.isPersisted()) {\n\t\t\tconst currentSessionFile = this.runtime.session.sessionFile!;\n\t\t\tconst sessionDir = this.runtime.sessionManager.getSessionDir();\n\t\t\tif (!selectedEntry.parentId) {\n\t\t\t\tconst sessionManager = SessionManager.create(this.runtime.cwd, sessionDir);\n\t\t\t\tsessionManager.newSession({ parentSession: currentSessionFile });\n\t\t\t\tawait this.replace({\n\t\t\t\t\tcwd: this.runtime.cwd,\n\t\t\t\t\tsessionManager,\n\t\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile },\n\t\t\t\t});\n\t\t\t\treturn { cancelled: false, selectedText };\n\t\t\t}\n\n\t\t\tconst sourceManager = SessionManager.open(currentSessionFile, sessionDir);\n\t\t\tconst forkedSessionPath = sourceManager.createBranchedSession(selectedEntry.parentId)!;\n\t\t\tconst sessionManager = SessionManager.open(forkedSessionPath, sessionDir);\n\t\t\tawait this.replace({\n\t\t\t\tcwd: sessionManager.getCwd(),\n\t\t\t\tsessionManager,\n\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile },\n\t\t\t});\n\t\t\treturn { cancelled: false, selectedText };\n\t\t}\n\n\t\tconst sessionManager = this.runtime.sessionManager;\n\t\tif (!selectedEntry.parentId) {\n\t\t\tsessionManager.newSession({ parentSession: this.runtime.session.sessionFile });\n\t\t} else {\n\t\t\tsessionManager.createBranchedSession(selectedEntry.parentId);\n\t\t}\n\t\tawait this.replace({\n\t\t\tcwd: this.runtime.cwd,\n\t\t\tsessionManager,\n\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile },\n\t\t});\n\t\treturn { cancelled: false, selectedText };\n\t}\n\n\t/**\n\t * Import a JSONL session file into the current session directory and replace\n\t * the active runtime with the imported session.\n\t */\n\tasync importFromJsonl(inputPath: string): Promise<{ cancelled: boolean }> {\n\t\tconst resolvedPath = resolve(inputPath);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tthrow new Error(`File not found: ${resolvedPath}`);\n\t\t}\n\n\t\tconst sessionDir = this.runtime.sessionManager.getSessionDir();\n\t\tif (!existsSync(sessionDir)) {\n\t\t\tmkdirSync(sessionDir, { recursive: true });\n\t\t}\n\n\t\tconst destinationPath = join(sessionDir, basename(resolvedPath));\n\t\tconst beforeResult = await this.emitBeforeSwitch(\"resume\", destinationPath);\n\t\tif (beforeResult.cancelled) {\n\t\t\treturn beforeResult;\n\t\t}\n\n\t\tconst previousSessionFile = this.runtime.session.sessionFile;\n\t\tif (resolve(destinationPath) !== resolvedPath) {\n\t\t\tcopyFileSync(resolvedPath, destinationPath);\n\t\t}\n\n\t\tconst sessionManager = SessionManager.open(destinationPath, sessionDir);\n\t\tawait this.replace({\n\t\t\tcwd: sessionManager.getCwd(),\n\t\t\tsessionManager,\n\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"resume\", previousSessionFile },\n\t\t});\n\t\treturn { cancelled: false };\n\t}\n\n\t/** Emit session shutdown for the active runtime and dispose it permanently. */\n\tasync dispose(): Promise<void> {\n\t\tawait emitSessionShutdownEvent(this.runtime.session.extensionRunner);\n\t\tthis.runtime.session.dispose();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent-session-runtime.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,6BAA6B,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACvG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,+BAAgC,SAAQ,wBAAwB;IAChF,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,WAAW,EAAE,6BAA6B,EAAE,CAAC;CAC7C;AAED;;;;;;GAMG;AACH,MAAM,MAAM,gCAAgC,GAAG,CAAC,OAAO,EAAE;IACxD,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACtC,KAAK,OAAO,CAAC,+BAA+B,CAAC,CAAC;AAa/C;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAE9B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,qBAAqB,CAAC;IAL/B,YACS,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,oBAAoB,EACtB,aAAa,EAAE,gCAAgC,EACxD,YAAY,GAAE,6BAA6B,EAAO,EAClD,qBAAqB,CAAC,oBAAQ,EACnC;IAEJ,IAAI,QAAQ,IAAI,oBAAoB,CAEnC;IAED,IAAI,OAAO,IAAI,YAAY,CAE1B;IAED,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED,IAAI,WAAW,IAAI,SAAS,6BAA6B,EAAE,CAE1D;IAED,IAAI,oBAAoB,IAAI,MAAM,GAAG,SAAS,CAE7C;YAEa,gBAAgB;YAiBhB,cAAc;YAad,eAAe;IAK7B,OAAO,CAAC,KAAK;IAUP,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAkBxE;IAEK,UAAU,CAAC,OAAO,CAAC,EAAE;QAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,KAAK,CAAC,EAAE,CAAC,cAAc,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KAC1D,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CA2BlC;IAEK,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAoElF;IAEK,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAiCxE;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAG7B;CACD;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC9C,aAAa,EAAE,gCAAgC,EAC/C,OAAO,EAAE;IACR,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACtC,GACC,OAAO,CAAC,mBAAmB,CAAC,CAY9B;AAED,OAAO,EACN,KAAK,6BAA6B,EAClC,KAAK,oBAAoB,EACzB,KAAK,qCAAqC,EAC1C,KAAK,iCAAiC,EACtC,8BAA8B,EAC9B,0BAA0B,GAC1B,MAAM,6BAA6B,CAAC","sourcesContent":["import { copyFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { basename, join, resolve } from \"node:path\";\nimport type { AgentSession } from \"./agent-session.js\";\nimport type { AgentSessionRuntimeDiagnostic, AgentSessionServices } from \"./agent-session-services.js\";\nimport type { SessionStartEvent } from \"./extensions/index.js\";\nimport { emitSessionShutdownEvent } from \"./extensions/runner.js\";\nimport type { CreateAgentSessionResult } from \"./sdk.js\";\nimport { SessionManager } from \"./session-manager.js\";\n\n/**\n * Result returned by runtime creation.\n *\n * The caller gets the created session, its cwd-bound services, and all\n * diagnostics collected during setup.\n */\nexport interface CreateAgentSessionRuntimeResult extends CreateAgentSessionResult {\n\tservices: AgentSessionServices;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\n/**\n * Creates a full runtime for a target cwd and session manager.\n *\n * The factory closes over process-global fixed inputs, recreates cwd-bound\n * services for the effective cwd, resolves session options against those\n * services, and finally creates the AgentSession.\n */\nexport type CreateAgentSessionRuntimeFactory = (options: {\n\tcwd: string;\n\tagentDir: string;\n\tsessionManager: SessionManager;\n\tsessionStartEvent?: SessionStartEvent;\n}) => Promise<CreateAgentSessionRuntimeResult>;\n\nfunction extractUserMessageText(content: string | Array<{ type: string; text?: string }>): string {\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\n\treturn content\n\t\t.filter((part): part is { type: \"text\"; text: string } => part.type === \"text\" && typeof part.text === \"string\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\");\n}\n\n/**\n * Owns the current AgentSession plus its cwd-bound services.\n *\n * Session replacement methods tear down the current runtime first, then create\n * and apply the next runtime. If creation fails, the error is propagated to the\n * caller. The caller is responsible for user-facing error handling.\n */\nexport class AgentSessionRuntime {\n\tconstructor(\n\t\tprivate _session: AgentSession,\n\t\tprivate _services: AgentSessionServices,\n\t\tprivate readonly createRuntime: CreateAgentSessionRuntimeFactory,\n\t\tprivate _diagnostics: AgentSessionRuntimeDiagnostic[] = [],\n\t\tprivate _modelFallbackMessage?: string,\n\t) {}\n\n\tget services(): AgentSessionServices {\n\t\treturn this._services;\n\t}\n\n\tget session(): AgentSession {\n\t\treturn this._session;\n\t}\n\n\tget cwd(): string {\n\t\treturn this._services.cwd;\n\t}\n\n\tget diagnostics(): readonly AgentSessionRuntimeDiagnostic[] {\n\t\treturn this._diagnostics;\n\t}\n\n\tget modelFallbackMessage(): string | undefined {\n\t\treturn this._modelFallbackMessage;\n\t}\n\n\tprivate async emitBeforeSwitch(\n\t\treason: \"new\" | \"resume\",\n\t\ttargetSessionFile?: string,\n\t): Promise<{ cancelled: boolean }> {\n\t\tconst runner = this.session.extensionRunner;\n\t\tif (!runner?.hasHandlers(\"session_before_switch\")) {\n\t\t\treturn { cancelled: false };\n\t\t}\n\n\t\tconst result = await runner.emit({\n\t\t\ttype: \"session_before_switch\",\n\t\t\treason,\n\t\t\ttargetSessionFile,\n\t\t});\n\t\treturn { cancelled: result?.cancel === true };\n\t}\n\n\tprivate async emitBeforeFork(entryId: string): Promise<{ cancelled: boolean }> {\n\t\tconst runner = this.session.extensionRunner;\n\t\tif (!runner?.hasHandlers(\"session_before_fork\")) {\n\t\t\treturn { cancelled: false };\n\t\t}\n\n\t\tconst result = await runner.emit({\n\t\t\ttype: \"session_before_fork\",\n\t\t\tentryId,\n\t\t});\n\t\treturn { cancelled: result?.cancel === true };\n\t}\n\n\tprivate async teardownCurrent(): Promise<void> {\n\t\tawait emitSessionShutdownEvent(this.session.extensionRunner);\n\t\tthis.session.dispose();\n\t}\n\n\tprivate apply(result: CreateAgentSessionRuntimeResult): void {\n\t\tif (process.cwd() !== result.services.cwd) {\n\t\t\tprocess.chdir(result.services.cwd);\n\t\t}\n\t\tthis._session = result.session;\n\t\tthis._services = result.services;\n\t\tthis._diagnostics = result.diagnostics;\n\t\tthis._modelFallbackMessage = result.modelFallbackMessage;\n\t}\n\n\tasync switchSession(sessionPath: string): Promise<{ cancelled: boolean }> {\n\t\tconst beforeResult = await this.emitBeforeSwitch(\"resume\", sessionPath);\n\t\tif (beforeResult.cancelled) {\n\t\t\treturn beforeResult;\n\t\t}\n\n\t\tconst previousSessionFile = this.session.sessionFile;\n\t\tconst sessionManager = SessionManager.open(sessionPath);\n\t\tawait this.teardownCurrent();\n\t\tthis.apply(\n\t\t\tawait this.createRuntime({\n\t\t\t\tcwd: sessionManager.getCwd(),\n\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\tsessionManager,\n\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"resume\", previousSessionFile },\n\t\t\t}),\n\t\t);\n\t\treturn { cancelled: false };\n\t}\n\n\tasync newSession(options?: {\n\t\tparentSession?: string;\n\t\tsetup?: (sessionManager: SessionManager) => Promise<void>;\n\t}): Promise<{ cancelled: boolean }> {\n\t\tconst beforeResult = await this.emitBeforeSwitch(\"new\");\n\t\tif (beforeResult.cancelled) {\n\t\t\treturn beforeResult;\n\t\t}\n\n\t\tconst previousSessionFile = this.session.sessionFile;\n\t\tconst sessionDir = this.session.sessionManager.getSessionDir();\n\t\tconst sessionManager = SessionManager.create(this.cwd, sessionDir);\n\t\tif (options?.parentSession) {\n\t\t\tsessionManager.newSession({ parentSession: options.parentSession });\n\t\t}\n\n\t\tawait this.teardownCurrent();\n\t\tthis.apply(\n\t\t\tawait this.createRuntime({\n\t\t\t\tcwd: this.cwd,\n\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\tsessionManager,\n\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"new\", previousSessionFile },\n\t\t\t}),\n\t\t);\n\t\tif (options?.setup) {\n\t\t\tawait options.setup(this.session.sessionManager);\n\t\t\tthis.session.agent.state.messages = this.session.sessionManager.buildSessionContext().messages;\n\t\t}\n\t\treturn { cancelled: false };\n\t}\n\n\tasync fork(entryId: string): Promise<{ cancelled: boolean; selectedText?: string }> {\n\t\tconst beforeResult = await this.emitBeforeFork(entryId);\n\t\tif (beforeResult.cancelled) {\n\t\t\treturn { cancelled: true };\n\t\t}\n\n\t\tconst selectedEntry = this.session.sessionManager.getEntry(entryId);\n\t\tif (!selectedEntry || selectedEntry.type !== \"message\" || selectedEntry.message.role !== \"user\") {\n\t\t\tthrow new Error(\"Invalid entry ID for forking\");\n\t\t}\n\n\t\tconst previousSessionFile = this.session.sessionFile;\n\t\tconst selectedText = extractUserMessageText(selectedEntry.message.content);\n\t\tif (this.session.sessionManager.isPersisted()) {\n\t\t\tconst currentSessionFile = this.session.sessionFile;\n\t\t\tif (!currentSessionFile) {\n\t\t\t\tthrow new Error(\"Persisted session is missing a session file\");\n\t\t\t}\n\t\t\tconst sessionDir = this.session.sessionManager.getSessionDir();\n\t\t\tif (!selectedEntry.parentId) {\n\t\t\t\tconst sessionManager = SessionManager.create(this.cwd, sessionDir);\n\t\t\t\tsessionManager.newSession({ parentSession: currentSessionFile });\n\t\t\t\tawait this.teardownCurrent();\n\t\t\t\tthis.apply(\n\t\t\t\t\tawait this.createRuntime({\n\t\t\t\t\t\tcwd: this.cwd,\n\t\t\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\t\t\tsessionManager,\n\t\t\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile },\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn { cancelled: false, selectedText };\n\t\t\t}\n\n\t\t\tconst sourceManager = SessionManager.open(currentSessionFile, sessionDir);\n\t\t\tconst forkedSessionPath = sourceManager.createBranchedSession(selectedEntry.parentId);\n\t\t\tif (!forkedSessionPath) {\n\t\t\t\tthrow new Error(\"Failed to create forked session\");\n\t\t\t}\n\t\t\tconst sessionManager = SessionManager.open(forkedSessionPath, sessionDir);\n\t\t\tawait this.teardownCurrent();\n\t\t\tthis.apply(\n\t\t\t\tawait this.createRuntime({\n\t\t\t\t\tcwd: sessionManager.getCwd(),\n\t\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\t\tsessionManager,\n\t\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile },\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn { cancelled: false, selectedText };\n\t\t}\n\n\t\tconst sessionManager = this.session.sessionManager;\n\t\tif (!selectedEntry.parentId) {\n\t\t\tsessionManager.newSession({ parentSession: this.session.sessionFile });\n\t\t} else {\n\t\t\tsessionManager.createBranchedSession(selectedEntry.parentId);\n\t\t}\n\t\tawait this.teardownCurrent();\n\t\tthis.apply(\n\t\t\tawait this.createRuntime({\n\t\t\t\tcwd: this.cwd,\n\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\tsessionManager,\n\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile },\n\t\t\t}),\n\t\t);\n\t\treturn { cancelled: false, selectedText };\n\t}\n\n\tasync importFromJsonl(inputPath: string): Promise<{ cancelled: boolean }> {\n\t\tconst resolvedPath = resolve(inputPath);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tthrow new Error(`File not found: ${resolvedPath}`);\n\t\t}\n\n\t\tconst sessionDir = this.session.sessionManager.getSessionDir();\n\t\tif (!existsSync(sessionDir)) {\n\t\t\tmkdirSync(sessionDir, { recursive: true });\n\t\t}\n\n\t\tconst destinationPath = join(sessionDir, basename(resolvedPath));\n\t\tconst beforeResult = await this.emitBeforeSwitch(\"resume\", destinationPath);\n\t\tif (beforeResult.cancelled) {\n\t\t\treturn beforeResult;\n\t\t}\n\n\t\tconst previousSessionFile = this.session.sessionFile;\n\t\tif (resolve(destinationPath) !== resolvedPath) {\n\t\t\tcopyFileSync(resolvedPath, destinationPath);\n\t\t}\n\n\t\tconst sessionManager = SessionManager.open(destinationPath, sessionDir);\n\t\tawait this.teardownCurrent();\n\t\tthis.apply(\n\t\t\tawait this.createRuntime({\n\t\t\t\tcwd: sessionManager.getCwd(),\n\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\tsessionManager,\n\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"resume\", previousSessionFile },\n\t\t\t}),\n\t\t);\n\t\treturn { cancelled: false };\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\tawait emitSessionShutdownEvent(this.session.extensionRunner);\n\t\tthis.session.dispose();\n\t}\n}\n\n/**\n * Create the initial runtime from a runtime factory and initial session target.\n *\n * The same factory is stored on the returned AgentSessionRuntime and reused for\n * later /new, /resume, /fork, and import flows.\n */\nexport async function createAgentSessionRuntime(\n\tcreateRuntime: CreateAgentSessionRuntimeFactory,\n\toptions: {\n\t\tcwd: string;\n\t\tagentDir: string;\n\t\tsessionManager: SessionManager;\n\t\tsessionStartEvent?: SessionStartEvent;\n\t},\n): Promise<AgentSessionRuntime> {\n\tconst result = await createRuntime(options);\n\tif (process.cwd() !== result.services.cwd) {\n\t\tprocess.chdir(result.services.cwd);\n\t}\n\treturn new AgentSessionRuntime(\n\t\tresult.session,\n\t\tresult.services,\n\t\tcreateRuntime,\n\t\tresult.diagnostics,\n\t\tresult.modelFallbackMessage,\n\t);\n}\n\nexport {\n\ttype AgentSessionRuntimeDiagnostic,\n\ttype AgentSessionServices,\n\ttype CreateAgentSessionFromServicesOptions,\n\ttype CreateAgentSessionServicesOptions,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./agent-session-services.js\";\n"]}
|
|
@@ -1,68 +1,7 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, mkdirSync } from "node:fs";
|
|
2
2
|
import { basename, join, resolve } from "node:path";
|
|
3
|
-
import { getAgentDir } from "../config.js";
|
|
4
|
-
import { AuthStorage } from "./auth-storage.js";
|
|
5
3
|
import { emitSessionShutdownEvent } from "./extensions/runner.js";
|
|
6
|
-
import { ModelRegistry } from "./model-registry.js";
|
|
7
|
-
import { DefaultResourceLoader } from "./resource-loader.js";
|
|
8
|
-
import { createAgentSession } from "./sdk.js";
|
|
9
4
|
import { SessionManager } from "./session-manager.js";
|
|
10
|
-
import { SettingsManager } from "./settings-manager.js";
|
|
11
|
-
/**
|
|
12
|
-
* Create one runtime instance containing an AgentSession plus the cwd-bound
|
|
13
|
-
* services it depends on.
|
|
14
|
-
*
|
|
15
|
-
* Most SDK callers should keep the returned value wrapped in an
|
|
16
|
-
* AgentSessionRuntimeHost instead of holding it directly. The host owns
|
|
17
|
-
* replacing the runtime when switching sessions across files or working
|
|
18
|
-
* directories.
|
|
19
|
-
*/
|
|
20
|
-
export async function createAgentSessionRuntime(bootstrap, options) {
|
|
21
|
-
const cwd = options.cwd;
|
|
22
|
-
const agentDir = bootstrap.agentDir ?? getAgentDir();
|
|
23
|
-
const authStorage = bootstrap.authStorage ?? AuthStorage.create(join(agentDir, "auth.json"));
|
|
24
|
-
const settingsManager = SettingsManager.create(cwd, agentDir);
|
|
25
|
-
const modelRegistry = ModelRegistry.create(authStorage, join(agentDir, "models.json"));
|
|
26
|
-
const resourceLoader = typeof bootstrap.resourceLoader === "function"
|
|
27
|
-
? await bootstrap.resourceLoader(cwd, agentDir)
|
|
28
|
-
: new DefaultResourceLoader({
|
|
29
|
-
...(bootstrap.resourceLoader ?? {}),
|
|
30
|
-
cwd,
|
|
31
|
-
agentDir,
|
|
32
|
-
settingsManager,
|
|
33
|
-
});
|
|
34
|
-
await resourceLoader.reload();
|
|
35
|
-
const extensionsResult = resourceLoader.getExtensions();
|
|
36
|
-
for (const { name, config } of extensionsResult.runtime.pendingProviderRegistrations) {
|
|
37
|
-
modelRegistry.registerProvider(name, config);
|
|
38
|
-
}
|
|
39
|
-
extensionsResult.runtime.pendingProviderRegistrations = [];
|
|
40
|
-
const created = await createAgentSession({
|
|
41
|
-
cwd,
|
|
42
|
-
agentDir,
|
|
43
|
-
authStorage,
|
|
44
|
-
modelRegistry,
|
|
45
|
-
settingsManager,
|
|
46
|
-
resourceLoader,
|
|
47
|
-
sessionManager: options.sessionManager,
|
|
48
|
-
model: bootstrap.model,
|
|
49
|
-
thinkingLevel: bootstrap.thinkingLevel,
|
|
50
|
-
scopedModels: bootstrap.scopedModels,
|
|
51
|
-
tools: bootstrap.tools,
|
|
52
|
-
customTools: bootstrap.customTools,
|
|
53
|
-
sessionStartEvent: options.sessionStartEvent,
|
|
54
|
-
});
|
|
55
|
-
return {
|
|
56
|
-
...created,
|
|
57
|
-
cwd,
|
|
58
|
-
agentDir,
|
|
59
|
-
authStorage,
|
|
60
|
-
modelRegistry,
|
|
61
|
-
settingsManager,
|
|
62
|
-
resourceLoader,
|
|
63
|
-
sessionManager: created.session.sessionManager,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
5
|
function extractUserMessageText(content) {
|
|
67
6
|
if (typeof content === "string") {
|
|
68
7
|
return content;
|
|
@@ -73,23 +12,37 @@ function extractUserMessageText(content) {
|
|
|
73
12
|
.join("");
|
|
74
13
|
}
|
|
75
14
|
/**
|
|
76
|
-
*
|
|
15
|
+
* Owns the current AgentSession plus its cwd-bound services.
|
|
77
16
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
17
|
+
* Session replacement methods tear down the current runtime first, then create
|
|
18
|
+
* and apply the next runtime. If creation fails, the error is propagated to the
|
|
19
|
+
* caller. The caller is responsible for user-facing error handling.
|
|
81
20
|
*/
|
|
82
|
-
export class
|
|
83
|
-
constructor(
|
|
84
|
-
this.
|
|
85
|
-
this.
|
|
21
|
+
export class AgentSessionRuntime {
|
|
22
|
+
constructor(_session, _services, createRuntime, _diagnostics = [], _modelFallbackMessage) {
|
|
23
|
+
this._session = _session;
|
|
24
|
+
this._services = _services;
|
|
25
|
+
this.createRuntime = createRuntime;
|
|
26
|
+
this._diagnostics = _diagnostics;
|
|
27
|
+
this._modelFallbackMessage = _modelFallbackMessage;
|
|
28
|
+
}
|
|
29
|
+
get services() {
|
|
30
|
+
return this._services;
|
|
86
31
|
}
|
|
87
|
-
/** The currently active session instance. Re-read this after runtime replacement. */
|
|
88
32
|
get session() {
|
|
89
|
-
return this.
|
|
33
|
+
return this._session;
|
|
34
|
+
}
|
|
35
|
+
get cwd() {
|
|
36
|
+
return this._services.cwd;
|
|
37
|
+
}
|
|
38
|
+
get diagnostics() {
|
|
39
|
+
return this._diagnostics;
|
|
40
|
+
}
|
|
41
|
+
get modelFallbackMessage() {
|
|
42
|
+
return this._modelFallbackMessage;
|
|
90
43
|
}
|
|
91
44
|
async emitBeforeSwitch(reason, targetSessionFile) {
|
|
92
|
-
const runner = this.
|
|
45
|
+
const runner = this.session.extensionRunner;
|
|
93
46
|
if (!runner?.hasHandlers("session_before_switch")) {
|
|
94
47
|
return { cancelled: false };
|
|
95
48
|
}
|
|
@@ -101,7 +54,7 @@ export class AgentSessionRuntimeHost {
|
|
|
101
54
|
return { cancelled: result?.cancel === true };
|
|
102
55
|
}
|
|
103
56
|
async emitBeforeFork(entryId) {
|
|
104
|
-
const runner = this.
|
|
57
|
+
const runner = this.session.extensionRunner;
|
|
105
58
|
if (!runner?.hasHandlers("session_before_fork")) {
|
|
106
59
|
return { cancelled: false };
|
|
107
60
|
}
|
|
@@ -111,128 +64,125 @@ export class AgentSessionRuntimeHost {
|
|
|
111
64
|
});
|
|
112
65
|
return { cancelled: result?.cancel === true };
|
|
113
66
|
}
|
|
114
|
-
async
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
67
|
+
async teardownCurrent() {
|
|
68
|
+
await emitSessionShutdownEvent(this.session.extensionRunner);
|
|
69
|
+
this.session.dispose();
|
|
70
|
+
}
|
|
71
|
+
apply(result) {
|
|
72
|
+
if (process.cwd() !== result.services.cwd) {
|
|
73
|
+
process.chdir(result.services.cwd);
|
|
74
|
+
}
|
|
75
|
+
this._session = result.session;
|
|
76
|
+
this._services = result.services;
|
|
77
|
+
this._diagnostics = result.diagnostics;
|
|
78
|
+
this._modelFallbackMessage = result.modelFallbackMessage;
|
|
122
79
|
}
|
|
123
|
-
/**
|
|
124
|
-
* Replace the active runtime with one opened from an existing session file.
|
|
125
|
-
*
|
|
126
|
-
* Emits `session_before_switch` before replacement and returns
|
|
127
|
-
* `{ cancelled: true }` if an extension vetoes the switch.
|
|
128
|
-
*/
|
|
129
80
|
async switchSession(sessionPath) {
|
|
130
81
|
const beforeResult = await this.emitBeforeSwitch("resume", sessionPath);
|
|
131
82
|
if (beforeResult.cancelled) {
|
|
132
83
|
return beforeResult;
|
|
133
84
|
}
|
|
134
|
-
const previousSessionFile = this.
|
|
85
|
+
const previousSessionFile = this.session.sessionFile;
|
|
135
86
|
const sessionManager = SessionManager.open(sessionPath);
|
|
136
|
-
await this.
|
|
87
|
+
await this.teardownCurrent();
|
|
88
|
+
this.apply(await this.createRuntime({
|
|
137
89
|
cwd: sessionManager.getCwd(),
|
|
90
|
+
agentDir: this.services.agentDir,
|
|
138
91
|
sessionManager,
|
|
139
92
|
sessionStartEvent: { type: "session_start", reason: "resume", previousSessionFile },
|
|
140
|
-
});
|
|
93
|
+
}));
|
|
141
94
|
return { cancelled: false };
|
|
142
95
|
}
|
|
143
|
-
/**
|
|
144
|
-
* Replace the active runtime with a fresh session in the current cwd.
|
|
145
|
-
*
|
|
146
|
-
* `setup` runs after replacement against the new session manager, which lets
|
|
147
|
-
* callers seed entries before normal use begins.
|
|
148
|
-
*/
|
|
149
96
|
async newSession(options) {
|
|
150
97
|
const beforeResult = await this.emitBeforeSwitch("new");
|
|
151
98
|
if (beforeResult.cancelled) {
|
|
152
99
|
return beforeResult;
|
|
153
100
|
}
|
|
154
|
-
const previousSessionFile = this.
|
|
155
|
-
const sessionDir = this.
|
|
156
|
-
const sessionManager = SessionManager.create(this.
|
|
101
|
+
const previousSessionFile = this.session.sessionFile;
|
|
102
|
+
const sessionDir = this.session.sessionManager.getSessionDir();
|
|
103
|
+
const sessionManager = SessionManager.create(this.cwd, sessionDir);
|
|
157
104
|
if (options?.parentSession) {
|
|
158
105
|
sessionManager.newSession({ parentSession: options.parentSession });
|
|
159
106
|
}
|
|
160
|
-
await this.
|
|
161
|
-
|
|
107
|
+
await this.teardownCurrent();
|
|
108
|
+
this.apply(await this.createRuntime({
|
|
109
|
+
cwd: this.cwd,
|
|
110
|
+
agentDir: this.services.agentDir,
|
|
162
111
|
sessionManager,
|
|
163
112
|
sessionStartEvent: { type: "session_start", reason: "new", previousSessionFile },
|
|
164
|
-
});
|
|
113
|
+
}));
|
|
165
114
|
if (options?.setup) {
|
|
166
|
-
await options.setup(this.
|
|
167
|
-
this.
|
|
115
|
+
await options.setup(this.session.sessionManager);
|
|
116
|
+
this.session.agent.state.messages = this.session.sessionManager.buildSessionContext().messages;
|
|
168
117
|
}
|
|
169
118
|
return { cancelled: false };
|
|
170
119
|
}
|
|
171
|
-
/**
|
|
172
|
-
* Replace the active runtime with a fork rooted at the given user-message
|
|
173
|
-
* entry.
|
|
174
|
-
*
|
|
175
|
-
* Returns the selected user text so UIs can restore it into the editor after
|
|
176
|
-
* the fork completes.
|
|
177
|
-
*/
|
|
178
120
|
async fork(entryId) {
|
|
179
121
|
const beforeResult = await this.emitBeforeFork(entryId);
|
|
180
122
|
if (beforeResult.cancelled) {
|
|
181
123
|
return { cancelled: true };
|
|
182
124
|
}
|
|
183
|
-
const selectedEntry = this.
|
|
125
|
+
const selectedEntry = this.session.sessionManager.getEntry(entryId);
|
|
184
126
|
if (!selectedEntry || selectedEntry.type !== "message" || selectedEntry.message.role !== "user") {
|
|
185
127
|
throw new Error("Invalid entry ID for forking");
|
|
186
128
|
}
|
|
187
|
-
const previousSessionFile = this.
|
|
129
|
+
const previousSessionFile = this.session.sessionFile;
|
|
188
130
|
const selectedText = extractUserMessageText(selectedEntry.message.content);
|
|
189
|
-
if (this.
|
|
190
|
-
const currentSessionFile = this.
|
|
191
|
-
|
|
131
|
+
if (this.session.sessionManager.isPersisted()) {
|
|
132
|
+
const currentSessionFile = this.session.sessionFile;
|
|
133
|
+
if (!currentSessionFile) {
|
|
134
|
+
throw new Error("Persisted session is missing a session file");
|
|
135
|
+
}
|
|
136
|
+
const sessionDir = this.session.sessionManager.getSessionDir();
|
|
192
137
|
if (!selectedEntry.parentId) {
|
|
193
|
-
const sessionManager = SessionManager.create(this.
|
|
138
|
+
const sessionManager = SessionManager.create(this.cwd, sessionDir);
|
|
194
139
|
sessionManager.newSession({ parentSession: currentSessionFile });
|
|
195
|
-
await this.
|
|
196
|
-
|
|
140
|
+
await this.teardownCurrent();
|
|
141
|
+
this.apply(await this.createRuntime({
|
|
142
|
+
cwd: this.cwd,
|
|
143
|
+
agentDir: this.services.agentDir,
|
|
197
144
|
sessionManager,
|
|
198
145
|
sessionStartEvent: { type: "session_start", reason: "fork", previousSessionFile },
|
|
199
|
-
});
|
|
146
|
+
}));
|
|
200
147
|
return { cancelled: false, selectedText };
|
|
201
148
|
}
|
|
202
149
|
const sourceManager = SessionManager.open(currentSessionFile, sessionDir);
|
|
203
150
|
const forkedSessionPath = sourceManager.createBranchedSession(selectedEntry.parentId);
|
|
151
|
+
if (!forkedSessionPath) {
|
|
152
|
+
throw new Error("Failed to create forked session");
|
|
153
|
+
}
|
|
204
154
|
const sessionManager = SessionManager.open(forkedSessionPath, sessionDir);
|
|
205
|
-
await this.
|
|
155
|
+
await this.teardownCurrent();
|
|
156
|
+
this.apply(await this.createRuntime({
|
|
206
157
|
cwd: sessionManager.getCwd(),
|
|
158
|
+
agentDir: this.services.agentDir,
|
|
207
159
|
sessionManager,
|
|
208
160
|
sessionStartEvent: { type: "session_start", reason: "fork", previousSessionFile },
|
|
209
|
-
});
|
|
161
|
+
}));
|
|
210
162
|
return { cancelled: false, selectedText };
|
|
211
163
|
}
|
|
212
|
-
const sessionManager = this.
|
|
164
|
+
const sessionManager = this.session.sessionManager;
|
|
213
165
|
if (!selectedEntry.parentId) {
|
|
214
|
-
sessionManager.newSession({ parentSession: this.
|
|
166
|
+
sessionManager.newSession({ parentSession: this.session.sessionFile });
|
|
215
167
|
}
|
|
216
168
|
else {
|
|
217
169
|
sessionManager.createBranchedSession(selectedEntry.parentId);
|
|
218
170
|
}
|
|
219
|
-
await this.
|
|
220
|
-
|
|
171
|
+
await this.teardownCurrent();
|
|
172
|
+
this.apply(await this.createRuntime({
|
|
173
|
+
cwd: this.cwd,
|
|
174
|
+
agentDir: this.services.agentDir,
|
|
221
175
|
sessionManager,
|
|
222
176
|
sessionStartEvent: { type: "session_start", reason: "fork", previousSessionFile },
|
|
223
|
-
});
|
|
177
|
+
}));
|
|
224
178
|
return { cancelled: false, selectedText };
|
|
225
179
|
}
|
|
226
|
-
/**
|
|
227
|
-
* Import a JSONL session file into the current session directory and replace
|
|
228
|
-
* the active runtime with the imported session.
|
|
229
|
-
*/
|
|
230
180
|
async importFromJsonl(inputPath) {
|
|
231
181
|
const resolvedPath = resolve(inputPath);
|
|
232
182
|
if (!existsSync(resolvedPath)) {
|
|
233
183
|
throw new Error(`File not found: ${resolvedPath}`);
|
|
234
184
|
}
|
|
235
|
-
const sessionDir = this.
|
|
185
|
+
const sessionDir = this.session.sessionManager.getSessionDir();
|
|
236
186
|
if (!existsSync(sessionDir)) {
|
|
237
187
|
mkdirSync(sessionDir, { recursive: true });
|
|
238
188
|
}
|
|
@@ -241,22 +191,37 @@ export class AgentSessionRuntimeHost {
|
|
|
241
191
|
if (beforeResult.cancelled) {
|
|
242
192
|
return beforeResult;
|
|
243
193
|
}
|
|
244
|
-
const previousSessionFile = this.
|
|
194
|
+
const previousSessionFile = this.session.sessionFile;
|
|
245
195
|
if (resolve(destinationPath) !== resolvedPath) {
|
|
246
196
|
copyFileSync(resolvedPath, destinationPath);
|
|
247
197
|
}
|
|
248
198
|
const sessionManager = SessionManager.open(destinationPath, sessionDir);
|
|
249
|
-
await this.
|
|
199
|
+
await this.teardownCurrent();
|
|
200
|
+
this.apply(await this.createRuntime({
|
|
250
201
|
cwd: sessionManager.getCwd(),
|
|
202
|
+
agentDir: this.services.agentDir,
|
|
251
203
|
sessionManager,
|
|
252
204
|
sessionStartEvent: { type: "session_start", reason: "resume", previousSessionFile },
|
|
253
|
-
});
|
|
205
|
+
}));
|
|
254
206
|
return { cancelled: false };
|
|
255
207
|
}
|
|
256
|
-
/** Emit session shutdown for the active runtime and dispose it permanently. */
|
|
257
208
|
async dispose() {
|
|
258
|
-
await emitSessionShutdownEvent(this.
|
|
259
|
-
this.
|
|
209
|
+
await emitSessionShutdownEvent(this.session.extensionRunner);
|
|
210
|
+
this.session.dispose();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Create the initial runtime from a runtime factory and initial session target.
|
|
215
|
+
*
|
|
216
|
+
* The same factory is stored on the returned AgentSessionRuntime and reused for
|
|
217
|
+
* later /new, /resume, /fork, and import flows.
|
|
218
|
+
*/
|
|
219
|
+
export async function createAgentSessionRuntime(createRuntime, options) {
|
|
220
|
+
const result = await createRuntime(options);
|
|
221
|
+
if (process.cwd() !== result.services.cwd) {
|
|
222
|
+
process.chdir(result.services.cwd);
|
|
260
223
|
}
|
|
224
|
+
return new AgentSessionRuntime(result.session, result.services, createRuntime, result.diagnostics, result.modelFallbackMessage);
|
|
261
225
|
}
|
|
226
|
+
export { createAgentSessionFromServices, createAgentSessionServices, } from "./agent-session-services.js";
|
|
262
227
|
//# sourceMappingURL=agent-session-runtime.js.map
|