@dexto/agent-management 1.4.0 → 1.5.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.
Files changed (78) hide show
  1. package/dist/AgentFactory.cjs +1 -2
  2. package/dist/AgentFactory.d.ts +1 -1
  3. package/dist/AgentFactory.d.ts.map +1 -1
  4. package/dist/AgentFactory.js +1 -2
  5. package/dist/config/config-enrichment.cjs +50 -1
  6. package/dist/config/config-enrichment.d.ts +2 -2
  7. package/dist/config/config-enrichment.d.ts.map +1 -1
  8. package/dist/config/config-enrichment.js +51 -3
  9. package/dist/config/discover-prompts.cjs +13 -0
  10. package/dist/config/discover-prompts.d.ts +13 -0
  11. package/dist/config/discover-prompts.d.ts.map +1 -1
  12. package/dist/config/discover-prompts.js +12 -0
  13. package/dist/config/errors.cjs +2 -2
  14. package/dist/config/errors.js +2 -2
  15. package/dist/index.cjs +69 -0
  16. package/dist/index.d.ts +4 -3
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +72 -2
  19. package/dist/installation.cjs +0 -13
  20. package/dist/installation.d.ts +0 -2
  21. package/dist/installation.d.ts.map +1 -1
  22. package/dist/installation.js +0 -13
  23. package/dist/models/custom-models.cjs +46 -2
  24. package/dist/models/custom-models.d.ts +54 -6
  25. package/dist/models/custom-models.d.ts.map +1 -1
  26. package/dist/models/custom-models.js +45 -2
  27. package/dist/models/index.cjs +89 -0
  28. package/dist/models/index.d.ts +11 -0
  29. package/dist/models/index.d.ts.map +1 -0
  30. package/dist/models/index.js +68 -0
  31. package/dist/models/path-resolver.cjs +154 -0
  32. package/dist/models/path-resolver.d.ts +77 -0
  33. package/dist/models/path-resolver.d.ts.map +1 -0
  34. package/dist/models/path-resolver.js +108 -0
  35. package/dist/models/state-manager.cjs +220 -0
  36. package/dist/models/state-manager.d.ts +138 -0
  37. package/dist/models/state-manager.d.ts.map +1 -0
  38. package/dist/models/state-manager.js +184 -0
  39. package/dist/preferences/error-codes.cjs +2 -0
  40. package/dist/preferences/error-codes.d.ts +3 -1
  41. package/dist/preferences/error-codes.d.ts.map +1 -1
  42. package/dist/preferences/error-codes.js +2 -0
  43. package/dist/preferences/index.d.ts +1 -1
  44. package/dist/preferences/index.d.ts.map +1 -1
  45. package/dist/preferences/loader.cjs +35 -6
  46. package/dist/preferences/loader.d.ts +25 -4
  47. package/dist/preferences/loader.d.ts.map +1 -1
  48. package/dist/preferences/loader.js +35 -6
  49. package/dist/preferences/schemas.cjs +24 -3
  50. package/dist/preferences/schemas.d.ts +64 -24
  51. package/dist/preferences/schemas.d.ts.map +1 -1
  52. package/dist/preferences/schemas.js +31 -4
  53. package/dist/registry/registry.cjs +7 -43
  54. package/dist/registry/registry.d.ts +3 -6
  55. package/dist/registry/registry.d.ts.map +1 -1
  56. package/dist/registry/registry.js +7 -43
  57. package/dist/registry/types.d.ts +2 -4
  58. package/dist/registry/types.d.ts.map +1 -1
  59. package/dist/resolver.cjs +20 -20
  60. package/dist/resolver.d.ts +1 -2
  61. package/dist/resolver.d.ts.map +1 -1
  62. package/dist/resolver.js +20 -20
  63. package/dist/utils/api-key-resolver.cjs +19 -1
  64. package/dist/utils/api-key-resolver.d.ts.map +1 -1
  65. package/dist/utils/api-key-resolver.js +19 -1
  66. package/dist/utils/api-key-store.cjs +46 -0
  67. package/dist/utils/api-key-store.d.ts +27 -0
  68. package/dist/utils/api-key-store.d.ts.map +1 -1
  69. package/dist/utils/api-key-store.js +44 -0
  70. package/dist/utils/env-file.cjs +20 -68
  71. package/dist/utils/env-file.d.ts +2 -1
  72. package/dist/utils/env-file.d.ts.map +1 -1
  73. package/dist/utils/env-file.js +20 -68
  74. package/dist/writer.cjs +20 -2
  75. package/dist/writer.d.ts +1 -0
  76. package/dist/writer.d.ts.map +1 -1
  77. package/dist/writer.js +20 -2
  78. package/package.json +2 -2
