sparkecoder 0.1.87 → 0.1.93
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 +1 -1
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.js +158 -68
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +416 -108
- package/dist/cli.js.map +1 -1
- package/dist/db/index.d.ts +2 -2
- package/dist/{index-BvIissiB.d.ts → index-Bn0Zox8f.d.ts} +23 -23
- package/dist/index.d.ts +5 -5
- package/dist/index.js +272 -97
- package/dist/index.js.map +1 -1
- package/dist/{schema-CohdIL13.d.ts → schema-EmpbnQeQ.d.ts} +3 -3
- package/dist/{search-CCffrVJE.d.ts → search-BRnGaIl-.d.ts} +7 -7
- package/dist/server/index.js +272 -97
- package/dist/server/index.js.map +1 -1
- package/dist/tools/index.d.ts +30 -3
- package/dist/tools/index.js +38 -4
- package/dist/tools/index.js.map +1 -1
- package/package.json +5 -5
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/embed/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/index.html +1 -1
- package/web/.next/standalone/web/.next/server/app/index.rsc +4 -4
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__36edac7c._.js +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__be5e2967._.js +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_app_(main)_page_tsx_5ac4794b._.js +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_components_sessions-sidebar_tsx_92510070._.js +1 -1
- package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
- package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/{static/chunks/26eb5fab5216f3cc.js → standalone/web/.next/static/chunks/58fd0aaa2746b444.js} +1 -1
- package/web/.next/standalone/web/.next/static/chunks/9fce2ce79c4c834e.js +1 -0
- package/web/.next/standalone/web/.next/static/chunks/{8d3efc76109d2efc.js → a888d448ceab1abe.js} +1 -1
- package/web/.next/standalone/web/.next/static/static/chunks/{26eb5fab5216f3cc.js → 58fd0aaa2746b444.js} +1 -1
- package/web/.next/standalone/web/.next/static/static/chunks/9fce2ce79c4c834e.js +1 -0
- package/web/.next/{static/chunks/8d3efc76109d2efc.js → standalone/web/.next/static/static/chunks/a888d448ceab1abe.js} +1 -1
- package/web/.next/standalone/web/package-lock.json +27 -27
- package/web/.next/standalone/web/package.json +1 -1
- package/web/.next/standalone/web/src/app/(main)/page.tsx +2 -2
- package/web/.next/standalone/web/src/app/api/config/route.ts +3 -2
- package/web/.next/standalone/web/src/components/sessions-sidebar.tsx +1 -1
- package/web/.next/standalone/web/src/lib/config.ts +2 -1
- package/web/.next/{standalone/web/.next/static/chunks/26eb5fab5216f3cc.js → static/chunks/58fd0aaa2746b444.js} +1 -1
- package/web/.next/static/chunks/9fce2ce79c4c834e.js +1 -0
- package/web/.next/{standalone/web/.next/static/static/chunks/8d3efc76109d2efc.js → static/chunks/a888d448ceab1abe.js} +1 -1
- package/web/package.json +1 -1
- package/web/.next/standalone/web/.next/static/chunks/b31b0765abe0c427.js +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/b31b0765abe0c427.js +0 -1
- package/web/.next/static/chunks/b31b0765abe0c427.js +0 -1
- /package/web/.next/standalone/web/.next/static/{static/uUaN7Xe5kF_pP6zhfaeYi → -ax3tJNqBGukss29jpu41}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{static/uUaN7Xe5kF_pP6zhfaeYi → -ax3tJNqBGukss29jpu41}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{static/uUaN7Xe5kF_pP6zhfaeYi → -ax3tJNqBGukss29jpu41}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → static/-ax3tJNqBGukss29jpu41}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → static/-ax3tJNqBGukss29jpu41}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → static/-ax3tJNqBGukss29jpu41}/_ssgManifest.js +0 -0
- /package/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → -ax3tJNqBGukss29jpu41}/_buildManifest.js +0 -0
- /package/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → -ax3tJNqBGukss29jpu41}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → -ax3tJNqBGukss29jpu41}/_ssgManifest.js +0 -0
package/dist/index.js
CHANGED
|
@@ -107,7 +107,7 @@ var init_types = __esm({
|
|
|
107
107
|
}).optional();
|
|
108
108
|
SparkcoderConfigSchema = z.object({
|
|
109
109
|
// Default model to use (Vercel AI Gateway format)
|
|
110
|
-
defaultModel: z.string().default("anthropic/claude-opus-4
|
|
110
|
+
defaultModel: z.string().default("anthropic/claude-opus-4.7"),
|
|
111
111
|
// Working directory for file operations
|
|
112
112
|
workingDirectory: z.string().optional(),
|
|
113
113
|
// Tool approval settings
|
|
@@ -466,6 +466,14 @@ function loadApiKeysIntoEnv() {
|
|
|
466
466
|
}
|
|
467
467
|
}
|
|
468
468
|
}
|
|
469
|
+
function isRemoteInferenceConfigured() {
|
|
470
|
+
try {
|
|
471
|
+
const config = getConfig();
|
|
472
|
+
return config.resolvedRemoteServer.isConfigured;
|
|
473
|
+
} catch {
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
469
477
|
function setApiKey(provider, apiKey) {
|
|
470
478
|
const normalizedProvider = provider.toLowerCase();
|
|
471
479
|
const envVar = PROVIDER_ENV_MAP[normalizedProvider];
|
|
@@ -515,11 +523,11 @@ function getApiKeyStatus() {
|
|
|
515
523
|
};
|
|
516
524
|
});
|
|
517
525
|
}
|
|
518
|
-
function maskApiKey(
|
|
519
|
-
if (
|
|
520
|
-
return "****" +
|
|
526
|
+
function maskApiKey(key2) {
|
|
527
|
+
if (key2.length <= 12) {
|
|
528
|
+
return "****" + key2.slice(-4);
|
|
521
529
|
}
|
|
522
|
-
return
|
|
530
|
+
return key2.slice(0, 4) + "..." + key2.slice(-4);
|
|
523
531
|
}
|
|
524
532
|
var CONFIG_FILE_NAMES, cachedConfig, AUTH_KEY_FILE, API_KEYS_FILE, PROVIDER_ENV_MAP, SUPPORTED_PROVIDERS;
|
|
525
533
|
var init_config = __esm({
|
|
@@ -566,9 +574,9 @@ __export(remote_exports, {
|
|
|
566
574
|
remoteToolExecutionQueries: () => remoteToolExecutionQueries,
|
|
567
575
|
storageQueries: () => storageQueries
|
|
568
576
|
});
|
|
569
|
-
function initRemoteDatabase(serverUrl,
|
|
577
|
+
function initRemoteDatabase(serverUrl, key2) {
|
|
570
578
|
remoteServerUrl = serverUrl.replace(/\/$/, "");
|
|
571
|
-
authKey =
|
|
579
|
+
authKey = key2;
|
|
572
580
|
}
|
|
573
581
|
function closeRemoteDatabase() {
|
|
574
582
|
remoteServerUrl = null;
|
|
@@ -582,14 +590,14 @@ function parseDates(obj) {
|
|
|
582
590
|
if (Array.isArray(obj)) return obj.map(parseDates);
|
|
583
591
|
if (typeof obj !== "object" || obj instanceof Date) return obj;
|
|
584
592
|
const result = { ...obj };
|
|
585
|
-
for (const
|
|
586
|
-
if (MODEL_MESSAGE_FIELDS.includes(
|
|
593
|
+
for (const key2 of Object.keys(result)) {
|
|
594
|
+
if (MODEL_MESSAGE_FIELDS.includes(key2)) {
|
|
587
595
|
continue;
|
|
588
596
|
}
|
|
589
|
-
if (DATE_FIELDS.includes(
|
|
590
|
-
result[
|
|
591
|
-
} else if (typeof result[
|
|
592
|
-
result[
|
|
597
|
+
if (DATE_FIELDS.includes(key2) && typeof result[key2] === "string") {
|
|
598
|
+
result[key2] = new Date(result[key2]);
|
|
599
|
+
} else if (typeof result[key2] === "object") {
|
|
600
|
+
result[key2] = parseDates(result[key2]);
|
|
593
601
|
}
|
|
594
602
|
}
|
|
595
603
|
return result;
|
|
@@ -1462,10 +1470,10 @@ function parseSkillFrontmatter(content) {
|
|
|
1462
1470
|
}
|
|
1463
1471
|
const colonIndex = line.indexOf(":");
|
|
1464
1472
|
if (colonIndex > 0) {
|
|
1465
|
-
const
|
|
1473
|
+
const key2 = line.slice(0, colonIndex).trim();
|
|
1466
1474
|
let value = line.slice(colonIndex + 1).trim();
|
|
1467
1475
|
if (value === "" || value === "[]") {
|
|
1468
|
-
currentArrayKey =
|
|
1476
|
+
currentArrayKey = key2;
|
|
1469
1477
|
currentArray = [];
|
|
1470
1478
|
continue;
|
|
1471
1479
|
}
|
|
@@ -1478,18 +1486,18 @@ function parseSkillFrontmatter(content) {
|
|
|
1478
1486
|
}
|
|
1479
1487
|
return trimmed;
|
|
1480
1488
|
}).filter((item) => item.length > 0);
|
|
1481
|
-
data[
|
|
1489
|
+
data[key2] = items;
|
|
1482
1490
|
continue;
|
|
1483
1491
|
}
|
|
1484
1492
|
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
1485
1493
|
value = value.slice(1, -1);
|
|
1486
1494
|
}
|
|
1487
1495
|
if (value === "true") {
|
|
1488
|
-
data[
|
|
1496
|
+
data[key2] = true;
|
|
1489
1497
|
} else if (value === "false") {
|
|
1490
|
-
data[
|
|
1498
|
+
data[key2] = false;
|
|
1491
1499
|
} else {
|
|
1492
|
-
data[
|
|
1500
|
+
data[key2] = value;
|
|
1493
1501
|
}
|
|
1494
1502
|
}
|
|
1495
1503
|
}
|
|
@@ -1821,9 +1829,9 @@ var init_chunker = __esm({
|
|
|
1821
1829
|
});
|
|
1822
1830
|
|
|
1823
1831
|
// src/semantic/client.ts
|
|
1824
|
-
function initVectorClient(serverUrl,
|
|
1832
|
+
function initVectorClient(serverUrl, key2) {
|
|
1825
1833
|
remoteServerUrl2 = serverUrl.replace(/\/$/, "");
|
|
1826
|
-
authKey2 =
|
|
1834
|
+
authKey2 = key2;
|
|
1827
1835
|
}
|
|
1828
1836
|
function isVectorClientConfigured() {
|
|
1829
1837
|
return !!remoteServerUrl2 && !!authKey2;
|
|
@@ -2422,7 +2430,7 @@ import { promisify as promisify6 } from "util";
|
|
|
2422
2430
|
import { writeFile as writeFile5, mkdir as mkdir4, readFile as readFile11, unlink as unlink2, readdir as readdir5, rm } from "fs/promises";
|
|
2423
2431
|
import { join as join9 } from "path";
|
|
2424
2432
|
import { tmpdir as tmpdir2 } from "os";
|
|
2425
|
-
import { nanoid as
|
|
2433
|
+
import { nanoid as nanoid5 } from "nanoid";
|
|
2426
2434
|
async function checkFfmpeg() {
|
|
2427
2435
|
try {
|
|
2428
2436
|
await execAsync6("ffmpeg -version", { timeout: 5e3 });
|
|
@@ -2477,7 +2485,7 @@ var init_recorder = __esm({
|
|
|
2477
2485
|
*/
|
|
2478
2486
|
async encode() {
|
|
2479
2487
|
if (this.frames.length === 0) return null;
|
|
2480
|
-
const workDir = join9(tmpdir2(), `sparkecoder-recording-${
|
|
2488
|
+
const workDir = join9(tmpdir2(), `sparkecoder-recording-${nanoid5(8)}`);
|
|
2481
2489
|
await mkdir4(workDir, { recursive: true });
|
|
2482
2490
|
try {
|
|
2483
2491
|
for (let i = 0; i < this.frames.length; i++) {
|
|
@@ -2697,6 +2705,23 @@ function isAnthropicModel(modelId) {
|
|
|
2697
2705
|
const normalized = modelId.trim().toLowerCase();
|
|
2698
2706
|
return normalized.startsWith(ANTHROPIC_PREFIX) || normalized.startsWith("claude-");
|
|
2699
2707
|
}
|
|
2708
|
+
function requiresAdaptiveThinking(modelId) {
|
|
2709
|
+
const m = modelId.toLowerCase().match(/claude-(?:opus|sonnet|haiku)-(\d+)[.-](\d{1,2})(?!\d)/);
|
|
2710
|
+
if (!m) return false;
|
|
2711
|
+
const major = Number(m[1]);
|
|
2712
|
+
const minor = Number(m[2]);
|
|
2713
|
+
if (Number.isNaN(major) || Number.isNaN(minor)) return false;
|
|
2714
|
+
if (major > 4) return true;
|
|
2715
|
+
if (major === 4 && minor >= 6) return true;
|
|
2716
|
+
return false;
|
|
2717
|
+
}
|
|
2718
|
+
function getAnthropicProviderOptions(modelId, opts = {}) {
|
|
2719
|
+
const { toolStreaming, budgetTokens = 1e4 } = opts;
|
|
2720
|
+
const thinking = requiresAdaptiveThinking(modelId) ? { type: "adaptive" } : { type: "enabled", budgetTokens };
|
|
2721
|
+
const out = { thinking };
|
|
2722
|
+
if (toolStreaming) out.toolStreaming = true;
|
|
2723
|
+
return out;
|
|
2724
|
+
}
|
|
2700
2725
|
function resolveModel(modelId) {
|
|
2701
2726
|
try {
|
|
2702
2727
|
const config = getConfig();
|
|
@@ -2720,7 +2745,7 @@ var SUBAGENT_MODELS = {
|
|
|
2720
2745
|
init_db();
|
|
2721
2746
|
init_config();
|
|
2722
2747
|
import { z as z15 } from "zod";
|
|
2723
|
-
import { nanoid as
|
|
2748
|
+
import { nanoid as nanoid6 } from "nanoid";
|
|
2724
2749
|
|
|
2725
2750
|
// src/tools/bash.ts
|
|
2726
2751
|
import { tool } from "ai";
|
|
@@ -3070,11 +3095,11 @@ async function sendInput(terminalId, input, options = {}) {
|
|
|
3070
3095
|
return false;
|
|
3071
3096
|
}
|
|
3072
3097
|
}
|
|
3073
|
-
async function sendKey(terminalId,
|
|
3098
|
+
async function sendKey(terminalId, key2) {
|
|
3074
3099
|
const session = getSessionName(terminalId);
|
|
3075
3100
|
try {
|
|
3076
3101
|
await execAsync(`tmux has-session -t ${session}`, { timeout: 1e3 });
|
|
3077
|
-
await execAsync(`tmux send-keys -t ${session} ${
|
|
3102
|
+
await execAsync(`tmux send-keys -t ${session} ${key2}`, { timeout: 1e3 });
|
|
3078
3103
|
return true;
|
|
3079
3104
|
} catch {
|
|
3080
3105
|
return false;
|
|
@@ -3213,7 +3238,7 @@ bash({ id: "abc123", input: "my text" }) // send text input
|
|
|
3213
3238
|
Terminal output is stored in the global SparkECoder data directory. Use the \`tail\` option to read recent output.`,
|
|
3214
3239
|
inputSchema: bashInputSchema,
|
|
3215
3240
|
execute: async (inputArgs) => {
|
|
3216
|
-
const { command, background, id, kill, tail, input: textInput, key } = inputArgs;
|
|
3241
|
+
const { command, background, id, kill, tail, input: textInput, key: key2 } = inputArgs;
|
|
3217
3242
|
if (id) {
|
|
3218
3243
|
if (kill) {
|
|
3219
3244
|
const success = await killTerminal(id);
|
|
@@ -3244,8 +3269,8 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
|
|
|
3244
3269
|
message: `Sent input "${textInput}" to terminal`
|
|
3245
3270
|
};
|
|
3246
3271
|
}
|
|
3247
|
-
if (
|
|
3248
|
-
const success = await sendKey(id,
|
|
3272
|
+
if (key2) {
|
|
3273
|
+
const success = await sendKey(id, key2);
|
|
3249
3274
|
if (!success) {
|
|
3250
3275
|
return {
|
|
3251
3276
|
success: false,
|
|
@@ -3261,7 +3286,7 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
|
|
|
3261
3286
|
id,
|
|
3262
3287
|
output: truncatedOutput2,
|
|
3263
3288
|
status: status2,
|
|
3264
|
-
message: `Sent key "${
|
|
3289
|
+
message: `Sent key "${key2}" to terminal`
|
|
3265
3290
|
};
|
|
3266
3291
|
}
|
|
3267
3292
|
const { output, status } = await getLogs(id, options.workingDirectory, { tail, sessionId: options.sessionId });
|
|
@@ -3403,13 +3428,13 @@ async function resizeImageIfNeeded(buffer, mediaType) {
|
|
|
3403
3428
|
const needsResize = longEdge > MAX_LONG_EDGE;
|
|
3404
3429
|
const needsShrink = buffer.length > MAX_FILE_BYTES;
|
|
3405
3430
|
if (!needsResize && !needsShrink) return { buffer, mediaType: inputMediaType };
|
|
3406
|
-
const
|
|
3431
|
+
const key2 = cacheKey(buffer);
|
|
3407
3432
|
const cacheDir = getCacheDir();
|
|
3408
3433
|
const isPng = inputMediaType.includes("png");
|
|
3409
3434
|
const willConvertToJpeg = isPng && (needsShrink || buffer.length > 2 * 1024 * 1024);
|
|
3410
3435
|
const outputMediaType = willConvertToJpeg || !isPng ? "image/jpeg" : "image/png";
|
|
3411
3436
|
const ext = outputMediaType === "image/png" ? ".png" : ".jpg";
|
|
3412
|
-
const cachePath = join3(cacheDir,
|
|
3437
|
+
const cachePath = join3(cacheDir, key2 + ext);
|
|
3413
3438
|
if (existsSync3(cachePath)) {
|
|
3414
3439
|
console.log(`[image-resize] Cache hit for ${width}x${height} image`);
|
|
3415
3440
|
return { buffer: readFileSync2(cachePath), mediaType: outputMediaType };
|
|
@@ -4300,31 +4325,31 @@ async function getClientForFile(filePath) {
|
|
|
4300
4325
|
return null;
|
|
4301
4326
|
}
|
|
4302
4327
|
const root = dirname4(normalized);
|
|
4303
|
-
const
|
|
4304
|
-
const existing = state.clients.get(
|
|
4328
|
+
const key2 = `${serverDef.id}:${root}`;
|
|
4329
|
+
const existing = state.clients.get(key2);
|
|
4305
4330
|
if (existing) {
|
|
4306
4331
|
return existing;
|
|
4307
4332
|
}
|
|
4308
|
-
if (state.broken.has(
|
|
4333
|
+
if (state.broken.has(key2)) {
|
|
4309
4334
|
return null;
|
|
4310
4335
|
}
|
|
4311
4336
|
try {
|
|
4312
4337
|
const handle = await serverDef.spawn(root);
|
|
4313
4338
|
if (!handle) {
|
|
4314
|
-
state.broken.add(
|
|
4339
|
+
state.broken.add(key2);
|
|
4315
4340
|
return null;
|
|
4316
4341
|
}
|
|
4317
4342
|
console.log(`[lsp] Started ${serverDef.name} for ${root}`);
|
|
4318
4343
|
const client = await createClient(serverDef.id, handle, root);
|
|
4319
|
-
state.clients.set(
|
|
4344
|
+
state.clients.set(key2, client);
|
|
4320
4345
|
handle.process.on("exit", (code) => {
|
|
4321
4346
|
console.log(`[lsp] ${serverDef.name} exited with code ${code}`);
|
|
4322
|
-
state.clients.delete(
|
|
4347
|
+
state.clients.delete(key2);
|
|
4323
4348
|
});
|
|
4324
4349
|
return client;
|
|
4325
4350
|
} catch (error) {
|
|
4326
4351
|
console.error(`[lsp] Failed to start ${serverDef.name}:`, error);
|
|
4327
|
-
state.broken.add(
|
|
4352
|
+
state.broken.add(key2);
|
|
4328
4353
|
return null;
|
|
4329
4354
|
}
|
|
4330
4355
|
}
|
|
@@ -6056,6 +6081,7 @@ init_semantic_search();
|
|
|
6056
6081
|
import { tool as tool11 } from "ai";
|
|
6057
6082
|
import { z as z12 } from "zod";
|
|
6058
6083
|
import Ajv from "ajv";
|
|
6084
|
+
import { nanoid as nanoid3 } from "nanoid";
|
|
6059
6085
|
var ajv = new Ajv({ allErrors: true });
|
|
6060
6086
|
function createCompleteTaskTool(options) {
|
|
6061
6087
|
const validate = ajv.compile(options.outputSchema);
|
|
@@ -6102,6 +6128,37 @@ function createTaskFailedTool(options) {
|
|
|
6102
6128
|
}
|
|
6103
6129
|
});
|
|
6104
6130
|
}
|
|
6131
|
+
function createAskQuestionToUserTool(options) {
|
|
6132
|
+
return tool11({
|
|
6133
|
+
description: "Ask the user a blocking clarification question when you cannot safely continue without more information. Use this only after trying to infer the answer from the available context. The task will pause until the orchestrator or user answers.",
|
|
6134
|
+
inputSchema: z12.object({
|
|
6135
|
+
question: z12.string().min(1).describe("The concise question you need answered."),
|
|
6136
|
+
context: z12.string().optional().describe("Brief context explaining why this answer is needed and what you already tried."),
|
|
6137
|
+
choices: z12.array(z12.string().min(1)).max(10).optional().describe("Optional suggested answer choices when the question is multiple choice.")
|
|
6138
|
+
}),
|
|
6139
|
+
execute: async (input) => {
|
|
6140
|
+
if (!options.onQuestion) {
|
|
6141
|
+
return {
|
|
6142
|
+
status: "unavailable",
|
|
6143
|
+
message: "Question routing is not configured for this task. Continue with the best safe assumption or call task_failed if blocked."
|
|
6144
|
+
};
|
|
6145
|
+
}
|
|
6146
|
+
const questionId = `q_${nanoid3(12)}`;
|
|
6147
|
+
const answer = await options.onQuestion({
|
|
6148
|
+
questionId,
|
|
6149
|
+
question: input.question,
|
|
6150
|
+
context: input.context,
|
|
6151
|
+
choices: input.choices
|
|
6152
|
+
});
|
|
6153
|
+
return {
|
|
6154
|
+
status: "answered",
|
|
6155
|
+
questionId,
|
|
6156
|
+
answer: answer.answer,
|
|
6157
|
+
answeredBy: answer.answeredBy ?? "unknown"
|
|
6158
|
+
};
|
|
6159
|
+
}
|
|
6160
|
+
});
|
|
6161
|
+
}
|
|
6105
6162
|
|
|
6106
6163
|
// src/tools/upload-file.ts
|
|
6107
6164
|
import { tool as tool12 } from "ai";
|
|
@@ -6207,7 +6264,7 @@ import { promisify as promisify5 } from "util";
|
|
|
6207
6264
|
import { mkdirSync as mkdirSync5, existsSync as existsSync15, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
|
|
6208
6265
|
import { join as join8 } from "path";
|
|
6209
6266
|
import { tmpdir } from "os";
|
|
6210
|
-
import { nanoid as
|
|
6267
|
+
import { nanoid as nanoid4 } from "nanoid";
|
|
6211
6268
|
var execAsync5 = promisify5(exec5);
|
|
6212
6269
|
var DEFAULT_WIDTH = 1280;
|
|
6213
6270
|
var DEFAULT_HEIGHT = 800;
|
|
@@ -6331,9 +6388,9 @@ async function runScroll(dx, dy) {
|
|
|
6331
6388
|
{ timeout: 5e3 }
|
|
6332
6389
|
);
|
|
6333
6390
|
}
|
|
6334
|
-
function translateKeyForCliclick(
|
|
6335
|
-
if (!
|
|
6336
|
-
const parts =
|
|
6391
|
+
function translateKeyForCliclick(key2) {
|
|
6392
|
+
if (!key2) return [];
|
|
6393
|
+
const parts = key2.split("+").map((p) => p.trim()).filter(Boolean);
|
|
6337
6394
|
if (parts.length === 0) return [];
|
|
6338
6395
|
const modMap = {
|
|
6339
6396
|
ctrl: "ctrl",
|
|
@@ -6429,7 +6486,7 @@ function createComputerUseTool(options) {
|
|
|
6429
6486
|
try {
|
|
6430
6487
|
switch (input.action) {
|
|
6431
6488
|
case "screenshot": {
|
|
6432
|
-
const path = join8(tmpdir(), `cu-${
|
|
6489
|
+
const path = join8(tmpdir(), `cu-${nanoid4(8)}.png`);
|
|
6433
6490
|
await runScreencapture(path);
|
|
6434
6491
|
const resized = await resizeScreenshotToPoints(path, displayWidth, displayHeight);
|
|
6435
6492
|
try {
|
|
@@ -6560,7 +6617,7 @@ function createComputerUseTool(options) {
|
|
|
6560
6617
|
case "zoom": {
|
|
6561
6618
|
const region = input.region ?? [0, 0, displayWidth, displayHeight];
|
|
6562
6619
|
const [x1, y1, x2, y2] = region;
|
|
6563
|
-
const tmpPath = join8(tmpdir(), `cu-zoom-${
|
|
6620
|
+
const tmpPath = join8(tmpdir(), `cu-zoom-${nanoid4(8)}.png`);
|
|
6564
6621
|
await runScreencapture(tmpPath);
|
|
6565
6622
|
const sharpModule = await import("sharp");
|
|
6566
6623
|
const sharp2 = sharpModule.default || sharpModule;
|
|
@@ -6840,6 +6897,7 @@ async function createTools(options) {
|
|
|
6840
6897
|
if (options.taskTools) {
|
|
6841
6898
|
tools.complete_task = createCompleteTaskTool(options.taskTools);
|
|
6842
6899
|
tools.task_failed = createTaskFailedTool(options.taskTools);
|
|
6900
|
+
tools.ask_question_to_user = createAskQuestionToUserTool(options.taskTools);
|
|
6843
6901
|
}
|
|
6844
6902
|
return tools;
|
|
6845
6903
|
}
|
|
@@ -7247,9 +7305,10 @@ If you need to give the user a downloadable file (report, image, export, etc.),
|
|
|
7247
7305
|
### Rules
|
|
7248
7306
|
1. Work independently \u2014 no human will approve tool calls. All tools run without approval.
|
|
7249
7307
|
2. Keep working until the task is fully complete \u2014 and then VERIFY it is complete before finishing.
|
|
7250
|
-
3.
|
|
7251
|
-
4.
|
|
7252
|
-
5.
|
|
7308
|
+
3. If you are blocked by missing information, call \`ask_question_to_user\` with a concise question. The run will pause until the orchestrator or user answers, then you should continue from that answer.
|
|
7309
|
+
4. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
|
|
7310
|
+
5. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
|
|
7311
|
+
6. Do NOT stop without calling \`complete_task\`, \`task_failed\`, or \`ask_question_to_user\` when blocked.
|
|
7253
7312
|
|
|
7254
7313
|
### Verification \u2014 BE EXTREMELY THOROUGH
|
|
7255
7314
|
Before calling \`complete_task\`, you MUST verify your work completely. Do not just assume it worked. Actually check.
|
|
@@ -7320,6 +7379,7 @@ ${JSON.stringify(outputSchema, null, 2)}
|
|
|
7320
7379
|
### Completion Tools
|
|
7321
7380
|
- **\`complete_task({ result: ... })\`** \u2014 Call ONLY after thorough verification. The result is validated against the schema above. If validation fails you will get errors back \u2014 fix and retry.
|
|
7322
7381
|
- **\`task_failed({ reason: "..." })\`** \u2014 Call only if the task truly cannot be completed.
|
|
7382
|
+
- **\`ask_question_to_user({ question, context?, choices? })\`** \u2014 Call only when you need information that is not available in the repo, task prompt, files, logs, or tools. Ask one clear question; after the answer is returned, continue working.
|
|
7323
7383
|
`;
|
|
7324
7384
|
}
|
|
7325
7385
|
function createSummaryPrompt(conversationHistory) {
|
|
@@ -7475,6 +7535,7 @@ function sanitizeModelMessages(messages) {
|
|
|
7475
7535
|
|
|
7476
7536
|
// src/agent/model-limits.ts
|
|
7477
7537
|
var MODEL_LIMITS = {
|
|
7538
|
+
"anthropic/claude-opus-4.7": { contextWindow: 2e5, rollingTarget: 15e4 },
|
|
7478
7539
|
"anthropic/claude-opus-4-6": { contextWindow: 2e5, rollingTarget: 15e4 },
|
|
7479
7540
|
"anthropic/claude-sonnet-4": { contextWindow: 2e5, rollingTarget: 15e4 },
|
|
7480
7541
|
"anthropic/claude-3.5-sonnet": { contextWindow: 2e5, rollingTarget: 15e4 },
|
|
@@ -7811,17 +7872,65 @@ function repairToolPairing(messages) {
|
|
|
7811
7872
|
|
|
7812
7873
|
// src/agent/index.ts
|
|
7813
7874
|
init_webhook();
|
|
7875
|
+
|
|
7876
|
+
// src/tasks/questions.ts
|
|
7877
|
+
var pendingQuestions = /* @__PURE__ */ new Map();
|
|
7878
|
+
var answeredQuestions = /* @__PURE__ */ new Map();
|
|
7879
|
+
function key(taskId, questionId) {
|
|
7880
|
+
return `${taskId}:${questionId}`;
|
|
7881
|
+
}
|
|
7882
|
+
function waitForTaskQuestionAnswer(question) {
|
|
7883
|
+
const k = key(question.taskId, question.questionId);
|
|
7884
|
+
if (pendingQuestions.has(k)) {
|
|
7885
|
+
return Promise.reject(new Error(`Question already pending: ${question.questionId}`));
|
|
7886
|
+
}
|
|
7887
|
+
return new Promise((resolve11, reject) => {
|
|
7888
|
+
pendingQuestions.set(k, {
|
|
7889
|
+
...question,
|
|
7890
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
7891
|
+
resolve: resolve11,
|
|
7892
|
+
reject
|
|
7893
|
+
});
|
|
7894
|
+
});
|
|
7895
|
+
}
|
|
7896
|
+
function answerTaskQuestion(taskId, questionId, answer) {
|
|
7897
|
+
const k = key(taskId, questionId);
|
|
7898
|
+
const pending = pendingQuestions.get(k);
|
|
7899
|
+
if (!pending) return answeredQuestions.has(k) ? "already_answered" : "not_found";
|
|
7900
|
+
pendingQuestions.delete(k);
|
|
7901
|
+
answeredQuestions.set(k, answer);
|
|
7902
|
+
pending.resolve(answer);
|
|
7903
|
+
return "answered";
|
|
7904
|
+
}
|
|
7905
|
+
function rejectTaskQuestions(taskId, reason) {
|
|
7906
|
+
for (const [k, pending] of pendingQuestions) {
|
|
7907
|
+
if (pending.taskId !== taskId) continue;
|
|
7908
|
+
pendingQuestions.delete(k);
|
|
7909
|
+
pending.reject(new Error(reason));
|
|
7910
|
+
}
|
|
7911
|
+
}
|
|
7912
|
+
function getPendingTaskQuestion(taskId, questionId) {
|
|
7913
|
+
const pending = pendingQuestions.get(key(taskId, questionId));
|
|
7914
|
+
if (!pending) return null;
|
|
7915
|
+
const { resolve: _resolve, reject: _reject, ...question } = pending;
|
|
7916
|
+
return question;
|
|
7917
|
+
}
|
|
7918
|
+
function getAnsweredTaskQuestion(taskId, questionId) {
|
|
7919
|
+
return answeredQuestions.get(key(taskId, questionId)) ?? null;
|
|
7920
|
+
}
|
|
7921
|
+
|
|
7922
|
+
// src/agent/index.ts
|
|
7814
7923
|
var MAX_SSE_FIELD_LENGTH = 8 * 1024;
|
|
7815
7924
|
var SSE_PREVIEW_LENGTH = 2 * 1024;
|
|
7816
7925
|
function truncateWriteFileInput(input) {
|
|
7817
7926
|
const out = { ...input };
|
|
7818
|
-
for (const
|
|
7819
|
-
const val = out[
|
|
7927
|
+
for (const key2 of ["content", "old_string", "new_string"]) {
|
|
7928
|
+
const val = out[key2];
|
|
7820
7929
|
if (typeof val === "string" && val.length > MAX_SSE_FIELD_LENGTH) {
|
|
7821
|
-
out[
|
|
7930
|
+
out[key2] = `${val.slice(0, SSE_PREVIEW_LENGTH)}
|
|
7822
7931
|
... (truncated)`;
|
|
7823
|
-
out[`${
|
|
7824
|
-
out[`${
|
|
7932
|
+
out[`${key2}Truncated`] = true;
|
|
7933
|
+
out[`${key2}Length`] = val.length;
|
|
7825
7934
|
}
|
|
7826
7935
|
}
|
|
7827
7936
|
return out;
|
|
@@ -7991,13 +8100,7 @@ ${prompt}` });
|
|
|
7991
8100
|
abortSignal: options.abortSignal,
|
|
7992
8101
|
// Enable extended thinking/reasoning for models that support it
|
|
7993
8102
|
providerOptions: useAnthropic ? {
|
|
7994
|
-
anthropic: {
|
|
7995
|
-
toolStreaming: true,
|
|
7996
|
-
thinking: {
|
|
7997
|
-
type: "enabled",
|
|
7998
|
-
budgetTokens: 1e4
|
|
7999
|
-
}
|
|
8000
|
-
}
|
|
8103
|
+
anthropic: getAnthropicProviderOptions(this.session.model, { toolStreaming: true })
|
|
8001
8104
|
} : void 0,
|
|
8002
8105
|
onStepFinish: async (step) => {
|
|
8003
8106
|
options.onStepFinish?.(step);
|
|
@@ -8044,12 +8147,7 @@ ${prompt}` });
|
|
|
8044
8147
|
stopWhen: stepCountIs2(500),
|
|
8045
8148
|
// Enable extended thinking/reasoning for models that support it
|
|
8046
8149
|
providerOptions: useAnthropic ? {
|
|
8047
|
-
anthropic:
|
|
8048
|
-
thinking: {
|
|
8049
|
-
type: "enabled",
|
|
8050
|
-
budgetTokens: 1e4
|
|
8051
|
-
}
|
|
8052
|
-
}
|
|
8150
|
+
anthropic: getAnthropicProviderOptions(this.session.model)
|
|
8053
8151
|
} : void 0
|
|
8054
8152
|
});
|
|
8055
8153
|
const responseMessages = result.response.messages;
|
|
@@ -8136,7 +8234,38 @@ ${prompt}` });
|
|
|
8136
8234
|
},
|
|
8137
8235
|
taskTools: {
|
|
8138
8236
|
outputSchema: options.taskConfig.outputSchema,
|
|
8139
|
-
onComplete
|
|
8237
|
+
onComplete,
|
|
8238
|
+
onQuestion: async (question) => {
|
|
8239
|
+
const payload = {
|
|
8240
|
+
questionId: question.questionId,
|
|
8241
|
+
question: question.question,
|
|
8242
|
+
context: question.context,
|
|
8243
|
+
choices: question.choices,
|
|
8244
|
+
status: "pending"
|
|
8245
|
+
};
|
|
8246
|
+
const answerPromise = waitForTaskQuestionAnswer({
|
|
8247
|
+
taskId: this.session.id,
|
|
8248
|
+
questionId: question.questionId,
|
|
8249
|
+
question: question.question,
|
|
8250
|
+
context: question.context,
|
|
8251
|
+
choices: question.choices
|
|
8252
|
+
});
|
|
8253
|
+
fireWebhook("task.question", payload);
|
|
8254
|
+
if (emit) {
|
|
8255
|
+
await emit(JSON.stringify({ type: "task-question", data: payload }));
|
|
8256
|
+
}
|
|
8257
|
+
const answer = await answerPromise;
|
|
8258
|
+
const answeredPayload = {
|
|
8259
|
+
questionId: question.questionId,
|
|
8260
|
+
answer: answer.answer,
|
|
8261
|
+
answeredBy: answer.answeredBy
|
|
8262
|
+
};
|
|
8263
|
+
fireWebhook("task.question_answered", answeredPayload);
|
|
8264
|
+
if (emit) {
|
|
8265
|
+
await emit(JSON.stringify({ type: "task-question-answered", data: answeredPayload }));
|
|
8266
|
+
}
|
|
8267
|
+
return answer;
|
|
8268
|
+
}
|
|
8140
8269
|
}
|
|
8141
8270
|
});
|
|
8142
8271
|
const baseSystemPrompt = await buildSystemPrompt({
|
|
@@ -8181,10 +8310,7 @@ ${taskAddendum}`;
|
|
|
8181
8310
|
stopWhen: stepCountIs2(500),
|
|
8182
8311
|
abortSignal: options.abortSignal,
|
|
8183
8312
|
providerOptions: useAnthropic ? {
|
|
8184
|
-
anthropic: {
|
|
8185
|
-
toolStreaming: true,
|
|
8186
|
-
thinking: { type: "enabled", budgetTokens: 1e4 }
|
|
8187
|
-
}
|
|
8313
|
+
anthropic: getAnthropicProviderOptions(this.session.model, { toolStreaming: true })
|
|
8188
8314
|
} : void 0,
|
|
8189
8315
|
onStepFinish: async (step) => {
|
|
8190
8316
|
options.onStepFinish?.(step);
|
|
@@ -8471,7 +8597,7 @@ ${taskAddendum}`;
|
|
|
8471
8597
|
description: originalTool.description || "",
|
|
8472
8598
|
inputSchema: originalTool.inputSchema || z15.object({}),
|
|
8473
8599
|
execute: async (input, toolOptions) => {
|
|
8474
|
-
const toolCallId = toolOptions.toolCallId ||
|
|
8600
|
+
const toolCallId = toolOptions.toolCallId || nanoid6();
|
|
8475
8601
|
const execution = toolExecutionQueries.create({
|
|
8476
8602
|
sessionId: this.session.id,
|
|
8477
8603
|
toolName: name,
|
|
@@ -8598,7 +8724,7 @@ import { z as z16 } from "zod";
|
|
|
8598
8724
|
import { existsSync as existsSync16, mkdirSync as mkdirSync6, writeFileSync as writeFileSync3, readdirSync as readdirSync2, statSync as statSync2, unlinkSync as unlinkSync3 } from "fs";
|
|
8599
8725
|
import { readdir as readdir6 } from "fs/promises";
|
|
8600
8726
|
import { join as join10, basename as basename5, extname as extname8, relative as relative9 } from "path";
|
|
8601
|
-
import { nanoid as
|
|
8727
|
+
import { nanoid as nanoid7 } from "nanoid";
|
|
8602
8728
|
init_config();
|
|
8603
8729
|
|
|
8604
8730
|
// src/server/devtools-store.ts
|
|
@@ -9141,7 +9267,7 @@ sessions.post("/:id/attachments", async (c) => {
|
|
|
9141
9267
|
return c.json({ error: "No file provided" }, 400);
|
|
9142
9268
|
}
|
|
9143
9269
|
const dir = ensureAttachmentsDir(sessionId);
|
|
9144
|
-
const id =
|
|
9270
|
+
const id = nanoid7(10);
|
|
9145
9271
|
const ext = extname8(file.name) || "";
|
|
9146
9272
|
const safeFilename = `${id}_${basename5(file.name).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
|
|
9147
9273
|
const filePath = join10(dir, safeFilename);
|
|
@@ -9167,7 +9293,7 @@ sessions.post("/:id/attachments", async (c) => {
|
|
|
9167
9293
|
return c.json({ error: "Missing filename or data" }, 400);
|
|
9168
9294
|
}
|
|
9169
9295
|
const dir = ensureAttachmentsDir(sessionId);
|
|
9170
|
-
const id =
|
|
9296
|
+
const id = nanoid7(10);
|
|
9171
9297
|
const ext = extname8(body.filename) || "";
|
|
9172
9298
|
const safeFilename = `${id}_${basename5(body.filename).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
|
|
9173
9299
|
const filePath = join10(dir, safeFilename);
|
|
@@ -9459,9 +9585,9 @@ var store = /* @__PURE__ */ new Map();
|
|
|
9459
9585
|
var channels = /* @__PURE__ */ new Map();
|
|
9460
9586
|
var cleanupInterval = setInterval(() => {
|
|
9461
9587
|
const now = Date.now();
|
|
9462
|
-
for (const [
|
|
9588
|
+
for (const [key2, data] of store.entries()) {
|
|
9463
9589
|
if (data.expiresAt && data.expiresAt < now) {
|
|
9464
|
-
store.delete(
|
|
9590
|
+
store.delete(key2);
|
|
9465
9591
|
}
|
|
9466
9592
|
}
|
|
9467
9593
|
}, 6e4);
|
|
@@ -9485,27 +9611,27 @@ var publisher = {
|
|
|
9485
9611
|
}
|
|
9486
9612
|
}
|
|
9487
9613
|
},
|
|
9488
|
-
set: async (
|
|
9614
|
+
set: async (key2, value, options) => {
|
|
9489
9615
|
const expiresAt = options?.EX ? Date.now() + options.EX * 1e3 : void 0;
|
|
9490
|
-
store.set(
|
|
9616
|
+
store.set(key2, { value, expiresAt });
|
|
9491
9617
|
if (options?.EX) {
|
|
9492
|
-
setTimeout(() => store.delete(
|
|
9618
|
+
setTimeout(() => store.delete(key2), options.EX * 1e3);
|
|
9493
9619
|
}
|
|
9494
9620
|
},
|
|
9495
|
-
get: async (
|
|
9496
|
-
const data = store.get(
|
|
9621
|
+
get: async (key2) => {
|
|
9622
|
+
const data = store.get(key2);
|
|
9497
9623
|
if (!data) return null;
|
|
9498
9624
|
if (data.expiresAt && data.expiresAt < Date.now()) {
|
|
9499
|
-
store.delete(
|
|
9625
|
+
store.delete(key2);
|
|
9500
9626
|
return null;
|
|
9501
9627
|
}
|
|
9502
9628
|
return data.value;
|
|
9503
9629
|
},
|
|
9504
|
-
incr: async (
|
|
9505
|
-
const data = store.get(
|
|
9630
|
+
incr: async (key2) => {
|
|
9631
|
+
const data = store.get(key2);
|
|
9506
9632
|
const current = data ? parseInt(data.value, 10) : 0;
|
|
9507
9633
|
const next = (isNaN(current) ? 0 : current) + 1;
|
|
9508
|
-
store.set(
|
|
9634
|
+
store.set(key2, { value: String(next), expiresAt: data?.expiresAt });
|
|
9509
9635
|
return next;
|
|
9510
9636
|
}
|
|
9511
9637
|
};
|
|
@@ -9537,7 +9663,7 @@ var streamContext = createResumableStreamContext({
|
|
|
9537
9663
|
});
|
|
9538
9664
|
|
|
9539
9665
|
// src/server/routes/agents.ts
|
|
9540
|
-
import { nanoid as
|
|
9666
|
+
import { nanoid as nanoid8 } from "nanoid";
|
|
9541
9667
|
init_stream_proxy();
|
|
9542
9668
|
init_recorder();
|
|
9543
9669
|
init_remote();
|
|
@@ -10096,7 +10222,7 @@ ${prompt}` });
|
|
|
10096
10222
|
userMessageContent = prompt;
|
|
10097
10223
|
}
|
|
10098
10224
|
await messageQueries.create(id, { role: "user", content: userMessageContent });
|
|
10099
|
-
const streamId = `stream_${id}_${
|
|
10225
|
+
const streamId = `stream_${id}_${nanoid8(10)}`;
|
|
10100
10226
|
console.log(`[STREAM] Creating stream ${streamId} for session ${id}`);
|
|
10101
10227
|
await activeStreamQueries.create(id, streamId);
|
|
10102
10228
|
const stream = await streamContext.resumableStream(
|
|
@@ -10301,7 +10427,7 @@ agents.post(
|
|
|
10301
10427
|
});
|
|
10302
10428
|
const session = agent.getSession();
|
|
10303
10429
|
const enrichedPrompt = enrichPromptWithDevtoolsContext(session.id, body.prompt);
|
|
10304
|
-
const streamId = `stream_${session.id}_${
|
|
10430
|
+
const streamId = `stream_${session.id}_${nanoid8(10)}`;
|
|
10305
10431
|
await createCheckpoint(session.id, session.workingDirectory, 0);
|
|
10306
10432
|
await activeStreamQueries.create(session.id, streamId);
|
|
10307
10433
|
const createQuickStreamProducer = () => {
|
|
@@ -10905,7 +11031,8 @@ health.get("/", async (c) => {
|
|
|
10905
11031
|
const config = getConfig();
|
|
10906
11032
|
const apiKeyStatus = getApiKeyStatus();
|
|
10907
11033
|
const gatewayKey = apiKeyStatus.find((s) => s.provider === "ai-gateway");
|
|
10908
|
-
const
|
|
11034
|
+
const remoteInference = isRemoteInferenceConfigured();
|
|
11035
|
+
const hasApiKey = remoteInference || (gatewayKey?.configured ?? false);
|
|
10909
11036
|
let hwid;
|
|
10910
11037
|
try {
|
|
10911
11038
|
hwid = getHardwareIdCached();
|
|
@@ -10916,6 +11043,7 @@ health.get("/", async (c) => {
|
|
|
10916
11043
|
version: currentVersion,
|
|
10917
11044
|
uptime: process.uptime(),
|
|
10918
11045
|
apiKeyConfigured: hasApiKey,
|
|
11046
|
+
inferenceMode: remoteInference ? "remote" : "local",
|
|
10919
11047
|
hwid,
|
|
10920
11048
|
config: {
|
|
10921
11049
|
workingDirectory: config.resolvedWorkingDirectory,
|
|
@@ -11342,7 +11470,7 @@ init_db();
|
|
|
11342
11470
|
import { Hono as Hono5 } from "hono";
|
|
11343
11471
|
import { zValidator as zValidator5 } from "@hono/zod-validator";
|
|
11344
11472
|
import { z as z20 } from "zod";
|
|
11345
|
-
import { nanoid as
|
|
11473
|
+
import { nanoid as nanoid9 } from "nanoid";
|
|
11346
11474
|
init_config();
|
|
11347
11475
|
var tasks = new Hono5();
|
|
11348
11476
|
var taskAbortControllers = /* @__PURE__ */ new Map();
|
|
@@ -11416,7 +11544,7 @@ tasks.post(
|
|
|
11416
11544
|
const taskId = agent.sessionId;
|
|
11417
11545
|
const abortController = new AbortController();
|
|
11418
11546
|
taskAbortControllers.set(taskId, abortController);
|
|
11419
|
-
const streamId = `stream_${taskId}_${
|
|
11547
|
+
const streamId = `stream_${taskId}_${nanoid9(10)}`;
|
|
11420
11548
|
await activeStreamQueries.create(taskId, streamId);
|
|
11421
11549
|
const taskStreamProducer = () => {
|
|
11422
11550
|
const { readable, writable } = new TransformStream();
|
|
@@ -11543,6 +11671,7 @@ tasks.post("/:id/cancel", async (c) => {
|
|
|
11543
11671
|
abortController.abort();
|
|
11544
11672
|
taskAbortControllers.delete(id);
|
|
11545
11673
|
}
|
|
11674
|
+
rejectTaskQuestions(id, "Task cancelled by user");
|
|
11546
11675
|
const cancelledTask = {
|
|
11547
11676
|
...task,
|
|
11548
11677
|
status: "failed",
|
|
@@ -11564,6 +11693,52 @@ tasks.post("/:id/cancel", async (c) => {
|
|
|
11564
11693
|
}
|
|
11565
11694
|
return c.json({ taskId: id, status: "failed", error: "Task cancelled by user" });
|
|
11566
11695
|
});
|
|
11696
|
+
var answerQuestionSchema = z20.object({
|
|
11697
|
+
answer: z20.string().min(1),
|
|
11698
|
+
answeredBy: z20.enum(["orchestrator", "user", "system"]).optional()
|
|
11699
|
+
});
|
|
11700
|
+
tasks.post(
|
|
11701
|
+
"/:id/questions/:questionId/answer",
|
|
11702
|
+
zValidator5("json", answerQuestionSchema),
|
|
11703
|
+
async (c) => {
|
|
11704
|
+
const id = c.req.param("id");
|
|
11705
|
+
const questionId = c.req.param("questionId");
|
|
11706
|
+
const body = c.req.valid("json");
|
|
11707
|
+
const session = await sessionQueries.getById(id);
|
|
11708
|
+
if (!session) {
|
|
11709
|
+
return c.json({ error: "Task not found" }, 404);
|
|
11710
|
+
}
|
|
11711
|
+
const task = session.config?.task;
|
|
11712
|
+
if (!task?.enabled) {
|
|
11713
|
+
return c.json({ error: "Session is not a task" }, 400);
|
|
11714
|
+
}
|
|
11715
|
+
const pending = getPendingTaskQuestion(id, questionId);
|
|
11716
|
+
if (!pending) {
|
|
11717
|
+
if (getAnsweredTaskQuestion(id, questionId)) {
|
|
11718
|
+
return c.json({
|
|
11719
|
+
taskId: id,
|
|
11720
|
+
questionId,
|
|
11721
|
+
status: "answered",
|
|
11722
|
+
alreadyAnswered: true
|
|
11723
|
+
});
|
|
11724
|
+
}
|
|
11725
|
+
return c.json({ error: "Question is not pending" }, 404);
|
|
11726
|
+
}
|
|
11727
|
+
const answerStatus = answerTaskQuestion(id, questionId, {
|
|
11728
|
+
answer: body.answer,
|
|
11729
|
+
answeredBy: body.answeredBy
|
|
11730
|
+
});
|
|
11731
|
+
if (answerStatus === "not_found") {
|
|
11732
|
+
return c.json({ error: "Question is not pending" }, 404);
|
|
11733
|
+
}
|
|
11734
|
+
return c.json({
|
|
11735
|
+
taskId: id,
|
|
11736
|
+
questionId,
|
|
11737
|
+
status: "answered",
|
|
11738
|
+
alreadyAnswered: answerStatus === "already_answered"
|
|
11739
|
+
});
|
|
11740
|
+
}
|
|
11741
|
+
);
|
|
11567
11742
|
var tasks_default = tasks;
|
|
11568
11743
|
|
|
11569
11744
|
// src/server/routes/system.ts
|
|
@@ -11657,15 +11832,15 @@ function loadPublicKey(input) {
|
|
|
11657
11832
|
if (!input.includes("BEGIN") && existsSync18(input)) {
|
|
11658
11833
|
pem = readFileSync11(input, "utf8");
|
|
11659
11834
|
}
|
|
11660
|
-
const
|
|
11661
|
-
if (
|
|
11835
|
+
const key2 = createPublicKey({ key: pem, format: "pem" });
|
|
11836
|
+
if (key2.asymmetricKeyType !== "ed25519") {
|
|
11662
11837
|
throw new Error(
|
|
11663
|
-
`expected an ed25519 public key, got ${
|
|
11838
|
+
`expected an ed25519 public key, got ${key2.asymmetricKeyType}. Generate with personal-agents/scripts/generate-signing-keys.mjs.`
|
|
11664
11839
|
);
|
|
11665
11840
|
}
|
|
11666
|
-
_cachedKey =
|
|
11841
|
+
_cachedKey = key2;
|
|
11667
11842
|
_cachedFromInput = input;
|
|
11668
|
-
return
|
|
11843
|
+
return key2;
|
|
11669
11844
|
}
|
|
11670
11845
|
function bodyHashB64(body) {
|
|
11671
11846
|
const hash = createHash3("sha256");
|