@lasso-ai/cli 2.1.1 → 2.1.3

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.
@@ -151,6 +151,22 @@ async function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort
151
151
  ...readEnvFile(root, ".env.local"),
152
152
  ...readEnvFile(root, ".env.production"),
153
153
  }), {});
154
+ // Resolve the user's own model-provider key (BYOK) for hosted runs: the
155
+ // server calls the provider with it and never stores it.
156
+ const PROVIDER_ENV_KEYS = {
157
+ anthropic: ["ANTHROPIC_API_KEY"],
158
+ openai: ["OPENAI_API_KEY"],
159
+ google: ["GOOGLE_GENERATIVE_AI_API_KEY", "GOOGLE_API_KEY"],
160
+ nvidia: ["NVIDIA_API_KEY"],
161
+ };
162
+ function providerApiKeyFor(provider) {
163
+ for (const envName of PROVIDER_ENV_KEYS[provider] || []) {
164
+ const value = (process.env[envName] || fileEnv[envName] || "").trim();
165
+ if (value)
166
+ return value;
167
+ }
168
+ return undefined;
169
+ }
154
170
  const cliCredentials = (0, auth_1.loadCredentials)();
155
171
  const resolvedLassoKey = cliCredentials?.apiKey ||
156
172
  (0, project_1.resolveLassoApiKey)(fileEnv) ||
@@ -425,7 +441,7 @@ async function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort
425
441
  // already rolled back at that point).
426
442
  await facade.runSession(session.id, cwd, (event) => {
427
443
  handleRuntimeEvent(event, socket, taskId, session, `Runtime session: ${instruction}`, true);
428
- }, controller.signal);
444
+ }, controller.signal, { providerApiKey: providerApiKeyFor(provider) });
429
445
  }
430
446
  catch (error) {
431
447
  socket.send(JSON.stringify({
@@ -575,7 +591,7 @@ async function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort
575
591
  try {
576
592
  await facade.runSession(session.id, cwd, (event) => {
577
593
  handleRuntimeEvent(event, socket, taskId, session, "Corrective run", true);
578
- }, controller.signal);
594
+ }, controller.signal, { providerApiKey: providerApiKeyFor(session.model?.provider || "") });
579
595
  }
580
596
  catch (error) {
581
597
  socket.send(JSON.stringify({
@@ -734,7 +750,7 @@ async function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort
734
750
  message: "Oneshot completed",
735
751
  }));
736
752
  }
737
- }, controller.signal);
753
+ }, controller.signal, { providerApiKey: providerApiKeyFor(provider) });
738
754
  }
