sparkecoder 0.1.59 → 0.1.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/index.d.ts +4 -3
- package/dist/agent/index.js +662 -203
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +906 -129
- package/dist/cli.js.map +1 -1
- package/dist/db/index.d.ts +3 -2
- package/dist/db/index.js.map +1 -1
- package/dist/{index-Csad1Nx4.d.ts → index-DuGtMaAJ.d.ts} +85 -4
- package/dist/index.d.ts +6 -5
- package/dist/index.js +1302 -711
- package/dist/index.js.map +1 -1
- package/dist/schema-C7Mm4Ykn.d.ts +1410 -0
- package/dist/{search-BETuS1vh.d.ts → search-C_IFImt1.d.ts} +3 -3
- package/dist/server/index.js +692 -101
- package/dist/server/index.js.map +1 -1
- package/dist/skills/default/browser.md +143 -0
- package/dist/skills/default/code-review.md +122 -0
- package/dist/skills/default/debugging.md +105 -0
- package/dist/skills/default/refactoring.md +197 -0
- package/dist/tools/index.d.ts +54 -4
- package/dist/tools/index.js +304 -29
- package/dist/tools/index.js.map +1 -1
- package/package.json +6 -1
- package/src/skills/default/browser.md +143 -0
- package/src/skills/default/code-review.md +122 -0
- package/src/skills/default/debugging.md +105 -0
- package/src/skills/default/refactoring.md +197 -0
- 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.js.nft.json +1 -1
- 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.js.nft.json +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 +2 -2
- package/web/.next/standalone/web/.next/server/app/api/config/route.js.nft.json +1 -1
- package/web/.next/standalone/web/.next/server/app/api/health/route.js.nft.json +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 +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +2 -2
- 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 +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
- 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 +1 -1
- 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 +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +2 -2
- 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 +2 -2
- 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 +1 -1
- 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 +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +2 -2
- 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 +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
- 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 +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +2 -2
- 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 +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/embed/[id]/page.js.nft.json +1 -1
- 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 +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_19289e11._.js → 2374f_03d22c16._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_b4b86c1f._.js → 2374f_0d0b1fb9._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_4858a1ea._.js → 2374f_3f7d6d28._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_51385fed._.js → 2374f_6166d14d._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_40e35a02._.js → 2374f_67b9525f._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_fb95e3c9._.js → 2374f_6b436efc._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_2f0d9f6f._.js → 2374f_784d851c._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_35475cbe._.js → 2374f_976b2ded._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_7db22cde._.js → 2374f_98eba491._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_90b8e4fb._.js → 2374f_99b7b533._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_4666c827._.js → 2374f_a1a36483._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_076f03ec._.js → 2374f_b98835eb._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_b17fce11._.js → 2374f_e19eaecc._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_d8b9ce38._.js → 2374f_e3aec189._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__7775f784._.js → [root-of-the-server]__4f176a16._.js} +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__d59f831d._.js +15 -0
- package/web/.next/standalone/web/.next/server/chunks/ssr/{web_645f4b90._.js → web_693f514e._.js} +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_a42a2651._.js +7 -0
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_dc6ce793._.js +7 -0
- 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/standalone/web/.next/static/chunks/0358a0e7a40cfb93.css +1 -0
- package/web/.next/standalone/web/.next/static/chunks/1ecde4c0d426a635.js +1 -0
- package/web/.next/standalone/web/.next/static/chunks/20e0fa99c7a1c1fc.js +13 -0
- package/web/.next/standalone/web/.next/static/chunks/36688a049d72e8ab.js +5 -0
- package/web/.next/standalone/web/.next/static/chunks/95436454a7559b0d.js +7 -0
- package/web/.next/standalone/web/.next/static/chunks/a751ca474cc46212.js +5 -0
- package/web/.next/standalone/web/.next/static/static/chunks/0358a0e7a40cfb93.css +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/1ecde4c0d426a635.js +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/20e0fa99c7a1c1fc.js +13 -0
- package/web/.next/standalone/web/.next/static/static/chunks/36688a049d72e8ab.js +5 -0
- package/web/.next/standalone/web/.next/static/static/chunks/95436454a7559b0d.js +7 -0
- package/web/.next/standalone/web/.next/static/static/chunks/a751ca474cc46212.js +5 -0
- package/web/.next/standalone/web/src/components/ai-elements/complete-task-tool.tsx +126 -0
- package/web/.next/standalone/web/src/components/chat-interface.tsx +68 -3
- package/web/.next/standalone/web/src/components/sessions-sidebar.tsx +18 -1
- package/web/.next/standalone/web/src/lib/api.ts +12 -0
- package/web/.next/static/chunks/0358a0e7a40cfb93.css +1 -0
- package/web/.next/static/chunks/1ecde4c0d426a635.js +1 -0
- package/web/.next/static/chunks/20e0fa99c7a1c1fc.js +13 -0
- package/web/.next/static/chunks/36688a049d72e8ab.js +5 -0
- package/web/.next/static/chunks/95436454a7559b0d.js +7 -0
- package/web/.next/static/chunks/a751ca474cc46212.js +5 -0
- package/dist/schema-NcQknWCg.d.ts +0 -295
- package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__bd396152._.js +0 -15
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_9c9f0e3b._.js +0 -7
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_d08270f7._.js +0 -7
- package/web/.next/standalone/web/.next/static/chunks/2868b007ce5163fc.css +0 -1
- package/web/.next/standalone/web/.next/static/chunks/3f295b6960943c38.js +0 -1
- package/web/.next/standalone/web/.next/static/chunks/631b023d37a08635.js +0 -13
- package/web/.next/standalone/web/.next/static/chunks/a2b4737b190d1b54.js +0 -5
- package/web/.next/standalone/web/.next/static/chunks/e97212fcc8221479.js +0 -5
- package/web/.next/standalone/web/.next/static/chunks/f6e47c8a9766ce91.js +0 -7
- package/web/.next/standalone/web/.next/static/static/chunks/2868b007ce5163fc.css +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/3f295b6960943c38.js +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/631b023d37a08635.js +0 -13
- package/web/.next/standalone/web/.next/static/static/chunks/a2b4737b190d1b54.js +0 -5
- package/web/.next/standalone/web/.next/static/static/chunks/e97212fcc8221479.js +0 -5
- package/web/.next/standalone/web/.next/static/static/chunks/f6e47c8a9766ce91.js +0 -7
- package/web/.next/static/chunks/2868b007ce5163fc.css +0 -1
- package/web/.next/static/chunks/3f295b6960943c38.js +0 -1
- package/web/.next/static/chunks/631b023d37a08635.js +0 -13
- package/web/.next/static/chunks/a2b4737b190d1b54.js +0 -5
- package/web/.next/static/chunks/e97212fcc8221479.js +0 -5
- package/web/.next/static/chunks/f6e47c8a9766ce91.js +0 -7
- /package/web/.next/standalone/web/.next/static/{static/u5qqIWWrYpWW_mZUgKKjg → 8zJH-RqrUQ3scBGbdaCmn}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{static/u5qqIWWrYpWW_mZUgKKjg → 8zJH-RqrUQ3scBGbdaCmn}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{static/u5qqIWWrYpWW_mZUgKKjg → 8zJH-RqrUQ3scBGbdaCmn}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → static/8zJH-RqrUQ3scBGbdaCmn}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → static/8zJH-RqrUQ3scBGbdaCmn}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → static/8zJH-RqrUQ3scBGbdaCmn}/_ssgManifest.js +0 -0
- /package/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → 8zJH-RqrUQ3scBGbdaCmn}/_buildManifest.js +0 -0
- /package/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → 8zJH-RqrUQ3scBGbdaCmn}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → 8zJH-RqrUQ3scBGbdaCmn}/_ssgManifest.js +0 -0
package/dist/server/index.js
CHANGED
|
@@ -367,7 +367,7 @@ var init_db = __esm({
|
|
|
367
367
|
|
|
368
368
|
// src/config/types.ts
|
|
369
369
|
import { z } from "zod";
|
|
370
|
-
var ToolApprovalConfigSchema, SkillMetadataSchema, SessionConfigSchema, VectorGatewayConfigSchema, RemoteServerConfigSchema, SparkcoderConfigSchema;
|
|
370
|
+
var ToolApprovalConfigSchema, SkillMetadataSchema, TaskConfigSchema, SessionConfigSchema, VectorGatewayConfigSchema, RemoteServerConfigSchema, SparkcoderConfigSchema;
|
|
371
371
|
var init_types = __esm({
|
|
372
372
|
"src/config/types.ts"() {
|
|
373
373
|
"use strict";
|
|
@@ -386,11 +386,22 @@ var init_types = __esm({
|
|
|
386
386
|
// Glob patterns - auto-inject when working with matching files
|
|
387
387
|
globs: z.array(z.string()).optional().default([])
|
|
388
388
|
});
|
|
389
|
+
TaskConfigSchema = z.object({
|
|
390
|
+
enabled: z.boolean(),
|
|
391
|
+
outputSchema: z.record(z.string(), z.unknown()),
|
|
392
|
+
webhookUrl: z.string().url().optional(),
|
|
393
|
+
maxIterations: z.number().optional(),
|
|
394
|
+
status: z.enum(["running", "completed", "failed"]),
|
|
395
|
+
result: z.unknown().optional(),
|
|
396
|
+
error: z.string().optional(),
|
|
397
|
+
iterations: z.number().optional()
|
|
398
|
+
});
|
|
389
399
|
SessionConfigSchema = z.object({
|
|
390
400
|
toolApprovals: z.record(z.string(), z.boolean()).optional(),
|
|
391
401
|
approvalWebhook: z.string().url().optional(),
|
|
392
402
|
skillsDirectory: z.string().optional(),
|
|
393
|
-
maxContextChars: z.number().optional().default(2e5)
|
|
403
|
+
maxContextChars: z.number().optional().default(2e5),
|
|
404
|
+
task: TaskConfigSchema.optional()
|
|
394
405
|
});
|
|
395
406
|
VectorGatewayConfigSchema = z.object({
|
|
396
407
|
// Redis cluster nodes URL for Vector Gateway (or use REDIS_CLUSTER_NODES env var)
|
|
@@ -521,8 +532,15 @@ function discoverSkillDirectories(workingDir) {
|
|
|
521
532
|
if (existsSync(agentsMd)) {
|
|
522
533
|
agentsMdPath = agentsMd;
|
|
523
534
|
}
|
|
524
|
-
const
|
|
525
|
-
|
|
535
|
+
const baseDir = dirname(import.meta.url.replace("file://", ""));
|
|
536
|
+
const builtInCandidates = [
|
|
537
|
+
resolve(baseDir, "../skills/default"),
|
|
538
|
+
// dev: src/config → src/skills/default
|
|
539
|
+
resolve(baseDir, "./skills/default")
|
|
540
|
+
// prod: dist/ → dist/skills/default
|
|
541
|
+
];
|
|
542
|
+
const builtInSkillsDir = builtInCandidates.find((p) => existsSync(p));
|
|
543
|
+
if (builtInSkillsDir) {
|
|
526
544
|
onDemandDirs.push({ path: builtInSkillsDir, priority: 100 });
|
|
527
545
|
allDirectories.push(builtInSkillsDir);
|
|
528
546
|
}
|
|
@@ -691,6 +709,9 @@ function getConfig() {
|
|
|
691
709
|
}
|
|
692
710
|
function requiresApproval(toolName, sessionConfig) {
|
|
693
711
|
const config = getConfig();
|
|
712
|
+
if (sessionConfig?.toolApprovals?.["*"] !== void 0) {
|
|
713
|
+
return sessionConfig.toolApprovals["*"];
|
|
714
|
+
}
|
|
694
715
|
if (sessionConfig?.toolApprovals?.[toolName] !== void 0) {
|
|
695
716
|
return sessionConfig.toolApprovals[toolName];
|
|
696
717
|
}
|
|
@@ -874,7 +895,7 @@ __export(skills_exports, {
|
|
|
874
895
|
loadSkillsFromDirectory: () => loadSkillsFromDirectory
|
|
875
896
|
});
|
|
876
897
|
import { readFile as readFile6, readdir } from "fs/promises";
|
|
877
|
-
import { resolve as resolve6, basename, extname as
|
|
898
|
+
import { resolve as resolve6, basename, extname as extname4, relative as relative4 } from "path";
|
|
878
899
|
import { existsSync as existsSync8 } from "fs";
|
|
879
900
|
import { minimatch } from "minimatch";
|
|
880
901
|
function parseSkillFrontmatter(content) {
|
|
@@ -945,7 +966,7 @@ function parseSkillFrontmatter(content) {
|
|
|
945
966
|
}
|
|
946
967
|
}
|
|
947
968
|
function getSkillNameFromPath(filePath) {
|
|
948
|
-
return basename(filePath,
|
|
969
|
+
return basename(filePath, extname4(filePath)).replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
949
970
|
}
|
|
950
971
|
async function loadSkillsFromDirectory(directory, options = {}) {
|
|
951
972
|
const {
|
|
@@ -1250,7 +1271,7 @@ var init_hasher = __esm({
|
|
|
1250
1271
|
});
|
|
1251
1272
|
|
|
1252
1273
|
// src/semantic/chunker.ts
|
|
1253
|
-
import { extname as
|
|
1274
|
+
import { extname as extname6, basename as basename2 } from "path";
|
|
1254
1275
|
var init_chunker = __esm({
|
|
1255
1276
|
"src/semantic/chunker.ts"() {
|
|
1256
1277
|
"use strict";
|
|
@@ -1598,7 +1619,7 @@ var init_semantic_search = __esm({
|
|
|
1598
1619
|
|
|
1599
1620
|
// src/server/index.ts
|
|
1600
1621
|
import "dotenv/config";
|
|
1601
|
-
import { Hono as
|
|
1622
|
+
import { Hono as Hono6 } from "hono";
|
|
1602
1623
|
import { serve } from "@hono/node-server";
|
|
1603
1624
|
import { cors } from "hono/cors";
|
|
1604
1625
|
import { logger } from "hono/logger";
|
|
@@ -1612,28 +1633,186 @@ import { fileURLToPath as fileURLToPath4 } from "url";
|
|
|
1612
1633
|
init_db();
|
|
1613
1634
|
import { Hono } from "hono";
|
|
1614
1635
|
import { zValidator } from "@hono/zod-validator";
|
|
1615
|
-
import { z as
|
|
1636
|
+
import { z as z14 } from "zod";
|
|
1616
1637
|
import { existsSync as existsSync13, mkdirSync as mkdirSync3, writeFileSync as writeFileSync2, readdirSync, statSync as statSync2, unlinkSync } from "fs";
|
|
1617
1638
|
import { readdir as readdir5 } from "fs/promises";
|
|
1618
|
-
import { join as join5, basename as basename4, extname as
|
|
1639
|
+
import { join as join5, basename as basename4, extname as extname7, relative as relative9 } from "path";
|
|
1619
1640
|
import { nanoid as nanoid4 } from "nanoid";
|
|
1620
1641
|
|
|
1621
1642
|
// src/agent/index.ts
|
|
1622
1643
|
import {
|
|
1623
1644
|
streamText as streamText2,
|
|
1624
1645
|
generateText as generateText3,
|
|
1625
|
-
tool as
|
|
1646
|
+
tool as tool12,
|
|
1626
1647
|
stepCountIs as stepCountIs2
|
|
1627
1648
|
} from "ai";
|
|
1628
1649
|
|
|
1629
1650
|
// src/agent/model.ts
|
|
1630
1651
|
import { gateway } from "@ai-sdk/gateway";
|
|
1652
|
+
|
|
1653
|
+
// src/agent/remote-model.ts
|
|
1654
|
+
function serializePrompt(prompt) {
|
|
1655
|
+
return prompt.map((msg) => {
|
|
1656
|
+
if (!Array.isArray(msg.content)) return msg;
|
|
1657
|
+
return {
|
|
1658
|
+
...msg,
|
|
1659
|
+
content: msg.content.map((part) => {
|
|
1660
|
+
if (part.type === "file" && part.data instanceof Uint8Array) {
|
|
1661
|
+
return {
|
|
1662
|
+
...part,
|
|
1663
|
+
data: Buffer.from(part.data).toString("base64"),
|
|
1664
|
+
_base64: true
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
return part;
|
|
1668
|
+
})
|
|
1669
|
+
};
|
|
1670
|
+
});
|
|
1671
|
+
}
|
|
1672
|
+
function deserializeValue(value) {
|
|
1673
|
+
if (value && typeof value === "object") {
|
|
1674
|
+
if (value.__uint8array && typeof value.data === "string") {
|
|
1675
|
+
return Buffer.from(value.data, "base64");
|
|
1676
|
+
}
|
|
1677
|
+
if (Array.isArray(value)) {
|
|
1678
|
+
return value.map(deserializeValue);
|
|
1679
|
+
}
|
|
1680
|
+
const result = {};
|
|
1681
|
+
for (const [k, v] of Object.entries(value)) {
|
|
1682
|
+
result[k] = deserializeValue(v);
|
|
1683
|
+
}
|
|
1684
|
+
return result;
|
|
1685
|
+
}
|
|
1686
|
+
return value;
|
|
1687
|
+
}
|
|
1688
|
+
function prepareOptions(options) {
|
|
1689
|
+
const { abortSignal, ...rest } = options;
|
|
1690
|
+
return {
|
|
1691
|
+
...rest,
|
|
1692
|
+
prompt: serializePrompt(options.prompt)
|
|
1693
|
+
};
|
|
1694
|
+
}
|
|
1695
|
+
function createRemoteModel(modelId, config) {
|
|
1696
|
+
const baseUrl = config.url.replace(/\/$/, "");
|
|
1697
|
+
const headers = {
|
|
1698
|
+
"Content-Type": "application/json",
|
|
1699
|
+
"Authorization": `Bearer ${config.authKey}`
|
|
1700
|
+
};
|
|
1701
|
+
return {
|
|
1702
|
+
specificationVersion: "v3",
|
|
1703
|
+
provider: "remote-proxy",
|
|
1704
|
+
modelId,
|
|
1705
|
+
supportedUrls: {},
|
|
1706
|
+
async doGenerate(options) {
|
|
1707
|
+
const res = await fetch(`${baseUrl}/inference/generate`, {
|
|
1708
|
+
method: "POST",
|
|
1709
|
+
headers,
|
|
1710
|
+
body: JSON.stringify({
|
|
1711
|
+
modelId,
|
|
1712
|
+
options: prepareOptions(options)
|
|
1713
|
+
}),
|
|
1714
|
+
signal: options.abortSignal
|
|
1715
|
+
});
|
|
1716
|
+
if (!res.ok) {
|
|
1717
|
+
const err = await res.json().catch(() => ({}));
|
|
1718
|
+
throw new Error(
|
|
1719
|
+
`Remote inference failed (${res.status}): ${err.error || res.statusText}`
|
|
1720
|
+
);
|
|
1721
|
+
}
|
|
1722
|
+
const result = await res.json();
|
|
1723
|
+
return deserializeValue(result);
|
|
1724
|
+
},
|
|
1725
|
+
async doStream(options) {
|
|
1726
|
+
const res = await fetch(`${baseUrl}/inference/stream`, {
|
|
1727
|
+
method: "POST",
|
|
1728
|
+
headers,
|
|
1729
|
+
body: JSON.stringify({
|
|
1730
|
+
modelId,
|
|
1731
|
+
options: prepareOptions(options)
|
|
1732
|
+
}),
|
|
1733
|
+
signal: options.abortSignal
|
|
1734
|
+
});
|
|
1735
|
+
if (!res.ok) {
|
|
1736
|
+
const err = await res.json().catch(() => ({}));
|
|
1737
|
+
throw new Error(
|
|
1738
|
+
`Remote inference failed (${res.status}): ${err.error || res.statusText}`
|
|
1739
|
+
);
|
|
1740
|
+
}
|
|
1741
|
+
const reader = res.body.getReader();
|
|
1742
|
+
const decoder = new TextDecoder();
|
|
1743
|
+
let buffer = "";
|
|
1744
|
+
const stream = new ReadableStream({
|
|
1745
|
+
async pull(controller) {
|
|
1746
|
+
while (true) {
|
|
1747
|
+
const { done, value } = await reader.read();
|
|
1748
|
+
if (done) {
|
|
1749
|
+
if (buffer.trim()) {
|
|
1750
|
+
try {
|
|
1751
|
+
const parsed = deserializeValue(JSON.parse(buffer.trim()));
|
|
1752
|
+
if (parsed.type === "error") {
|
|
1753
|
+
controller.error(new Error(parsed.error));
|
|
1754
|
+
} else {
|
|
1755
|
+
controller.enqueue(parsed);
|
|
1756
|
+
}
|
|
1757
|
+
} catch {
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
controller.close();
|
|
1761
|
+
return;
|
|
1762
|
+
}
|
|
1763
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1764
|
+
const lines = buffer.split("\n");
|
|
1765
|
+
buffer = lines.pop() || "";
|
|
1766
|
+
for (const line of lines) {
|
|
1767
|
+
if (!line.trim()) continue;
|
|
1768
|
+
try {
|
|
1769
|
+
const parsed = deserializeValue(JSON.parse(line));
|
|
1770
|
+
if (parsed.type === "error") {
|
|
1771
|
+
controller.error(new Error(parsed.error));
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
controller.enqueue(parsed);
|
|
1775
|
+
} catch {
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
},
|
|
1780
|
+
cancel() {
|
|
1781
|
+
reader.cancel();
|
|
1782
|
+
}
|
|
1783
|
+
});
|
|
1784
|
+
const responseHeaders = {};
|
|
1785
|
+
res.headers.forEach((v, k) => {
|
|
1786
|
+
if (k.startsWith("x-upstream-")) {
|
|
1787
|
+
responseHeaders[k.replace("x-upstream-", "")] = v;
|
|
1788
|
+
}
|
|
1789
|
+
});
|
|
1790
|
+
return {
|
|
1791
|
+
stream,
|
|
1792
|
+
response: Object.keys(responseHeaders).length > 0 ? { headers: responseHeaders } : void 0
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
// src/agent/model.ts
|
|
1799
|
+
init_config();
|
|
1631
1800
|
var ANTHROPIC_PREFIX = "anthropic/";
|
|
1632
1801
|
function isAnthropicModel(modelId) {
|
|
1633
1802
|
const normalized = modelId.trim().toLowerCase();
|
|
1634
1803
|
return normalized.startsWith(ANTHROPIC_PREFIX) || normalized.startsWith("claude-");
|
|
1635
1804
|
}
|
|
1636
1805
|
function resolveModel(modelId) {
|
|
1806
|
+
try {
|
|
1807
|
+
const config = getConfig();
|
|
1808
|
+
if (config.resolvedRemoteServer.isConfigured) {
|
|
1809
|
+
return createRemoteModel(modelId.trim(), {
|
|
1810
|
+
url: config.resolvedRemoteServer.url,
|
|
1811
|
+
authKey: config.resolvedRemoteServer.authKey
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
} catch {
|
|
1815
|
+
}
|
|
1637
1816
|
return gateway(modelId.trim());
|
|
1638
1817
|
}
|
|
1639
1818
|
var SUBAGENT_MODELS = {
|
|
@@ -1645,7 +1824,7 @@ var SUBAGENT_MODELS = {
|
|
|
1645
1824
|
// src/agent/index.ts
|
|
1646
1825
|
init_db();
|
|
1647
1826
|
init_config();
|
|
1648
|
-
import { z as
|
|
1827
|
+
import { z as z13 } from "zod";
|
|
1649
1828
|
import { nanoid as nanoid3 } from "nanoid";
|
|
1650
1829
|
|
|
1651
1830
|
// src/tools/bash.ts
|
|
@@ -2226,26 +2405,41 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
|
|
|
2226
2405
|
import { tool as tool2 } from "ai";
|
|
2227
2406
|
import { z as z3 } from "zod";
|
|
2228
2407
|
import { readFile as readFile2, stat } from "fs/promises";
|
|
2229
|
-
import { resolve as resolve2, relative, isAbsolute } from "path";
|
|
2408
|
+
import { resolve as resolve2, relative, isAbsolute, extname } from "path";
|
|
2230
2409
|
import { existsSync as existsSync3 } from "fs";
|
|
2231
2410
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
2411
|
+
var MAX_IMAGE_SIZE = 20 * 1024 * 1024;
|
|
2232
2412
|
var MAX_OUTPUT_CHARS3 = 5e4;
|
|
2413
|
+
var IMAGE_EXTENSIONS = {
|
|
2414
|
+
".png": "image/png",
|
|
2415
|
+
".jpg": "image/jpeg",
|
|
2416
|
+
".jpeg": "image/jpeg",
|
|
2417
|
+
".gif": "image/gif",
|
|
2418
|
+
".webp": "image/webp"
|
|
2419
|
+
};
|
|
2420
|
+
function isImageFile(filePath) {
|
|
2421
|
+
return extname(filePath).toLowerCase() in IMAGE_EXTENSIONS;
|
|
2422
|
+
}
|
|
2423
|
+
function getImageMediaType(filePath) {
|
|
2424
|
+
return IMAGE_EXTENSIONS[extname(filePath).toLowerCase()] || "image/png";
|
|
2425
|
+
}
|
|
2233
2426
|
var readFileInputSchema = z3.object({
|
|
2234
|
-
path: z3.string().describe("The path to the file to read. Can be relative to working directory or absolute."),
|
|
2235
|
-
startLine: z3.number().optional().describe("Optional: Start reading from this line number (1-indexed)"),
|
|
2236
|
-
endLine: z3.number().optional().describe("Optional: Stop reading at this line number (1-indexed, inclusive)")
|
|
2427
|
+
path: z3.string().describe("The path to the file to read. Can be relative to working directory or absolute. Supports text files and images (png, jpg, jpeg, gif, webp)."),
|
|
2428
|
+
startLine: z3.number().optional().describe("Optional: Start reading from this line number (1-indexed). Only for text files."),
|
|
2429
|
+
endLine: z3.number().optional().describe("Optional: Stop reading at this line number (1-indexed, inclusive). Only for text files.")
|
|
2237
2430
|
});
|
|
2238
2431
|
function createReadFileTool(options) {
|
|
2239
2432
|
return tool2({
|
|
2240
2433
|
description: `Read the contents of a file. Provide a path relative to the working directory (${options.workingDirectory}) or an absolute path.
|
|
2241
|
-
|
|
2242
|
-
|
|
2434
|
+
Supports text files (automatically truncated if large) and image files (png, jpg, jpeg, gif, webp).
|
|
2435
|
+
For images, the file contents are returned as visual data you can see and analyze.
|
|
2436
|
+
Use this to understand existing code, check file contents, view screenshots, or gather context.`,
|
|
2243
2437
|
inputSchema: readFileInputSchema,
|
|
2244
|
-
execute: async ({ path, startLine, endLine }) => {
|
|
2438
|
+
execute: async ({ path: filePath, startLine, endLine }) => {
|
|
2245
2439
|
try {
|
|
2246
|
-
const absolutePath = isAbsolute(
|
|
2440
|
+
const absolutePath = isAbsolute(filePath) ? filePath : resolve2(options.workingDirectory, filePath);
|
|
2247
2441
|
const relativePath = relative(options.workingDirectory, absolutePath);
|
|
2248
|
-
if (relativePath.startsWith("..") && !isAbsolute(
|
|
2442
|
+
if (relativePath.startsWith("..") && !isAbsolute(filePath)) {
|
|
2249
2443
|
return {
|
|
2250
2444
|
success: false,
|
|
2251
2445
|
error: "Path escapes the working directory. Use an absolute path if intentional.",
|
|
@@ -2255,22 +2449,43 @@ Use this to understand existing code, check file contents, or gather context.`,
|
|
|
2255
2449
|
if (!existsSync3(absolutePath)) {
|
|
2256
2450
|
return {
|
|
2257
2451
|
success: false,
|
|
2258
|
-
error: `File not found: ${
|
|
2452
|
+
error: `File not found: ${filePath}`,
|
|
2259
2453
|
content: null
|
|
2260
2454
|
};
|
|
2261
2455
|
}
|
|
2262
2456
|
const stats = await stat(absolutePath);
|
|
2263
|
-
if (stats.
|
|
2457
|
+
if (stats.isDirectory()) {
|
|
2264
2458
|
return {
|
|
2265
2459
|
success: false,
|
|
2266
|
-
error:
|
|
2460
|
+
error: 'Path is a directory, not a file. Use bash with "ls" to list directory contents.',
|
|
2267
2461
|
content: null
|
|
2268
2462
|
};
|
|
2269
2463
|
}
|
|
2270
|
-
if (
|
|
2464
|
+
if (isImageFile(absolutePath)) {
|
|
2465
|
+
if (stats.size > MAX_IMAGE_SIZE) {
|
|
2466
|
+
return {
|
|
2467
|
+
success: false,
|
|
2468
|
+
error: `Image is too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Maximum size is ${MAX_IMAGE_SIZE / 1024 / 1024}MB.`,
|
|
2469
|
+
content: null
|
|
2470
|
+
};
|
|
2471
|
+
}
|
|
2472
|
+
const buffer = await readFile2(absolutePath);
|
|
2473
|
+
const base64 = buffer.toString("base64");
|
|
2474
|
+
const mediaType = getImageMediaType(absolutePath);
|
|
2475
|
+
return {
|
|
2476
|
+
success: true,
|
|
2477
|
+
path: absolutePath,
|
|
2478
|
+
relativePath: relative(options.workingDirectory, absolutePath),
|
|
2479
|
+
content: `[Image: ${relativePath} (${mediaType}, ${(stats.size / 1024).toFixed(1)}KB)]`,
|
|
2480
|
+
mediaType,
|
|
2481
|
+
imageData: base64,
|
|
2482
|
+
sizeBytes: stats.size
|
|
2483
|
+
};
|
|
2484
|
+
}
|
|
2485
|
+
if (stats.size > MAX_FILE_SIZE) {
|
|
2271
2486
|
return {
|
|
2272
2487
|
success: false,
|
|
2273
|
-
error:
|
|
2488
|
+
error: `File is too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Maximum size is ${MAX_FILE_SIZE / 1024 / 1024}MB.`,
|
|
2274
2489
|
content: null
|
|
2275
2490
|
};
|
|
2276
2491
|
}
|
|
@@ -2286,9 +2501,7 @@ Use this to understand existing code, check file contents, or gather context.`,
|
|
|
2286
2501
|
content: null
|
|
2287
2502
|
};
|
|
2288
2503
|
}
|
|
2289
|
-
content = lines.slice(start, end).join("\n");
|
|
2290
|
-
const lineNumbers = lines.slice(start, end).map((line, idx) => `${(start + idx + 1).toString().padStart(4)}: ${line}`).join("\n");
|
|
2291
|
-
content = lineNumbers;
|
|
2504
|
+
content = lines.slice(start, end).map((line, idx) => `${(start + idx + 1).toString().padStart(4)}: ${line}`).join("\n");
|
|
2292
2505
|
}
|
|
2293
2506
|
const truncatedContent = truncateOutput(content, MAX_OUTPUT_CHARS3);
|
|
2294
2507
|
const wasTruncated = truncatedContent.length < content.length;
|
|
@@ -2315,6 +2528,19 @@ Use this to understand existing code, check file contents, or gather context.`,
|
|
|
2315
2528
|
content: null
|
|
2316
2529
|
};
|
|
2317
2530
|
}
|
|
2531
|
+
},
|
|
2532
|
+
toModelOutput: ({ output }) => {
|
|
2533
|
+
if (output && typeof output === "object" && "imageData" in output && output.imageData) {
|
|
2534
|
+
const result = output;
|
|
2535
|
+
return {
|
|
2536
|
+
type: "content",
|
|
2537
|
+
value: [
|
|
2538
|
+
{ type: "text", text: result.content },
|
|
2539
|
+
{ type: "image-data", data: result.imageData, mediaType: result.mediaType }
|
|
2540
|
+
]
|
|
2541
|
+
};
|
|
2542
|
+
}
|
|
2543
|
+
return typeof output === "string" ? { type: "text", value: output } : { type: "json", value: output };
|
|
2318
2544
|
}
|
|
2319
2545
|
});
|
|
2320
2546
|
}
|
|
@@ -2515,7 +2741,7 @@ function clearCheckpointManager(sessionId) {
|
|
|
2515
2741
|
}
|
|
2516
2742
|
|
|
2517
2743
|
// src/lsp/index.ts
|
|
2518
|
-
import { extname as
|
|
2744
|
+
import { extname as extname3, dirname as dirname4 } from "path";
|
|
2519
2745
|
|
|
2520
2746
|
// src/lsp/servers.ts
|
|
2521
2747
|
import { spawn } from "child_process";
|
|
@@ -2638,9 +2864,9 @@ import {
|
|
|
2638
2864
|
import { pathToFileURL, fileURLToPath } from "url";
|
|
2639
2865
|
import { readFile as readFile4 } from "fs/promises";
|
|
2640
2866
|
import { existsSync as existsSync6 } from "fs";
|
|
2641
|
-
import { extname, normalize } from "path";
|
|
2867
|
+
import { extname as extname2, normalize } from "path";
|
|
2642
2868
|
function getLanguageId(filePath) {
|
|
2643
|
-
const ext =
|
|
2869
|
+
const ext = extname2(filePath).toLowerCase();
|
|
2644
2870
|
const map = {
|
|
2645
2871
|
".ts": "typescript",
|
|
2646
2872
|
".tsx": "typescriptreact",
|
|
@@ -3028,7 +3254,7 @@ var state = {
|
|
|
3028
3254
|
};
|
|
3029
3255
|
async function getClientForFile(filePath) {
|
|
3030
3256
|
const normalized = normalizePath(filePath);
|
|
3031
|
-
const ext =
|
|
3257
|
+
const ext = extname3(normalized);
|
|
3032
3258
|
const serverDef = getServerForExtension(ext);
|
|
3033
3259
|
if (!serverDef) {
|
|
3034
3260
|
return null;
|
|
@@ -3121,7 +3347,7 @@ async function formatDiagnosticsOutput(filePath, options = {}) {
|
|
|
3121
3347
|
return formatDiagnosticsForAgent(filePath, diagnostics, options);
|
|
3122
3348
|
}
|
|
3123
3349
|
function isSupported(filePath) {
|
|
3124
|
-
const ext =
|
|
3350
|
+
const ext = extname3(filePath);
|
|
3125
3351
|
return getServerForExtension(ext) !== null;
|
|
3126
3352
|
}
|
|
3127
3353
|
|
|
@@ -3548,7 +3774,7 @@ Once loaded, a skill's content will be available in the conversation context.`,
|
|
|
3548
3774
|
// src/tools/linter.ts
|
|
3549
3775
|
import { tool as tool6 } from "ai";
|
|
3550
3776
|
import { z as z7 } from "zod";
|
|
3551
|
-
import { resolve as resolve7, relative as relative5, isAbsolute as isAbsolute3, extname as
|
|
3777
|
+
import { resolve as resolve7, relative as relative5, isAbsolute as isAbsolute3, extname as extname5 } from "path";
|
|
3552
3778
|
import { existsSync as existsSync9 } from "fs";
|
|
3553
3779
|
import { readdir as readdir2, stat as stat2 } from "fs/promises";
|
|
3554
3780
|
var linterInputSchema = z7.object({
|
|
@@ -3571,7 +3797,7 @@ async function findSupportedFiles(dir, workingDirectory, maxFiles = 50) {
|
|
|
3571
3797
|
}
|
|
3572
3798
|
await walk(fullPath);
|
|
3573
3799
|
} else if (entry.isFile()) {
|
|
3574
|
-
const ext =
|
|
3800
|
+
const ext = extname5(entry.name);
|
|
3575
3801
|
if (supportedExtensions.includes(ext)) {
|
|
3576
3802
|
files.push(fullPath);
|
|
3577
3803
|
}
|
|
@@ -4908,6 +5134,59 @@ Context: ${context}` : query;
|
|
|
4908
5134
|
|
|
4909
5135
|
// src/tools/index.ts
|
|
4910
5136
|
init_semantic_search();
|
|
5137
|
+
|
|
5138
|
+
// src/tools/task.ts
|
|
5139
|
+
import { tool as tool11 } from "ai";
|
|
5140
|
+
import { z as z12 } from "zod";
|
|
5141
|
+
import Ajv from "ajv";
|
|
5142
|
+
var ajv = new Ajv({ allErrors: true });
|
|
5143
|
+
function createCompleteTaskTool(options) {
|
|
5144
|
+
const validate = ajv.compile(options.outputSchema);
|
|
5145
|
+
return tool11({
|
|
5146
|
+
description: "Call this tool when you have completed the task. Pass the result as a JSON object matching the required output schema. If the result does not match the schema, you will receive validation errors and should fix and retry.",
|
|
5147
|
+
inputSchema: z12.object({
|
|
5148
|
+
result: z12.record(z12.string(), z12.unknown()).describe("The task result as a JSON object matching the output schema")
|
|
5149
|
+
}),
|
|
5150
|
+
execute: async (input) => {
|
|
5151
|
+
const valid = validate(input.result);
|
|
5152
|
+
if (!valid) {
|
|
5153
|
+
const errors = validate.errors?.map((e) => ({
|
|
5154
|
+
path: e.instancePath || "/",
|
|
5155
|
+
message: e.message,
|
|
5156
|
+
params: e.params
|
|
5157
|
+
}));
|
|
5158
|
+
return {
|
|
5159
|
+
status: "validation_error",
|
|
5160
|
+
message: "The result does not match the required output schema. Fix the errors and call complete_task again.",
|
|
5161
|
+
errors,
|
|
5162
|
+
expectedSchema: options.outputSchema
|
|
5163
|
+
};
|
|
5164
|
+
}
|
|
5165
|
+
options.onComplete({ status: "completed", result: input.result });
|
|
5166
|
+
return {
|
|
5167
|
+
status: "completed",
|
|
5168
|
+
message: "Task completed successfully."
|
|
5169
|
+
};
|
|
5170
|
+
}
|
|
5171
|
+
});
|
|
5172
|
+
}
|
|
5173
|
+
function createTaskFailedTool(options) {
|
|
5174
|
+
return tool11({
|
|
5175
|
+
description: "Call this tool if you are unable to complete the task. Provide a clear reason explaining why the task cannot be completed.",
|
|
5176
|
+
inputSchema: z12.object({
|
|
5177
|
+
reason: z12.string().describe("Explanation of why the task cannot be completed")
|
|
5178
|
+
}),
|
|
5179
|
+
execute: async (input) => {
|
|
5180
|
+
options.onComplete({ status: "failed", error: input.reason });
|
|
5181
|
+
return {
|
|
5182
|
+
status: "failed",
|
|
5183
|
+
message: `Task marked as failed: ${input.reason}`
|
|
5184
|
+
};
|
|
5185
|
+
}
|
|
5186
|
+
});
|
|
5187
|
+
}
|
|
5188
|
+
|
|
5189
|
+
// src/tools/index.ts
|
|
4911
5190
|
init_semantic();
|
|
4912
5191
|
init_semantic_search();
|
|
4913
5192
|
async function createTools(options) {
|
|
@@ -4959,6 +5238,10 @@ async function createTools(options) {
|
|
|
4959
5238
|
} catch {
|
|
4960
5239
|
}
|
|
4961
5240
|
}
|
|
5241
|
+
if (options.taskTools) {
|
|
5242
|
+
tools.complete_task = createCompleteTaskTool(options.taskTools);
|
|
5243
|
+
tools.task_failed = createTaskFailedTool(options.taskTools);
|
|
5244
|
+
}
|
|
4962
5245
|
return tools;
|
|
4963
5246
|
}
|
|
4964
5247
|
|
|
@@ -5276,6 +5559,30 @@ function formatTodosForContext(todos) {
|
|
|
5276
5559
|
}
|
|
5277
5560
|
return lines.join("\n");
|
|
5278
5561
|
}
|
|
5562
|
+
function buildTaskPromptAddendum(outputSchema) {
|
|
5563
|
+
return `
|
|
5564
|
+
## Task Mode
|
|
5565
|
+
|
|
5566
|
+
You are running in **task mode**. You have been given a specific task to complete autonomously.
|
|
5567
|
+
|
|
5568
|
+
### Rules
|
|
5569
|
+
1. Work independently \u2014 no human will approve tool calls. All tools run without approval.
|
|
5570
|
+
2. Keep working until the task is fully complete.
|
|
5571
|
+
3. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
|
|
5572
|
+
4. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
|
|
5573
|
+
5. Do NOT stop without calling one of these two tools.
|
|
5574
|
+
|
|
5575
|
+
### Output Schema
|
|
5576
|
+
The \`complete_task\` tool expects a \`result\` object matching this JSON Schema:
|
|
5577
|
+
\`\`\`json
|
|
5578
|
+
${JSON.stringify(outputSchema, null, 2)}
|
|
5579
|
+
\`\`\`
|
|
5580
|
+
|
|
5581
|
+
### Completion Tools
|
|
5582
|
+
- **\`complete_task({ result: ... })\`** \u2014 Call when the task is done. The result is validated against the schema above. If validation fails you will get errors back \u2014 fix and retry.
|
|
5583
|
+
- **\`task_failed({ reason: "..." })\`** \u2014 Call only if the task truly cannot be completed.
|
|
5584
|
+
`;
|
|
5585
|
+
}
|
|
5279
5586
|
function createSummaryPrompt(conversationHistory) {
|
|
5280
5587
|
return `Please provide a concise summary of the following conversation history. Focus on:
|
|
5281
5588
|
1. The main task or goal being worked on
|
|
@@ -5537,6 +5844,25 @@ ${this.summary}`
|
|
|
5537
5844
|
}
|
|
5538
5845
|
};
|
|
5539
5846
|
|
|
5847
|
+
// src/utils/webhook.ts
|
|
5848
|
+
async function sendWebhook(url, event) {
|
|
5849
|
+
try {
|
|
5850
|
+
const controller = new AbortController();
|
|
5851
|
+
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
5852
|
+
await fetch(url, {
|
|
5853
|
+
method: "POST",
|
|
5854
|
+
headers: {
|
|
5855
|
+
"Content-Type": "application/json",
|
|
5856
|
+
"X-SparkECoder-Event": event.type
|
|
5857
|
+
},
|
|
5858
|
+
body: JSON.stringify(event),
|
|
5859
|
+
signal: controller.signal
|
|
5860
|
+
});
|
|
5861
|
+
clearTimeout(timeout);
|
|
5862
|
+
} catch {
|
|
5863
|
+
}
|
|
5864
|
+
}
|
|
5865
|
+
|
|
5540
5866
|
// src/agent/index.ts
|
|
5541
5867
|
var approvalResolvers = /* @__PURE__ */ new Map();
|
|
5542
5868
|
var Agent = class _Agent {
|
|
@@ -5756,6 +6082,145 @@ ${prompt}` });
|
|
|
5756
6082
|
steps: result.steps
|
|
5757
6083
|
};
|
|
5758
6084
|
}
|
|
6085
|
+
/**
|
|
6086
|
+
* Run the agent in task mode — loops autonomously until the agent calls
|
|
6087
|
+
* complete_task or task_failed (or hits maxIterations).
|
|
6088
|
+
* All tools run without approval. Webhook events are fired throughout.
|
|
6089
|
+
*/
|
|
6090
|
+
async runTask(options) {
|
|
6091
|
+
const config = getConfig();
|
|
6092
|
+
const maxIterations = options.taskConfig.maxIterations ?? 50;
|
|
6093
|
+
const webhookUrl = options.taskConfig.webhookUrl;
|
|
6094
|
+
const fireWebhook = (type, data) => {
|
|
6095
|
+
if (!webhookUrl) return;
|
|
6096
|
+
sendWebhook(webhookUrl, {
|
|
6097
|
+
type,
|
|
6098
|
+
taskId: this.session.id,
|
|
6099
|
+
sessionId: this.session.id,
|
|
6100
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6101
|
+
data
|
|
6102
|
+
});
|
|
6103
|
+
};
|
|
6104
|
+
const completion = { signal: null };
|
|
6105
|
+
const onComplete = (signal) => {
|
|
6106
|
+
completion.signal = signal;
|
|
6107
|
+
};
|
|
6108
|
+
const taskTools = await createTools({
|
|
6109
|
+
sessionId: this.session.id,
|
|
6110
|
+
workingDirectory: this.session.workingDirectory,
|
|
6111
|
+
skillsDirectories: config.resolvedSkillsDirectories,
|
|
6112
|
+
onBashProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "bash", data: progress }) : void 0,
|
|
6113
|
+
onWriteFileProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "write_file", data: progress }) : void 0,
|
|
6114
|
+
onSearchProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "explore_agent", data: progress }) : void 0,
|
|
6115
|
+
taskTools: {
|
|
6116
|
+
outputSchema: options.taskConfig.outputSchema,
|
|
6117
|
+
onComplete
|
|
6118
|
+
}
|
|
6119
|
+
});
|
|
6120
|
+
const baseSystemPrompt = await buildSystemPrompt({
|
|
6121
|
+
workingDirectory: this.session.workingDirectory,
|
|
6122
|
+
skillsDirectories: config.resolvedSkillsDirectories,
|
|
6123
|
+
sessionId: this.session.id,
|
|
6124
|
+
discoveredSkills: config.discoveredSkills,
|
|
6125
|
+
activeFiles: []
|
|
6126
|
+
});
|
|
6127
|
+
const taskAddendum = buildTaskPromptAddendum(options.taskConfig.outputSchema);
|
|
6128
|
+
const systemPrompt = `${baseSystemPrompt}
|
|
6129
|
+
|
|
6130
|
+
${taskAddendum}`;
|
|
6131
|
+
fireWebhook("task.started", { prompt: options.prompt });
|
|
6132
|
+
this.context.addUserMessage(options.prompt);
|
|
6133
|
+
let iteration = 0;
|
|
6134
|
+
while (iteration < maxIterations) {
|
|
6135
|
+
iteration++;
|
|
6136
|
+
if (options.abortSignal?.aborted) {
|
|
6137
|
+
const cancelError = "Task was cancelled";
|
|
6138
|
+
fireWebhook("task.failed", { status: "failed", error: cancelError, iterations: iteration });
|
|
6139
|
+
return { status: "failed", error: cancelError, iterations: iteration };
|
|
6140
|
+
}
|
|
6141
|
+
const messages = await this.context.getMessages();
|
|
6142
|
+
const useAnthropic = isAnthropicModel(this.session.model);
|
|
6143
|
+
const result = await generateText3({
|
|
6144
|
+
model: resolveModel(this.session.model),
|
|
6145
|
+
system: systemPrompt,
|
|
6146
|
+
messages,
|
|
6147
|
+
tools: taskTools,
|
|
6148
|
+
stopWhen: stepCountIs2(500),
|
|
6149
|
+
abortSignal: options.abortSignal,
|
|
6150
|
+
providerOptions: useAnthropic ? {
|
|
6151
|
+
anthropic: {
|
|
6152
|
+
thinking: { type: "enabled", budgetTokens: 1e4 }
|
|
6153
|
+
}
|
|
6154
|
+
} : void 0,
|
|
6155
|
+
onStepFinish: (step) => {
|
|
6156
|
+
options.onStepFinish?.(step);
|
|
6157
|
+
fireWebhook("task.step_finished", { iteration, text: step.text });
|
|
6158
|
+
}
|
|
6159
|
+
});
|
|
6160
|
+
const responseMessages = result.response.messages;
|
|
6161
|
+
this.context.addResponseMessages(responseMessages);
|
|
6162
|
+
if (result.text) {
|
|
6163
|
+
options.onText?.(result.text);
|
|
6164
|
+
fireWebhook("task.message", { iteration, text: result.text });
|
|
6165
|
+
}
|
|
6166
|
+
for (const step of result.steps) {
|
|
6167
|
+
if (step.toolCalls) {
|
|
6168
|
+
for (const tc of step.toolCalls) {
|
|
6169
|
+
options.onToolCall?.({ toolCallId: tc.toolCallId, toolName: tc.toolName, input: tc.args });
|
|
6170
|
+
fireWebhook("task.tool_call", { iteration, toolName: tc.toolName, toolCallId: tc.toolCallId, input: tc.args });
|
|
6171
|
+
}
|
|
6172
|
+
}
|
|
6173
|
+
if (step.toolResults) {
|
|
6174
|
+
for (const tr of step.toolResults) {
|
|
6175
|
+
options.onToolResult?.({ toolCallId: tr.toolCallId, toolName: tr.toolName, output: tr.result });
|
|
6176
|
+
fireWebhook("task.tool_result", { iteration, toolName: tr.toolName, toolCallId: tr.toolCallId, output: tr.result });
|
|
6177
|
+
}
|
|
6178
|
+
}
|
|
6179
|
+
}
|
|
6180
|
+
if (completion.signal) {
|
|
6181
|
+
const sig = completion.signal;
|
|
6182
|
+
const finalStatus = sig.status;
|
|
6183
|
+
const eventType = finalStatus === "completed" ? "task.completed" : "task.failed";
|
|
6184
|
+
fireWebhook(eventType, {
|
|
6185
|
+
status: finalStatus,
|
|
6186
|
+
result: sig.result,
|
|
6187
|
+
error: sig.error,
|
|
6188
|
+
iterations: iteration
|
|
6189
|
+
});
|
|
6190
|
+
const updatedTask2 = {
|
|
6191
|
+
...options.taskConfig,
|
|
6192
|
+
status: finalStatus,
|
|
6193
|
+
result: sig.result,
|
|
6194
|
+
error: sig.error,
|
|
6195
|
+
iterations: iteration
|
|
6196
|
+
};
|
|
6197
|
+
await sessionQueries.update(this.session.id, {
|
|
6198
|
+
config: { ...this.session.config, task: updatedTask2 }
|
|
6199
|
+
});
|
|
6200
|
+
return {
|
|
6201
|
+
status: finalStatus,
|
|
6202
|
+
result: sig.result,
|
|
6203
|
+
error: sig.error,
|
|
6204
|
+
iterations: iteration
|
|
6205
|
+
};
|
|
6206
|
+
}
|
|
6207
|
+
this.context.addUserMessage(
|
|
6208
|
+
"Continue working on the task. When done, call `complete_task` with the result. If you cannot complete it, call `task_failed` with a reason."
|
|
6209
|
+
);
|
|
6210
|
+
}
|
|
6211
|
+
const timeoutError = `Task did not complete within ${maxIterations} iterations`;
|
|
6212
|
+
fireWebhook("task.failed", { status: "failed", error: timeoutError, iterations: iteration });
|
|
6213
|
+
const updatedTask = {
|
|
6214
|
+
...options.taskConfig,
|
|
6215
|
+
status: "failed",
|
|
6216
|
+
error: timeoutError,
|
|
6217
|
+
iterations: iteration
|
|
6218
|
+
};
|
|
6219
|
+
await sessionQueries.update(this.session.id, {
|
|
6220
|
+
config: { ...this.session.config, task: updatedTask }
|
|
6221
|
+
});
|
|
6222
|
+
return { status: "failed", error: timeoutError, iterations: iteration };
|
|
6223
|
+
}
|
|
5759
6224
|
/**
|
|
5760
6225
|
* Wrap tools to add approval checking
|
|
5761
6226
|
*/
|
|
@@ -5769,9 +6234,9 @@ ${prompt}` });
|
|
|
5769
6234
|
wrappedTools[name] = originalTool;
|
|
5770
6235
|
continue;
|
|
5771
6236
|
}
|
|
5772
|
-
wrappedTools[name] =
|
|
6237
|
+
wrappedTools[name] = tool12({
|
|
5773
6238
|
description: originalTool.description || "",
|
|
5774
|
-
inputSchema: originalTool.inputSchema ||
|
|
6239
|
+
inputSchema: originalTool.inputSchema || z13.object({}),
|
|
5775
6240
|
execute: async (input, toolOptions) => {
|
|
5776
6241
|
const toolCallId = toolOptions.toolCallId || nanoid3();
|
|
5777
6242
|
const execution = toolExecutionQueries.create({
|
|
@@ -5912,18 +6377,18 @@ function cleanupPendingInputs() {
|
|
|
5912
6377
|
}
|
|
5913
6378
|
}
|
|
5914
6379
|
}
|
|
5915
|
-
var createSessionSchema =
|
|
5916
|
-
name:
|
|
5917
|
-
workingDirectory:
|
|
5918
|
-
model:
|
|
5919
|
-
toolApprovals:
|
|
6380
|
+
var createSessionSchema = z14.object({
|
|
6381
|
+
name: z14.string().optional(),
|
|
6382
|
+
workingDirectory: z14.string().optional(),
|
|
6383
|
+
model: z14.string().optional(),
|
|
6384
|
+
toolApprovals: z14.record(z14.string(), z14.boolean()).optional()
|
|
5920
6385
|
});
|
|
5921
|
-
var paginationQuerySchema =
|
|
5922
|
-
limit:
|
|
5923
|
-
offset:
|
|
6386
|
+
var paginationQuerySchema = z14.object({
|
|
6387
|
+
limit: z14.string().optional(),
|
|
6388
|
+
offset: z14.string().optional()
|
|
5924
6389
|
});
|
|
5925
|
-
var messagesQuerySchema =
|
|
5926
|
-
limit:
|
|
6390
|
+
var messagesQuerySchema = z14.object({
|
|
6391
|
+
limit: z14.string().optional()
|
|
5927
6392
|
});
|
|
5928
6393
|
sessions.get(
|
|
5929
6394
|
"/",
|
|
@@ -6062,10 +6527,10 @@ sessions.get("/:id/tools", async (c) => {
|
|
|
6062
6527
|
count: executions.length
|
|
6063
6528
|
});
|
|
6064
6529
|
});
|
|
6065
|
-
var updateSessionSchema =
|
|
6066
|
-
model:
|
|
6067
|
-
name:
|
|
6068
|
-
toolApprovals:
|
|
6530
|
+
var updateSessionSchema = z14.object({
|
|
6531
|
+
model: z14.string().optional(),
|
|
6532
|
+
name: z14.string().optional(),
|
|
6533
|
+
toolApprovals: z14.record(z14.string(), z14.boolean()).optional()
|
|
6069
6534
|
});
|
|
6070
6535
|
sessions.patch(
|
|
6071
6536
|
"/:id",
|
|
@@ -6135,8 +6600,8 @@ sessions.post("/:id/clear", async (c) => {
|
|
|
6135
6600
|
await agent.clearContext();
|
|
6136
6601
|
return c.json({ success: true, sessionId: id });
|
|
6137
6602
|
});
|
|
6138
|
-
var pendingInputSchema =
|
|
6139
|
-
text:
|
|
6603
|
+
var pendingInputSchema = z14.object({
|
|
6604
|
+
text: z14.string()
|
|
6140
6605
|
});
|
|
6141
6606
|
sessions.post(
|
|
6142
6607
|
"/:id/pending-input",
|
|
@@ -6167,13 +6632,13 @@ sessions.get("/:id/pending-input", async (c) => {
|
|
|
6167
6632
|
createdAt: pending.createdAt.toISOString()
|
|
6168
6633
|
});
|
|
6169
6634
|
});
|
|
6170
|
-
var devtoolsContextSchema =
|
|
6171
|
-
url:
|
|
6172
|
-
path:
|
|
6173
|
-
pageName:
|
|
6174
|
-
screenWidth:
|
|
6175
|
-
screenHeight:
|
|
6176
|
-
devicePixelRatio:
|
|
6635
|
+
var devtoolsContextSchema = z14.object({
|
|
6636
|
+
url: z14.string(),
|
|
6637
|
+
path: z14.string(),
|
|
6638
|
+
pageName: z14.string().optional(),
|
|
6639
|
+
screenWidth: z14.number().optional(),
|
|
6640
|
+
screenHeight: z14.number().optional(),
|
|
6641
|
+
devicePixelRatio: z14.number().optional()
|
|
6177
6642
|
});
|
|
6178
6643
|
sessions.post(
|
|
6179
6644
|
"/:id/devtools-context",
|
|
@@ -6395,7 +6860,7 @@ sessions.post("/:id/attachments", async (c) => {
|
|
|
6395
6860
|
}
|
|
6396
6861
|
const dir = ensureAttachmentsDir(sessionId);
|
|
6397
6862
|
const id = nanoid4(10);
|
|
6398
|
-
const ext =
|
|
6863
|
+
const ext = extname7(file.name) || "";
|
|
6399
6864
|
const safeFilename = `${id}_${basename4(file.name).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
|
|
6400
6865
|
const filePath = join5(dir, safeFilename);
|
|
6401
6866
|
const arrayBuffer = await file.arrayBuffer();
|
|
@@ -6421,7 +6886,7 @@ sessions.post("/:id/attachments", async (c) => {
|
|
|
6421
6886
|
}
|
|
6422
6887
|
const dir = ensureAttachmentsDir(sessionId);
|
|
6423
6888
|
const id = nanoid4(10);
|
|
6424
|
-
const ext =
|
|
6889
|
+
const ext = extname7(body.filename) || "";
|
|
6425
6890
|
const safeFilename = `${id}_${basename4(body.filename).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
|
|
6426
6891
|
const filePath = join5(dir, safeFilename);
|
|
6427
6892
|
let base64Data = body.data;
|
|
@@ -6464,10 +6929,10 @@ sessions.delete("/:id/attachments/:attachmentId", async (c) => {
|
|
|
6464
6929
|
unlinkSync(filePath);
|
|
6465
6930
|
return c.json({ success: true, id: attachmentId });
|
|
6466
6931
|
});
|
|
6467
|
-
var filesQuerySchema =
|
|
6468
|
-
query:
|
|
6932
|
+
var filesQuerySchema = z14.object({
|
|
6933
|
+
query: z14.string().optional(),
|
|
6469
6934
|
// Filter query (e.g., "src/com" to match "src/components")
|
|
6470
|
-
limit:
|
|
6935
|
+
limit: z14.string().optional()
|
|
6471
6936
|
// Max results (default 50)
|
|
6472
6937
|
});
|
|
6473
6938
|
var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
@@ -6551,7 +7016,7 @@ async function listWorkspaceFiles(baseDir, currentDir, query, limit, results = [
|
|
|
6551
7016
|
if (entry.name.startsWith(".")) {
|
|
6552
7017
|
continue;
|
|
6553
7018
|
}
|
|
6554
|
-
const ext =
|
|
7019
|
+
const ext = extname7(entry.name).toLowerCase();
|
|
6555
7020
|
if (IGNORED_EXTENSIONS.has(ext)) {
|
|
6556
7021
|
continue;
|
|
6557
7022
|
}
|
|
@@ -6645,7 +7110,7 @@ sessions.get(
|
|
|
6645
7110
|
init_db();
|
|
6646
7111
|
import { Hono as Hono2 } from "hono";
|
|
6647
7112
|
import { zValidator as zValidator2 } from "@hono/zod-validator";
|
|
6648
|
-
import { z as
|
|
7113
|
+
import { z as z15 } from "zod";
|
|
6649
7114
|
import { existsSync as existsSync14, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
6650
7115
|
import { join as join6 } from "path";
|
|
6651
7116
|
init_config();
|
|
@@ -6810,30 +7275,30 @@ function enrichPromptWithDevtoolsContext(sessionId, prompt) {
|
|
|
6810
7275
|
${prompt}`;
|
|
6811
7276
|
}
|
|
6812
7277
|
var agents = new Hono2();
|
|
6813
|
-
var attachmentSchema =
|
|
6814
|
-
type:
|
|
6815
|
-
data:
|
|
7278
|
+
var attachmentSchema = z15.object({
|
|
7279
|
+
type: z15.enum(["image", "file"]),
|
|
7280
|
+
data: z15.string(),
|
|
6816
7281
|
// base64 data URL or raw base64
|
|
6817
|
-
mediaType:
|
|
6818
|
-
filename:
|
|
7282
|
+
mediaType: z15.string().optional(),
|
|
7283
|
+
filename: z15.string().optional()
|
|
6819
7284
|
});
|
|
6820
|
-
var runPromptSchema =
|
|
6821
|
-
prompt:
|
|
7285
|
+
var runPromptSchema = z15.object({
|
|
7286
|
+
prompt: z15.string(),
|
|
6822
7287
|
// Can be empty if attachments are provided
|
|
6823
|
-
attachments:
|
|
7288
|
+
attachments: z15.array(attachmentSchema).optional()
|
|
6824
7289
|
}).refine(
|
|
6825
7290
|
(data) => data.prompt.trim().length > 0 || data.attachments && data.attachments.length > 0,
|
|
6826
7291
|
{ message: "Either prompt or attachments must be provided" }
|
|
6827
7292
|
);
|
|
6828
|
-
var quickStartSchema =
|
|
6829
|
-
prompt:
|
|
6830
|
-
name:
|
|
6831
|
-
workingDirectory:
|
|
6832
|
-
model:
|
|
6833
|
-
toolApprovals:
|
|
7293
|
+
var quickStartSchema = z15.object({
|
|
7294
|
+
prompt: z15.string().min(1),
|
|
7295
|
+
name: z15.string().optional(),
|
|
7296
|
+
workingDirectory: z15.string().optional(),
|
|
7297
|
+
model: z15.string().optional(),
|
|
7298
|
+
toolApprovals: z15.record(z15.string(), z15.boolean()).optional()
|
|
6834
7299
|
});
|
|
6835
|
-
var rejectSchema =
|
|
6836
|
-
reason:
|
|
7300
|
+
var rejectSchema = z15.object({
|
|
7301
|
+
reason: z15.string().optional()
|
|
6837
7302
|
}).optional();
|
|
6838
7303
|
var streamAbortControllers = /* @__PURE__ */ new Map();
|
|
6839
7304
|
function getAttachmentsDirectory(sessionId) {
|
|
@@ -7263,7 +7728,7 @@ agents.get("/:id/watch", async (c) => {
|
|
|
7263
7728
|
"Cache-Control": "no-cache",
|
|
7264
7729
|
"Connection": "keep-alive",
|
|
7265
7730
|
"x-vercel-ai-ui-message-stream": "v1",
|
|
7266
|
-
"x-stream-id": streamId
|
|
7731
|
+
"x-stream-id": streamId ?? ""
|
|
7267
7732
|
}
|
|
7268
7733
|
});
|
|
7269
7734
|
});
|
|
@@ -7621,7 +8086,7 @@ agents.post(
|
|
|
7621
8086
|
init_config();
|
|
7622
8087
|
import { Hono as Hono3 } from "hono";
|
|
7623
8088
|
import { zValidator as zValidator3 } from "@hono/zod-validator";
|
|
7624
|
-
import { z as
|
|
8089
|
+
import { z as z16 } from "zod";
|
|
7625
8090
|
import { readFileSync as readFileSync5 } from "fs";
|
|
7626
8091
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7627
8092
|
import { dirname as dirname6, join as join7 } from "path";
|
|
@@ -7731,9 +8196,9 @@ health.get("/api-keys", async (c) => {
|
|
|
7731
8196
|
supportedProviders: SUPPORTED_PROVIDERS
|
|
7732
8197
|
});
|
|
7733
8198
|
});
|
|
7734
|
-
var setApiKeySchema =
|
|
7735
|
-
provider:
|
|
7736
|
-
apiKey:
|
|
8199
|
+
var setApiKeySchema = z16.object({
|
|
8200
|
+
provider: z16.string(),
|
|
8201
|
+
apiKey: z16.string().min(1)
|
|
7737
8202
|
});
|
|
7738
8203
|
health.post(
|
|
7739
8204
|
"/api-keys",
|
|
@@ -7772,13 +8237,13 @@ health.delete("/api-keys/:provider", async (c) => {
|
|
|
7772
8237
|
// src/server/routes/terminals.ts
|
|
7773
8238
|
import { Hono as Hono4 } from "hono";
|
|
7774
8239
|
import { zValidator as zValidator4 } from "@hono/zod-validator";
|
|
7775
|
-
import { z as
|
|
8240
|
+
import { z as z17 } from "zod";
|
|
7776
8241
|
init_db();
|
|
7777
8242
|
var terminals = new Hono4();
|
|
7778
|
-
var spawnSchema =
|
|
7779
|
-
command:
|
|
7780
|
-
cwd:
|
|
7781
|
-
name:
|
|
8243
|
+
var spawnSchema = z17.object({
|
|
8244
|
+
command: z17.string(),
|
|
8245
|
+
cwd: z17.string().optional(),
|
|
8246
|
+
name: z17.string().optional()
|
|
7782
8247
|
});
|
|
7783
8248
|
terminals.post(
|
|
7784
8249
|
"/:sessionId/terminals",
|
|
@@ -7859,8 +8324,8 @@ terminals.get("/:sessionId/terminals/:terminalId", async (c) => {
|
|
|
7859
8324
|
// We don't track exit codes in tmux mode
|
|
7860
8325
|
});
|
|
7861
8326
|
});
|
|
7862
|
-
var logsQuerySchema =
|
|
7863
|
-
tail:
|
|
8327
|
+
var logsQuerySchema = z17.object({
|
|
8328
|
+
tail: z17.string().optional().transform((v) => v ? parseInt(v, 10) : void 0)
|
|
7864
8329
|
});
|
|
7865
8330
|
terminals.get(
|
|
7866
8331
|
"/:sessionId/terminals/:terminalId/logs",
|
|
@@ -7884,8 +8349,8 @@ terminals.get(
|
|
|
7884
8349
|
});
|
|
7885
8350
|
}
|
|
7886
8351
|
);
|
|
7887
|
-
var killSchema =
|
|
7888
|
-
signal:
|
|
8352
|
+
var killSchema = z17.object({
|
|
8353
|
+
signal: z17.enum(["SIGTERM", "SIGKILL"]).optional()
|
|
7889
8354
|
});
|
|
7890
8355
|
terminals.post(
|
|
7891
8356
|
"/:sessionId/terminals/:terminalId/kill",
|
|
@@ -7899,8 +8364,8 @@ terminals.post(
|
|
|
7899
8364
|
return c.json({ success: true, message: "Terminal killed" });
|
|
7900
8365
|
}
|
|
7901
8366
|
);
|
|
7902
|
-
var writeSchema =
|
|
7903
|
-
input:
|
|
8367
|
+
var writeSchema = z17.object({
|
|
8368
|
+
input: z17.string()
|
|
7904
8369
|
});
|
|
7905
8370
|
terminals.post(
|
|
7906
8371
|
"/:sessionId/terminals/:terminalId/write",
|
|
@@ -8081,6 +8546,131 @@ data: ${JSON.stringify({ status: "stopped" })}
|
|
|
8081
8546
|
);
|
|
8082
8547
|
});
|
|
8083
8548
|
|
|
8549
|
+
// src/server/routes/tasks.ts
|
|
8550
|
+
init_db();
|
|
8551
|
+
import { Hono as Hono5 } from "hono";
|
|
8552
|
+
import { zValidator as zValidator5 } from "@hono/zod-validator";
|
|
8553
|
+
import { z as z18 } from "zod";
|
|
8554
|
+
init_config();
|
|
8555
|
+
var tasks = new Hono5();
|
|
8556
|
+
var taskAbortControllers = /* @__PURE__ */ new Map();
|
|
8557
|
+
var createTaskSchema = z18.object({
|
|
8558
|
+
prompt: z18.string().min(1),
|
|
8559
|
+
outputSchema: z18.record(z18.string(), z18.unknown()),
|
|
8560
|
+
webhookUrl: z18.string().url().optional(),
|
|
8561
|
+
model: z18.string().optional(),
|
|
8562
|
+
workingDirectory: z18.string().optional(),
|
|
8563
|
+
name: z18.string().optional(),
|
|
8564
|
+
maxIterations: z18.number().int().min(1).max(500).optional()
|
|
8565
|
+
});
|
|
8566
|
+
tasks.post(
|
|
8567
|
+
"/",
|
|
8568
|
+
zValidator5("json", createTaskSchema),
|
|
8569
|
+
async (c) => {
|
|
8570
|
+
const body = c.req.valid("json");
|
|
8571
|
+
const config = getConfig();
|
|
8572
|
+
const taskConfig = {
|
|
8573
|
+
enabled: true,
|
|
8574
|
+
outputSchema: body.outputSchema,
|
|
8575
|
+
webhookUrl: body.webhookUrl,
|
|
8576
|
+
maxIterations: body.maxIterations ?? 50,
|
|
8577
|
+
status: "running"
|
|
8578
|
+
};
|
|
8579
|
+
const agent = await Agent.create({
|
|
8580
|
+
name: body.name || "Task",
|
|
8581
|
+
workingDirectory: body.workingDirectory || config.resolvedWorkingDirectory,
|
|
8582
|
+
model: body.model || config.defaultModel,
|
|
8583
|
+
sessionConfig: {
|
|
8584
|
+
toolApprovals: { bash: false, write_file: false, read_file: false },
|
|
8585
|
+
task: taskConfig
|
|
8586
|
+
}
|
|
8587
|
+
});
|
|
8588
|
+
const taskId = agent.sessionId;
|
|
8589
|
+
const abortController = new AbortController();
|
|
8590
|
+
taskAbortControllers.set(taskId, abortController);
|
|
8591
|
+
(async () => {
|
|
8592
|
+
try {
|
|
8593
|
+
await agent.runTask({
|
|
8594
|
+
prompt: body.prompt,
|
|
8595
|
+
taskConfig,
|
|
8596
|
+
abortSignal: abortController.signal
|
|
8597
|
+
});
|
|
8598
|
+
} catch (err) {
|
|
8599
|
+
if (err.name === "AbortError" || abortController.signal.aborted) {
|
|
8600
|
+
console.log(`[TASK] Task ${taskId} was cancelled`);
|
|
8601
|
+
} else {
|
|
8602
|
+
console.error(`[TASK] Error in task ${taskId}:`, err.message);
|
|
8603
|
+
const failedTask = {
|
|
8604
|
+
...taskConfig,
|
|
8605
|
+
status: "failed",
|
|
8606
|
+
error: err.message || "Unknown error"
|
|
8607
|
+
};
|
|
8608
|
+
await sessionQueries.update(taskId, {
|
|
8609
|
+
config: {
|
|
8610
|
+
toolApprovals: { bash: false, write_file: false, read_file: false },
|
|
8611
|
+
task: failedTask
|
|
8612
|
+
}
|
|
8613
|
+
});
|
|
8614
|
+
}
|
|
8615
|
+
} finally {
|
|
8616
|
+
taskAbortControllers.delete(taskId);
|
|
8617
|
+
}
|
|
8618
|
+
})();
|
|
8619
|
+
return c.json({ taskId, status: "running" }, 201);
|
|
8620
|
+
}
|
|
8621
|
+
);
|
|
8622
|
+
tasks.get("/:id", async (c) => {
|
|
8623
|
+
const id = c.req.param("id");
|
|
8624
|
+
const session = await sessionQueries.getById(id);
|
|
8625
|
+
if (!session) {
|
|
8626
|
+
return c.json({ error: "Task not found" }, 404);
|
|
8627
|
+
}
|
|
8628
|
+
const task = session.config?.task;
|
|
8629
|
+
if (!task?.enabled) {
|
|
8630
|
+
return c.json({ error: "Session is not a task" }, 400);
|
|
8631
|
+
}
|
|
8632
|
+
return c.json({
|
|
8633
|
+
taskId: id,
|
|
8634
|
+
status: task.status,
|
|
8635
|
+
result: task.result,
|
|
8636
|
+
error: task.error,
|
|
8637
|
+
iterations: task.iterations,
|
|
8638
|
+
model: session.model,
|
|
8639
|
+
name: session.name,
|
|
8640
|
+
createdAt: session.createdAt.toISOString(),
|
|
8641
|
+
updatedAt: session.updatedAt.toISOString()
|
|
8642
|
+
});
|
|
8643
|
+
});
|
|
8644
|
+
tasks.post("/:id/cancel", async (c) => {
|
|
8645
|
+
const id = c.req.param("id");
|
|
8646
|
+
const session = await sessionQueries.getById(id);
|
|
8647
|
+
if (!session) {
|
|
8648
|
+
return c.json({ error: "Task not found" }, 404);
|
|
8649
|
+
}
|
|
8650
|
+
const task = session.config?.task;
|
|
8651
|
+
if (!task?.enabled) {
|
|
8652
|
+
return c.json({ error: "Session is not a task" }, 400);
|
|
8653
|
+
}
|
|
8654
|
+
if (task.status !== "running") {
|
|
8655
|
+
return c.json({ error: `Task is already ${task.status}` }, 400);
|
|
8656
|
+
}
|
|
8657
|
+
const abortController = taskAbortControllers.get(id);
|
|
8658
|
+
if (abortController) {
|
|
8659
|
+
abortController.abort();
|
|
8660
|
+
taskAbortControllers.delete(id);
|
|
8661
|
+
}
|
|
8662
|
+
const cancelledTask = {
|
|
8663
|
+
...task,
|
|
8664
|
+
status: "failed",
|
|
8665
|
+
error: "Task cancelled by user"
|
|
8666
|
+
};
|
|
8667
|
+
await sessionQueries.update(id, {
|
|
8668
|
+
config: { ...session.config, task: cancelledTask }
|
|
8669
|
+
});
|
|
8670
|
+
return c.json({ taskId: id, status: "failed", error: "Task cancelled by user" });
|
|
8671
|
+
});
|
|
8672
|
+
var tasks_default = tasks;
|
|
8673
|
+
|
|
8084
8674
|
// src/server/index.ts
|
|
8085
8675
|
init_config();
|
|
8086
8676
|
init_db();
|
|
@@ -8417,7 +9007,7 @@ function stopWebUI() {
|
|
|
8417
9007
|
}
|
|
8418
9008
|
}
|
|
8419
9009
|
async function createApp(options = {}) {
|
|
8420
|
-
const app = new
|
|
9010
|
+
const app = new Hono6();
|
|
8421
9011
|
app.use("*", cors({
|
|
8422
9012
|
origin: "*",
|
|
8423
9013
|
// Allow all origins
|
|
@@ -8435,6 +9025,7 @@ async function createApp(options = {}) {
|
|
|
8435
9025
|
app.route("/agents", agents);
|
|
8436
9026
|
app.route("/sessions", terminals);
|
|
8437
9027
|
app.route("/terminals", terminals);
|
|
9028
|
+
app.route("/tasks", tasks_default);
|
|
8438
9029
|
app.get("/openapi.json", async (c) => {
|
|
8439
9030
|
return c.json(generateOpenAPISpec());
|
|
8440
9031
|
});
|