diff --git a/packages/builtin-tool-creds/src/executor/index.ts b/packages/builtin-tool-creds/src/executor/index.ts index ba2e8c990c..ff22dcf7de 100644 --- a/packages/builtin-tool-creds/src/executor/index.ts +++ b/packages/builtin-tool-creds/src/executor/index.ts @@ -370,21 +370,49 @@ class CredsExecutor extends BaseExecutor { _ctx?: BuiltinToolContext, ): Promise => { try { - log('[CredsExecutor] saveCreds - key:', params.key, 'name:', params.name); + // Normalize params: AI may send `displayName` instead of `name`, + // or `value` (env-style string) instead of `values` (Record) + const raw = params as any; + const name: string = params.name || raw.displayName || params.key; + + let values: Record = params.values; + if (!values && typeof raw.value === 'string') { + values = {}; + for (const line of (raw.value as string).split('\n')) { + const idx = line.indexOf('='); + if (idx > 0) { + values[line.slice(0, idx).trim()] = line.slice(idx + 1).trim(); + } + } + } + + if (!values || Object.keys(values).length === 0) { + return { + content: + 'Failed to save credential: values must be a non-empty object of key-value pairs (e.g., { "API_KEY": "sk-xxx" }).', + error: { + message: 'values is empty or missing. Provide key-value pairs, not a raw string.', + type: 'InvalidParams', + }, + success: false, + }; + } + + log('[CredsExecutor] saveCreds - key:', params.key, 'name:', name); await lambdaClient.market.creds.createKV.mutate({ description: params.description, key: params.key, - name: params.name, + name, type: params.type as 'kv-env' | 'kv-header', - values: params.values, + values, }); return { - content: `Credential "${params.name}" saved successfully with key "${params.key}"`, + content: `Credential "${name}" saved successfully with key "${params.key}"`, state: { key: params.key, - message: `Credential "${params.name}" saved successfully`, + message: `Credential "${name}" saved successfully`, success: true, }, success: true, diff --git a/packages/builtin-tool-creds/src/systemRole.ts b/packages/builtin-tool-creds/src/systemRole.ts index 2c9d51fdb6..00799ed457 100644 --- a/packages/builtin-tool-creds/src/systemRole.ts +++ b/packages/builtin-tool-creds/src/systemRole.ts @@ -29,6 +29,10 @@ Sandbox mode: {{sandbox_enabled}} - **getPlaintextCred**: Retrieve the plaintext value of a credential by key. Only use when you need to actually use the credential. - **injectCredsToSandbox**: Inject credentials into the sandbox environment. Only available when sandbox mode is enabled. - **saveCreds**: Save new credentials securely. Use when user wants to store sensitive information. + - Parameters: \`key\` (unique identifier, lowercase with hyphens), \`name\` (display name), \`type\` ("kv-env" or "kv-header"), \`values\` (object of key-value pairs, NOT a string), \`description\` (optional) + - Example: \`saveCreds({ key: "openai", name: "OpenAI API Key", type: "kv-env", values: { "OPENAI_API_KEY": "sk-xxx" } })\` + - For multiple env vars: \`saveCreds({ key: "my-config", name: "My Config", type: "kv-env", values: { "APP_URL": "http://localhost:3000", "DB_URL": "postgres://..." } })\` + - IMPORTANT: \`values\` must be a JSON object (Record), NOT a raw string. Each environment variable should be a separate key-value pair in the object. @@ -61,7 +65,7 @@ Proactively suggest saving credentials when you detect: When suggesting to save, always: 1. Explain that the credential will be encrypted and stored securely 2. Ask the user for a meaningful name and optional description -3. Use the \`saveCreds\` tool to store it +3. Use the \`saveCreds\` tool to store it with \`values\` as a JSON object (e.g., \`{ "API_KEY": "sk-xxx" }\`), NOT a raw string