openwork 0.1.1-rc.2 → 0.1.1-rc.4
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/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# openwork
|
|
2
2
|
|
|
3
|
+
[](https://github.com/langchain-ai/openwork/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/openwork)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
3
7
|
A tactical agent interface for [deepagentsjs](https://github.com/langchain-ai/deepagentsjs) - an opinionated harness for building deep agents with filesystem capabilities, planning, and subagent delegation.
|
|
4
8
|
|
|
5
9
|

|
package/out/main/index.js
CHANGED
|
@@ -6,6 +6,7 @@ const deepagents = require("deepagents");
|
|
|
6
6
|
const Store = require("electron-store");
|
|
7
7
|
const fs$1 = require("fs/promises");
|
|
8
8
|
const fs = require("fs");
|
|
9
|
+
const os = require("os");
|
|
9
10
|
const anthropic = require("@langchain/anthropic");
|
|
10
11
|
const openai = require("@langchain/openai");
|
|
11
12
|
const initSqlJs = require("sql.js");
|
|
@@ -96,23 +97,83 @@ function notifyRenderer(threadId, workspacePath) {
|
|
|
96
97
|
});
|
|
97
98
|
}
|
|
98
99
|
}
|
|
100
|
+
const OPENWORK_DIR = path.join(os.homedir(), ".openwork");
|
|
101
|
+
const ENV_FILE = path.join(OPENWORK_DIR, ".env");
|
|
102
|
+
const ENV_VAR_NAMES = {
|
|
103
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
104
|
+
openai: "OPENAI_API_KEY"
|
|
105
|
+
};
|
|
106
|
+
function getOpenworkDir() {
|
|
107
|
+
if (!fs.existsSync(OPENWORK_DIR)) {
|
|
108
|
+
fs.mkdirSync(OPENWORK_DIR, { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
return OPENWORK_DIR;
|
|
111
|
+
}
|
|
112
|
+
function getDbPath() {
|
|
113
|
+
return path.join(getOpenworkDir(), "openwork.sqlite");
|
|
114
|
+
}
|
|
115
|
+
function getCheckpointDbPath() {
|
|
116
|
+
return path.join(getOpenworkDir(), "langgraph.sqlite");
|
|
117
|
+
}
|
|
118
|
+
function getEnvFilePath() {
|
|
119
|
+
return ENV_FILE;
|
|
120
|
+
}
|
|
121
|
+
function parseEnvFile() {
|
|
122
|
+
const envPath = getEnvFilePath();
|
|
123
|
+
if (!fs.existsSync(envPath)) return {};
|
|
124
|
+
const content = fs.readFileSync(envPath, "utf-8");
|
|
125
|
+
const result = {};
|
|
126
|
+
for (const line of content.split("\n")) {
|
|
127
|
+
const trimmed = line.trim();
|
|
128
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
129
|
+
const eqIndex = trimmed.indexOf("=");
|
|
130
|
+
if (eqIndex > 0) {
|
|
131
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
132
|
+
const value = trimmed.slice(eqIndex + 1).trim();
|
|
133
|
+
result[key] = value;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
function writeEnvFile(env) {
|
|
139
|
+
getOpenworkDir();
|
|
140
|
+
const lines = Object.entries(env).filter(([_, v]) => v).map(([k, v]) => `${k}=${v}`);
|
|
141
|
+
fs.writeFileSync(getEnvFilePath(), lines.join("\n") + "\n");
|
|
142
|
+
}
|
|
143
|
+
function getApiKey(provider) {
|
|
144
|
+
const envVarName = ENV_VAR_NAMES[provider];
|
|
145
|
+
if (!envVarName) return void 0;
|
|
146
|
+
const env = parseEnvFile();
|
|
147
|
+
if (env[envVarName]) return env[envVarName];
|
|
148
|
+
return process.env[envVarName];
|
|
149
|
+
}
|
|
150
|
+
function setApiKey(provider, apiKey) {
|
|
151
|
+
const envVarName = ENV_VAR_NAMES[provider];
|
|
152
|
+
if (!envVarName) return;
|
|
153
|
+
const env = parseEnvFile();
|
|
154
|
+
env[envVarName] = apiKey;
|
|
155
|
+
writeEnvFile(env);
|
|
156
|
+
process.env[envVarName] = apiKey;
|
|
157
|
+
}
|
|
158
|
+
function deleteApiKey(provider) {
|
|
159
|
+
const envVarName = ENV_VAR_NAMES[provider];
|
|
160
|
+
if (!envVarName) return;
|
|
161
|
+
const env = parseEnvFile();
|
|
162
|
+
delete env[envVarName];
|
|
163
|
+
writeEnvFile(env);
|
|
164
|
+
delete process.env[envVarName];
|
|
165
|
+
}
|
|
166
|
+
function hasApiKey(provider) {
|
|
167
|
+
return !!getApiKey(provider);
|
|
168
|
+
}
|
|
99
169
|
const store = new Store({
|
|
100
|
-
name: "
|
|
101
|
-
|
|
102
|
-
// In production, derive from machine ID
|
|
170
|
+
name: "settings",
|
|
171
|
+
cwd: getOpenworkDir()
|
|
103
172
|
});
|
|
104
173
|
const PROVIDERS = [
|
|
105
174
|
{ id: "anthropic", name: "Anthropic" },
|
|
106
|
-
{ id: "openai", name: "OpenAI" }
|
|
107
|
-
{ id: "google", name: "Google" }
|
|
175
|
+
{ id: "openai", name: "OpenAI" }
|
|
108
176
|
];
|
|
109
|
-
const ENV_VAR_MAP = {
|
|
110
|
-
anthropic: "ANTHROPIC_API_KEY",
|
|
111
|
-
openai: "OPENAI_API_KEY",
|
|
112
|
-
google: "GOOGLE_API_KEY",
|
|
113
|
-
ollama: ""
|
|
114
|
-
// Ollama doesn't need API key
|
|
115
|
-
};
|
|
116
177
|
const AVAILABLE_MODELS = [
|
|
117
178
|
// Anthropic Claude 4.5 series (latest as of Jan 2026)
|
|
118
179
|
{
|
|
@@ -120,7 +181,7 @@ const AVAILABLE_MODELS = [
|
|
|
120
181
|
name: "Claude Opus 4.5",
|
|
121
182
|
provider: "anthropic",
|
|
122
183
|
model: "claude-opus-4-5-20251101",
|
|
123
|
-
description: "
|
|
184
|
+
description: "Premium model with maximum intelligence",
|
|
124
185
|
available: true
|
|
125
186
|
},
|
|
126
187
|
{
|
|
@@ -128,7 +189,7 @@ const AVAILABLE_MODELS = [
|
|
|
128
189
|
name: "Claude Sonnet 4.5",
|
|
129
190
|
provider: "anthropic",
|
|
130
191
|
model: "claude-sonnet-4-5-20250929",
|
|
131
|
-
description: "
|
|
192
|
+
description: "Best balance of intelligence, speed, and cost for agents",
|
|
132
193
|
available: true
|
|
133
194
|
},
|
|
134
195
|
{
|
|
@@ -136,7 +197,24 @@ const AVAILABLE_MODELS = [
|
|
|
136
197
|
name: "Claude Haiku 4.5",
|
|
137
198
|
provider: "anthropic",
|
|
138
199
|
model: "claude-haiku-4-5-20251001",
|
|
139
|
-
description: "
|
|
200
|
+
description: "Fastest model with near-frontier intelligence",
|
|
201
|
+
available: true
|
|
202
|
+
},
|
|
203
|
+
// Anthropic Claude legacy models
|
|
204
|
+
{
|
|
205
|
+
id: "claude-opus-4-1-20250805",
|
|
206
|
+
name: "Claude Opus 4.1",
|
|
207
|
+
provider: "anthropic",
|
|
208
|
+
model: "claude-opus-4-1-20250805",
|
|
209
|
+
description: "Previous generation premium model with extended thinking",
|
|
210
|
+
available: true
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
id: "claude-sonnet-4-20250514",
|
|
214
|
+
name: "Claude Sonnet 4",
|
|
215
|
+
provider: "anthropic",
|
|
216
|
+
model: "claude-sonnet-4-20250514",
|
|
217
|
+
description: "Fast and capable previous generation model",
|
|
140
218
|
available: true
|
|
141
219
|
},
|
|
142
220
|
// OpenAI GPT-5 series (latest as of Jan 2026)
|
|
@@ -229,15 +307,6 @@ const AVAILABLE_MODELS = [
|
|
|
229
307
|
model: "gpt-4o-mini",
|
|
230
308
|
description: "Cost-efficient variant with faster response times",
|
|
231
309
|
available: true
|
|
232
|
-
},
|
|
233
|
-
// Google Gemini 3 series (latest as of Jan 2026)
|
|
234
|
-
{
|
|
235
|
-
id: "gemini-3-flash-preview",
|
|
236
|
-
name: "Gemini 3 Flash",
|
|
237
|
-
provider: "google",
|
|
238
|
-
model: "gemini-3-flash-preview",
|
|
239
|
-
description: "Fast, 3x faster than 2.5 Pro with 1M context",
|
|
240
|
-
available: true
|
|
241
310
|
}
|
|
242
311
|
];
|
|
243
312
|
function registerModelHandlers(ipcMain) {
|
|
@@ -256,22 +325,14 @@ function registerModelHandlers(ipcMain) {
|
|
|
256
325
|
ipcMain.handle(
|
|
257
326
|
"models:setApiKey",
|
|
258
327
|
async (_event, { provider, apiKey }) => {
|
|
259
|
-
|
|
260
|
-
const envVar = ENV_VAR_MAP[provider];
|
|
261
|
-
if (envVar) {
|
|
262
|
-
process.env[envVar] = apiKey;
|
|
263
|
-
}
|
|
328
|
+
setApiKey(provider, apiKey);
|
|
264
329
|
}
|
|
265
330
|
);
|
|
266
331
|
ipcMain.handle("models:getApiKey", async (_event, provider) => {
|
|
267
|
-
return
|
|
332
|
+
return getApiKey(provider) ?? null;
|
|
268
333
|
});
|
|
269
334
|
ipcMain.handle("models:deleteApiKey", async (_event, provider) => {
|
|
270
|
-
|
|
271
|
-
const envVar = ENV_VAR_MAP[provider];
|
|
272
|
-
if (envVar) {
|
|
273
|
-
delete process.env[envVar];
|
|
274
|
-
}
|
|
335
|
+
deleteApiKey(provider);
|
|
275
336
|
});
|
|
276
337
|
ipcMain.handle("models:listProviders", async () => {
|
|
277
338
|
return PROVIDERS.map((provider) => ({
|
|
@@ -432,18 +493,6 @@ function registerModelHandlers(ipcMain) {
|
|
|
432
493
|
}
|
|
433
494
|
);
|
|
434
495
|
}
|
|
435
|
-
function hasApiKey(provider) {
|
|
436
|
-
const storedKey = store.get(`apiKeys.${provider}`);
|
|
437
|
-
if (storedKey) return true;
|
|
438
|
-
const envVar = ENV_VAR_MAP[provider];
|
|
439
|
-
return envVar ? !!process.env[envVar] : false;
|
|
440
|
-
}
|
|
441
|
-
function getApiKey(provider) {
|
|
442
|
-
const storedKey = store.get(`apiKeys.${provider}`);
|
|
443
|
-
if (storedKey) return storedKey;
|
|
444
|
-
const envVar = ENV_VAR_MAP[provider];
|
|
445
|
-
return envVar ? process.env[envVar] : void 0;
|
|
446
|
-
}
|
|
447
496
|
function getDefaultModel() {
|
|
448
497
|
return store.get("defaultModel", "claude-sonnet-4-5-20250929");
|
|
449
498
|
}
|
|
@@ -877,8 +926,7 @@ function getSystemPrompt(workspacePath) {
|
|
|
877
926
|
let checkpointer = null;
|
|
878
927
|
async function getCheckpointer() {
|
|
879
928
|
if (!checkpointer) {
|
|
880
|
-
|
|
881
|
-
checkpointer = new SqlJsSaver(dbPath);
|
|
929
|
+
checkpointer = new SqlJsSaver(getCheckpointDbPath());
|
|
882
930
|
await checkpointer.initialize();
|
|
883
931
|
}
|
|
884
932
|
return checkpointer;
|
|
@@ -906,8 +954,6 @@ function getModelInstance(modelId) {
|
|
|
906
954
|
model,
|
|
907
955
|
openAIApiKey: apiKey
|
|
908
956
|
});
|
|
909
|
-
} else if (model.startsWith("gemini")) {
|
|
910
|
-
throw new Error("Gemini support coming soon");
|
|
911
957
|
}
|
|
912
958
|
return model;
|
|
913
959
|
}
|
|
@@ -938,7 +984,6 @@ async function createAgentRuntime(options) {
|
|
|
938
984
|
console.log("[Runtime] Deep agent created with FilesystemBackend at:", workspacePath);
|
|
939
985
|
return agent;
|
|
940
986
|
}
|
|
941
|
-
const getDbPath = () => path.join(electron.app.getPath("userData"), "openwork.sqlite");
|
|
942
987
|
let db = null;
|
|
943
988
|
let saveTimer = null;
|
|
944
989
|
let dirty = false;
|
|
@@ -34262,7 +34262,13 @@ var BaseMessage = class extends Serializable {
|
|
|
34262
34262
|
function isOpenAIToolCallArray(value) {
|
|
34263
34263
|
return Array.isArray(value) && value.every((v2) => typeof v2.index === "number");
|
|
34264
34264
|
}
|
|
34265
|
-
|
|
34265
|
+
const DEFAULT_MERGE_IGNORE_KEYS = [
|
|
34266
|
+
"index",
|
|
34267
|
+
"created",
|
|
34268
|
+
"timestamp"
|
|
34269
|
+
];
|
|
34270
|
+
function _mergeDicts(left, right, options) {
|
|
34271
|
+
const ignoreKeys = options?.ignoreKeys ?? DEFAULT_MERGE_IGNORE_KEYS;
|
|
34266
34272
|
if (left === void 0 && right === void 0) return void 0;
|
|
34267
34273
|
if (left === void 0 || right === void 0) return left ?? right;
|
|
34268
34274
|
const merged = { ...left };
|
|
@@ -34277,15 +34283,18 @@ function _mergeDicts(left, right) {
|
|
|
34277
34283
|
"model_provider"
|
|
34278
34284
|
].includes(key2)) {
|
|
34279
34285
|
if (value) merged[key2] = value;
|
|
34280
|
-
} else
|
|
34281
|
-
else
|
|
34282
|
-
else if (typeof merged[key2] === "
|
|
34283
|
-
|
|
34286
|
+
} else if (ignoreKeys.includes(key2)) continue;
|
|
34287
|
+
else merged[key2] += value;
|
|
34288
|
+
else if (typeof merged[key2] === "number") {
|
|
34289
|
+
if (ignoreKeys.includes(key2)) continue;
|
|
34290
|
+
merged[key2] = merged[key2] + value;
|
|
34291
|
+
} else if (typeof merged[key2] === "object" && !Array.isArray(merged[key2])) merged[key2] = _mergeDicts(merged[key2], value, options);
|
|
34292
|
+
else if (Array.isArray(merged[key2])) merged[key2] = _mergeLists(merged[key2], value, options);
|
|
34284
34293
|
else if (merged[key2] === value) continue;
|
|
34285
34294
|
else console.warn(`field[${key2}] already exists in this message chunk and value has unsupported type.`);
|
|
34286
34295
|
return merged;
|
|
34287
34296
|
}
|
|
34288
|
-
function _mergeLists(left, right) {
|
|
34297
|
+
function _mergeLists(left, right, options) {
|
|
34289
34298
|
if (left === void 0 && right === void 0) return void 0;
|
|
34290
34299
|
else if (left === void 0 || right === void 0) return left || right;
|
|
34291
34300
|
else {
|
|
@@ -34298,22 +34307,22 @@ function _mergeLists(left, right) {
|
|
|
34298
34307
|
const eitherItemMissingID = !("id" in leftItem) || !leftItem?.id || !("id" in item) || !item?.id;
|
|
34299
34308
|
return isObject && indiciesMatch && (idsMatch || eitherItemMissingID);
|
|
34300
34309
|
});
|
|
34301
|
-
if (toMerge !== -1 && typeof merged[toMerge] === "object" && merged[toMerge] !== null) merged[toMerge] = _mergeDicts(merged[toMerge], item);
|
|
34310
|
+
if (toMerge !== -1 && typeof merged[toMerge] === "object" && merged[toMerge] !== null) merged[toMerge] = _mergeDicts(merged[toMerge], item, options);
|
|
34302
34311
|
else merged.push(item);
|
|
34303
34312
|
} else if (typeof item === "object" && item !== null && "text" in item && item.text === "") continue;
|
|
34304
34313
|
else merged.push(item);
|
|
34305
34314
|
return merged;
|
|
34306
34315
|
}
|
|
34307
34316
|
}
|
|
34308
|
-
function _mergeObj(left, right) {
|
|
34317
|
+
function _mergeObj(left, right, options) {
|
|
34309
34318
|
if (left === void 0 && right === void 0) return void 0;
|
|
34310
34319
|
if (left === void 0 || right === void 0) return left ?? right;
|
|
34311
34320
|
else if (typeof left !== typeof right) throw new Error(`Cannot merge objects of different types.
|
|
34312
34321
|
Left ${typeof left}
|
|
34313
34322
|
Right ${typeof right}`);
|
|
34314
34323
|
else if (typeof left === "string" && typeof right === "string") return left + right;
|
|
34315
|
-
else if (Array.isArray(left) && Array.isArray(right)) return _mergeLists(left, right);
|
|
34316
|
-
else if (typeof left === "object" && typeof right === "object") return _mergeDicts(left, right);
|
|
34324
|
+
else if (Array.isArray(left) && Array.isArray(right)) return _mergeLists(left, right, options);
|
|
34325
|
+
else if (typeof left === "object" && typeof right === "object") return _mergeDicts(left, right, options);
|
|
34317
34326
|
else if (left === right) return left;
|
|
34318
34327
|
else throw new Error(`Can not merge objects of different types.
|
|
34319
34328
|
Left ${left}
|
|
@@ -47969,12 +47978,14 @@ const STATUS_NO_RETRY$1 = [
|
|
|
47969
47978
|
409
|
|
47970
47979
|
];
|
|
47971
47980
|
const defaultFailedAttemptHandler = (error) => {
|
|
47972
|
-
if (error
|
|
47973
|
-
if (error
|
|
47974
|
-
|
|
47981
|
+
if (typeof error !== "object" || error === null) return;
|
|
47982
|
+
if ("message" in error && typeof error.message === "string" && (error.message.startsWith("Cancel") || error.message.startsWith("AbortError")) || "name" in error && typeof error.name === "string" && error.name === "AbortError") throw error;
|
|
47983
|
+
if ("code" in error && typeof error.code === "string" && error.code === "ECONNABORTED") throw error;
|
|
47984
|
+
const status = "response" in error && typeof error.response === "object" && error.response !== null && "status" in error.response && typeof error.response.status === "number" ? error.response.status : void 0;
|
|
47975
47985
|
if (status && STATUS_NO_RETRY$1.includes(+status)) throw error;
|
|
47976
|
-
|
|
47977
|
-
|
|
47986
|
+
const code2 = "error" in error && typeof error.error === "object" && error.error !== null && "code" in error.error && typeof error.error.code === "string" ? error.error.code : void 0;
|
|
47987
|
+
if (code2 === "insufficient_quota") {
|
|
47988
|
+
const err = new Error("message" in error && typeof error.message === "string" ? error.message : "Insufficient quota");
|
|
47978
47989
|
err.name = "InsufficientQuotaError";
|
|
47979
47990
|
throw err;
|
|
47980
47991
|
}
|
|
@@ -57172,6 +57183,7 @@ __export(messages_exports, {
|
|
|
57172
57183
|
BaseMessageChunk: () => BaseMessageChunk,
|
|
57173
57184
|
ChatMessage: () => ChatMessage,
|
|
57174
57185
|
ChatMessageChunk: () => ChatMessageChunk,
|
|
57186
|
+
DEFAULT_MERGE_IGNORE_KEYS: () => DEFAULT_MERGE_IGNORE_KEYS,
|
|
57175
57187
|
FunctionMessage: () => FunctionMessage,
|
|
57176
57188
|
FunctionMessageChunk: () => FunctionMessageChunk,
|
|
57177
57189
|
HumanMessage: () => HumanMessage,
|
|
@@ -73456,20 +73468,15 @@ function AnthropicIcon({ className }) {
|
|
|
73456
73468
|
function OpenAIIcon({ className }) {
|
|
73457
73469
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M22.282 9.821a5.985 5.985 0 0 0-.516-4.91 6.046 6.046 0 0 0-6.51-2.9A6.065 6.065 0 0 0 4.981 4.18a5.985 5.985 0 0 0-3.998 2.9 6.046 6.046 0 0 0 .743 7.097 5.98 5.98 0 0 0 .51 4.911 6.051 6.051 0 0 0 6.515 2.9A5.985 5.985 0 0 0 13.26 24a6.056 6.056 0 0 0 5.772-4.206 5.99 5.99 0 0 0 3.997-2.9 6.056 6.056 0 0 0-.747-7.073zM13.26 22.43a4.476 4.476 0 0 1-2.876-1.04l.141-.081 4.779-2.758a.795.795 0 0 0 .392-.681v-6.737l2.02 1.168a.071.071 0 0 1 .038.052v5.583a4.504 4.504 0 0 1-4.494 4.494zM3.6 18.304a4.47 4.47 0 0 1-.535-3.014l.142.085 4.783 2.759a.771.771 0 0 0 .78 0l5.843-3.369v2.332a.08.08 0 0 1-.033.062L9.74 19.95a4.5 4.5 0 0 1-6.14-1.646zM2.34 7.896a4.485 4.485 0 0 1 2.366-1.973V11.6a.766.766 0 0 0 .388.676l5.815 3.355-2.02 1.168a.076.076 0 0 1-.071 0l-4.83-2.786A4.504 4.504 0 0 1 2.34 7.872zm16.597 3.855l-5.833-3.387L15.119 7.2a.076.076 0 0 1 .071 0l4.83 2.791a4.494 4.494 0 0 1-.676 8.105v-5.678a.79.79 0 0 0-.407-.667zm2.01-3.023l-.141-.085-4.774-2.782a.776.776 0 0 0-.785 0L9.409 9.23V6.897a.066.066 0 0 1 .028-.061l4.83-2.787a4.5 4.5 0 0 1 6.68 4.66zm-12.64 4.135l-2.02-1.164a.08.08 0 0 1-.038-.057V6.075a4.5 4.5 0 0 1 7.375-3.453l-.142.08L8.704 5.46a.795.795 0 0 0-.393.681zm1.097-2.365l2.602-1.5 2.607 1.5v2.999l-2.597 1.5-2.607-1.5z" }) });
|
|
73458
73470
|
}
|
|
73459
|
-
function GoogleIcon({ className }) {
|
|
73460
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z" }) });
|
|
73461
|
-
}
|
|
73462
73471
|
const PROVIDER_ICONS = {
|
|
73463
73472
|
anthropic: AnthropicIcon,
|
|
73464
73473
|
openai: OpenAIIcon,
|
|
73465
|
-
google: GoogleIcon,
|
|
73466
73474
|
ollama: () => null
|
|
73467
73475
|
// No icon for ollama yet
|
|
73468
73476
|
};
|
|
73469
73477
|
const FALLBACK_PROVIDERS = [
|
|
73470
73478
|
{ id: "anthropic", name: "Anthropic", hasApiKey: false },
|
|
73471
|
-
{ id: "openai", name: "OpenAI", hasApiKey: false }
|
|
73472
|
-
{ id: "google", name: "Google AI", hasApiKey: false }
|
|
73479
|
+
{ id: "openai", name: "OpenAI", hasApiKey: false }
|
|
73473
73480
|
];
|
|
73474
73481
|
function ModelSwitcher() {
|
|
73475
73482
|
const [open, setOpen] = reactExports.useState(false);
|
|
@@ -73587,29 +73594,31 @@ function ModelSwitcher() {
|
|
|
73587
73594
|
)
|
|
73588
73595
|
] })
|
|
73589
73596
|
) : (
|
|
73590
|
-
// Show models list
|
|
73591
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "
|
|
73592
|
-
|
|
73593
|
-
|
|
73594
|
-
|
|
73595
|
-
|
|
73596
|
-
|
|
73597
|
-
|
|
73598
|
-
|
|
73599
|
-
|
|
73600
|
-
|
|
73601
|
-
|
|
73602
|
-
|
|
73603
|
-
|
|
73604
|
-
|
|
73605
|
-
|
|
73606
|
-
|
|
73607
|
-
|
|
73597
|
+
// Show models list with scrollable area
|
|
73598
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-[200px]", children: [
|
|
73599
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "overflow-y-auto flex-1 space-y-0.5", children: [
|
|
73600
|
+
filteredModels.map((model) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
73601
|
+
"button",
|
|
73602
|
+
{
|
|
73603
|
+
onClick: () => handleModelSelect(model.id),
|
|
73604
|
+
className: cn(
|
|
73605
|
+
"w-full flex items-center gap-1.5 px-2 py-1 rounded-sm text-xs transition-colors text-left font-mono",
|
|
73606
|
+
currentModel === model.id ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
|
|
73607
|
+
),
|
|
73608
|
+
children: [
|
|
73609
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 truncate", children: model.id }),
|
|
73610
|
+
currentModel === model.id && /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 shrink-0 text-foreground" })
|
|
73611
|
+
]
|
|
73612
|
+
},
|
|
73613
|
+
model.id
|
|
73614
|
+
)),
|
|
73615
|
+
filteredModels.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground px-2 py-4", children: "No models available" })
|
|
73616
|
+
] }),
|
|
73608
73617
|
selectedProvider?.hasApiKey && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
73609
73618
|
"button",
|
|
73610
73619
|
{
|
|
73611
73620
|
onClick: () => handleConfigureApiKey(selectedProvider),
|
|
73612
|
-
className: "w-full flex items-center gap-2 px-2 py-1.5 rounded-sm text-xs text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors mt-2",
|
|
73621
|
+
className: "w-full flex items-center gap-2 px-2 py-1.5 rounded-sm text-xs text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors mt-2 border-t border-border pt-2",
|
|
73613
73622
|
children: [
|
|
73614
73623
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Key, { className: "size-3.5" }),
|
|
73615
73624
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Edit API Key" })
|
|
@@ -74676,7 +74685,7 @@ function ChatContainer({ threadId }) {
|
|
|
74676
74685
|
"button",
|
|
74677
74686
|
{
|
|
74678
74687
|
type: "button",
|
|
74679
|
-
className: "inline-flex items-center justify-center rounded-md border border-border bg-background px-2 h-7 text-xs gap-1.5 text-amber-500 hover:bg-accent/50 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
74688
|
+
className: "inline-flex items-center justify-center rounded-md border border-border bg-background px-2 h-7 text-xs gap-1.5 text-amber-500 hover:bg-accent/50 transition-color duration-100 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
74680
74689
|
onClick: handleSelectWorkspaceFromEmptyState,
|
|
74681
74690
|
children: [
|
|
74682
74691
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Folder, { className: "size-3.5" }),
|
|
@@ -75120,7 +75129,7 @@ function TaskItem({ todo }) {
|
|
|
75120
75129
|
function FilesContent() {
|
|
75121
75130
|
const { workspaceFiles, workspacePath, currentThreadId, setWorkspacePath, setWorkspaceFiles } = useAppStore();
|
|
75122
75131
|
const [syncing, setSyncing] = reactExports.useState(false);
|
|
75123
|
-
const [syncSuccess
|
|
75132
|
+
const [syncSuccess] = reactExports.useState(false);
|
|
75124
75133
|
reactExports.useEffect(() => {
|
|
75125
75134
|
async function loadWorkspace() {
|
|
75126
75135
|
if (currentThreadId) {
|
|
@@ -75136,6 +75145,19 @@ function FilesContent() {
|
|
|
75136
75145
|
}
|
|
75137
75146
|
loadWorkspace();
|
|
75138
75147
|
}, [currentThreadId, setWorkspacePath, setWorkspaceFiles]);
|
|
75148
|
+
reactExports.useEffect(() => {
|
|
75149
|
+
if (!currentThreadId) return;
|
|
75150
|
+
const cleanup = window.api.workspace.onFilesChanged(async (data) => {
|
|
75151
|
+
if (data.threadId === currentThreadId) {
|
|
75152
|
+
console.log("[FilesContent] Files changed, reloading...", data);
|
|
75153
|
+
const result = await window.api.workspace.loadFromDisk(currentThreadId);
|
|
75154
|
+
if (result.success && result.files) {
|
|
75155
|
+
setWorkspaceFiles(result.files);
|
|
75156
|
+
}
|
|
75157
|
+
}
|
|
75158
|
+
});
|
|
75159
|
+
return cleanup;
|
|
75160
|
+
}, [currentThreadId, setWorkspaceFiles]);
|
|
75139
75161
|
async function handleSelectFolder() {
|
|
75140
75162
|
if (!currentThreadId) return;
|
|
75141
75163
|
setSyncing(true);
|
|
@@ -75535,7 +75557,7 @@ function App() {
|
|
|
75535
75557
|
},
|
|
75536
75558
|
children: [
|
|
75537
75559
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "app-badge-name", children: "OPENWORK" }),
|
|
75538
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "app-badge-version", children: "0.1.1-rc.
|
|
75560
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "app-badge-version", children: "0.1.1-rc.4" })
|
|
75539
75561
|
]
|
|
75540
75562
|
}
|
|
75541
75563
|
),
|
|
@@ -652,6 +652,10 @@
|
|
|
652
652
|
height: 180px;
|
|
653
653
|
}
|
|
654
654
|
|
|
655
|
+
.h-\[200px\] {
|
|
656
|
+
height: 200px;
|
|
657
|
+
}
|
|
658
|
+
|
|
655
659
|
.h-full {
|
|
656
660
|
height: 100%;
|
|
657
661
|
}
|
|
@@ -951,6 +955,10 @@
|
|
|
951
955
|
overflow-x: auto;
|
|
952
956
|
}
|
|
953
957
|
|
|
958
|
+
.overflow-y-auto {
|
|
959
|
+
overflow-y: auto;
|
|
960
|
+
}
|
|
961
|
+
|
|
954
962
|
.rounded {
|
|
955
963
|
border-radius: .25rem;
|
|
956
964
|
}
|
|
@@ -1462,6 +1470,10 @@
|
|
|
1462
1470
|
padding-top: calc(var(--spacing) * 0);
|
|
1463
1471
|
}
|
|
1464
1472
|
|
|
1473
|
+
.pt-2 {
|
|
1474
|
+
padding-top: calc(var(--spacing) * 2);
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1465
1477
|
.pr-2 {
|
|
1466
1478
|
padding-right: calc(var(--spacing) * 2);
|
|
1467
1479
|
}
|
|
@@ -1795,6 +1807,11 @@
|
|
|
1795
1807
|
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
|
1796
1808
|
}
|
|
1797
1809
|
|
|
1810
|
+
.duration-100 {
|
|
1811
|
+
--tw-duration: .1s;
|
|
1812
|
+
transition-duration: .1s;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1798
1815
|
.duration-200 {
|
|
1799
1816
|
--tw-duration: .2s;
|
|
1800
1817
|
transition-duration: .2s;
|
package/out/renderer/index.html
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
http-equiv="Content-Security-Policy"
|
|
8
8
|
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
|
|
9
9
|
/>
|
|
10
|
-
<script type="module" crossorigin src="./assets/index-
|
|
11
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
10
|
+
<script type="module" crossorigin src="./assets/index-BttVUwrw.js"></script>
|
|
11
|
+
<link rel="stylesheet" crossorigin href="./assets/index-DjlJs7Yy.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
14
14
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openwork",
|
|
3
|
-
"version": "0.1.1-rc.
|
|
3
|
+
"version": "0.1.1-rc.4",
|
|
4
4
|
"description": "A tactical agent interface for deepagentsjs",
|
|
5
5
|
"main": "./out/main/index.js",
|
|
6
6
|
"files": [
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"electron": "^39.2.6",
|
|
50
|
-
"@langchain/anthropic": "^1.3.
|
|
51
|
-
"@langchain/core": "
|
|
50
|
+
"@langchain/anthropic": "^1.3.10",
|
|
51
|
+
"@langchain/core": "1.1.15",
|
|
52
52
|
"@langchain/langgraph": "^1.0.15",
|
|
53
53
|
"@langchain/langgraph-checkpoint": "^1.0.0",
|
|
54
54
|
"@langchain/langgraph-sdk": "^1.5.3",
|
|
55
|
-
"@langchain/openai": "^1.2.
|
|
55
|
+
"@langchain/openai": "^1.2.2",
|
|
56
56
|
"@radix-ui/react-context-menu": "^2.2.16",
|
|
57
57
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
58
58
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|