@psnext/slingcli 2.4.20260601-1 → 2.5.20260602-2
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/node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler/package.json +4 -4
- package/node_modules/@aws-sdk/credential-provider-node/dist-cjs/index.js +12 -1
- package/node_modules/@aws-sdk/credential-provider-node/dist-es/runtime/memoize-chain.js +12 -1
- package/node_modules/@aws-sdk/credential-provider-node/package.json +1 -1
- package/node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler/package.json +4 -4
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +81 -18
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +14 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +197 -190
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +84 -21
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +24 -14
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +5 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.js +5 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +2 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js +2 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +130 -62
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +18 -12
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +4 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +5 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/stream.js +14 -2
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js +34 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +8 -7
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +179 -79
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js +27 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +9 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +29 -5
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js +21 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/footer-data-provider.js +29 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +65 -13
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js +134 -11
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +12 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +167 -96
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +14 -9
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +0 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js +7 -10
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js +5 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +6 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js +17 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +5 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/index.js +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +69 -16
- package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js +118 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +2 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +61 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/print-mode.js +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +4 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.js +13 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js +7 -0
- package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +71 -56
- package/node_modules/@earendil-works/pi-coding-agent/package.json +7 -7
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +9 -53
- package/node_modules/@earendil-works/pi-tui/dist/components/input.js +6 -54
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +34 -7
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js +172 -37
- package/node_modules/@earendil-works/pi-tui/dist/tui.js +166 -22
- package/node_modules/@earendil-works/pi-tui/dist/utils.js +8 -3
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js +96 -0
- package/node_modules/@earendil-works/pi-tui/package.json +2 -2
- package/node_modules/@mariozechner/clipboard/Cargo.toml +3 -3
- package/node_modules/@mariozechner/clipboard/index.d.ts +34 -20
- package/node_modules/@mariozechner/clipboard/index.js +546 -257
- package/node_modules/@mariozechner/clipboard/package.json +14 -14
- package/node_modules/@mariozechner/clipboard/src/lib.rs +4 -9
- package/node_modules/@mariozechner/clipboard-linux-x64-gnu/clipboard.linux-x64-gnu.node +0 -0
- package/node_modules/@mariozechner/clipboard-linux-x64-gnu/package.json +2 -2
- package/node_modules/@smithy/core/dist-cjs/submodules/retry/index.browser.js +39 -22
- package/node_modules/@smithy/core/dist-cjs/submodules/retry/index.js +39 -22
- package/node_modules/@smithy/core/dist-es/submodules/retry/middleware-retry/configurations.js +19 -6
- package/node_modules/@smithy/core/dist-es/submodules/retry/middleware-retry/retryMiddleware.js +4 -5
- package/node_modules/@smithy/core/dist-es/submodules/retry/service-error-classification/constants.js +1 -1
- package/node_modules/@smithy/core/dist-es/submodules/retry/util-retry/ConfiguredRetryStrategy.js +4 -5
- package/node_modules/@smithy/core/dist-es/submodules/retry/util-retry/DefaultRetryToken.js +3 -0
- package/node_modules/@smithy/core/dist-es/submodules/retry/util-retry/StandardRetryStrategy.js +9 -5
- package/node_modules/@smithy/core/dist-types/submodules/retry/middleware-retry/configurations.d.ts +4 -1
- package/node_modules/@smithy/core/dist-types/submodules/retry/util-retry/ConfiguredRetryStrategy.d.ts +1 -2
- package/node_modules/@smithy/core/dist-types/submodules/retry/util-retry/DefaultRetryToken.d.ts +3 -0
- package/node_modules/@smithy/core/dist-types/submodules/retry/util-retry/StandardRetryStrategy.d.ts +1 -1
- package/node_modules/@smithy/core/package.json +2 -2
- package/node_modules/@smithy/credential-provider-imds/package.json +3 -3
- package/node_modules/@smithy/fetch-http-handler/package.json +4 -4
- package/node_modules/@smithy/signature-v4/package.json +3 -3
- package/node_modules/@smithy/types/dist-types/retry.d.ts +25 -0
- package/node_modules/@smithy/types/package.json +1 -1
- package/package.json +6 -6
- package/slingshot/index.js +231 -230
|
@@ -70,6 +70,15 @@ function resolveBranchWithGitAsync(repoDir) {
|
|
|
70
70
|
});
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
|
+
function isWslEnvironment() {
|
|
74
|
+
return process.platform === "linux" && !!(process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP);
|
|
75
|
+
}
|
|
76
|
+
function isWindowsMountedRepoPath(repoDir) {
|
|
77
|
+
return /^\/mnt\/[a-z](?:\/|$)/i.test(repoDir);
|
|
78
|
+
}
|
|
79
|
+
function shouldPollGitHead(repoDir) {
|
|
80
|
+
return isWslEnvironment() && isWindowsMountedRepoPath(repoDir);
|
|
81
|
+
}
|
|
73
82
|
/**
|
|
74
83
|
* Provides git branch and extension statuses - data not otherwise accessible to extensions.
|
|
75
84
|
* Token stats, model info available via ctx.sessionManager and ctx.model.
|
|
@@ -81,6 +90,8 @@ export class FooterDataProvider {
|
|
|
81
90
|
cachedBranch = undefined;
|
|
82
91
|
gitPaths = undefined;
|
|
83
92
|
headWatcher = null;
|
|
93
|
+
headWatchFilePath = null;
|
|
94
|
+
headWatchFileListener = null;
|
|
84
95
|
reftableWatcher = null;
|
|
85
96
|
reftableTablesListWatcher = null;
|
|
86
97
|
reftableTablesListPath = null;
|
|
@@ -236,6 +247,11 @@ export class FooterDataProvider {
|
|
|
236
247
|
clearGitWatchers() {
|
|
237
248
|
closeWatcher(this.headWatcher);
|
|
238
249
|
this.headWatcher = null;
|
|
250
|
+
if (this.headWatchFilePath && this.headWatchFileListener) {
|
|
251
|
+
unwatchFile(this.headWatchFilePath, this.headWatchFileListener);
|
|
252
|
+
this.headWatchFilePath = null;
|
|
253
|
+
this.headWatchFileListener = null;
|
|
254
|
+
}
|
|
239
255
|
closeWatcher(this.reftableWatcher);
|
|
240
256
|
this.reftableWatcher = null;
|
|
241
257
|
closeWatcher(this.reftableTablesListWatcher);
|
|
@@ -266,6 +282,7 @@ export class FooterDataProvider {
|
|
|
266
282
|
this.clearGitWatchers();
|
|
267
283
|
if (!this.gitPaths)
|
|
268
284
|
return;
|
|
285
|
+
const pollGitHead = shouldPollGitHead(this.gitPaths.repoDir);
|
|
269
286
|
// Watch the directory containing HEAD, not HEAD itself.
|
|
270
287
|
// Git uses atomic writes (write temp, rename over HEAD), which changes the inode.
|
|
271
288
|
// fs.watch on a file stops working after the inode changes.
|
|
@@ -274,7 +291,18 @@ export class FooterDataProvider {
|
|
|
274
291
|
this.scheduleRefresh();
|
|
275
292
|
}
|
|
276
293
|
}, () => this.handleGitWatcherError());
|
|
277
|
-
if (
|
|
294
|
+
if (pollGitHead) {
|
|
295
|
+
this.headWatchFilePath = this.gitPaths.headPath;
|
|
296
|
+
this.headWatchFileListener = (current, previous) => {
|
|
297
|
+
if (current.mtimeMs !== previous.mtimeMs ||
|
|
298
|
+
current.ctimeMs !== previous.ctimeMs ||
|
|
299
|
+
current.size !== previous.size) {
|
|
300
|
+
this.scheduleRefresh();
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
watchFile(this.headWatchFilePath, { interval: 1000 }, this.headWatchFileListener);
|
|
304
|
+
}
|
|
305
|
+
if (!this.headWatcher && !pollGitHead) {
|
|
278
306
|
return;
|
|
279
307
|
}
|
|
280
308
|
// In reftable repos, branch switches update files in the reftable directory
|
|
@@ -8,9 +8,11 @@ import { join } from "path";
|
|
|
8
8
|
import { Type } from "typebox";
|
|
9
9
|
import { Compile } from "typebox/compile";
|
|
10
10
|
import { getAgentDir } from "../config.js";
|
|
11
|
+
import { warnDeprecation } from "../utils/deprecation.js";
|
|
12
|
+
import { stripJsonComments } from "../utils/json.js";
|
|
11
13
|
import { normalizePath } from "../utils/paths.js";
|
|
12
14
|
import { BUILT_IN_PROVIDER_DISPLAY_NAMES } from "./provider-display-names.js";
|
|
13
|
-
import { clearConfigValueCache, resolveConfigValueOrThrow, resolveConfigValueUncached, resolveHeadersOrThrow, } from "./resolve-config-value.js";
|
|
15
|
+
import { clearConfigValueCache, getConfigValueEnvVarNames, isCommandConfigValue, isConfigValueConfigured, isLegacyEnvVarNameConfigValue, resolveConfigValueOrThrow, resolveConfigValueUncached, resolveHeadersOrThrow, } from "./resolve-config-value.js";
|
|
14
16
|
// Schema for OpenRouter routing preferences
|
|
15
17
|
const PercentileCutoffsSchema = Type.Object({
|
|
16
18
|
p50: Type.Optional(Type.Number()),
|
|
@@ -166,11 +168,56 @@ function formatValidationPath(error) {
|
|
|
166
168
|
const path = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
|
|
167
169
|
return path || "root";
|
|
168
170
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
function migrateLegacyRegisterProviderConfigValue(providerName, field, value) {
|
|
172
|
+
if (!isLegacyEnvVarNameConfigValue(value))
|
|
173
|
+
return value;
|
|
174
|
+
warnDeprecation(`registerProvider("${providerName}") ${field} value "${value}" is treated as a legacy environment variable reference. This will no longer be detected as an environment variable reference in a future release. Pass "$${value}" instead.`);
|
|
175
|
+
return `$${value}`;
|
|
176
|
+
}
|
|
177
|
+
function migrateLegacyRegisterProviderHeaders(providerName, field, headers) {
|
|
178
|
+
if (!headers)
|
|
179
|
+
return undefined;
|
|
180
|
+
let migratedHeaders;
|
|
181
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
182
|
+
const migratedValue = migrateLegacyRegisterProviderConfigValue(providerName, `${field} header "${key}"`, value);
|
|
183
|
+
if (migratedValue === value)
|
|
184
|
+
continue;
|
|
185
|
+
migratedHeaders ??= { ...headers };
|
|
186
|
+
migratedHeaders[key] = migratedValue;
|
|
187
|
+
}
|
|
188
|
+
return migratedHeaders ?? headers;
|
|
189
|
+
}
|
|
190
|
+
function migrateLegacyRegisterProviderConfigValues(providerName, config) {
|
|
191
|
+
let migratedConfig;
|
|
192
|
+
const setMigratedConfigValue = (key, value) => {
|
|
193
|
+
migratedConfig ??= { ...config };
|
|
194
|
+
migratedConfig[key] = value;
|
|
195
|
+
};
|
|
196
|
+
if (config.apiKey) {
|
|
197
|
+
const apiKey = migrateLegacyRegisterProviderConfigValue(providerName, "apiKey", config.apiKey);
|
|
198
|
+
if (apiKey !== config.apiKey) {
|
|
199
|
+
setMigratedConfigValue("apiKey", apiKey);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const headers = migrateLegacyRegisterProviderHeaders(providerName, "headers", config.headers);
|
|
203
|
+
if (headers !== config.headers) {
|
|
204
|
+
setMigratedConfigValue("headers", headers);
|
|
205
|
+
}
|
|
206
|
+
if (config.models) {
|
|
207
|
+
let models;
|
|
208
|
+
for (let index = 0; index < config.models.length; index++) {
|
|
209
|
+
const model = config.models[index];
|
|
210
|
+
const modelHeaders = migrateLegacyRegisterProviderHeaders(providerName, `model "${model.id}" headers`, model.headers);
|
|
211
|
+
if (modelHeaders === model.headers)
|
|
212
|
+
continue;
|
|
213
|
+
models ??= [...config.models];
|
|
214
|
+
models[index] = { ...model, headers: modelHeaders };
|
|
215
|
+
}
|
|
216
|
+
if (models) {
|
|
217
|
+
setMigratedConfigValue("models", models);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return migratedConfig ?? config;
|
|
174
221
|
}
|
|
175
222
|
function emptyCustomModelsResult(error) {
|
|
176
223
|
return { models: [], overrides: new Map(), modelOverrides: new Map(), error };
|
|
@@ -491,8 +538,9 @@ export class ModelRegistry {
|
|
|
491
538
|
* Get API key for a model.
|
|
492
539
|
*/
|
|
493
540
|
hasConfiguredAuth(model) {
|
|
541
|
+
const providerApiKey = this.providerRequestConfigs.get(model.provider)?.apiKey;
|
|
494
542
|
return (this.authStorage.hasAuth(model.provider) ||
|
|
495
|
-
|
|
543
|
+
(providerApiKey !== undefined && isConfigValueConfigured(providerApiKey)));
|
|
496
544
|
}
|
|
497
545
|
getModelRequestKey(provider, modelId) {
|
|
498
546
|
return `${provider}:${modelId}`;
|
|
@@ -563,11 +611,14 @@ export class ModelRegistry {
|
|
|
563
611
|
if (!providerApiKey) {
|
|
564
612
|
return authStatus;
|
|
565
613
|
}
|
|
566
|
-
if (providerApiKey
|
|
614
|
+
if (isCommandConfigValue(providerApiKey)) {
|
|
567
615
|
return { configured: true, source: "models_json_command" };
|
|
568
616
|
}
|
|
569
|
-
|
|
570
|
-
|
|
617
|
+
const envVarNames = getConfigValueEnvVarNames(providerApiKey);
|
|
618
|
+
if (envVarNames.length > 0) {
|
|
619
|
+
return isConfigValueConfigured(providerApiKey)
|
|
620
|
+
? { configured: true, source: "environment", label: envVarNames.join(", ") }
|
|
621
|
+
: { configured: false };
|
|
571
622
|
}
|
|
572
623
|
return { configured: true, source: "models_json_key" };
|
|
573
624
|
}
|
|
@@ -609,9 +660,10 @@ export class ModelRegistry {
|
|
|
609
660
|
* If provider has oauth: registers OAuth provider for /login support.
|
|
610
661
|
*/
|
|
611
662
|
registerProvider(providerName, config) {
|
|
612
|
-
|
|
613
|
-
this.
|
|
614
|
-
this.
|
|
663
|
+
const migratedConfig = migrateLegacyRegisterProviderConfigValues(providerName, config);
|
|
664
|
+
this.validateProviderConfig(providerName, migratedConfig);
|
|
665
|
+
this.applyProviderConfig(providerName, migratedConfig);
|
|
666
|
+
this.upsertRegisteredProvider(providerName, migratedConfig);
|
|
615
667
|
}
|
|
616
668
|
/**
|
|
617
669
|
* Unregister a previously registered provider.
|
|
@@ -9,7 +9,7 @@ import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
|
9
9
|
/** Default model IDs for each known provider */
|
|
10
10
|
export const defaultModelPerProvider = {
|
|
11
11
|
"amazon-bedrock": "us.anthropic.claude-opus-4-6-v1",
|
|
12
|
-
anthropic: "claude-opus-4-
|
|
12
|
+
anthropic: "claude-opus-4-8",
|
|
13
13
|
openai: "gpt-5.4",
|
|
14
14
|
"azure-openai-responses": "gpt-5.4",
|
|
15
15
|
"openai-codex": "gpt-5.5",
|
|
@@ -6,17 +6,130 @@ import { execSync, spawnSync } from "child_process";
|
|
|
6
6
|
import { getShellConfig } from "../utils/shell.js";
|
|
7
7
|
// Cache for shell command results (persists for process lifetime)
|
|
8
8
|
const commandResultCache = new Map();
|
|
9
|
+
const ENV_VAR_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
10
|
+
const ENV_VAR_NAME_PREFIX_RE = /^[A-Za-z_][A-Za-z0-9_]*/;
|
|
11
|
+
const LEGACY_ENV_VAR_NAME_RE = /^[A-Z_][A-Z0-9_]*$/;
|
|
12
|
+
function appendLiteral(parts, value) {
|
|
13
|
+
if (!value)
|
|
14
|
+
return;
|
|
15
|
+
const previousPart = parts[parts.length - 1];
|
|
16
|
+
if (previousPart?.type === "literal") {
|
|
17
|
+
previousPart.value += value;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
parts.push({ type: "literal", value });
|
|
21
|
+
}
|
|
22
|
+
function parseConfigValueTemplate(config) {
|
|
23
|
+
const parts = [];
|
|
24
|
+
let index = 0;
|
|
25
|
+
while (index < config.length) {
|
|
26
|
+
const dollarIndex = config.indexOf("$", index);
|
|
27
|
+
if (dollarIndex < 0) {
|
|
28
|
+
appendLiteral(parts, config.slice(index));
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
appendLiteral(parts, config.slice(index, dollarIndex));
|
|
32
|
+
const nextChar = config[dollarIndex + 1];
|
|
33
|
+
if (nextChar === "$" || nextChar === "!") {
|
|
34
|
+
appendLiteral(parts, nextChar);
|
|
35
|
+
index = dollarIndex + 2;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (nextChar === "{") {
|
|
39
|
+
const endIndex = config.indexOf("}", dollarIndex + 2);
|
|
40
|
+
if (endIndex < 0) {
|
|
41
|
+
appendLiteral(parts, "$");
|
|
42
|
+
index = dollarIndex + 1;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const name = config.slice(dollarIndex + 2, endIndex);
|
|
46
|
+
if (ENV_VAR_NAME_RE.test(name)) {
|
|
47
|
+
parts.push({ type: "env", name });
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
appendLiteral(parts, config.slice(dollarIndex, endIndex + 1));
|
|
51
|
+
}
|
|
52
|
+
index = endIndex + 1;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const match = config.slice(dollarIndex + 1).match(ENV_VAR_NAME_PREFIX_RE);
|
|
56
|
+
if (match) {
|
|
57
|
+
parts.push({ type: "env", name: match[0] });
|
|
58
|
+
index = dollarIndex + 1 + match[0].length;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
appendLiteral(parts, "$");
|
|
62
|
+
index = dollarIndex + 1;
|
|
63
|
+
}
|
|
64
|
+
return parts;
|
|
65
|
+
}
|
|
66
|
+
function parseConfigValueReference(config) {
|
|
67
|
+
if (config.startsWith("!")) {
|
|
68
|
+
return { type: "command", config };
|
|
69
|
+
}
|
|
70
|
+
return { type: "template", parts: parseConfigValueTemplate(config) };
|
|
71
|
+
}
|
|
72
|
+
function resolveEnvConfigValue(name) {
|
|
73
|
+
return process.env[name] || undefined;
|
|
74
|
+
}
|
|
75
|
+
function getTemplateEnvVarNames(parts) {
|
|
76
|
+
const names = [];
|
|
77
|
+
for (const part of parts) {
|
|
78
|
+
if (part.type !== "env" || names.includes(part.name))
|
|
79
|
+
continue;
|
|
80
|
+
names.push(part.name);
|
|
81
|
+
}
|
|
82
|
+
return names;
|
|
83
|
+
}
|
|
84
|
+
function resolveTemplate(parts) {
|
|
85
|
+
let resolved = "";
|
|
86
|
+
for (const part of parts) {
|
|
87
|
+
if (part.type === "literal") {
|
|
88
|
+
resolved += part.value;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const envValue = resolveEnvConfigValue(part.name);
|
|
92
|
+
if (envValue === undefined)
|
|
93
|
+
return undefined;
|
|
94
|
+
resolved += envValue;
|
|
95
|
+
}
|
|
96
|
+
return resolved;
|
|
97
|
+
}
|
|
98
|
+
export function getConfigValueEnvVarName(config) {
|
|
99
|
+
const reference = parseConfigValueReference(config);
|
|
100
|
+
if (reference.type !== "template")
|
|
101
|
+
return undefined;
|
|
102
|
+
return reference.parts.length === 1 && reference.parts[0]?.type === "env" ? reference.parts[0].name : undefined;
|
|
103
|
+
}
|
|
104
|
+
export function getConfigValueEnvVarNames(config) {
|
|
105
|
+
const reference = parseConfigValueReference(config);
|
|
106
|
+
return reference.type === "template" ? getTemplateEnvVarNames(reference.parts) : [];
|
|
107
|
+
}
|
|
108
|
+
export function getMissingConfigValueEnvVarNames(config) {
|
|
109
|
+
return getConfigValueEnvVarNames(config).filter((name) => resolveEnvConfigValue(name) === undefined);
|
|
110
|
+
}
|
|
111
|
+
export function isCommandConfigValue(config) {
|
|
112
|
+
return parseConfigValueReference(config).type === "command";
|
|
113
|
+
}
|
|
114
|
+
export function isConfigValueConfigured(config) {
|
|
115
|
+
return getMissingConfigValueEnvVarNames(config).length === 0;
|
|
116
|
+
}
|
|
117
|
+
export function isLegacyEnvVarNameConfigValue(config) {
|
|
118
|
+
return LEGACY_ENV_VAR_NAME_RE.test(config);
|
|
119
|
+
}
|
|
9
120
|
/**
|
|
10
121
|
* Resolve a config value (API key, header value, etc.) to an actual value.
|
|
11
122
|
* - If starts with "!", executes the rest as a shell command and uses stdout (cached)
|
|
12
|
-
* -
|
|
123
|
+
* - Interpolates "$ENV_VAR" or "${ENV_VAR}" references with the named environment variable
|
|
124
|
+
* - In non-command values, "$$" escapes a literal "$" and "$!" escapes a literal "!"
|
|
125
|
+
* - Otherwise treats the value as a literal
|
|
13
126
|
*/
|
|
14
127
|
export function resolveConfigValue(config) {
|
|
15
|
-
|
|
16
|
-
|
|
128
|
+
const reference = parseConfigValueReference(config);
|
|
129
|
+
if (reference.type === "command") {
|
|
130
|
+
return executeCommand(reference.config);
|
|
17
131
|
}
|
|
18
|
-
|
|
19
|
-
return envValue || config;
|
|
132
|
+
return resolveTemplate(reference.parts);
|
|
20
133
|
}
|
|
21
134
|
function executeWithConfiguredShell(command) {
|
|
22
135
|
try {
|
|
@@ -79,19 +192,29 @@ function executeCommand(commandConfig) {
|
|
|
79
192
|
* Resolve all header values using the same resolution logic as API keys.
|
|
80
193
|
*/
|
|
81
194
|
export function resolveConfigValueUncached(config) {
|
|
82
|
-
|
|
83
|
-
|
|
195
|
+
const reference = parseConfigValueReference(config);
|
|
196
|
+
if (reference.type === "command") {
|
|
197
|
+
return executeCommandUncached(reference.config);
|
|
84
198
|
}
|
|
85
|
-
|
|
86
|
-
return envValue || config;
|
|
199
|
+
return resolveTemplate(reference.parts);
|
|
87
200
|
}
|
|
88
201
|
export function resolveConfigValueOrThrow(config, description) {
|
|
89
202
|
const resolvedValue = resolveConfigValueUncached(config);
|
|
90
203
|
if (resolvedValue !== undefined) {
|
|
91
204
|
return resolvedValue;
|
|
92
205
|
}
|
|
93
|
-
|
|
94
|
-
|
|
206
|
+
const reference = parseConfigValueReference(config);
|
|
207
|
+
if (reference.type === "command") {
|
|
208
|
+
throw new Error(`Failed to resolve ${description} from shell command: ${reference.config.slice(1)}`);
|
|
209
|
+
}
|
|
210
|
+
if (reference.type === "template") {
|
|
211
|
+
const missingEnvVars = getMissingConfigValueEnvVarNames(config);
|
|
212
|
+
if (missingEnvVars.length === 1) {
|
|
213
|
+
throw new Error(`Failed to resolve ${description} from environment variable: ${missingEnvVars[0]}`);
|
|
214
|
+
}
|
|
215
|
+
if (missingEnvVars.length > 1) {
|
|
216
|
+
throw new Error(`Failed to resolve ${description} from environment variables: ${missingEnvVars.join(", ")}`);
|
|
217
|
+
}
|
|
95
218
|
}
|
|
96
219
|
throw new Error(`Failed to resolve ${description}`);
|
|
97
220
|
}
|
|
@@ -155,11 +155,9 @@ export async function createAgentSession(options = {}) {
|
|
|
155
155
|
}
|
|
156
156
|
const defaultActiveToolNames = ["read", "bash", "edit", "write"];
|
|
157
157
|
const allowedToolNames = options.tools ?? (options.noTools === "all" ? [] : undefined);
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
? []
|
|
162
|
-
: defaultActiveToolNames;
|
|
158
|
+
const excludedToolNames = options.excludeTools;
|
|
159
|
+
const excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;
|
|
160
|
+
const initialActiveToolNames = (options.tools ? [...options.tools] : options.noTools ? [] : defaultActiveToolNames).filter((name) => !excludedToolNameSet?.has(name));
|
|
163
161
|
let agent;
|
|
164
162
|
// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)
|
|
165
163
|
const convertToLlmWithBlockImages = (messages) => {
|
|
@@ -206,11 +204,18 @@ export async function createAgentSession(options = {}) {
|
|
|
206
204
|
throw new Error(auth.error);
|
|
207
205
|
}
|
|
208
206
|
const providerRetrySettings = settingsManager.getProviderRetrySettings();
|
|
207
|
+
const httpIdleTimeoutMs = settingsManager.getHttpIdleTimeoutMs();
|
|
208
|
+
// SDKs treat timeout=0 as 0ms (immediate timeout), not "no timeout".
|
|
209
|
+
// Use max int32 to effectively disable the timeout.
|
|
210
|
+
const effectiveTimeoutMs = httpIdleTimeoutMs === 0 ? 2147483647 : httpIdleTimeoutMs;
|
|
211
|
+
const timeoutMs = options?.timeoutMs ?? providerRetrySettings.timeoutMs ?? effectiveTimeoutMs;
|
|
212
|
+
const websocketConnectTimeoutMs = options?.websocketConnectTimeoutMs ?? settingsManager.getWebSocketConnectTimeoutMs();
|
|
209
213
|
const attributionHeaders = getAttributionHeaders(model, settingsManager, options?.sessionId);
|
|
210
214
|
return streamSimple(model, context, {
|
|
211
215
|
...options,
|
|
212
216
|
apiKey: auth.apiKey,
|
|
213
|
-
timeoutMs
|
|
217
|
+
timeoutMs,
|
|
218
|
+
websocketConnectTimeoutMs,
|
|
214
219
|
maxRetries: options?.maxRetries ?? providerRetrySettings.maxRetries,
|
|
215
220
|
maxRetryDelayMs: options?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,
|
|
216
221
|
headers: attributionHeaders || auth.headers || options?.headers
|
|
@@ -274,6 +279,7 @@ export async function createAgentSession(options = {}) {
|
|
|
274
279
|
modelRegistry,
|
|
275
280
|
initialActiveToolNames,
|
|
276
281
|
allowedToolNames,
|
|
282
|
+
excludedToolNames,
|
|
277
283
|
extensionRunnerRef,
|
|
278
284
|
sessionStartEvent: options.sessionStartEvent,
|
|
279
285
|
});
|