sparkecoder 0.1.87 → 0.1.94
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-C7Kkn5vq.d.ts} +29 -29
- 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-D7BJyHLl.d.ts} +3 -3
- package/dist/{search-CCffrVJE.d.ts → search-CVVfuBPZ.d.ts} +4 -4
- package/dist/server/index.js +272 -97
- package/dist/server/index.js.map +1 -1
- package/dist/tools/index.d.ts +31 -4
- 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 → glGjCSPew_3EV65tkHmVO}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{static/uUaN7Xe5kF_pP6zhfaeYi → glGjCSPew_3EV65tkHmVO}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{static/uUaN7Xe5kF_pP6zhfaeYi → glGjCSPew_3EV65tkHmVO}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → static/glGjCSPew_3EV65tkHmVO}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → static/glGjCSPew_3EV65tkHmVO}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → static/glGjCSPew_3EV65tkHmVO}/_ssgManifest.js +0 -0
- /package/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → glGjCSPew_3EV65tkHmVO}/_buildManifest.js +0 -0
- /package/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → glGjCSPew_3EV65tkHmVO}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → glGjCSPew_3EV65tkHmVO}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -139,7 +139,7 @@ Create a `sparkecoder.config.json` file:
|
|
|
139
139
|
|
|
140
140
|
| Option | Description | Default |
|
|
141
141
|
|--------|-------------|---------|
|
|
142
|
-
| `defaultModel` | Vercel AI Gateway model string | `anthropic/claude-opus-4
|
|
142
|
+
| `defaultModel` | Vercel AI Gateway model string | `anthropic/claude-opus-4.7` |
|
|
143
143
|
| `workingDirectory` | Base directory for file operations | Current directory |
|
|
144
144
|
| `toolApprovals` | Which tools require user approval | `{ bash: true }` |
|
|
145
145
|
| `skills.directory` | Directory containing skill files | `./skills` |
|
package/dist/agent/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import 'ai';
|
|
2
|
-
import '../schema-
|
|
3
|
-
export { A as Agent, a as AgentOptions, b as AgentRunOptions, c as AgentStreamResult, C as ContextManager, M as MessageAttachment, d as buildSystemPrompt, e as buildTaskPromptAddendum } from '../index-
|
|
4
|
-
import '../search-
|
|
2
|
+
import '../schema-D7BJyHLl.js';
|
|
3
|
+
export { A as Agent, a as AgentOptions, b as AgentRunOptions, c as AgentStreamResult, C as ContextManager, M as MessageAttachment, d as buildSystemPrompt, e as buildTaskPromptAddendum } from '../index-C7Kkn5vq.js';
|
|
4
|
+
import '../search-CVVfuBPZ.js';
|
|
5
5
|
import 'drizzle-orm/sqlite-core';
|
|
6
6
|
import 'zod';
|
package/dist/agent/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
|
|
@@ -225,9 +225,9 @@ __export(remote_exports, {
|
|
|
225
225
|
remoteToolExecutionQueries: () => remoteToolExecutionQueries,
|
|
226
226
|
storageQueries: () => storageQueries
|
|
227
227
|
});
|
|
228
|
-
function initRemoteDatabase(serverUrl,
|
|
228
|
+
function initRemoteDatabase(serverUrl, key2) {
|
|
229
229
|
remoteServerUrl = serverUrl.replace(/\/$/, "");
|
|
230
|
-
authKey =
|
|
230
|
+
authKey = key2;
|
|
231
231
|
}
|
|
232
232
|
function closeRemoteDatabase() {
|
|
233
233
|
remoteServerUrl = null;
|
|
@@ -241,14 +241,14 @@ function parseDates(obj) {
|
|
|
241
241
|
if (Array.isArray(obj)) return obj.map(parseDates);
|
|
242
242
|
if (typeof obj !== "object" || obj instanceof Date) return obj;
|
|
243
243
|
const result = { ...obj };
|
|
244
|
-
for (const
|
|
245
|
-
if (MODEL_MESSAGE_FIELDS.includes(
|
|
244
|
+
for (const key2 of Object.keys(result)) {
|
|
245
|
+
if (MODEL_MESSAGE_FIELDS.includes(key2)) {
|
|
246
246
|
continue;
|
|
247
247
|
}
|
|
248
|
-
if (DATE_FIELDS.includes(
|
|
249
|
-
result[
|
|
250
|
-
} else if (typeof result[
|
|
251
|
-
result[
|
|
248
|
+
if (DATE_FIELDS.includes(key2) && typeof result[key2] === "string") {
|
|
249
|
+
result[key2] = new Date(result[key2]);
|
|
250
|
+
} else if (typeof result[key2] === "object") {
|
|
251
|
+
result[key2] = parseDates(result[key2]);
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
return result;
|
|
@@ -729,10 +729,10 @@ function parseSkillFrontmatter(content) {
|
|
|
729
729
|
}
|
|
730
730
|
const colonIndex = line.indexOf(":");
|
|
731
731
|
if (colonIndex > 0) {
|
|
732
|
-
const
|
|
732
|
+
const key2 = line.slice(0, colonIndex).trim();
|
|
733
733
|
let value = line.slice(colonIndex + 1).trim();
|
|
734
734
|
if (value === "" || value === "[]") {
|
|
735
|
-
currentArrayKey =
|
|
735
|
+
currentArrayKey = key2;
|
|
736
736
|
currentArray = [];
|
|
737
737
|
continue;
|
|
738
738
|
}
|
|
@@ -745,18 +745,18 @@ function parseSkillFrontmatter(content) {
|
|
|
745
745
|
}
|
|
746
746
|
return trimmed;
|
|
747
747
|
}).filter((item) => item.length > 0);
|
|
748
|
-
data[
|
|
748
|
+
data[key2] = items;
|
|
749
749
|
continue;
|
|
750
750
|
}
|
|
751
751
|
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
752
752
|
value = value.slice(1, -1);
|
|
753
753
|
}
|
|
754
754
|
if (value === "true") {
|
|
755
|
-
data[
|
|
755
|
+
data[key2] = true;
|
|
756
756
|
} else if (value === "false") {
|
|
757
|
-
data[
|
|
757
|
+
data[key2] = false;
|
|
758
758
|
} else {
|
|
759
|
-
data[
|
|
759
|
+
data[key2] = value;
|
|
760
760
|
}
|
|
761
761
|
}
|
|
762
762
|
}
|
|
@@ -1088,9 +1088,9 @@ var init_chunker = __esm({
|
|
|
1088
1088
|
});
|
|
1089
1089
|
|
|
1090
1090
|
// src/semantic/client.ts
|
|
1091
|
-
function initVectorClient(serverUrl,
|
|
1091
|
+
function initVectorClient(serverUrl, key2) {
|
|
1092
1092
|
remoteServerUrl2 = serverUrl.replace(/\/$/, "");
|
|
1093
|
-
authKey2 =
|
|
1093
|
+
authKey2 = key2;
|
|
1094
1094
|
}
|
|
1095
1095
|
function isVectorClientConfigured() {
|
|
1096
1096
|
return !!remoteServerUrl2 && !!authKey2;
|
|
@@ -1636,7 +1636,7 @@ import { promisify as promisify6 } from "util";
|
|
|
1636
1636
|
import { writeFile as writeFile5, mkdir as mkdir4, readFile as readFile11, unlink as unlink2, readdir as readdir5, rm } from "fs/promises";
|
|
1637
1637
|
import { join as join9 } from "path";
|
|
1638
1638
|
import { tmpdir as tmpdir2 } from "os";
|
|
1639
|
-
import { nanoid as
|
|
1639
|
+
import { nanoid as nanoid5 } from "nanoid";
|
|
1640
1640
|
async function checkFfmpeg() {
|
|
1641
1641
|
try {
|
|
1642
1642
|
await execAsync6("ffmpeg -version", { timeout: 5e3 });
|
|
@@ -1691,7 +1691,7 @@ var init_recorder = __esm({
|
|
|
1691
1691
|
*/
|
|
1692
1692
|
async encode() {
|
|
1693
1693
|
if (this.frames.length === 0) return null;
|
|
1694
|
-
const workDir = join9(tmpdir2(), `sparkecoder-recording-${
|
|
1694
|
+
const workDir = join9(tmpdir2(), `sparkecoder-recording-${nanoid5(8)}`);
|
|
1695
1695
|
await mkdir4(workDir, { recursive: true });
|
|
1696
1696
|
try {
|
|
1697
1697
|
for (let i = 0; i < this.frames.length; i++) {
|
|
@@ -1911,6 +1911,23 @@ function isAnthropicModel(modelId) {
|
|
|
1911
1911
|
const normalized = modelId.trim().toLowerCase();
|
|
1912
1912
|
return normalized.startsWith(ANTHROPIC_PREFIX) || normalized.startsWith("claude-");
|
|
1913
1913
|
}
|
|
1914
|
+
function requiresAdaptiveThinking(modelId) {
|
|
1915
|
+
const m = modelId.toLowerCase().match(/claude-(?:opus|sonnet|haiku)-(\d+)[.-](\d{1,2})(?!\d)/);
|
|
1916
|
+
if (!m) return false;
|
|
1917
|
+
const major = Number(m[1]);
|
|
1918
|
+
const minor = Number(m[2]);
|
|
1919
|
+
if (Number.isNaN(major) || Number.isNaN(minor)) return false;
|
|
1920
|
+
if (major > 4) return true;
|
|
1921
|
+
if (major === 4 && minor >= 6) return true;
|
|
1922
|
+
return false;
|
|
1923
|
+
}
|
|
1924
|
+
function getAnthropicProviderOptions(modelId, opts = {}) {
|
|
1925
|
+
const { toolStreaming, budgetTokens = 1e4 } = opts;
|
|
1926
|
+
const thinking = requiresAdaptiveThinking(modelId) ? { type: "adaptive" } : { type: "enabled", budgetTokens };
|
|
1927
|
+
const out = { thinking };
|
|
1928
|
+
if (toolStreaming) out.toolStreaming = true;
|
|
1929
|
+
return out;
|
|
1930
|
+
}
|
|
1914
1931
|
function resolveModel(modelId) {
|
|
1915
1932
|
try {
|
|
1916
1933
|
const config = getConfig();
|
|
@@ -1934,7 +1951,7 @@ var SUBAGENT_MODELS = {
|
|
|
1934
1951
|
init_db();
|
|
1935
1952
|
init_config();
|
|
1936
1953
|
import { z as z15 } from "zod";
|
|
1937
|
-
import { nanoid as
|
|
1954
|
+
import { nanoid as nanoid6 } from "nanoid";
|
|
1938
1955
|
|
|
1939
1956
|
// src/tools/bash.ts
|
|
1940
1957
|
import { tool } from "ai";
|
|
@@ -2219,11 +2236,11 @@ async function sendInput(terminalId, input, options = {}) {
|
|
|
2219
2236
|
return false;
|
|
2220
2237
|
}
|
|
2221
2238
|
}
|
|
2222
|
-
async function sendKey(terminalId,
|
|
2239
|
+
async function sendKey(terminalId, key2) {
|
|
2223
2240
|
const session = getSessionName(terminalId);
|
|
2224
2241
|
try {
|
|
2225
2242
|
await execAsync(`tmux has-session -t ${session}`, { timeout: 1e3 });
|
|
2226
|
-
await execAsync(`tmux send-keys -t ${session} ${
|
|
2243
|
+
await execAsync(`tmux send-keys -t ${session} ${key2}`, { timeout: 1e3 });
|
|
2227
2244
|
return true;
|
|
2228
2245
|
} catch {
|
|
2229
2246
|
return false;
|
|
@@ -2362,7 +2379,7 @@ bash({ id: "abc123", input: "my text" }) // send text input
|
|
|
2362
2379
|
Terminal output is stored in the global SparkECoder data directory. Use the \`tail\` option to read recent output.`,
|
|
2363
2380
|
inputSchema: bashInputSchema,
|
|
2364
2381
|
execute: async (inputArgs) => {
|
|
2365
|
-
const { command, background, id, kill, tail, input: textInput, key } = inputArgs;
|
|
2382
|
+
const { command, background, id, kill, tail, input: textInput, key: key2 } = inputArgs;
|
|
2366
2383
|
if (id) {
|
|
2367
2384
|
if (kill) {
|
|
2368
2385
|
const success = await killTerminal(id);
|
|
@@ -2393,8 +2410,8 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
|
|
|
2393
2410
|
message: `Sent input "${textInput}" to terminal`
|
|
2394
2411
|
};
|
|
2395
2412
|
}
|
|
2396
|
-
if (
|
|
2397
|
-
const success = await sendKey(id,
|
|
2413
|
+
if (key2) {
|
|
2414
|
+
const success = await sendKey(id, key2);
|
|
2398
2415
|
if (!success) {
|
|
2399
2416
|
return {
|
|
2400
2417
|
success: false,
|
|
@@ -2410,7 +2427,7 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
|
|
|
2410
2427
|
id,
|
|
2411
2428
|
output: truncatedOutput2,
|
|
2412
2429
|
status: status2,
|
|
2413
|
-
message: `Sent key "${
|
|
2430
|
+
message: `Sent key "${key2}" to terminal`
|
|
2414
2431
|
};
|
|
2415
2432
|
}
|
|
2416
2433
|
const { output, status } = await getLogs(id, options.workingDirectory, { tail, sessionId: options.sessionId });
|
|
@@ -2552,13 +2569,13 @@ async function resizeImageIfNeeded(buffer, mediaType) {
|
|
|
2552
2569
|
const needsResize = longEdge > MAX_LONG_EDGE;
|
|
2553
2570
|
const needsShrink = buffer.length > MAX_FILE_BYTES;
|
|
2554
2571
|
if (!needsResize && !needsShrink) return { buffer, mediaType: inputMediaType };
|
|
2555
|
-
const
|
|
2572
|
+
const key2 = cacheKey(buffer);
|
|
2556
2573
|
const cacheDir = getCacheDir();
|
|
2557
2574
|
const isPng = inputMediaType.includes("png");
|
|
2558
2575
|
const willConvertToJpeg = isPng && (needsShrink || buffer.length > 2 * 1024 * 1024);
|
|
2559
2576
|
const outputMediaType = willConvertToJpeg || !isPng ? "image/jpeg" : "image/png";
|
|
2560
2577
|
const ext = outputMediaType === "image/png" ? ".png" : ".jpg";
|
|
2561
|
-
const cachePath = join3(cacheDir,
|
|
2578
|
+
const cachePath = join3(cacheDir, key2 + ext);
|
|
2562
2579
|
if (existsSync3(cachePath)) {
|
|
2563
2580
|
console.log(`[image-resize] Cache hit for ${width}x${height} image`);
|
|
2564
2581
|
return { buffer: readFileSync2(cachePath), mediaType: outputMediaType };
|
|
@@ -3313,31 +3330,31 @@ async function getClientForFile(filePath) {
|
|
|
3313
3330
|
return null;
|
|
3314
3331
|
}
|
|
3315
3332
|
const root = dirname4(normalized);
|
|
3316
|
-
const
|
|
3317
|
-
const existing = state.clients.get(
|
|
3333
|
+
const key2 = `${serverDef.id}:${root}`;
|
|
3334
|
+
const existing = state.clients.get(key2);
|
|
3318
3335
|
if (existing) {
|
|
3319
3336
|
return existing;
|
|
3320
3337
|
}
|
|
3321
|
-
if (state.broken.has(
|
|
3338
|
+
if (state.broken.has(key2)) {
|
|
3322
3339
|
return null;
|
|
3323
3340
|
}
|
|
3324
3341
|
try {
|
|
3325
3342
|
const handle = await serverDef.spawn(root);
|
|
3326
3343
|
if (!handle) {
|
|
3327
|
-
state.broken.add(
|
|
3344
|
+
state.broken.add(key2);
|
|
3328
3345
|
return null;
|
|
3329
3346
|
}
|
|
3330
3347
|
console.log(`[lsp] Started ${serverDef.name} for ${root}`);
|
|
3331
3348
|
const client = await createClient(serverDef.id, handle, root);
|
|
3332
|
-
state.clients.set(
|
|
3349
|
+
state.clients.set(key2, client);
|
|
3333
3350
|
handle.process.on("exit", (code) => {
|
|
3334
3351
|
console.log(`[lsp] ${serverDef.name} exited with code ${code}`);
|
|
3335
|
-
state.clients.delete(
|
|
3352
|
+
state.clients.delete(key2);
|
|
3336
3353
|
});
|
|
3337
3354
|
return client;
|
|
3338
3355
|
} catch (error) {
|
|
3339
3356
|
console.error(`[lsp] Failed to start ${serverDef.name}:`, error);
|
|
3340
|
-
state.broken.add(
|
|
3357
|
+
state.broken.add(key2);
|
|
3341
3358
|
return null;
|
|
3342
3359
|
}
|
|
3343
3360
|
}
|
|
@@ -5437,6 +5454,7 @@ init_semantic_search();
|
|
|
5437
5454
|
import { tool as tool11 } from "ai";
|
|
5438
5455
|
import { z as z12 } from "zod";
|
|
5439
5456
|
import Ajv from "ajv";
|
|
5457
|
+
import { nanoid as nanoid3 } from "nanoid";
|
|
5440
5458
|
var ajv = new Ajv({ allErrors: true });
|
|
5441
5459
|
function createCompleteTaskTool(options) {
|
|
5442
5460
|
const validate = ajv.compile(options.outputSchema);
|
|
@@ -5483,6 +5501,37 @@ function createTaskFailedTool(options) {
|
|
|
5483
5501
|
}
|
|
5484
5502
|
});
|
|
5485
5503
|
}
|
|
5504
|
+
function createAskQuestionToUserTool(options) {
|
|
5505
|
+
return tool11({
|
|
5506
|
+
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.",
|
|
5507
|
+
inputSchema: z12.object({
|
|
5508
|
+
question: z12.string().min(1).describe("The concise question you need answered."),
|
|
5509
|
+
context: z12.string().optional().describe("Brief context explaining why this answer is needed and what you already tried."),
|
|
5510
|
+
choices: z12.array(z12.string().min(1)).max(10).optional().describe("Optional suggested answer choices when the question is multiple choice.")
|
|
5511
|
+
}),
|
|
5512
|
+
execute: async (input) => {
|
|
5513
|
+
if (!options.onQuestion) {
|
|
5514
|
+
return {
|
|
5515
|
+
status: "unavailable",
|
|
5516
|
+
message: "Question routing is not configured for this task. Continue with the best safe assumption or call task_failed if blocked."
|
|
5517
|
+
};
|
|
5518
|
+
}
|
|
5519
|
+
const questionId = `q_${nanoid3(12)}`;
|
|
5520
|
+
const answer = await options.onQuestion({
|
|
5521
|
+
questionId,
|
|
5522
|
+
question: input.question,
|
|
5523
|
+
context: input.context,
|
|
5524
|
+
choices: input.choices
|
|
5525
|
+
});
|
|
5526
|
+
return {
|
|
5527
|
+
status: "answered",
|
|
5528
|
+
questionId,
|
|
5529
|
+
answer: answer.answer,
|
|
5530
|
+
answeredBy: answer.answeredBy ?? "unknown"
|
|
5531
|
+
};
|
|
5532
|
+
}
|
|
5533
|
+
});
|
|
5534
|
+
}
|
|
5486
5535
|
|
|
5487
5536
|
// src/tools/upload-file.ts
|
|
5488
5537
|
import { tool as tool12 } from "ai";
|
|
@@ -5588,7 +5637,7 @@ import { promisify as promisify5 } from "util";
|
|
|
5588
5637
|
import { mkdirSync as mkdirSync5, existsSync as existsSync15, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
|
|
5589
5638
|
import { join as join8 } from "path";
|
|
5590
5639
|
import { tmpdir } from "os";
|
|
5591
|
-
import { nanoid as
|
|
5640
|
+
import { nanoid as nanoid4 } from "nanoid";
|
|
5592
5641
|
var execAsync5 = promisify5(exec5);
|
|
5593
5642
|
var DEFAULT_WIDTH = 1280;
|
|
5594
5643
|
var DEFAULT_HEIGHT = 800;
|
|
@@ -5712,9 +5761,9 @@ async function runScroll(dx, dy) {
|
|
|
5712
5761
|
{ timeout: 5e3 }
|
|
5713
5762
|
);
|
|
5714
5763
|
}
|
|
5715
|
-
function translateKeyForCliclick(
|
|
5716
|
-
if (!
|
|
5717
|
-
const parts =
|
|
5764
|
+
function translateKeyForCliclick(key2) {
|
|
5765
|
+
if (!key2) return [];
|
|
5766
|
+
const parts = key2.split("+").map((p) => p.trim()).filter(Boolean);
|
|
5718
5767
|
if (parts.length === 0) return [];
|
|
5719
5768
|
const modMap = {
|
|
5720
5769
|
ctrl: "ctrl",
|
|
@@ -5810,7 +5859,7 @@ function createComputerUseTool(options) {
|
|
|
5810
5859
|
try {
|
|
5811
5860
|
switch (input.action) {
|
|
5812
5861
|
case "screenshot": {
|
|
5813
|
-
const path = join8(tmpdir(), `cu-${
|
|
5862
|
+
const path = join8(tmpdir(), `cu-${nanoid4(8)}.png`);
|
|
5814
5863
|
await runScreencapture(path);
|
|
5815
5864
|
const resized = await resizeScreenshotToPoints(path, displayWidth, displayHeight);
|
|
5816
5865
|
try {
|
|
@@ -5941,7 +5990,7 @@ function createComputerUseTool(options) {
|
|
|
5941
5990
|
case "zoom": {
|
|
5942
5991
|
const region = input.region ?? [0, 0, displayWidth, displayHeight];
|
|
5943
5992
|
const [x1, y1, x2, y2] = region;
|
|
5944
|
-
const tmpPath = join8(tmpdir(), `cu-zoom-${
|
|
5993
|
+
const tmpPath = join8(tmpdir(), `cu-zoom-${nanoid4(8)}.png`);
|
|
5945
5994
|
await runScreencapture(tmpPath);
|
|
5946
5995
|
const sharpModule = await import("sharp");
|
|
5947
5996
|
const sharp2 = sharpModule.default || sharpModule;
|
|
@@ -6220,6 +6269,7 @@ async function createTools(options) {
|
|
|
6220
6269
|
if (options.taskTools) {
|
|
6221
6270
|
tools.complete_task = createCompleteTaskTool(options.taskTools);
|
|
6222
6271
|
tools.task_failed = createTaskFailedTool(options.taskTools);
|
|
6272
|
+
tools.ask_question_to_user = createAskQuestionToUserTool(options.taskTools);
|
|
6223
6273
|
}
|
|
6224
6274
|
return tools;
|
|
6225
6275
|
}
|
|
@@ -6626,9 +6676,10 @@ If you need to give the user a downloadable file (report, image, export, etc.),
|
|
|
6626
6676
|
### Rules
|
|
6627
6677
|
1. Work independently \u2014 no human will approve tool calls. All tools run without approval.
|
|
6628
6678
|
2. Keep working until the task is fully complete \u2014 and then VERIFY it is complete before finishing.
|
|
6629
|
-
3.
|
|
6630
|
-
4.
|
|
6631
|
-
5.
|
|
6679
|
+
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.
|
|
6680
|
+
4. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
|
|
6681
|
+
5. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
|
|
6682
|
+
6. Do NOT stop without calling \`complete_task\`, \`task_failed\`, or \`ask_question_to_user\` when blocked.
|
|
6632
6683
|
|
|
6633
6684
|
### Verification \u2014 BE EXTREMELY THOROUGH
|
|
6634
6685
|
Before calling \`complete_task\`, you MUST verify your work completely. Do not just assume it worked. Actually check.
|
|
@@ -6699,6 +6750,7 @@ ${JSON.stringify(outputSchema, null, 2)}
|
|
|
6699
6750
|
### Completion Tools
|
|
6700
6751
|
- **\`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.
|
|
6701
6752
|
- **\`task_failed({ reason: "..." })\`** \u2014 Call only if the task truly cannot be completed.
|
|
6753
|
+
- **\`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.
|
|
6702
6754
|
`;
|
|
6703
6755
|
}
|
|
6704
6756
|
function createSummaryPrompt(conversationHistory) {
|
|
@@ -6854,6 +6906,7 @@ function sanitizeModelMessages(messages) {
|
|
|
6854
6906
|
|
|
6855
6907
|
// src/agent/model-limits.ts
|
|
6856
6908
|
var MODEL_LIMITS = {
|
|
6909
|
+
"anthropic/claude-opus-4.7": { contextWindow: 2e5, rollingTarget: 15e4 },
|
|
6857
6910
|
"anthropic/claude-opus-4-6": { contextWindow: 2e5, rollingTarget: 15e4 },
|
|
6858
6911
|
"anthropic/claude-sonnet-4": { contextWindow: 2e5, rollingTarget: 15e4 },
|
|
6859
6912
|
"anthropic/claude-3.5-sonnet": { contextWindow: 2e5, rollingTarget: 15e4 },
|
|
@@ -7231,18 +7284,38 @@ async function sendWebhook(url, event) {
|
|
|
7231
7284
|
}
|
|
7232
7285
|
}
|
|
7233
7286
|
|
|
7287
|
+
// src/tasks/questions.ts
|
|
7288
|
+
var pendingQuestions = /* @__PURE__ */ new Map();
|
|
7289
|
+
function key(taskId, questionId) {
|
|
7290
|
+
return `${taskId}:${questionId}`;
|
|
7291
|
+
}
|
|
7292
|
+
function waitForTaskQuestionAnswer(question) {
|
|
7293
|
+
const k = key(question.taskId, question.questionId);
|
|
7294
|
+
if (pendingQuestions.has(k)) {
|
|
7295
|
+
return Promise.reject(new Error(`Question already pending: ${question.questionId}`));
|
|
7296
|
+
}
|
|
7297
|
+
return new Promise((resolve10, reject) => {
|
|
7298
|
+
pendingQuestions.set(k, {
|
|
7299
|
+
...question,
|
|
7300
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
7301
|
+
resolve: resolve10,
|
|
7302
|
+
reject
|
|
7303
|
+
});
|
|
7304
|
+
});
|
|
7305
|
+
}
|
|
7306
|
+
|
|
7234
7307
|
// src/agent/index.ts
|
|
7235
7308
|
var MAX_SSE_FIELD_LENGTH = 8 * 1024;
|
|
7236
7309
|
var SSE_PREVIEW_LENGTH = 2 * 1024;
|
|
7237
7310
|
function truncateWriteFileInput(input) {
|
|
7238
7311
|
const out = { ...input };
|
|
7239
|
-
for (const
|
|
7240
|
-
const val = out[
|
|
7312
|
+
for (const key2 of ["content", "old_string", "new_string"]) {
|
|
7313
|
+
const val = out[key2];
|
|
7241
7314
|
if (typeof val === "string" && val.length > MAX_SSE_FIELD_LENGTH) {
|
|
7242
|
-
out[
|
|
7315
|
+
out[key2] = `${val.slice(0, SSE_PREVIEW_LENGTH)}
|
|
7243
7316
|
... (truncated)`;
|
|
7244
|
-
out[`${
|
|
7245
|
-
out[`${
|
|
7317
|
+
out[`${key2}Truncated`] = true;
|
|
7318
|
+
out[`${key2}Length`] = val.length;
|
|
7246
7319
|
}
|
|
7247
7320
|
}
|
|
7248
7321
|
return out;
|
|
@@ -7412,13 +7485,7 @@ ${prompt}` });
|
|
|
7412
7485
|
abortSignal: options.abortSignal,
|
|
7413
7486
|
// Enable extended thinking/reasoning for models that support it
|
|
7414
7487
|
providerOptions: useAnthropic ? {
|
|
7415
|
-
anthropic: {
|
|
7416
|
-
toolStreaming: true,
|
|
7417
|
-
thinking: {
|
|
7418
|
-
type: "enabled",
|
|
7419
|
-
budgetTokens: 1e4
|
|
7420
|
-
}
|
|
7421
|
-
}
|
|
7488
|
+
anthropic: getAnthropicProviderOptions(this.session.model, { toolStreaming: true })
|
|
7422
7489
|
} : void 0,
|
|
7423
7490
|
onStepFinish: async (step) => {
|
|
7424
7491
|
options.onStepFinish?.(step);
|
|
@@ -7465,12 +7532,7 @@ ${prompt}` });
|
|
|
7465
7532
|
stopWhen: stepCountIs2(500),
|
|
7466
7533
|
// Enable extended thinking/reasoning for models that support it
|
|
7467
7534
|
providerOptions: useAnthropic ? {
|
|
7468
|
-
anthropic:
|
|
7469
|
-
thinking: {
|
|
7470
|
-
type: "enabled",
|
|
7471
|
-
budgetTokens: 1e4
|
|
7472
|
-
}
|
|
7473
|
-
}
|
|
7535
|
+
anthropic: getAnthropicProviderOptions(this.session.model)
|
|
7474
7536
|
} : void 0
|
|
7475
7537
|
});
|
|
7476
7538
|
const responseMessages = result.response.messages;
|
|
@@ -7557,7 +7619,38 @@ ${prompt}` });
|
|
|
7557
7619
|
},
|
|
7558
7620
|
taskTools: {
|
|
7559
7621
|
outputSchema: options.taskConfig.outputSchema,
|
|
7560
|
-
onComplete
|
|
7622
|
+
onComplete,
|
|
7623
|
+
onQuestion: async (question) => {
|
|
7624
|
+
const payload = {
|
|
7625
|
+
questionId: question.questionId,
|
|
7626
|
+
question: question.question,
|
|
7627
|
+
context: question.context,
|
|
7628
|
+
choices: question.choices,
|
|
7629
|
+
status: "pending"
|
|
7630
|
+
};
|
|
7631
|
+
const answerPromise = waitForTaskQuestionAnswer({
|
|
7632
|
+
taskId: this.session.id,
|
|
7633
|
+
questionId: question.questionId,
|
|
7634
|
+
question: question.question,
|
|
7635
|
+
context: question.context,
|
|
7636
|
+
choices: question.choices
|
|
7637
|
+
});
|
|
7638
|
+
fireWebhook("task.question", payload);
|
|
7639
|
+
if (emit) {
|
|
7640
|
+
await emit(JSON.stringify({ type: "task-question", data: payload }));
|
|
7641
|
+
}
|
|
7642
|
+
const answer = await answerPromise;
|
|
7643
|
+
const answeredPayload = {
|
|
7644
|
+
questionId: question.questionId,
|
|
7645
|
+
answer: answer.answer,
|
|
7646
|
+
answeredBy: answer.answeredBy
|
|
7647
|
+
};
|
|
7648
|
+
fireWebhook("task.question_answered", answeredPayload);
|
|
7649
|
+
if (emit) {
|
|
7650
|
+
await emit(JSON.stringify({ type: "task-question-answered", data: answeredPayload }));
|
|
7651
|
+
}
|
|
7652
|
+
return answer;
|
|
7653
|
+
}
|
|
7561
7654
|
}
|
|
7562
7655
|
});
|
|
7563
7656
|
const baseSystemPrompt = await buildSystemPrompt({
|
|
@@ -7602,10 +7695,7 @@ ${taskAddendum}`;
|
|
|
7602
7695
|
stopWhen: stepCountIs2(500),
|
|
7603
7696
|
abortSignal: options.abortSignal,
|
|
7604
7697
|
providerOptions: useAnthropic ? {
|
|
7605
|
-
anthropic: {
|
|
7606
|
-
toolStreaming: true,
|
|
7607
|
-
thinking: { type: "enabled", budgetTokens: 1e4 }
|
|
7608
|
-
}
|
|
7698
|
+
anthropic: getAnthropicProviderOptions(this.session.model, { toolStreaming: true })
|
|
7609
7699
|
} : void 0,
|
|
7610
7700
|
onStepFinish: async (step) => {
|
|
7611
7701
|
options.onStepFinish?.(step);
|
|
@@ -7892,7 +7982,7 @@ ${taskAddendum}`;
|
|
|
7892
7982
|
description: originalTool.description || "",
|
|
7893
7983
|
inputSchema: originalTool.inputSchema || z15.object({}),
|
|
7894
7984
|
execute: async (input, toolOptions) => {
|
|
7895
|
-
const toolCallId = toolOptions.toolCallId ||
|
|
7985
|
+
const toolCallId = toolOptions.toolCallId || nanoid6();
|
|
7896
7986
|
const execution = toolExecutionQueries.create({
|
|
7897
7987
|
sessionId: this.session.id,
|
|
7898
7988
|
toolName: name,
|