739
755
  catch (error) {
740
756
  socket.send(JSON.stringify({
@@ -14,7 +14,9 @@ export declare class LocalRuntime implements RuntimeFacade {
14
14
  private abortControllers;
15
15
  createSession(input: RuntimeSessionInput): Promise<RuntimeSession>;
16
16
  getSession(sessionId: string): Promise<RuntimeSession>;
17
- runSession(sessionId: string, projectPath: string, onEvent: RuntimeEventHandler, signal?: AbortSignal): Promise<void>;
17
+ runSession(sessionId: string, projectPath: string, onEvent: RuntimeEventHandler, signal?: AbortSignal, _opts?: {
18
+ providerApiKey?: string;
19
+ }): Promise<void>;
18
20
  verifySession(sessionId: string, projectPath: string): Promise<SessionVerificationResult>;
19
21
  switchModel(sessionId: string, model: {
20
22
  provider: string;
@@ -63,7 +63,8 @@ class LocalRuntime {
63
63
  throw new Error("Session not found");
64
64
  return this.toSession(record);
65
65
  }
66
- async runSession(sessionId, projectPath, onEvent, signal) {
66
+ async runSession(sessionId, projectPath, onEvent, signal, _opts // local agents run in-process; no server/model key needed
67
+ ) {
67
68
  const record = this.sessions.get(sessionId);
68
69
  if (!record)
69
70
  throw new Error("Session not found");
@@ -394,8 +394,32 @@ async function resolveWorkspaceConfig(fileEnv) {
394
394
  async function fetchModels(fileEnv) {
395
395
  const serverUrl = (0, auth_1.serverUrlFrom)(fileEnv).replace(/\/$/, "");
396
396
  const apiUrl = `${serverUrl}/api/v1`;
397
+ // Pass the user's own provider keys (BYOK) so the server can list live
398
+ // models per provider instead of falling back to empty/static lists.
399
+ const envKey = (...names) => {
400
+ for (const name of names) {
401
+ const value = (process.env[name] || fileEnv[name] || "").trim();
402
+ if (value)
403
+ return value;
404
+ }
405
+ return "";
406
+ };
407
+ const query = new URLSearchParams();
408
+ const anthropicKey = envKey("ANTHROPIC_API_KEY");
409
+ const openaiKey = envKey("OPENAI_API_KEY");
410
+ const googleKey = envKey("GOOGLE_GENERATIVE_AI_API_KEY", "GOOGLE_API_KEY");
411
+ const nvidiaKey = envKey("NVIDIA_API_KEY");
412
+ if (anthropicKey)
413
+ query.set("anthropicKey", anthropicKey);
414
+ if (openaiKey)
415
+ query.set("openaiKey", openaiKey);
416
+ if (googleKey)
417
+ query.set("googleKey", googleKey);
418
+ if (nvidiaKey)
419
+ query.set("nvidiaKey", nvidiaKey);
420
+ const qs = query.toString();
397
421
  try {
398
- const response = await (0, auth_1.fetchWithTimeout)(`${apiUrl}/models`, {
422
+ const response = await (0, auth_1.fetchWithTimeout)(`${apiUrl}/models${qs ? `?${qs}` : ""}`, {
399
423
  method: "GET",
400
424
  });
401
425
  if (!response.ok) {
@@ -137,7 +137,9 @@ export interface SessionVerificationResult {
137
137
  */
138
138
  export interface RuntimeFacade {
139
139
  createSession(input: RuntimeSessionInput): Promise<RuntimeSession>;
140
- runSession(sessionId: string, projectPath: string, onEvent: RuntimeEventHandler, signal?: AbortSignal): Promise<void>;
140
+ runSession(sessionId: string, projectPath: string, onEvent: RuntimeEventHandler, signal?: AbortSignal, opts?: {
141
+ providerApiKey?: string;
142
+ }): Promise<void>;
141
143
  getSession(sessionId: string): Promise<RuntimeSession>;
142
144
  verifySession(sessionId: string, projectPath: string): Promise<SessionVerificationResult>;
143
145
  switchModel(sessionId: string, model: {
@@ -288,7 +290,9 @@ export declare class RuntimeClient {
288
290
  * 3. On agent_completed: diff the workspace, roll it back, and cache the
289
291
  * changes for the review panel. Only user approval re-applies them.
290
292
  */
291
- runSession(sessionId: string, projectPath: string, onEvent: RuntimeEventHandler, signal?: AbortSignal): Promise<void>;
293
+ runSession(sessionId: string, projectPath: string, onEvent: RuntimeEventHandler, signal?: AbortSignal, opts?: {
294
+ providerApiKey?: string;
295
+ }): Promise<void>;
292
296
  /** Execute a tool_call request locally against the real project. */
293
297
  private executeToolCallLocally;
294
298
  /** Post a tool result back to the server (resolves its pending request). */
@@ -77,7 +77,7 @@ class RuntimeClient {
77
77
  * 3. On agent_completed: diff the workspace, roll it back, and cache the
78
78
  * changes for the review panel. Only user approval re-applies them.
79
79
  */
80
- async runSession(sessionId, projectPath, onEvent, signal) {
80
+ async runSession(sessionId, projectPath, onEvent, signal, opts) {
81
81
  // CLI-side snapshot: nothing the agent does is left on disk before review.
82
82
  let guard = null;
83
83
  try {
@@ -127,7 +127,9 @@ class RuntimeClient {
127
127
  "Content-Type": "application/json",
128
128
  ...(this.apiKey && { "Authorization": `Bearer ${this.apiKey}` }),
129
129
  },
130
- body: JSON.stringify({ projectPath }),
130
+ // providerApiKey is the user's own model-provider key (BYOK): the
131
+ // server calls the hosted model with it and never stores it.
132
+ body: JSON.stringify({ projectPath, apiKey: opts?.providerApiKey }),
131
133
  signal,
132
134
  });
133
135
  if (!response.ok) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lasso-ai/cli",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "Select any part of your running app, describe a change, and let AI edit the real source code.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/cli/index.js",