@aexol/spectral 0.7.1 → 0.7.5
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 +5 -0
- package/dist/agent/agents.js +1 -1
- package/dist/agent/index.js +199 -184
- package/dist/commands/serve.js +0 -3
- package/dist/designer/data/systems/renault/DESIGN.md +1 -1
- package/dist/designer/philosophies.js +668 -0
- package/dist/mcp/sampling-handler.js +1 -1
- package/dist/memory/commands/status.js +1 -1
- package/dist/memory/compaction.js +2 -2
- package/dist/memory/config.js +1 -1
- package/dist/memory/debug-log.js +1 -1
- package/dist/memory/hooks/compaction-hook.js +29 -0
- package/dist/memory/index.js +2 -0
- package/dist/memory/observer.js +2 -2
- package/dist/memory/project-observations-store.js +14 -0
- package/dist/memory/tokens.js +1 -1
- package/dist/memory/tools/read-project-observations.js +82 -0
- package/dist/memory/tools/recall-observation.js +2 -2
- package/dist/pi/agent-core/agent-loop.js +501 -0
- package/dist/pi/agent-core/agent.js +401 -0
- package/dist/pi/agent-core/harness/agent-harness.js +899 -0
- package/dist/pi/agent-core/harness/compaction/branch-summarization.js +173 -0
- package/dist/pi/agent-core/harness/compaction/compaction.js +532 -0
- package/dist/pi/agent-core/harness/compaction/utils.js +130 -0
- package/dist/pi/agent-core/harness/env/nodejs.js +485 -0
- package/dist/pi/agent-core/harness/messages.js +101 -0
- package/dist/pi/agent-core/harness/prompt-templates.js +229 -0
- package/dist/pi/agent-core/harness/session/jsonl-repo.js +100 -0
- package/dist/pi/agent-core/harness/session/jsonl-storage.js +230 -0
- package/dist/pi/agent-core/harness/session/memory-repo.js +41 -0
- package/dist/pi/agent-core/harness/session/memory-storage.js +113 -0
- package/dist/pi/agent-core/harness/session/repo-utils.js +38 -0
- package/dist/pi/agent-core/harness/session/session.js +196 -0
- package/dist/pi/agent-core/harness/session/uuid.js +49 -0
- package/dist/pi/agent-core/harness/skills.js +310 -0
- package/dist/pi/agent-core/harness/system-prompt.js +29 -0
- package/dist/pi/agent-core/harness/types.js +93 -0
- package/dist/pi/agent-core/harness/utils/shell-output.js +125 -0
- package/dist/pi/agent-core/harness/utils/truncate.js +289 -0
- package/dist/pi/agent-core/index.js +24 -0
- package/dist/pi/agent-core/node.js +2 -0
- package/dist/pi/agent-core/proxy.js +277 -0
- package/dist/pi/agent-core/types.js +1 -0
- package/dist/pi/ai/api-registry.js +43 -0
- package/dist/pi/ai/cli.js +120 -0
- package/dist/pi/ai/env-api-keys.js +169 -0
- package/dist/pi/ai/image-models.generated.js +441 -0
- package/dist/pi/ai/image-models.js +22 -0
- package/dist/pi/ai/images-api-registry.js +21 -0
- package/dist/pi/ai/images.js +13 -0
- package/dist/pi/ai/index.js +18 -0
- package/dist/pi/ai/models.generated.js +16220 -0
- package/dist/pi/ai/models.js +70 -0
- package/dist/pi/ai/oauth.js +1 -0
- package/dist/pi/ai/providers/anthropic.js +945 -0
- package/dist/pi/ai/providers/faux.js +367 -0
- package/dist/pi/ai/providers/github-copilot-headers.js +28 -0
- package/dist/pi/ai/providers/openai-completions.js +945 -0
- package/dist/pi/ai/providers/openai-prompt-cache.js +9 -0
- package/dist/pi/ai/providers/register-builtins.js +97 -0
- package/dist/pi/ai/providers/simple-options.js +40 -0
- package/dist/pi/ai/providers/transform-messages.js +183 -0
- package/dist/pi/ai/session-resources.js +21 -0
- package/dist/pi/ai/stream.js +26 -0
- package/dist/pi/ai/types.js +1 -0
- package/dist/pi/ai/utils/diagnostics.js +24 -0
- package/dist/pi/ai/utils/event-stream.js +80 -0
- package/dist/pi/ai/utils/hash.js +13 -0
- package/dist/pi/ai/utils/headers.js +7 -0
- package/dist/pi/ai/utils/json-parse.js +112 -0
- package/dist/pi/ai/utils/node-http-proxy.js +96 -0
- package/dist/pi/ai/utils/oauth/anthropic.js +334 -0
- package/dist/pi/ai/utils/oauth/device-code.js +54 -0
- package/dist/pi/ai/utils/oauth/github-copilot.js +270 -0
- package/dist/pi/ai/utils/oauth/index.js +121 -0
- package/dist/pi/ai/utils/oauth/oauth-page.js +104 -0
- package/dist/pi/ai/utils/oauth/openai-codex.js +384 -0
- package/dist/pi/ai/utils/oauth/pkce.js +30 -0
- package/dist/pi/ai/utils/oauth/types.js +1 -0
- package/dist/pi/ai/utils/overflow.js +150 -0
- package/dist/pi/ai/utils/sanitize-unicode.js +25 -0
- package/dist/pi/ai/utils/typebox-helpers.js +20 -0
- package/dist/pi/ai/utils/validation.js +280 -0
- package/dist/pi/coding-agent/bun/cli.js +7 -0
- package/dist/pi/coding-agent/bun/restore-sandbox-env.js +31 -0
- package/dist/pi/coding-agent/cli/args.js +340 -0
- package/dist/pi/coding-agent/cli/file-processor.js +82 -0
- package/dist/pi/coding-agent/cli/initial-message.js +21 -0
- package/dist/pi/coding-agent/cli.js +17 -0
- package/dist/pi/coding-agent/config.js +414 -0
- package/dist/pi/coding-agent/core/agent-session-runtime.js +299 -0
- package/dist/pi/coding-agent/core/agent-session-services.js +117 -0
- package/dist/pi/coding-agent/core/agent-session.js +2498 -0
- package/dist/pi/coding-agent/core/auth-guidance.js +20 -0
- package/dist/pi/coding-agent/core/auth-storage.js +441 -0
- package/dist/pi/coding-agent/core/bash-executor.js +110 -0
- package/dist/pi/coding-agent/core/compaction/branch-summarization.js +242 -0
- package/dist/pi/coding-agent/core/compaction/compaction.js +624 -0
- package/dist/pi/coding-agent/core/compaction/index.js +6 -0
- package/dist/pi/coding-agent/core/compaction/utils.js +152 -0
- package/dist/pi/coding-agent/core/defaults.js +1 -0
- package/dist/pi/coding-agent/core/diagnostics.js +1 -0
- package/dist/pi/coding-agent/core/event-bus.js +24 -0
- package/dist/pi/coding-agent/core/exec.js +74 -0
- package/dist/pi/coding-agent/core/export-html/ansi-to-html.js +248 -0
- package/dist/pi/coding-agent/core/export-html/index.js +225 -0
- package/dist/pi/coding-agent/core/export-html/tool-renderer.js +107 -0
- package/dist/pi/coding-agent/core/extensions/index.js +8 -0
- package/dist/pi/coding-agent/core/extensions/loader.js +485 -0
- package/dist/pi/coding-agent/core/extensions/runner.js +824 -0
- package/dist/pi/coding-agent/core/extensions/types.js +44 -0
- package/dist/pi/coding-agent/core/extensions/wrapper.js +21 -0
- package/dist/pi/coding-agent/core/footer-data-provider.js +309 -0
- package/dist/pi/coding-agent/core/http-dispatcher.js +47 -0
- package/dist/pi/coding-agent/core/index.js +11 -0
- package/dist/pi/coding-agent/core/keybindings.js +294 -0
- package/dist/pi/coding-agent/core/messages.js +122 -0
- package/dist/pi/coding-agent/core/model-registry.js +728 -0
- package/dist/pi/coding-agent/core/model-resolver.js +494 -0
- package/dist/pi/coding-agent/core/output-guard.js +58 -0
- package/dist/pi/coding-agent/core/package-manager.js +2020 -0
- package/dist/pi/coding-agent/core/prompt-templates.js +237 -0
- package/dist/pi/coding-agent/core/provider-display-names.js +32 -0
- package/dist/pi/coding-agent/core/resolve-config-value.js +125 -0
- package/dist/pi/coding-agent/core/resource-loader.js +733 -0
- package/dist/pi/coding-agent/core/sdk.js +282 -0
- package/dist/pi/coding-agent/core/session-cwd.js +37 -0
- package/dist/pi/coding-agent/core/session-manager.js +1146 -0
- package/dist/pi/coding-agent/core/settings-manager.js +794 -0
- package/dist/pi/coding-agent/core/skills.js +386 -0
- package/dist/pi/coding-agent/core/slash-commands.js +24 -0
- package/dist/pi/coding-agent/core/source-info.js +18 -0
- package/dist/pi/coding-agent/core/system-prompt.js +122 -0
- package/dist/pi/coding-agent/core/telemetry.js +8 -0
- package/dist/pi/coding-agent/core/timings.js +30 -0
- package/dist/pi/coding-agent/core/tools/bash.js +341 -0
- package/dist/pi/coding-agent/core/tools/edit-diff.js +344 -0
- package/dist/pi/coding-agent/core/tools/edit.js +324 -0
- package/dist/pi/coding-agent/core/tools/file-mutation-queue.js +36 -0
- package/dist/pi/coding-agent/core/tools/find.js +297 -0
- package/dist/pi/coding-agent/core/tools/grep.js +303 -0
- package/dist/pi/coding-agent/core/tools/index.js +111 -0
- package/dist/pi/coding-agent/core/tools/ls.js +168 -0
- package/dist/pi/coding-agent/core/tools/output-accumulator.js +183 -0
- package/dist/pi/coding-agent/core/tools/path-utils.js +61 -0
- package/dist/pi/coding-agent/core/tools/read.js +288 -0
- package/dist/pi/coding-agent/core/tools/render-utils.js +48 -0
- package/dist/pi/coding-agent/core/tools/tool-definition-wrapper.js +33 -0
- package/dist/pi/coding-agent/core/tools/truncate.js +214 -0
- package/dist/pi/coding-agent/core/tools/write.js +212 -0
- package/dist/pi/coding-agent/index.js +41 -0
- package/dist/pi/coding-agent/main.js +5 -0
- package/dist/pi/coding-agent/migrations.js +280 -0
- package/dist/pi/coding-agent/modes/index.js +7 -0
- package/dist/pi/coding-agent/modes/interactive/components/diff.js +132 -0
- package/dist/pi/coding-agent/modes/interactive/components/keybinding-hints.js +35 -0
- package/dist/pi/coding-agent/modes/interactive/components/visual-truncate.js +32 -0
- package/dist/pi/coding-agent/modes/interactive/interactive-mode.js +3 -0
- package/dist/pi/coding-agent/modes/interactive/theme/theme.js +1023 -0
- package/dist/pi/coding-agent/modes/print-mode.js +130 -0
- package/dist/pi/coding-agent/modes/rpc/jsonl.js +48 -0
- package/dist/pi/coding-agent/modes/rpc/rpc-client.js +409 -0
- package/dist/pi/coding-agent/modes/rpc/rpc-mode.js +600 -0
- package/dist/pi/coding-agent/modes/rpc/rpc-types.js +7 -0
- package/dist/pi/coding-agent/utils/ansi.js +51 -0
- package/dist/pi/coding-agent/utils/changelog.js +86 -0
- package/dist/pi/coding-agent/utils/child-process.js +87 -0
- package/dist/pi/coding-agent/utils/clipboard-image.js +244 -0
- package/dist/pi/coding-agent/utils/clipboard-native.js +13 -0
- package/dist/pi/coding-agent/utils/clipboard.js +116 -0
- package/dist/pi/coding-agent/utils/exif-orientation.js +157 -0
- package/dist/pi/coding-agent/utils/frontmatter.js +25 -0
- package/dist/pi/coding-agent/utils/fs-watch.js +24 -0
- package/dist/pi/coding-agent/utils/git.js +162 -0
- package/dist/pi/coding-agent/utils/html.js +39 -0
- package/dist/pi/coding-agent/utils/image-convert.js +38 -0
- package/dist/pi/coding-agent/utils/image-resize.js +136 -0
- package/dist/pi/coding-agent/utils/mime.js +68 -0
- package/dist/pi/coding-agent/utils/paths.js +91 -0
- package/dist/pi/coding-agent/utils/photon.js +120 -0
- package/dist/pi/coding-agent/utils/pi-user-agent.js +4 -0
- package/dist/pi/coding-agent/utils/shell.js +194 -0
- package/dist/pi/coding-agent/utils/sleep.js +16 -0
- package/dist/pi/coding-agent/utils/syntax-highlight.js +117 -0
- package/dist/pi/coding-agent/utils/tools-manager.js +327 -0
- package/dist/pi/coding-agent/utils/version-check.js +81 -0
- package/dist/pi/coding-agent/utils/windows-self-update.js +76 -0
- package/dist/pi/tui/autocomplete.js +631 -0
- package/dist/pi/tui/components/box.js +103 -0
- package/dist/pi/tui/components/cancellable-loader.js +34 -0
- package/dist/pi/tui/components/editor.js +1915 -0
- package/dist/pi/tui/components/image.js +88 -0
- package/dist/pi/tui/components/input.js +425 -0
- package/dist/pi/tui/components/loader.js +68 -0
- package/dist/pi/tui/components/markdown.js +633 -0
- package/dist/pi/tui/components/select-list.js +158 -0
- package/dist/pi/tui/components/settings-list.js +184 -0
- package/dist/pi/tui/components/spacer.js +22 -0
- package/dist/pi/tui/components/text.js +88 -0
- package/dist/pi/tui/components/truncated-text.js +50 -0
- package/dist/pi/tui/editor-component.js +1 -0
- package/dist/pi/tui/fuzzy.js +109 -0
- package/dist/pi/tui/index.js +31 -0
- package/dist/pi/tui/keybindings.js +173 -0
- package/dist/pi/tui/keys.js +1172 -0
- package/dist/pi/tui/kill-ring.js +43 -0
- package/dist/pi/tui/stdin-buffer.js +360 -0
- package/dist/pi/tui/terminal-image.js +335 -0
- package/dist/pi/tui/terminal.js +324 -0
- package/dist/pi/tui/tui.js +1076 -0
- package/dist/pi/tui/undo-stack.js +24 -0
- package/dist/pi/tui/utils.js +1016 -0
- package/dist/relay/dispatcher.js +30 -0
- package/dist/server/handlers/queue.js +52 -0
- package/dist/server/pi-bridge.js +9 -1
- package/dist/server/session-stream.js +76 -111
- package/dist/server/storage.js +154 -2
- package/dist/server/title-generator.js +14 -153
- package/package.json +24 -6
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { Agent } from "../../agent-core/index.js";
|
|
3
|
+
import { clampThinkingLevel, streamSimple } from "../../ai/index.js";
|
|
4
|
+
import { getAgentDir } from "../config.js";
|
|
5
|
+
import { resolvePath } from "../utils/paths.js";
|
|
6
|
+
import { AgentSession } from "./agent-session.js";
|
|
7
|
+
import { formatNoModelsAvailableMessage } from "./auth-guidance.js";
|
|
8
|
+
import { AuthStorage } from "./auth-storage.js";
|
|
9
|
+
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
10
|
+
import { convertToLlm } from "./messages.js";
|
|
11
|
+
import { ModelRegistry } from "./model-registry.js";
|
|
12
|
+
import { findInitialModel } from "./model-resolver.js";
|
|
13
|
+
import { DefaultResourceLoader } from "./resource-loader.js";
|
|
14
|
+
import { getDefaultSessionDir, SessionManager } from "./session-manager.js";
|
|
15
|
+
import { SettingsManager } from "./settings-manager.js";
|
|
16
|
+
import { isInstallTelemetryEnabled } from "./telemetry.js";
|
|
17
|
+
import { time } from "./timings.js";
|
|
18
|
+
import { createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createReadOnlyTools, createReadTool, createWriteTool, withFileMutationQueue, } from "./tools/index.js";
|
|
19
|
+
// Re-exports
|
|
20
|
+
export * from "./agent-session-runtime.js";
|
|
21
|
+
export { withFileMutationQueue,
|
|
22
|
+
// Tool factories (for custom cwd)
|
|
23
|
+
createCodingTools, createReadOnlyTools, createReadTool, createBashTool, createEditTool, createWriteTool, createGrepTool, createFindTool, createLsTool, };
|
|
24
|
+
// Helper Functions
|
|
25
|
+
function getDefaultAgentDir() {
|
|
26
|
+
return getAgentDir();
|
|
27
|
+
}
|
|
28
|
+
function getAttributionHeaders(model, settingsManager) {
|
|
29
|
+
if (!isInstallTelemetryEnabled(settingsManager)) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
if (model.provider === "openrouter" || model.baseUrl.includes("openrouter.ai")) {
|
|
33
|
+
return {
|
|
34
|
+
"HTTP-Referer": "https://pi.dev",
|
|
35
|
+
"X-OpenRouter-Title": "pi",
|
|
36
|
+
"X-OpenRouter-Categories": "cli-agent",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (model.provider === "cloudflare-workers-ai" ||
|
|
40
|
+
model.provider === "cloudflare-ai-gateway" ||
|
|
41
|
+
model.baseUrl.includes("api.cloudflare.com") ||
|
|
42
|
+
model.baseUrl.includes("gateway.ai.cloudflare.com")) {
|
|
43
|
+
return {
|
|
44
|
+
"User-Agent": "pi-coding-agent",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create an AgentSession with the specified options.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* // Minimal - uses defaults
|
|
55
|
+
* const { session } = await createAgentSession();
|
|
56
|
+
*
|
|
57
|
+
* // With explicit model
|
|
58
|
+
* import { getModel } from '../../ai/index.js';
|
|
59
|
+
* const { session } = await createAgentSession({
|
|
60
|
+
* model: getModel('anthropic', 'claude-opus-4-5'),
|
|
61
|
+
* thinkingLevel: 'high',
|
|
62
|
+
* });
|
|
63
|
+
*
|
|
64
|
+
* // Continue previous session
|
|
65
|
+
* const { session, modelFallbackMessage } = await createAgentSession({
|
|
66
|
+
* continueSession: true,
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* // Full control
|
|
70
|
+
* const loader = new DefaultResourceLoader({
|
|
71
|
+
* cwd: process.cwd(),
|
|
72
|
+
* agentDir: getAgentDir(),
|
|
73
|
+
* settingsManager: SettingsManager.create(),
|
|
74
|
+
* });
|
|
75
|
+
* await loader.reload();
|
|
76
|
+
* const { session } = await createAgentSession({
|
|
77
|
+
* model: myModel,
|
|
78
|
+
* tools: ["read", "bash"],
|
|
79
|
+
* resourceLoader: loader,
|
|
80
|
+
* sessionManager: SessionManager.inMemory(),
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export async function createAgentSession(options = {}) {
|
|
85
|
+
const cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());
|
|
86
|
+
const agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();
|
|
87
|
+
let resourceLoader = options.resourceLoader;
|
|
88
|
+
// Use provided or create AuthStorage and ModelRegistry
|
|
89
|
+
const authPath = options.agentDir ? join(agentDir, "auth.json") : undefined;
|
|
90
|
+
const modelsPath = options.agentDir ? join(agentDir, "models.json") : undefined;
|
|
91
|
+
const authStorage = options.authStorage ?? AuthStorage.create(authPath);
|
|
92
|
+
const modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, modelsPath);
|
|
93
|
+
const settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);
|
|
94
|
+
const sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));
|
|
95
|
+
if (!resourceLoader) {
|
|
96
|
+
resourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });
|
|
97
|
+
await resourceLoader.reload();
|
|
98
|
+
time("resourceLoader.reload");
|
|
99
|
+
}
|
|
100
|
+
// Check if session has existing data to restore
|
|
101
|
+
const existingSession = sessionManager.buildSessionContext();
|
|
102
|
+
const hasExistingSession = existingSession.messages.length > 0;
|
|
103
|
+
const hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === "thinking_level_change");
|
|
104
|
+
let model = options.model;
|
|
105
|
+
let modelFallbackMessage;
|
|
106
|
+
// If session has data, try to restore model from it
|
|
107
|
+
if (!model && hasExistingSession && existingSession.model) {
|
|
108
|
+
const restoredModel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);
|
|
109
|
+
if (restoredModel && modelRegistry.hasConfiguredAuth(restoredModel)) {
|
|
110
|
+
model = restoredModel;
|
|
111
|
+
}
|
|
112
|
+
if (!model) {
|
|
113
|
+
modelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// If still no model, use findInitialModel (checks settings default, then provider defaults)
|
|
117
|
+
if (!model) {
|
|
118
|
+
const result = await findInitialModel({
|
|
119
|
+
scopedModels: [],
|
|
120
|
+
isContinuing: hasExistingSession,
|
|
121
|
+
defaultProvider: settingsManager.getDefaultProvider(),
|
|
122
|
+
defaultModelId: settingsManager.getDefaultModel(),
|
|
123
|
+
defaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),
|
|
124
|
+
modelRegistry,
|
|
125
|
+
});
|
|
126
|
+
model = result.model;
|
|
127
|
+
if (!model) {
|
|
128
|
+
modelFallbackMessage = formatNoModelsAvailableMessage();
|
|
129
|
+
}
|
|
130
|
+
else if (modelFallbackMessage) {
|
|
131
|
+
modelFallbackMessage += `. Using ${model.provider}/${model.id}`;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
let thinkingLevel = options.thinkingLevel;
|
|
135
|
+
// If session has data, restore thinking level from it
|
|
136
|
+
if (thinkingLevel === undefined && hasExistingSession) {
|
|
137
|
+
thinkingLevel = hasThinkingEntry
|
|
138
|
+
? existingSession.thinkingLevel
|
|
139
|
+
: (settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);
|
|
140
|
+
}
|
|
141
|
+
// Fall back to settings default
|
|
142
|
+
if (thinkingLevel === undefined) {
|
|
143
|
+
thinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;
|
|
144
|
+
}
|
|
145
|
+
// Clamp to model capabilities
|
|
146
|
+
if (!model) {
|
|
147
|
+
thinkingLevel = "off";
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
thinkingLevel = clampThinkingLevel(model, thinkingLevel);
|
|
151
|
+
}
|
|
152
|
+
const defaultActiveToolNames = ["read", "bash", "edit", "write"];
|
|
153
|
+
const allowedToolNames = options.tools ?? (options.noTools === "all" ? [] : undefined);
|
|
154
|
+
const initialActiveToolNames = options.tools
|
|
155
|
+
? [...options.tools]
|
|
156
|
+
: options.noTools
|
|
157
|
+
? []
|
|
158
|
+
: defaultActiveToolNames;
|
|
159
|
+
let agent;
|
|
160
|
+
// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)
|
|
161
|
+
const convertToLlmWithBlockImages = (messages) => {
|
|
162
|
+
const converted = convertToLlm(messages);
|
|
163
|
+
// Check setting dynamically so mid-session changes take effect
|
|
164
|
+
if (!settingsManager.getBlockImages()) {
|
|
165
|
+
return converted;
|
|
166
|
+
}
|
|
167
|
+
// Filter out ImageContent from all messages, replacing with text placeholder
|
|
168
|
+
return converted.map((msg) => {
|
|
169
|
+
if (msg.role === "user" || msg.role === "toolResult") {
|
|
170
|
+
const content = msg.content;
|
|
171
|
+
if (Array.isArray(content)) {
|
|
172
|
+
const hasImages = content.some((c) => c.type === "image");
|
|
173
|
+
if (hasImages) {
|
|
174
|
+
const filteredContent = content
|
|
175
|
+
.map((c) => c.type === "image" ? { type: "text", text: "Image reading is disabled." } : c)
|
|
176
|
+
.filter((c, i, arr) =>
|
|
177
|
+
// Dedupe consecutive "Image reading is disabled." texts
|
|
178
|
+
!(c.type === "text" &&
|
|
179
|
+
c.text === "Image reading is disabled." &&
|
|
180
|
+
i > 0 &&
|
|
181
|
+
arr[i - 1].type === "text" &&
|
|
182
|
+
arr[i - 1].text === "Image reading is disabled."));
|
|
183
|
+
return { ...msg, content: filteredContent };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return msg;
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
const extensionRunnerRef = {};
|
|
191
|
+
agent = new Agent({
|
|
192
|
+
initialState: {
|
|
193
|
+
systemPrompt: "",
|
|
194
|
+
model,
|
|
195
|
+
thinkingLevel,
|
|
196
|
+
tools: [],
|
|
197
|
+
},
|
|
198
|
+
convertToLlm: convertToLlmWithBlockImages,
|
|
199
|
+
streamFn: async (model, context, options) => {
|
|
200
|
+
const auth = await modelRegistry.getApiKeyAndHeaders(model);
|
|
201
|
+
if (!auth.ok) {
|
|
202
|
+
throw new Error(auth.error);
|
|
203
|
+
}
|
|
204
|
+
const providerRetrySettings = settingsManager.getProviderRetrySettings();
|
|
205
|
+
const attributionHeaders = getAttributionHeaders(model, settingsManager);
|
|
206
|
+
return streamSimple(model, context, {
|
|
207
|
+
...options,
|
|
208
|
+
apiKey: auth.apiKey,
|
|
209
|
+
timeoutMs: options?.timeoutMs ?? providerRetrySettings.timeoutMs,
|
|
210
|
+
maxRetries: options?.maxRetries ?? providerRetrySettings.maxRetries,
|
|
211
|
+
maxRetryDelayMs: options?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,
|
|
212
|
+
headers: attributionHeaders || auth.headers || options?.headers
|
|
213
|
+
? { ...attributionHeaders, ...auth.headers, ...options?.headers }
|
|
214
|
+
: undefined,
|
|
215
|
+
});
|
|
216
|
+
},
|
|
217
|
+
onPayload: async (payload, _model) => {
|
|
218
|
+
const runner = extensionRunnerRef.current;
|
|
219
|
+
if (!runner?.hasHandlers("before_provider_request")) {
|
|
220
|
+
return payload;
|
|
221
|
+
}
|
|
222
|
+
return runner.emitBeforeProviderRequest(payload);
|
|
223
|
+
},
|
|
224
|
+
onResponse: async (response, _model) => {
|
|
225
|
+
const runner = extensionRunnerRef.current;
|
|
226
|
+
if (!runner?.hasHandlers("after_provider_response")) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
await runner.emit({
|
|
230
|
+
type: "after_provider_response",
|
|
231
|
+
status: response.status,
|
|
232
|
+
headers: response.headers,
|
|
233
|
+
});
|
|
234
|
+
},
|
|
235
|
+
sessionId: sessionManager.getSessionId(),
|
|
236
|
+
transformContext: async (messages) => {
|
|
237
|
+
const runner = extensionRunnerRef.current;
|
|
238
|
+
if (!runner)
|
|
239
|
+
return messages;
|
|
240
|
+
return runner.emitContext(messages);
|
|
241
|
+
},
|
|
242
|
+
steeringMode: settingsManager.getSteeringMode(),
|
|
243
|
+
followUpMode: settingsManager.getFollowUpMode(),
|
|
244
|
+
transport: settingsManager.getTransport(),
|
|
245
|
+
thinkingBudgets: settingsManager.getThinkingBudgets(),
|
|
246
|
+
maxRetryDelayMs: settingsManager.getProviderRetrySettings().maxRetryDelayMs,
|
|
247
|
+
});
|
|
248
|
+
// Restore messages if session has existing data
|
|
249
|
+
if (hasExistingSession) {
|
|
250
|
+
agent.state.messages = existingSession.messages;
|
|
251
|
+
if (!hasThinkingEntry) {
|
|
252
|
+
sessionManager.appendThinkingLevelChange(thinkingLevel);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
// Save initial model and thinking level for new sessions so they can be restored on resume
|
|
257
|
+
if (model) {
|
|
258
|
+
sessionManager.appendModelChange(model.provider, model.id);
|
|
259
|
+
}
|
|
260
|
+
sessionManager.appendThinkingLevelChange(thinkingLevel);
|
|
261
|
+
}
|
|
262
|
+
const session = new AgentSession({
|
|
263
|
+
agent,
|
|
264
|
+
sessionManager,
|
|
265
|
+
settingsManager,
|
|
266
|
+
cwd,
|
|
267
|
+
scopedModels: options.scopedModels,
|
|
268
|
+
resourceLoader,
|
|
269
|
+
customTools: options.customTools,
|
|
270
|
+
modelRegistry,
|
|
271
|
+
initialActiveToolNames,
|
|
272
|
+
allowedToolNames,
|
|
273
|
+
extensionRunnerRef,
|
|
274
|
+
sessionStartEvent: options.sessionStartEvent,
|
|
275
|
+
});
|
|
276
|
+
const extensionsResult = resourceLoader.getExtensions();
|
|
277
|
+
return {
|
|
278
|
+
session,
|
|
279
|
+
extensionsResult,
|
|
280
|
+
modelFallbackMessage,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
export function getMissingSessionCwdIssue(sessionManager, fallbackCwd) {
|
|
3
|
+
const sessionFile = sessionManager.getSessionFile();
|
|
4
|
+
if (!sessionFile) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
const sessionCwd = sessionManager.getCwd();
|
|
8
|
+
if (!sessionCwd || existsSync(sessionCwd)) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
sessionFile,
|
|
13
|
+
sessionCwd,
|
|
14
|
+
fallbackCwd,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function formatMissingSessionCwdError(issue) {
|
|
18
|
+
const sessionFile = issue.sessionFile ? `\nSession file: ${issue.sessionFile}` : "";
|
|
19
|
+
return `Stored session working directory does not exist: ${issue.sessionCwd}${sessionFile}\nCurrent working directory: ${issue.fallbackCwd}`;
|
|
20
|
+
}
|
|
21
|
+
export function formatMissingSessionCwdPrompt(issue) {
|
|
22
|
+
return `cwd from session file does not exist\n${issue.sessionCwd}\n\ncontinue in current cwd\n${issue.fallbackCwd}`;
|
|
23
|
+
}
|
|
24
|
+
export class MissingSessionCwdError extends Error {
|
|
25
|
+
issue;
|
|
26
|
+
constructor(issue) {
|
|
27
|
+
super(formatMissingSessionCwdError(issue));
|
|
28
|
+
this.name = "MissingSessionCwdError";
|
|
29
|
+
this.issue = issue;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function assertSessionCwdExists(sessionManager, fallbackCwd) {
|
|
33
|
+
const issue = getMissingSessionCwdIssue(sessionManager, fallbackCwd);
|
|
34
|
+
if (issue) {
|
|
35
|
+
throw new MissingSessionCwdError(issue);
|
|
36
|
+
}
|
|
37
|
+
}
|