@lasso-ai/cli 2.1.3 → 2.1.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/dist/cli/backends.d.ts +2 -0
- package/dist/cli/backends.js +8 -4
- package/dist/cli/bridge.d.ts +4 -0
- package/dist/cli/bridge.js +238 -58
- package/dist/cli/local-runtime.d.ts +5 -0
- package/dist/cli/local-runtime.js +2 -0
- package/dist/cli/oneshot.js +37 -16
- package/dist/cli/runtime-client.d.ts +13 -0
- package/dist/cli/runtime-client.js +1 -1
- package/dist/overlay.js +195 -203
- package/dist/runtime/action-executor.d.ts +2 -1
- package/dist/runtime/action-executor.js +14 -5
- package/dist/runtime/adapters/codex-cli-adapter.d.ts +1 -0
- package/dist/runtime/adapters/codex-cli-adapter.js +32 -4
- package/dist/runtime/adapters/cursor-adapter.js +1 -1
- package/dist/runtime/adapters/local-agent-adapter.js +10 -3
- package/dist/runtime/adapters/opencode-adapter.js +19 -7
- package/dist/runtime/agent-runtime.d.ts +4 -0
- package/dist/runtime/agent-state-machine.d.ts +4 -0
- package/dist/runtime/agent-state-machine.js +10 -2
- package/dist/runtime/backend-interface.d.ts +2 -0
- package/package.json +1 -1
|
@@ -72,7 +72,7 @@ class CodexCLIAdapter extends local_agent_adapter_1.LocalAgentAdapter {
|
|
|
72
72
|
const args = ["exec"];
|
|
73
73
|
if (resumeId) {
|
|
74
74
|
// `resume` does not accept -s; sandbox policy goes through a config override.
|
|
75
|
-
args.push("resume", resumeId, "--json", "--skip-git-repo-check", "-c",
|
|
75
|
+
args.push("resume", resumeId, "--json", "--skip-git-repo-check", "-c", `sandbox_mode="${context.mode === "conversation" ? "read-only" : "workspace-write"}"`);
|
|
76
76
|
if (this.modelId)
|
|
77
77
|
args.push("-m", this.modelId);
|
|
78
78
|
}
|
|
@@ -81,6 +81,11 @@ class CodexCLIAdapter extends local_agent_adapter_1.LocalAgentAdapter {
|
|
|
81
81
|
if (this.modelId)
|
|
82
82
|
args.push("-m", this.modelId);
|
|
83
83
|
}
|
|
84
|
+
if (context.mode === "conversation") {
|
|
85
|
+
const sandboxIndex = args.indexOf("workspace-write");
|
|
86
|
+
if (sandboxIndex >= 0)
|
|
87
|
+
args[sandboxIndex] = "read-only";
|
|
88
|
+
}
|
|
84
89
|
args.push(prompt);
|
|
85
90
|
return { bin: "codex", args, cwd: cfg.projectPath };
|
|
86
91
|
}
|
|
@@ -119,12 +124,12 @@ class CodexCLIAdapter extends local_agent_adapter_1.LocalAgentAdapter {
|
|
|
119
124
|
return true;
|
|
120
125
|
}
|
|
121
126
|
case "error": {
|
|
122
|
-
const message = event.message || event.error
|
|
127
|
+
const message = event.message || this.describeError(event.error) || "Codex reported an error";
|
|
123
128
|
this.recordFailure(sink, message);
|
|
124
129
|
return true;
|
|
125
130
|
}
|
|
126
131
|
case "turn.failed": {
|
|
127
|
-
const message = event.error
|
|
132
|
+
const message = this.describeError(event.error) || "Codex turn failed";
|
|
128
133
|
this.recordFailure(sink, message);
|
|
129
134
|
return true;
|
|
130
135
|
}
|
|
@@ -168,7 +173,7 @@ class CodexCLIAdapter extends local_agent_adapter_1.LocalAgentAdapter {
|
|
|
168
173
|
break;
|
|
169
174
|
}
|
|
170
175
|
case "error": {
|
|
171
|
-
const message = item.error
|
|
176
|
+
const message = this.describeError(item.error) || item.message || "Codex item error";
|
|
172
177
|
this.recordFailure(sink, message);
|
|
173
178
|
break;
|
|
174
179
|
}
|
|
@@ -187,6 +192,29 @@ class CodexCLIAdapter extends local_agent_adapter_1.LocalAgentAdapter {
|
|
|
187
192
|
sink.error(message, { recoverable: false, authFailure: sink.state.authFailure });
|
|
188
193
|
}
|
|
189
194
|
}
|
|
195
|
+
describeError(error) {
|
|
196
|
+
if (!error)
|
|
197
|
+
return undefined;
|
|
198
|
+
if (typeof error === "string")
|
|
199
|
+
return error;
|
|
200
|
+
if (typeof error === "object") {
|
|
201
|
+
const value = error;
|
|
202
|
+
const nested = [
|
|
203
|
+
value.message,
|
|
204
|
+
value.data?.message,
|
|
205
|
+
value.cause?.message,
|
|
206
|
+
].find((item) => typeof item === "string" && item.trim().length > 0);
|
|
207
|
+
if (nested)
|
|
208
|
+
return nested;
|
|
209
|
+
try {
|
|
210
|
+
return JSON.stringify(error).slice(0, 800);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return String(error);
|
|
217
|
+
}
|
|
190
218
|
inspectFailureText(text) {
|
|
191
219
|
if (!text)
|
|
192
220
|
return null;
|
|
@@ -103,7 +103,7 @@ class CursorAdapter extends local_agent_adapter_1.LocalAgentAdapter {
|
|
|
103
103
|
}
|
|
104
104
|
buildCommand(context) {
|
|
105
105
|
const resumeId = this.resumeSessionId(context);
|
|
106
|
-
const args = ["-p", "--output-format", "stream-json", "--trust"];
|
|
106
|
+
const args = ["-p", "--output-format", context.mode === "conversation" ? "json" : "stream-json", "--trust"];
|
|
107
107
|
if (this.modelId)
|
|
108
108
|
args.push("--model", this.modelId);
|
|
109
109
|
if (resumeId)
|
|
@@ -301,10 +301,17 @@ class LocalAgentAdapter {
|
|
|
301
301
|
/** Build the shared task prompt (project context + continuation context). */
|
|
302
302
|
buildTaskPrompt(context) {
|
|
303
303
|
const lines = [];
|
|
304
|
-
lines.push("You are
|
|
305
|
-
lines.push("Complete the following task by editing this project directly:");
|
|
304
|
+
lines.push("You are Lasso, an agentic AI coding assistant embedded in this live project.");
|
|
306
305
|
lines.push("");
|
|
307
|
-
lines.push(
|
|
306
|
+
lines.push("Instructions:");
|
|
307
|
+
lines.push("1. Understand user intent:");
|
|
308
|
+
lines.push(" - If the user is greeting you, asking a question, seeking advice, feedback, explanations, or having a conversation (and NOT asking you to edit or write code): answer conversationally and concisely. Do NOT edit files or run build/modification commands.");
|
|
309
|
+
lines.push(" - If the user asks to build, modify, fix, refactor, add, style, or remove code/files: perform the necessary edits directly on the project.");
|
|
310
|
+
lines.push(" - If the request is ambiguous, provide a helpful answer and ask for clarification before editing files.");
|
|
311
|
+
lines.push("2. All file changes will be captured as a diff, reviewed by the user, and only applied if approved.");
|
|
312
|
+
lines.push("3. Do not commit, push, or perform operations outside this project directory.");
|
|
313
|
+
lines.push("");
|
|
314
|
+
lines.push(`User request: ${context.userPrompt}`);
|
|
308
315
|
lines.push("");
|
|
309
316
|
lines.push("Project context:");
|
|
310
317
|
lines.push(`- Path: ${this.config.projectPath}`);
|
|
@@ -17,6 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
exports.OpenCodeAdapter = void 0;
|
|
18
18
|
const node_util_1 = require("node:util");
|
|
19
19
|
const local_agent_adapter_1 = require("./local-agent-adapter");
|
|
20
|
+
const backends_1 = require("../../cli/backends");
|
|
20
21
|
const execFileAsync = (0, node_util_1.promisify)(require("node:child_process").execFile);
|
|
21
22
|
const FILE_INPUT_KEYS = ["filePath", "file_path", "path", "filename"];
|
|
22
23
|
class OpenCodeAdapter extends local_agent_adapter_1.LocalAgentAdapter {
|
|
@@ -84,6 +85,9 @@ class OpenCodeAdapter extends local_agent_adapter_1.LocalAgentAdapter {
|
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
87
|
buildCommand(context) {
|
|
88
|
+
if (this.modelId && (0, backends_1.isOpenCodeHeadlessRestrictedModel)(this.modelId)) {
|
|
89
|
+
throw new Error(`OpenCode model ${this.modelId} is restricted to OpenCode's own app and cannot run through Lasso. Choose a non-free OpenCode model or configure another provider.`);
|
|
90
|
+
}
|
|
87
91
|
const resumeId = this.resumeSessionId(context);
|
|
88
92
|
const args = ["run", "--format", "json"];
|
|
89
93
|
if (this.modelId)
|
|
@@ -91,7 +95,10 @@ class OpenCodeAdapter extends local_agent_adapter_1.LocalAgentAdapter {
|
|
|
91
95
|
if (resumeId)
|
|
92
96
|
args.push("--session", resumeId);
|
|
93
97
|
args.push(this.buildTaskPrompt(context));
|
|
94
|
-
|
|
98
|
+
const env = context.mode === "conversation"
|
|
99
|
+
? { OPENCODE_PERMISSION: JSON.stringify({ "*": "deny" }) }
|
|
100
|
+
: undefined;
|
|
101
|
+
return { bin: "opencode", args, cwd: this.config.projectPath, env };
|
|
95
102
|
}
|
|
96
103
|
handleLine(line, context, sink) {
|
|
97
104
|
let event;
|
|
@@ -165,15 +172,20 @@ class OpenCodeAdapter extends local_agent_adapter_1.LocalAgentAdapter {
|
|
|
165
172
|
return error;
|
|
166
173
|
if (typeof error === "object") {
|
|
167
174
|
const e = error;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
175
|
+
const nested = [
|
|
176
|
+
e.message,
|
|
177
|
+
e.data?.message,
|
|
178
|
+
e.data?.error,
|
|
179
|
+
e.cause?.message,
|
|
180
|
+
].find((item) => typeof item === "string" && item.trim().length > 0);
|
|
181
|
+
if (nested)
|
|
182
|
+
return nested;
|
|
172
183
|
try {
|
|
173
|
-
|
|
184
|
+
const serialized = JSON.stringify(error).slice(0, 800);
|
|
185
|
+
return typeof e.name === "string" ? `${e.name}: ${serialized}` : serialized;
|
|
174
186
|
}
|
|
175
187
|
catch {
|
|
176
|
-
return undefined;
|
|
188
|
+
return typeof e.name === "string" ? e.name : undefined;
|
|
177
189
|
}
|
|
178
190
|
}
|
|
179
191
|
return String(error);
|
|
@@ -191,6 +191,8 @@ export interface LassoModelResponse {
|
|
|
191
191
|
status: "continue" | "waiting" | "complete" | "failed";
|
|
192
192
|
reasoning: {
|
|
193
193
|
summary: string;
|
|
194
|
+
/** Raw model thoughts / extended reasoning, when the provider exposes it. */
|
|
195
|
+
raw?: string;
|
|
194
196
|
};
|
|
195
197
|
decision: {
|
|
196
198
|
type: "inspect" | "plan" | "execute" | "verify" | "recover" | "ask_user";
|
|
@@ -211,6 +213,8 @@ export interface AgentReasoningEvent extends AgentEvent {
|
|
|
211
213
|
data: {
|
|
212
214
|
summary: string;
|
|
213
215
|
decision?: string;
|
|
216
|
+
/** Raw model thoughts for UI detail display. */
|
|
217
|
+
raw?: string;
|
|
214
218
|
};
|
|
215
219
|
}
|
|
216
220
|
export interface PhaseChangedEvent extends AgentEvent {
|
|
@@ -14,6 +14,10 @@ export declare class AgentStateMachine {
|
|
|
14
14
|
* Actions allowed in each phase
|
|
15
15
|
*/
|
|
16
16
|
private static readonly ALLOWED_ACTIONS;
|
|
17
|
+
/**
|
|
18
|
+
* Action types allowed in a phase (public, e.g. for model prompts).
|
|
19
|
+
*/
|
|
20
|
+
static allowedActions(phase: AgentPhase): string[];
|
|
17
21
|
/**
|
|
18
22
|
* Check if a phase transition is valid
|
|
19
23
|
*/
|
|
@@ -25,13 +25,19 @@ class AgentStateMachine {
|
|
|
25
25
|
*/
|
|
26
26
|
static ALLOWED_ACTIONS = {
|
|
27
27
|
understand: [],
|
|
28
|
-
inspect: ["read_file", "search_code", "inspect_project"],
|
|
28
|
+
inspect: ["read_file", "search_code", "inspect_project", "browser_check"],
|
|
29
29
|
plan: [],
|
|
30
30
|
execute: ["edit_file", "create_file", "delete_file", "run_command"],
|
|
31
31
|
verify: ["browser_check", "run_command"],
|
|
32
32
|
recover: ["edit_file", "read_file", "run_command"],
|
|
33
33
|
complete: [],
|
|
34
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Action types allowed in a phase (public, e.g. for model prompts).
|
|
37
|
+
*/
|
|
38
|
+
static allowedActions(phase) {
|
|
39
|
+
return [...(this.ALLOWED_ACTIONS[phase] || [])];
|
|
40
|
+
}
|
|
35
41
|
/**
|
|
36
42
|
* Check if a phase transition is valid
|
|
37
43
|
*/
|
|
@@ -189,7 +195,9 @@ class AgentStateMachine {
|
|
|
189
195
|
static shouldVerify(session) {
|
|
190
196
|
return (session.phase === "execute" &&
|
|
191
197
|
session.completedActions.length > 0 &&
|
|
192
|
-
|
|
198
|
+
// Validation feedback (model proposed a rejected action) is teaching
|
|
199
|
+
// material for the next prompt — it must not block verification.
|
|
200
|
+
session.errors.filter((e) => e.phase === "execute" && e.type !== "validation").length === 0);
|
|
193
201
|
}
|
|
194
202
|
/**
|
|
195
203
|
* Check if the session should trigger recovery
|
|
@@ -100,6 +100,8 @@ export interface TaskContext {
|
|
|
100
100
|
* User's prompt or instruction
|
|
101
101
|
*/
|
|
102
102
|
userPrompt: string;
|
|
103
|
+
/** Whether the backend should answer conversationally without project work. */
|
|
104
|
+
mode?: "conversation" | "task";
|
|
103
105
|
/**
|
|
104
106
|
* Project context
|
|
105
107
|
*/
|
package/package.json
CHANGED