@@ -31,7 +31,25 @@ const PROVIDER_API_KEY_MAP = {
31
31
  google: ["GOOGLE_GENERATIVE_AI_API_KEY", "GOOGLE_API_KEY", "GEMINI_API_KEY"],
32
32
  groq: ["GROQ_API_KEY"],
33
33
  cohere: ["COHERE_API_KEY"],
34
- xai: ["XAI_API_KEY", "X_AI_API_KEY"]
34
+ xai: ["XAI_API_KEY", "X_AI_API_KEY"],
35
+ openrouter: ["OPENROUTER_API_KEY"],
36
+ litellm: ["LITELLM_API_KEY", "LITELLM_KEY"],
37
+ glama: ["GLAMA_API_KEY"],
38
+ // Vertex uses ADC (Application Default Credentials), not API keys
39
+ // GOOGLE_APPLICATION_CREDENTIALS points to service account JSON (optional)
40
+ // Primary config is GOOGLE_VERTEX_PROJECT (required) + GOOGLE_VERTEX_LOCATION (optional)
41
+ vertex: [],
42
+ // Bedrock supports two auth methods:
43
+ // 1. AWS_BEARER_TOKEN_BEDROCK - Bedrock API key (simplest)
44
+ // 2. AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY + AWS_REGION (IAM credentials)
45
+ // AWS_SESSION_TOKEN (optional, for temporary credentials)
46
+ bedrock: ["AWS_BEARER_TOKEN_BEDROCK"],
47
+ // Local providers don't require API keys
48
+ local: [],
49
+ // Native node-llama-cpp execution
50
+ ollama: []
51
+ // Ollama server (may optionally use OLLAMA_API_KEY for remote servers)
52
+ // TODO: dexto: ['DEXTO_API_KEY'],
35
53
  // perplexity: ['PERPLEXITY_API_KEY'],
36
54
  // together: ['TOGETHER_API_KEY'],
37
55
  // fireworks: ['FIREWORKS_API_KEY'],
@@ -1 +1 @@
1
- {"version":3,"file":"api-key-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/api-key-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;GAGG;AAGH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,CAY9D,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAelF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CAGpE"}
1
+ {"version":3,"file":"api-key-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/api-key-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;GAGG;AAGH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,CA4B9D,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAelF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CAGpE"}
@@ -6,7 +6,25 @@ const PROVIDER_API_KEY_MAP = {
6
6
  google: ["GOOGLE_GENERATIVE_AI_API_KEY", "GOOGLE_API_KEY", "GEMINI_API_KEY"],
7
7
  groq: ["GROQ_API_KEY"],
8
8
  cohere: ["COHERE_API_KEY"],
9
- xai: ["XAI_API_KEY", "X_AI_API_KEY"]
9
+ xai: ["XAI_API_KEY", "X_AI_API_KEY"],
10
+ openrouter: ["OPENROUTER_API_KEY"],
11
+ litellm: ["LITELLM_API_KEY", "LITELLM_KEY"],
12
+ glama: ["GLAMA_API_KEY"],
13
+ // Vertex uses ADC (Application Default Credentials), not API keys
14
+ // GOOGLE_APPLICATION_CREDENTIALS points to service account JSON (optional)
15
+ // Primary config is GOOGLE_VERTEX_PROJECT (required) + GOOGLE_VERTEX_LOCATION (optional)
16
+ vertex: [],
17
+ // Bedrock supports two auth methods:
18
+ // 1. AWS_BEARER_TOKEN_BEDROCK - Bedrock API key (simplest)
19
+ // 2. AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY + AWS_REGION (IAM credentials)
20
+ // AWS_SESSION_TOKEN (optional, for temporary credentials)
21
+ bedrock: ["AWS_BEARER_TOKEN_BEDROCK"],
22
+ // Local providers don't require API keys
23
+ local: [],
24
+ // Native node-llama-cpp execution
25
+ ollama: []
26
+ // Ollama server (may optionally use OLLAMA_API_KEY for remote servers)
27
+ // TODO: dexto: ['DEXTO_API_KEY'],
10
28
  // perplexity: ['PERPLEXITY_API_KEY'],
11
29
  // together: ['TOGETHER_API_KEY'],
12
30
  // fireworks: ['FIREWORKS_API_KEY'],
@@ -18,6 +18,8 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var api_key_store_exports = {};
20
20
  __export(api_key_store_exports, {
21
+ SHARED_API_KEY_PROVIDERS: () => SHARED_API_KEY_PROVIDERS,
22
+ determineApiKeyStorage: () => determineApiKeyStorage,
21
23
  getProviderKeyStatus: () => getProviderKeyStatus,
22
24
  listProviderKeyStatus: () => listProviderKeyStatus,
23
25
  saveProviderApiKey: () => saveProviderApiKey
@@ -37,6 +39,27 @@ async function saveProviderApiKey(provider, apiKey, startPath) {
37
39
  return { envVar, targetEnvPath };
38
40
  }
39
41
  function getProviderKeyStatus(provider) {
42
+ if (provider === "vertex") {
43
+ const projectId = process.env.GOOGLE_VERTEX_PROJECT;
44
+ return {
45
+ hasApiKey: Boolean(projectId && projectId.trim()),
46
+ envVar: "GOOGLE_VERTEX_PROJECT"
47
+ };
48
+ }
49
+ if (provider === "bedrock") {
50
+ const apiKey = process.env.AWS_BEARER_TOKEN_BEDROCK;
51
+ if (apiKey && apiKey.trim()) {
52
+ return {
53
+ hasApiKey: true,
54
+ envVar: "AWS_BEARER_TOKEN_BEDROCK"
55
+ };
56
+ }
57
+ const region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION;
58
+ return {
59
+ hasApiKey: Boolean(region && region.trim()),
60
+ envVar: "AWS_REGION"
61
+ };
62
+ }
40
63
  const envVar = (0, import_api_key_resolver.getPrimaryApiKeyEnvVar)(provider);
41
64
  const key = (0, import_api_key_resolver.resolveApiKeyForProvider)(provider);
42
65
  return { hasApiKey: Boolean(key && key.trim()), envVar };
@@ -48,8 +71,31 @@ function listProviderKeyStatus() {
48
71
  }
49
72
  return result;
50
73
  }
74
+ const SHARED_API_KEY_PROVIDERS = ["glama", "openrouter", "litellm"];
75
+ function determineApiKeyStorage(provider, userEnteredKey, providerHasKey, existingProviderKey) {
76
+ const result = {
77
+ saveToProviderEnvVar: false,
78
+ saveAsPerModel: false
79
+ };
80
+ if (!userEnteredKey) {
81
+ return result;
82
+ }
83
+ const hasSharedEnvVarKey = SHARED_API_KEY_PROVIDERS.includes(provider);
84
+ if (hasSharedEnvVarKey) {
85
+ if (!providerHasKey) {
86
+ result.saveToProviderEnvVar = true;
87
+ } else if (existingProviderKey && userEnteredKey !== existingProviderKey) {
88
+ result.saveAsPerModel = true;
89
+ }
90
+ } else {
91
+ result.saveAsPerModel = true;
92
+ }
93
+ return result;
94
+ }
51
95
  // Annotate the CommonJS export names for ESM import in node:
52
96
  0 && (module.exports = {
97
+ SHARED_API_KEY_PROVIDERS,
98
+ determineApiKeyStorage,
53
99
  getProviderKeyStatus,
54
100
  listProviderKeyStatus,
55
101
  saveProviderApiKey
@@ -15,4 +15,31 @@ export declare function listProviderKeyStatus(): Record<string, {
15
15
  hasApiKey: boolean;
16
16
  envVar: string;
17
17
  }>;
18
+ /**
19
+ * Providers that use a shared env var for API keys (vs per-endpoint like openai-compatible).
20
+ * For these providers, we save to the env var if none exists, otherwise per-model override.
21
+ */
22
+ export declare const SHARED_API_KEY_PROVIDERS: readonly ["glama", "openrouter", "litellm"];
23
+ export type ApiKeyStorageStrategy = {
24
+ /** Save the key to provider env var (e.g., GLAMA_API_KEY) */
25
+ saveToProviderEnvVar: boolean;
26
+ /** Save the key as per-model override in custom model config */
27
+ saveAsPerModel: boolean;
28
+ };
29
+ /**
30
+ * Determine where to store an API key for a custom model.
31
+ *
32
+ * Logic:
33
+ * - For glama/openrouter/litellm (shared env var providers):
34
+ * - If NO provider key exists → save to provider env var for reuse
35
+ * - If provider key EXISTS and user entered SAME key → don't save (uses fallback)
36
+ * - If provider key EXISTS and user entered DIFFERENT key → save as per-model override
37
+ * - For openai-compatible: always save as per-model (each endpoint needs own key)
38
+ *
39
+ * @param provider - The custom model provider
40
+ * @param userEnteredKey - The API key entered by user (trimmed, may be empty)
41
+ * @param providerHasKey - Whether the provider already has a key configured
42
+ * @param existingProviderKey - The existing provider key value (for comparison)
43
+ */
44
+ export declare function determineApiKeyStorage(provider: string, userEnteredKey: string | undefined, providerHasKey: boolean, existingProviderKey: string | undefined): ApiKeyStorageStrategy;
18
45
  //# sourceMappingURL=api-key-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-key-store.d.ts","sourceRoot":"","sources":["../../src/utils/api-key-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C;;;GAGG;AACH,wBAAsB,kBAAkB,CACpC,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAYpD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,WAAW,GAAG;IACzD,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAClB,CAIA;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAM9F"}
1
+ {"version":3,"file":"api-key-store.d.ts","sourceRoot":"","sources":["../../src/utils/api-key-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C;;;GAGG;AACH,wBAAsB,kBAAkB,CACpC,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAYpD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,WAAW,GAAG;IACzD,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAClB,CA4CA;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAM9F;AAED;;;GAGG;AACH,eAAO,MAAM,wBAAwB,6CAA8C,CAAC;AAEpF,MAAM,MAAM,qBAAqB,GAAG;IAChC,6DAA6D;IAC7D,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gEAAgE;IAChE,cAAc,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAClC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,cAAc,EAAE,OAAO,EACvB,mBAAmB,EAAE,MAAM,GAAG,SAAS,GACxC,qBAAqB,CA2BvB"}
@@ -12,6 +12,27 @@ async function saveProviderApiKey(provider, apiKey, startPath) {
12
12
  return { envVar, targetEnvPath };
13
13
  }
14
14
  function getProviderKeyStatus(provider) {
15
+ if (provider === "vertex") {
16
+ const projectId = process.env.GOOGLE_VERTEX_PROJECT;
17
+ return {
18
+ hasApiKey: Boolean(projectId && projectId.trim()),
19
+ envVar: "GOOGLE_VERTEX_PROJECT"
20
+ };
21
+ }
22
+ if (provider === "bedrock") {
23
+ const apiKey = process.env.AWS_BEARER_TOKEN_BEDROCK;
24
+ if (apiKey && apiKey.trim()) {
25
+ return {
26
+ hasApiKey: true,
27
+ envVar: "AWS_BEARER_TOKEN_BEDROCK"
28
+ };
29
+ }
30
+ const region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION;
31
+ return {
32
+ hasApiKey: Boolean(region && region.trim()),
33
+ envVar: "AWS_REGION"
34
+ };
35
+ }
15
36
  const envVar = getPrimaryApiKeyEnvVar(provider);
16
37
  const key = resolveApiKeyForProvider(provider);
17
38
  return { hasApiKey: Boolean(key && key.trim()), envVar };
@@ -23,7 +44,30 @@ function listProviderKeyStatus() {
23
44
  }
24
45
  return result;
25
46
  }
47
+ const SHARED_API_KEY_PROVIDERS = ["glama", "openrouter", "litellm"];
48
+ function determineApiKeyStorage(provider, userEnteredKey, providerHasKey, existingProviderKey) {
49
+ const result = {
50
+ saveToProviderEnvVar: false,
51
+ saveAsPerModel: false
52
+ };
53
+ if (!userEnteredKey) {
54
+ return result;
55
+ }
56
+ const hasSharedEnvVarKey = SHARED_API_KEY_PROVIDERS.includes(provider);
57
+ if (hasSharedEnvVarKey) {
58
+ if (!providerHasKey) {
59
+ result.saveToProviderEnvVar = true;
60
+ } else if (existingProviderKey && userEnteredKey !== existingProviderKey) {
61
+ result.saveAsPerModel = true;
62
+ }
63
+ } else {
64
+ result.saveAsPerModel = true;
65
+ }
66
+ return result;
67
+ }
26
68
  export {
69
+ SHARED_API_KEY_PROVIDERS,
70
+ determineApiKeyStorage,
27
71
  getProviderKeyStatus,
28
72
  listProviderKeyStatus,
29
73
  saveProviderApiKey
@@ -33,84 +33,36 @@ __export(env_file_exports, {
33
33
  module.exports = __toCommonJS(env_file_exports);
34
34
  var path = __toESM(require("node:path"), 1);
35
35
  var import_node_fs = require("node:fs");
36
- const DEXTO_ENV_KEYS = [
37
- "OPENAI_API_KEY",
38
- "ANTHROPIC_API_KEY",
39
- "GOOGLE_GENERATIVE_AI_API_KEY",
40
- "GROQ_API_KEY",
41
- "COHERE_API_KEY",
42
- "XAI_API_KEY",
43
- "DEXTO_LOG_LEVEL"
44
- ];
45
- function isDextoEnvKey(value) {
46
- return DEXTO_ENV_KEYS.includes(value);
47
- }
48
36
  async function updateEnvFile(envFilePath, updates) {
49
37
  await import_node_fs.promises.mkdir(path.dirname(envFilePath), { recursive: true });
50
- let envLines = [];
38
+ let content = "";
51
39
  try {
52
- const existingEnv = await import_node_fs.promises.readFile(envFilePath, "utf8");
53
- envLines = existingEnv.split("\n");
40
+ content = await import_node_fs.promises.readFile(envFilePath, "utf8");
54
41
  } catch {
55
42
  }
56
- const currentValues = {};
57
- envLines.forEach((line) => {
58
- const match = line.match(/^([A-Z0-9_]+)=(.*)$/);
59
- if (match && match[1] && isDextoEnvKey(match[1])) {
60
- const value = match[2] ?? "";
61
- currentValues[match[1]] = value;
43
+ const lines = content.split("\n");
44
+ const updatedKeys = /* @__PURE__ */ new Set();
45
+ const updatedLines = lines.map((line) => {
46
+ const match = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
47
+ if (match && match[1] && match[1] in updates) {
48
+ const key = match[1];
49
+ updatedKeys.add(key);
50
+ return `${key}=${updates[key]}`;
62
51
  }
52
+ return line;
63
53
  });
64
- const updatedValues = Object.fromEntries(
65
- DEXTO_ENV_KEYS.map((key) => {
66
- const update = updates[key];
67
- const current = currentValues[key];
68
- const fallback = key === "DEXTO_LOG_LEVEL" ? "info" : "";
69
- const value = update !== void 0 ? update : current ?? fallback;
70
- return [key, value];
71
- })
72
- );
73
- const sectionHeader = "## Dexto env variables";
74
- const headerIndex = envLines.findIndex((line) => line.trim() === sectionHeader);
75
- let contentLines;
76
- if (headerIndex !== -1) {
77
- const beforeSection = envLines.slice(0, headerIndex);
78
- let sectionEnd = headerIndex + 1;
79
- while (sectionEnd < envLines.length && envLines[sectionEnd]?.trim() !== "") {
80
- sectionEnd++;
81
- }
82
- if (sectionEnd < envLines.length && envLines[sectionEnd]?.trim() === "") {
83
- sectionEnd++;
54
+ for (const [key, value] of Object.entries(updates)) {
55
+ if (!updatedKeys.has(key)) {
56
+ if (updatedLines.length > 0 && updatedLines[updatedLines.length - 1] !== "") {
57
+ updatedLines.push("");
58
+ }
59
+ updatedLines.push(`${key}=${value}`);
84
60
  }
85
- const afterSection = envLines.slice(sectionEnd);
86
- contentLines = [...beforeSection, ...afterSection];
87
- } else {
88
- contentLines = envLines;
89
61
  }
90
- const existingEnvVars = {};
91
- contentLines.forEach((line) => {
92
- const match = line.match(/^([A-Z0-9_]+)=(.*)$/);
93
- if (match && match[1] && isDextoEnvKey(match[1])) {
94
- const value = match[2] ?? "";
95
- existingEnvVars[match[1]] = value;
96
- }
97
- });
98
- if (contentLines.length > 0) {
99
- if (contentLines[contentLines.length - 1]?.trim() !== "") {
100
- contentLines.push("");
101
- }
102
- } else {
103
- contentLines.push("");
104
- }
105
- contentLines.push(sectionHeader);
106
- for (const key of DEXTO_ENV_KEYS) {
107
- if (key in existingEnvVars && !(key in updates)) {
108
- continue;
109
- }
110
- contentLines.push(`${key}=${updatedValues[key]}`);
62
+ if (updatedLines[updatedLines.length - 1] !== "") {
63
+ updatedLines.push("");
111
64
  }
112
- contentLines.push("");
113
- await import_node_fs.promises.writeFile(envFilePath, contentLines.join("\n"), "utf8");
65
+ await import_node_fs.promises.writeFile(envFilePath, updatedLines.join("\n"), "utf8");
114
66
  }
115
67
  // Annotate the CommonJS export names for ESM import in node:
116
68
  0 && (module.exports = {
@@ -1,5 +1,6 @@
1
1
  /**
2
- * Update a .env file with Dexto environment variables, ensuring our section stays consistent.
2
+ * Update a .env file with the provided key-value pairs.
3
+ * Existing keys are updated in place, new keys are appended.
3
4
  */
4
5
  export declare function updateEnvFile(envFilePath: string, updates: Record<string, string>): Promise<void>;
5
6
  //# sourceMappingURL=env-file.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"env-file.d.ts","sourceRoot":"","sources":["../../src/utils/env-file.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,wBAAsB,aAAa,CAC/B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC,CAgFf"}
1
+ {"version":3,"file":"env-file.d.ts","sourceRoot":"","sources":["../../src/utils/env-file.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAsB,aAAa,CAC/B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC,CAyCf"}
@@ -1,83 +1,35 @@
1
1
  import * as path from "node:path";
2
2
  import { promises as fs } from "node:fs";
3
- const DEXTO_ENV_KEYS = [
4
- "OPENAI_API_KEY",
5
- "ANTHROPIC_API_KEY",
6
- "GOOGLE_GENERATIVE_AI_API_KEY",
7
- "GROQ_API_KEY",
8
- "COHERE_API_KEY",
9
- "XAI_API_KEY",
10
- "DEXTO_LOG_LEVEL"
11
- ];
12
- function isDextoEnvKey(value) {
13
- return DEXTO_ENV_KEYS.includes(value);
14
- }
15
3
  async function updateEnvFile(envFilePath, updates) {
16
4
  await fs.mkdir(path.dirname(envFilePath), { recursive: true });
17
- let envLines = [];
5
+ let content = "";
18
6
  try {
19
- const existingEnv = await fs.readFile(envFilePath, "utf8");
20
- envLines = existingEnv.split("\n");
7
+ content = await fs.readFile(envFilePath, "utf8");
21
8
  } catch {
22
9
  }
23
- const currentValues = {};
24
- envLines.forEach((line) => {
25
- const match = line.match(/^([A-Z0-9_]+)=(.*)$/);
26
- if (match && match[1] && isDextoEnvKey(match[1])) {
27
- const value = match[2] ?? "";
28
- currentValues[match[1]] = value;
10
+ const lines = content.split("\n");
11
+ const updatedKeys = /* @__PURE__ */ new Set();
12
+ const updatedLines = lines.map((line) => {
13
+ const match = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
14
+ if (match && match[1] && match[1] in updates) {
15
+ const key = match[1];
16
+ updatedKeys.add(key);
17
+ return `${key}=${updates[key]}`;
29
18
  }
19
+ return line;
30
20
  });
31
- const updatedValues = Object.fromEntries(
32
- DEXTO_ENV_KEYS.map((key) => {
33
- const update = updates[key];
34
- const current = currentValues[key];
35
- const fallback = key === "DEXTO_LOG_LEVEL" ? "info" : "";
36
- const value = update !== void 0 ? update : current ?? fallback;
37
- return [key, value];
38
- })
39
- );
40
- const sectionHeader = "## Dexto env variables";
41
- const headerIndex = envLines.findIndex((line) => line.trim() === sectionHeader);
42
- let contentLines;
43
- if (headerIndex !== -1) {
44
- const beforeSection = envLines.slice(0, headerIndex);
45
- let sectionEnd = headerIndex + 1;
46
- while (sectionEnd < envLines.length && envLines[sectionEnd]?.trim() !== "") {
47
- sectionEnd++;
48
- }
49
- if (sectionEnd < envLines.length && envLines[sectionEnd]?.trim() === "") {
50
- sectionEnd++;
21
+ for (const [key, value] of Object.entries(updates)) {
22
+ if (!updatedKeys.has(key)) {
23
+ if (updatedLines.length > 0 && updatedLines[updatedLines.length - 1] !== "") {
24
+ updatedLines.push("");
25
+ }
26
+ updatedLines.push(`${key}=${value}`);
51
27
  }
52
- const afterSection = envLines.slice(sectionEnd);
53
- contentLines = [...beforeSection, ...afterSection];
54
- } else {
55
- contentLines = envLines;
56
28
  }
57
- const existingEnvVars = {};
58
- contentLines.forEach((line) => {
59
- const match = line.match(/^([A-Z0-9_]+)=(.*)$/);
60
- if (match && match[1] && isDextoEnvKey(match[1])) {
61
- const value = match[2] ?? "";
62
- existingEnvVars[match[1]] = value;
63
- }
64
- });
65
- if (contentLines.length > 0) {
66
- if (contentLines[contentLines.length - 1]?.trim() !== "") {
67
- contentLines.push("");
68
- }
69
- } else {
70
- contentLines.push("");
71
- }
72
- contentLines.push(sectionHeader);
73
- for (const key of DEXTO_ENV_KEYS) {
74
- if (key in existingEnvVars && !(key in updates)) {
75
- continue;
76
- }
77
- contentLines.push(`${key}=${updatedValues[key]}`);
29
+ if (updatedLines[updatedLines.length - 1] !== "") {
30
+ updatedLines.push("");
78
31
  }
79
- contentLines.push("");
80
- await fs.writeFile(envFilePath, contentLines.join("\n"), "utf8");
32
+ await fs.writeFile(envFilePath, updatedLines.join("\n"), "utf8");
81
33
  }
82
34
  export {
83
35
  updateEnvFile
package/dist/writer.cjs CHANGED
@@ -92,19 +92,37 @@ async function writeLLMPreferences(configPath, preferences, overrides) {
92
92
  const provider = overrides?.provider ?? preferences.llm.provider;
93
93
  const model = overrides?.model ?? preferences.llm.model;
94
94
  const apiKey = overrides?.apiKey ?? preferences.llm.apiKey;
95
+ const baseURL = overrides?.baseURL ?? preferences.llm.baseURL;
95
96
  import_core.logger.debug(`Applying LLM preferences`, {
96
97
  finalProvider: provider,
97
98
  finalModel: model,
98
99
  hasApiKey: Boolean(apiKey),
100
+ hasBaseURL: Boolean(baseURL),
99
101
  source: overrides ? "CLI overrides + preferences" : "preferences only"
100
102
  });
101
103
  let llmNode = doc.get("llm");
102
104
  if (!llmNode || typeof llmNode !== "object") {
103
- doc.set("llm", { provider, model, apiKey });
105
+ const llmConfig = { provider, model };
106
+ if (apiKey) {
107
+ llmConfig.apiKey = apiKey;
108
+ }
109
+ if (baseURL) {
110
+ llmConfig.baseURL = baseURL;
111
+ }
112
+ doc.set("llm", llmConfig);
104
113
  } else {
105
114
  doc.setIn(["llm", "provider"], provider);
106
115
  doc.setIn(["llm", "model"], model);
107
- doc.setIn(["llm", "apiKey"], apiKey);
116
+ if (apiKey) {
117
+ doc.setIn(["llm", "apiKey"], apiKey);
118
+ } else {
119
+ doc.deleteIn(["llm", "apiKey"]);
120
+ }
121
+ if (baseURL) {
122
+ doc.setIn(["llm", "baseURL"], baseURL);
123
+ } else {
124
+ doc.deleteIn(["llm", "baseURL"]);
125
+ }
108
126
  }
109
127
  await import_fs.promises.writeFile(configPath, doc.toString(), "utf-8");
110
128
  import_core.logger.info(`\u2713 Applied preferences to: ${path.basename(configPath)} (${provider}/${model})`);
package/dist/writer.d.ts CHANGED
@@ -4,6 +4,7 @@ export interface LLMOverrides {
4
4
  provider?: LLMProvider;
5
5
  model?: string;
6
6
  apiKey?: string;
7
+ baseURL?: string;
7
8
  }
8
9
  /**
9
10
  * Asynchronously writes the given agent configuration object to a YAML file.
@@ -1 +1 @@
1
- {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../src/writer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAIlE,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB5F;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACrC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,iBAAiB,EAC9B,SAAS,CAAC,EAAE,YAAY,GACzB,OAAO,CAAC,IAAI,CAAC,CAwEf;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CACzC,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,iBAAiB,EAC9B,SAAS,CAAC,EAAE,YAAY,GACzB,OAAO,CAAC,IAAI,CAAC,CAyBf"}
1
+ {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../src/writer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAIlE,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB5F;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACrC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,iBAAiB,EAC9B,SAAS,CAAC,EAAE,YAAY,GACzB,OAAO,CAAC,IAAI,CAAC,CA6Ff;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CACzC,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,iBAAiB,EAC9B,SAAS,CAAC,EAAE,YAAY,GACzB,OAAO,CAAC,IAAI,CAAC,CAyBf"}
package/dist/writer.js CHANGED
@@ -57,19 +57,37 @@ async function writeLLMPreferences(configPath, preferences, overrides) {
57
57
  const provider = overrides?.provider ?? preferences.llm.provider;
58
58
  const model = overrides?.model ?? preferences.llm.model;
59
59
  const apiKey = overrides?.apiKey ?? preferences.llm.apiKey;
60
+ const baseURL = overrides?.baseURL ?? preferences.llm.baseURL;
60
61
  logger.debug(`Applying LLM preferences`, {
61
62
  finalProvider: provider,
62
63
  finalModel: model,
63
64
  hasApiKey: Boolean(apiKey),
65
+ hasBaseURL: Boolean(baseURL),
64
66
  source: overrides ? "CLI overrides + preferences" : "preferences only"
65
67
  });
66
68
  let llmNode = doc.get("llm");
67
69
  if (!llmNode || typeof llmNode !== "object") {
68
- doc.set("llm", { provider, model, apiKey });
70
+ const llmConfig = { provider, model };
71
+ if (apiKey) {
72
+ llmConfig.apiKey = apiKey;
73
+ }
74
+ if (baseURL) {
75
+ llmConfig.baseURL = baseURL;
76
+ }
77
+ doc.set("llm", llmConfig);
69
78
  } else {
70
79
  doc.setIn(["llm", "provider"], provider);
71
80
  doc.setIn(["llm", "model"], model);
72
- doc.setIn(["llm", "apiKey"], apiKey);
81
+ if (apiKey) {
82
+ doc.setIn(["llm", "apiKey"], apiKey);
83
+ } else {
84
+ doc.deleteIn(["llm", "apiKey"]);
85
+ }
86
+ if (baseURL) {
87
+ doc.setIn(["llm", "baseURL"], baseURL);
88
+ } else {
89
+ doc.deleteIn(["llm", "baseURL"]);
90
+ }
73
91
  }
74
92
  await fs.writeFile(configPath, doc.toString(), "utf-8");
75
93
  logger.info(`\u2713 Applied preferences to: ${path.basename(configPath)} (${provider}/${model})`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dexto/agent-management",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -16,7 +16,7 @@
16
16
  "dependencies": {
17
17
  "yaml": "^2.7.1",
18
18
  "zod": "^3.25.0",
19
- "@dexto/core": "1.4.0"
19
+ "@dexto/core": "1.5.1"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/node": "^22.13.5"