sparkecoder 0.1.60 → 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 +588 -176
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +818 -95
- 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 +1202 -665
- 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 +605 -68
- package/dist/server/index.js.map +1 -1
- package/dist/tools/index.d.ts +38 -3
- package/dist/tools/index.js +230 -2
- package/dist/tools/index.js.map +1 -1
- package/package.json +5 -3
- 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/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_ssgManifest.js +0 -0
- /package/web/.next/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_buildManifest.js +0 -0
- /package/web/.next/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_ssgManifest.js +0 -0
package/dist/agent/index.js
CHANGED
|
@@ -8,6 +8,191 @@ var __export = (target, all) => {
|
|
|
8
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
// src/config/types.ts
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
var ToolApprovalConfigSchema, SkillMetadataSchema, TaskConfigSchema, SessionConfigSchema, VectorGatewayConfigSchema, RemoteServerConfigSchema, SparkcoderConfigSchema;
|
|
14
|
+
var init_types = __esm({
|
|
15
|
+
"src/config/types.ts"() {
|
|
16
|
+
"use strict";
|
|
17
|
+
ToolApprovalConfigSchema = z.object({
|
|
18
|
+
bash: z.boolean().optional().default(true),
|
|
19
|
+
write_file: z.boolean().optional().default(false),
|
|
20
|
+
read_file: z.boolean().optional().default(false),
|
|
21
|
+
load_skill: z.boolean().optional().default(false),
|
|
22
|
+
todo: z.boolean().optional().default(false)
|
|
23
|
+
});
|
|
24
|
+
SkillMetadataSchema = z.object({
|
|
25
|
+
name: z.string(),
|
|
26
|
+
description: z.string(),
|
|
27
|
+
// Whether to always inject this skill into context (vs on-demand loading)
|
|
28
|
+
alwaysApply: z.boolean().optional().default(false),
|
|
29
|
+
// Glob patterns - auto-inject when working with matching files
|
|
30
|
+
globs: z.array(z.string()).optional().default([])
|
|
31
|
+
});
|
|
32
|
+
TaskConfigSchema = z.object({
|
|
33
|
+
enabled: z.boolean(),
|
|
34
|
+
outputSchema: z.record(z.string(), z.unknown()),
|
|
35
|
+
webhookUrl: z.string().url().optional(),
|
|
36
|
+
maxIterations: z.number().optional(),
|
|
37
|
+
status: z.enum(["running", "completed", "failed"]),
|
|
38
|
+
result: z.unknown().optional(),
|
|
39
|
+
error: z.string().optional(),
|
|
40
|
+
iterations: z.number().optional()
|
|
41
|
+
});
|
|
42
|
+
SessionConfigSchema = z.object({
|
|
43
|
+
toolApprovals: z.record(z.string(), z.boolean()).optional(),
|
|
44
|
+
approvalWebhook: z.string().url().optional(),
|
|
45
|
+
skillsDirectory: z.string().optional(),
|
|
46
|
+
maxContextChars: z.number().optional().default(2e5),
|
|
47
|
+
task: TaskConfigSchema.optional()
|
|
48
|
+
});
|
|
49
|
+
VectorGatewayConfigSchema = z.object({
|
|
50
|
+
// Redis cluster nodes URL for Vector Gateway (or use REDIS_CLUSTER_NODES env var)
|
|
51
|
+
redisUrl: z.string().optional(),
|
|
52
|
+
// HTTP URL for database operations (or use VECTOR_HTTP_URL env var)
|
|
53
|
+
httpUrl: z.string().optional(),
|
|
54
|
+
// Embedding model to use (default: text-embedding-3-small)
|
|
55
|
+
embeddingModel: z.string().default("gemini-embedding-001"),
|
|
56
|
+
// Custom namespace override (auto-generated from git remote if not set)
|
|
57
|
+
namespace: z.string().optional(),
|
|
58
|
+
// File patterns to include in indexing
|
|
59
|
+
include: z.array(z.string()).optional().default([
|
|
60
|
+
"**/*.ts",
|
|
61
|
+
"**/*.tsx",
|
|
62
|
+
"**/*.js",
|
|
63
|
+
"**/*.jsx",
|
|
64
|
+
"**/*.py",
|
|
65
|
+
"**/*.go",
|
|
66
|
+
"**/*.rs",
|
|
67
|
+
"**/*.java",
|
|
68
|
+
"**/*.md",
|
|
69
|
+
"**/*.mdx",
|
|
70
|
+
"**/*.txt"
|
|
71
|
+
]),
|
|
72
|
+
// File patterns to exclude from indexing
|
|
73
|
+
exclude: z.array(z.string()).optional().default([
|
|
74
|
+
"**/node_modules/**",
|
|
75
|
+
"**/dist/**",
|
|
76
|
+
"**/build/**",
|
|
77
|
+
"**/.git/**",
|
|
78
|
+
"**/.next/**",
|
|
79
|
+
"**/*.min.js",
|
|
80
|
+
"**/*.bundle.js",
|
|
81
|
+
"**/pnpm-lock.yaml",
|
|
82
|
+
"**/package-lock.json",
|
|
83
|
+
"**/yarn.lock",
|
|
84
|
+
"**/.test-workspace/**",
|
|
85
|
+
"**/.semantic-test-workspace/**",
|
|
86
|
+
"**/.semantic-integration-test/**"
|
|
87
|
+
])
|
|
88
|
+
}).optional();
|
|
89
|
+
RemoteServerConfigSchema = z.object({
|
|
90
|
+
// URL of the remote server (e.g., https://agent.sparkecode.com)
|
|
91
|
+
url: z.string().url().optional(),
|
|
92
|
+
// Auth key for the remote server (auto-generated on first use if not set)
|
|
93
|
+
// Can also be set via SPARKECODER_AUTH_KEY env var
|
|
94
|
+
authKey: z.string().optional()
|
|
95
|
+
}).optional();
|
|
96
|
+
SparkcoderConfigSchema = z.object({
|
|
97
|
+
// Default model to use (Vercel AI Gateway format)
|
|
98
|
+
defaultModel: z.string().default("anthropic/claude-opus-4-6"),
|
|
99
|
+
// Working directory for file operations
|
|
100
|
+
workingDirectory: z.string().optional(),
|
|
101
|
+
// Tool approval settings
|
|
102
|
+
toolApprovals: ToolApprovalConfigSchema.optional().default({}),
|
|
103
|
+
// Approval webhook URL (called when approval is needed)
|
|
104
|
+
approvalWebhook: z.string().url().optional(),
|
|
105
|
+
// Skills configuration
|
|
106
|
+
skills: z.object({
|
|
107
|
+
// Directory containing skill files
|
|
108
|
+
directory: z.string().optional().default("./skills"),
|
|
109
|
+
// Additional skill directories to include
|
|
110
|
+
additionalDirectories: z.array(z.string()).optional().default([])
|
|
111
|
+
}).optional().default({}),
|
|
112
|
+
// Context management
|
|
113
|
+
context: z.object({
|
|
114
|
+
// Maximum context size before summarization (in characters)
|
|
115
|
+
maxChars: z.number().optional().default(2e5),
|
|
116
|
+
// Enable automatic summarization
|
|
117
|
+
autoSummarize: z.boolean().optional().default(true),
|
|
118
|
+
// Number of recent messages to keep after summarization
|
|
119
|
+
keepRecentMessages: z.number().optional().default(10)
|
|
120
|
+
}).optional().default({}),
|
|
121
|
+
// Server configuration
|
|
122
|
+
server: z.object({
|
|
123
|
+
port: z.number().default(3141),
|
|
124
|
+
host: z.string().default("127.0.0.1"),
|
|
125
|
+
// Public URL for web UI to connect to API (for Docker/remote access)
|
|
126
|
+
// If not set, defaults to http://{host}:{port}
|
|
127
|
+
publicUrl: z.string().url().optional()
|
|
128
|
+
}).default({ port: 3141, host: "127.0.0.1" }),
|
|
129
|
+
// Database path (used for local SQLite - ignored if remoteServer is configured)
|
|
130
|
+
databasePath: z.string().optional().default("./sparkecoder.db"),
|
|
131
|
+
// Remote server configuration (for centralized storage)
|
|
132
|
+
// If configured, uses remote MongoDB instead of local SQLite
|
|
133
|
+
remoteServer: RemoteServerConfigSchema,
|
|
134
|
+
// Vector Gateway configuration for semantic search
|
|
135
|
+
vectorGateway: VectorGatewayConfigSchema
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// src/config/index.ts
|
|
141
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync } from "fs";
|
|
142
|
+
import { resolve, dirname, join } from "path";
|
|
143
|
+
import { homedir, platform } from "os";
|
|
144
|
+
function getAppDataDirectory() {
|
|
145
|
+
const appName = "sparkecoder";
|
|
146
|
+
switch (platform()) {
|
|
147
|
+
case "darwin":
|
|
148
|
+
return join(homedir(), "Library", "Application Support", appName);
|
|
149
|
+
case "win32":
|
|
150
|
+
return join(process.env.APPDATA || join(homedir(), "AppData", "Roaming"), appName);
|
|
151
|
+
default:
|
|
152
|
+
return join(process.env.XDG_DATA_HOME || join(homedir(), ".local", "share"), appName);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function getConfig() {
|
|
156
|
+
if (!cachedConfig) {
|
|
157
|
+
throw new Error("Config not loaded. Call loadConfig first.");
|
|
158
|
+
}
|
|
159
|
+
return cachedConfig;
|
|
160
|
+
}
|
|
161
|
+
function requiresApproval(toolName, sessionConfig) {
|
|
162
|
+
const config = getConfig();
|
|
163
|
+
if (sessionConfig?.toolApprovals?.["*"] !== void 0) {
|
|
164
|
+
return sessionConfig.toolApprovals["*"];
|
|
165
|
+
}
|
|
166
|
+
if (sessionConfig?.toolApprovals?.[toolName] !== void 0) {
|
|
167
|
+
return sessionConfig.toolApprovals[toolName];
|
|
168
|
+
}
|
|
169
|
+
const globalApprovals = config.toolApprovals;
|
|
170
|
+
if (globalApprovals[toolName] !== void 0) {
|
|
171
|
+
return globalApprovals[toolName];
|
|
172
|
+
}
|
|
173
|
+
if (toolName === "bash") {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
var cachedConfig, PROVIDER_ENV_MAP, SUPPORTED_PROVIDERS;
|
|
179
|
+
var init_config = __esm({
|
|
180
|
+
"src/config/index.ts"() {
|
|
181
|
+
"use strict";
|
|
182
|
+
init_types();
|
|
183
|
+
init_types();
|
|
184
|
+
cachedConfig = null;
|
|
185
|
+
PROVIDER_ENV_MAP = {
|
|
186
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
187
|
+
openai: "OPENAI_API_KEY",
|
|
188
|
+
google: "GOOGLE_GENERATIVE_AI_API_KEY",
|
|
189
|
+
xai: "XAI_API_KEY",
|
|
190
|
+
"ai-gateway": "AI_GATEWAY_API_KEY"
|
|
191
|
+
};
|
|
192
|
+
SUPPORTED_PROVIDERS = Object.keys(PROVIDER_ENV_MAP);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
11
196
|
// src/db/remote.ts
|
|
12
197
|
function parseDates(obj) {
|
|
13
198
|
if (obj === null || obj === void 0) return obj;
|
|
@@ -298,177 +483,6 @@ var init_db = __esm({
|
|
|
298
483
|
}
|
|
299
484
|
});
|
|
300
485
|
|
|
301
|
-
// src/config/types.ts
|
|
302
|
-
import { z } from "zod";
|
|
303
|
-
var ToolApprovalConfigSchema, SkillMetadataSchema, SessionConfigSchema, VectorGatewayConfigSchema, RemoteServerConfigSchema, SparkcoderConfigSchema;
|
|
304
|
-
var init_types = __esm({
|
|
305
|
-
"src/config/types.ts"() {
|
|
306
|
-
"use strict";
|
|
307
|
-
ToolApprovalConfigSchema = z.object({
|
|
308
|
-
bash: z.boolean().optional().default(true),
|
|
309
|
-
write_file: z.boolean().optional().default(false),
|
|
310
|
-
read_file: z.boolean().optional().default(false),
|
|
311
|
-
load_skill: z.boolean().optional().default(false),
|
|
312
|
-
todo: z.boolean().optional().default(false)
|
|
313
|
-
});
|
|
314
|
-
SkillMetadataSchema = z.object({
|
|
315
|
-
name: z.string(),
|
|
316
|
-
description: z.string(),
|
|
317
|
-
// Whether to always inject this skill into context (vs on-demand loading)
|
|
318
|
-
alwaysApply: z.boolean().optional().default(false),
|
|
319
|
-
// Glob patterns - auto-inject when working with matching files
|
|
320
|
-
globs: z.array(z.string()).optional().default([])
|
|
321
|
-
});
|
|
322
|
-
SessionConfigSchema = z.object({
|
|
323
|
-
toolApprovals: z.record(z.string(), z.boolean()).optional(),
|
|
324
|
-
approvalWebhook: z.string().url().optional(),
|
|
325
|
-
skillsDirectory: z.string().optional(),
|
|
326
|
-
maxContextChars: z.number().optional().default(2e5)
|
|
327
|
-
});
|
|
328
|
-
VectorGatewayConfigSchema = z.object({
|
|
329
|
-
// Redis cluster nodes URL for Vector Gateway (or use REDIS_CLUSTER_NODES env var)
|
|
330
|
-
redisUrl: z.string().optional(),
|
|
331
|
-
// HTTP URL for database operations (or use VECTOR_HTTP_URL env var)
|
|
332
|
-
httpUrl: z.string().optional(),
|
|
333
|
-
// Embedding model to use (default: text-embedding-3-small)
|
|
334
|
-
embeddingModel: z.string().default("gemini-embedding-001"),
|
|
335
|
-
// Custom namespace override (auto-generated from git remote if not set)
|
|
336
|
-
namespace: z.string().optional(),
|
|
337
|
-
// File patterns to include in indexing
|
|
338
|
-
include: z.array(z.string()).optional().default([
|
|
339
|
-
"**/*.ts",
|
|
340
|
-
"**/*.tsx",
|
|
341
|
-
"**/*.js",
|
|
342
|
-
"**/*.jsx",
|
|
343
|
-
"**/*.py",
|
|
344
|
-
"**/*.go",
|
|
345
|
-
"**/*.rs",
|
|
346
|
-
"**/*.java",
|
|
347
|
-
"**/*.md",
|
|
348
|
-
"**/*.mdx",
|
|
349
|
-
"**/*.txt"
|
|
350
|
-
]),
|
|
351
|
-
// File patterns to exclude from indexing
|
|
352
|
-
exclude: z.array(z.string()).optional().default([
|
|
353
|
-
"**/node_modules/**",
|
|
354
|
-
"**/dist/**",
|
|
355
|
-
"**/build/**",
|
|
356
|
-
"**/.git/**",
|
|
357
|
-
"**/.next/**",
|
|
358
|
-
"**/*.min.js",
|
|
359
|
-
"**/*.bundle.js",
|
|
360
|
-
"**/pnpm-lock.yaml",
|
|
361
|
-
"**/package-lock.json",
|
|
362
|
-
"**/yarn.lock",
|
|
363
|
-
"**/.test-workspace/**",
|
|
364
|
-
"**/.semantic-test-workspace/**",
|
|
365
|
-
"**/.semantic-integration-test/**"
|
|
366
|
-
])
|
|
367
|
-
}).optional();
|
|
368
|
-
RemoteServerConfigSchema = z.object({
|
|
369
|
-
// URL of the remote server (e.g., https://agent.sparkecode.com)
|
|
370
|
-
url: z.string().url().optional(),
|
|
371
|
-
// Auth key for the remote server (auto-generated on first use if not set)
|
|
372
|
-
// Can also be set via SPARKECODER_AUTH_KEY env var
|
|
373
|
-
authKey: z.string().optional()
|
|
374
|
-
}).optional();
|
|
375
|
-
SparkcoderConfigSchema = z.object({
|
|
376
|
-
// Default model to use (Vercel AI Gateway format)
|
|
377
|
-
defaultModel: z.string().default("anthropic/claude-opus-4-6"),
|
|
378
|
-
// Working directory for file operations
|
|
379
|
-
workingDirectory: z.string().optional(),
|
|
380
|
-
// Tool approval settings
|
|
381
|
-
toolApprovals: ToolApprovalConfigSchema.optional().default({}),
|
|
382
|
-
// Approval webhook URL (called when approval is needed)
|
|
383
|
-
approvalWebhook: z.string().url().optional(),
|
|
384
|
-
// Skills configuration
|
|
385
|
-
skills: z.object({
|
|
386
|
-
// Directory containing skill files
|
|
387
|
-
directory: z.string().optional().default("./skills"),
|
|
388
|
-
// Additional skill directories to include
|
|
389
|
-
additionalDirectories: z.array(z.string()).optional().default([])
|
|
390
|
-
}).optional().default({}),
|
|
391
|
-
// Context management
|
|
392
|
-
context: z.object({
|
|
393
|
-
// Maximum context size before summarization (in characters)
|
|
394
|
-
maxChars: z.number().optional().default(2e5),
|
|
395
|
-
// Enable automatic summarization
|
|
396
|
-
autoSummarize: z.boolean().optional().default(true),
|
|
397
|
-
// Number of recent messages to keep after summarization
|
|
398
|
-
keepRecentMessages: z.number().optional().default(10)
|
|
399
|
-
}).optional().default({}),
|
|
400
|
-
// Server configuration
|
|
401
|
-
server: z.object({
|
|
402
|
-
port: z.number().default(3141),
|
|
403
|
-
host: z.string().default("127.0.0.1"),
|
|
404
|
-
// Public URL for web UI to connect to API (for Docker/remote access)
|
|
405
|
-
// If not set, defaults to http://{host}:{port}
|
|
406
|
-
publicUrl: z.string().url().optional()
|
|
407
|
-
}).default({ port: 3141, host: "127.0.0.1" }),
|
|
408
|
-
// Database path (used for local SQLite - ignored if remoteServer is configured)
|
|
409
|
-
databasePath: z.string().optional().default("./sparkecoder.db"),
|
|
410
|
-
// Remote server configuration (for centralized storage)
|
|
411
|
-
// If configured, uses remote MongoDB instead of local SQLite
|
|
412
|
-
remoteServer: RemoteServerConfigSchema,
|
|
413
|
-
// Vector Gateway configuration for semantic search
|
|
414
|
-
vectorGateway: VectorGatewayConfigSchema
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
// src/config/index.ts
|
|
420
|
-
import { existsSync, readFileSync, mkdirSync, writeFileSync } from "fs";
|
|
421
|
-
import { resolve, dirname, join } from "path";
|
|
422
|
-
import { homedir, platform } from "os";
|
|
423
|
-
function getAppDataDirectory() {
|
|
424
|
-
const appName = "sparkecoder";
|
|
425
|
-
switch (platform()) {
|
|
426
|
-
case "darwin":
|
|
427
|
-
return join(homedir(), "Library", "Application Support", appName);
|
|
428
|
-
case "win32":
|
|
429
|
-
return join(process.env.APPDATA || join(homedir(), "AppData", "Roaming"), appName);
|
|
430
|
-
default:
|
|
431
|
-
return join(process.env.XDG_DATA_HOME || join(homedir(), ".local", "share"), appName);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
function getConfig() {
|
|
435
|
-
if (!cachedConfig) {
|
|
436
|
-
throw new Error("Config not loaded. Call loadConfig first.");
|
|
437
|
-
}
|
|
438
|
-
return cachedConfig;
|
|
439
|
-
}
|
|
440
|
-
function requiresApproval(toolName, sessionConfig) {
|
|
441
|
-
const config = getConfig();
|
|
442
|
-
if (sessionConfig?.toolApprovals?.[toolName] !== void 0) {
|
|
443
|
-
return sessionConfig.toolApprovals[toolName];
|
|
444
|
-
}
|
|
445
|
-
const globalApprovals = config.toolApprovals;
|
|
446
|
-
if (globalApprovals[toolName] !== void 0) {
|
|
447
|
-
return globalApprovals[toolName];
|
|
448
|
-
}
|
|
449
|
-
if (toolName === "bash") {
|
|
450
|
-
return true;
|
|
451
|
-
}
|
|
452
|
-
return false;
|
|
453
|
-
}
|
|
454
|
-
var cachedConfig, PROVIDER_ENV_MAP, SUPPORTED_PROVIDERS;
|
|
455
|
-
var init_config = __esm({
|
|
456
|
-
"src/config/index.ts"() {
|
|
457
|
-
"use strict";
|
|
458
|
-
init_types();
|
|
459
|
-
init_types();
|
|
460
|
-
cachedConfig = null;
|
|
461
|
-
PROVIDER_ENV_MAP = {
|
|
462
|
-
anthropic: "ANTHROPIC_API_KEY",
|
|
463
|
-
openai: "OPENAI_API_KEY",
|
|
464
|
-
google: "GOOGLE_GENERATIVE_AI_API_KEY",
|
|
465
|
-
xai: "XAI_API_KEY",
|
|
466
|
-
"ai-gateway": "AI_GATEWAY_API_KEY"
|
|
467
|
-
};
|
|
468
|
-
SUPPORTED_PROVIDERS = Object.keys(PROVIDER_ENV_MAP);
|
|
469
|
-
}
|
|
470
|
-
});
|
|
471
|
-
|
|
472
486
|
// src/skills/index.ts
|
|
473
487
|
var skills_exports = {};
|
|
474
488
|
__export(skills_exports, {
|
|
@@ -1210,18 +1224,176 @@ var init_semantic_search = __esm({
|
|
|
1210
1224
|
import {
|
|
1211
1225
|
streamText as streamText2,
|
|
1212
1226
|
generateText as generateText3,
|
|
1213
|
-
tool as
|
|
1227
|
+
tool as tool12,
|
|
1214
1228
|
stepCountIs as stepCountIs2
|
|
1215
1229
|
} from "ai";
|
|
1216
1230
|
|
|
1217
1231
|
// src/agent/model.ts
|
|
1218
1232
|
import { gateway } from "@ai-sdk/gateway";
|
|
1233
|
+
|
|
1234
|
+
// src/agent/remote-model.ts
|
|
1235
|
+
function serializePrompt(prompt) {
|
|
1236
|
+
return prompt.map((msg) => {
|
|
1237
|
+
if (!Array.isArray(msg.content)) return msg;
|
|
1238
|
+
return {
|
|
1239
|
+
...msg,
|
|
1240
|
+
content: msg.content.map((part) => {
|
|
1241
|
+
if (part.type === "file" && part.data instanceof Uint8Array) {
|
|
1242
|
+
return {
|
|
1243
|
+
...part,
|
|
1244
|
+
data: Buffer.from(part.data).toString("base64"),
|
|
1245
|
+
_base64: true
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
1248
|
+
return part;
|
|
1249
|
+
})
|
|
1250
|
+
};
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
function deserializeValue(value) {
|
|
1254
|
+
if (value && typeof value === "object") {
|
|
1255
|
+
if (value.__uint8array && typeof value.data === "string") {
|
|
1256
|
+
return Buffer.from(value.data, "base64");
|
|
1257
|
+
}
|
|
1258
|
+
if (Array.isArray(value)) {
|
|
1259
|
+
return value.map(deserializeValue);
|
|
1260
|
+
}
|
|
1261
|
+
const result = {};
|
|
1262
|
+
for (const [k, v] of Object.entries(value)) {
|
|
1263
|
+
result[k] = deserializeValue(v);
|
|
1264
|
+
}
|
|
1265
|
+
return result;
|
|
1266
|
+
}
|
|
1267
|
+
return value;
|
|
1268
|
+
}
|
|
1269
|
+
function prepareOptions(options) {
|
|
1270
|
+
const { abortSignal, ...rest } = options;
|
|
1271
|
+
return {
|
|
1272
|
+
...rest,
|
|
1273
|
+
prompt: serializePrompt(options.prompt)
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
function createRemoteModel(modelId, config) {
|
|
1277
|
+
const baseUrl = config.url.replace(/\/$/, "");
|
|
1278
|
+
const headers = {
|
|
1279
|
+
"Content-Type": "application/json",
|
|
1280
|
+
"Authorization": `Bearer ${config.authKey}`
|
|
1281
|
+
};
|
|
1282
|
+
return {
|
|
1283
|
+
specificationVersion: "v3",
|
|
1284
|
+
provider: "remote-proxy",
|
|
1285
|
+
modelId,
|
|
1286
|
+
supportedUrls: {},
|
|
1287
|
+
async doGenerate(options) {
|
|
1288
|
+
const res = await fetch(`${baseUrl}/inference/generate`, {
|
|
1289
|
+
method: "POST",
|
|
1290
|
+
headers,
|
|
1291
|
+
body: JSON.stringify({
|
|
1292
|
+
modelId,
|
|
1293
|
+
options: prepareOptions(options)
|
|
1294
|
+
}),
|
|
1295
|
+
signal: options.abortSignal
|
|
1296
|
+
});
|
|
1297
|
+
if (!res.ok) {
|
|
1298
|
+
const err = await res.json().catch(() => ({}));
|
|
1299
|
+
throw new Error(
|
|
1300
|
+
`Remote inference failed (${res.status}): ${err.error || res.statusText}`
|
|
1301
|
+
);
|
|
1302
|
+
}
|
|
1303
|
+
const result = await res.json();
|
|
1304
|
+
return deserializeValue(result);
|
|
1305
|
+
},
|
|
1306
|
+
async doStream(options) {
|
|
1307
|
+
const res = await fetch(`${baseUrl}/inference/stream`, {
|
|
1308
|
+
method: "POST",
|
|
1309
|
+
headers,
|
|
1310
|
+
body: JSON.stringify({
|
|
1311
|
+
modelId,
|
|
1312
|
+
options: prepareOptions(options)
|
|
1313
|
+
}),
|
|
1314
|
+
signal: options.abortSignal
|
|
1315
|
+
});
|
|
1316
|
+
if (!res.ok) {
|
|
1317
|
+
const err = await res.json().catch(() => ({}));
|
|
1318
|
+
throw new Error(
|
|
1319
|
+
`Remote inference failed (${res.status}): ${err.error || res.statusText}`
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
const reader = res.body.getReader();
|
|
1323
|
+
const decoder = new TextDecoder();
|
|
1324
|
+
let buffer = "";
|
|
1325
|
+
const stream = new ReadableStream({
|
|
1326
|
+
async pull(controller) {
|
|
1327
|
+
while (true) {
|
|
1328
|
+
const { done, value } = await reader.read();
|
|
1329
|
+
if (done) {
|
|
1330
|
+
if (buffer.trim()) {
|
|
1331
|
+
try {
|
|
1332
|
+
const parsed = deserializeValue(JSON.parse(buffer.trim()));
|
|
1333
|
+
if (parsed.type === "error") {
|
|
1334
|
+
controller.error(new Error(parsed.error));
|
|
1335
|
+
} else {
|
|
1336
|
+
controller.enqueue(parsed);
|
|
1337
|
+
}
|
|
1338
|
+
} catch {
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
controller.close();
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1345
|
+
const lines = buffer.split("\n");
|
|
1346
|
+
buffer = lines.pop() || "";
|
|
1347
|
+
for (const line of lines) {
|
|
1348
|
+
if (!line.trim()) continue;
|
|
1349
|
+
try {
|
|
1350
|
+
const parsed = deserializeValue(JSON.parse(line));
|
|
1351
|
+
if (parsed.type === "error") {
|
|
1352
|
+
controller.error(new Error(parsed.error));
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
controller.enqueue(parsed);
|
|
1356
|
+
} catch {
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
},
|
|
1361
|
+
cancel() {
|
|
1362
|
+
reader.cancel();
|
|
1363
|
+
}
|
|
1364
|
+
});
|
|
1365
|
+
const responseHeaders = {};
|
|
1366
|
+
res.headers.forEach((v, k) => {
|
|
1367
|
+
if (k.startsWith("x-upstream-")) {
|
|
1368
|
+
responseHeaders[k.replace("x-upstream-", "")] = v;
|
|
1369
|
+
}
|
|
1370
|
+
});
|
|
1371
|
+
return {
|
|
1372
|
+
stream,
|
|
1373
|
+
response: Object.keys(responseHeaders).length > 0 ? { headers: responseHeaders } : void 0
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
// src/agent/model.ts
|
|
1380
|
+
init_config();
|
|
1219
1381
|
var ANTHROPIC_PREFIX = "anthropic/";
|
|
1220
1382
|
function isAnthropicModel(modelId) {
|
|
1221
1383
|
const normalized = modelId.trim().toLowerCase();
|
|
1222
1384
|
return normalized.startsWith(ANTHROPIC_PREFIX) || normalized.startsWith("claude-");
|
|
1223
1385
|
}
|
|
1224
1386
|
function resolveModel(modelId) {
|
|
1387
|
+
try {
|
|
1388
|
+
const config = getConfig();
|
|
1389
|
+
if (config.resolvedRemoteServer.isConfigured) {
|
|
1390
|
+
return createRemoteModel(modelId.trim(), {
|
|
1391
|
+
url: config.resolvedRemoteServer.url,
|
|
1392
|
+
authKey: config.resolvedRemoteServer.authKey
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
} catch {
|
|
1396
|
+
}
|
|
1225
1397
|
return gateway(modelId.trim());
|
|
1226
1398
|
}
|
|
1227
1399
|
var SUBAGENT_MODELS = {
|
|
@@ -1233,7 +1405,7 @@ var SUBAGENT_MODELS = {
|
|
|
1233
1405
|
// src/agent/index.ts
|
|
1234
1406
|
init_db();
|
|
1235
1407
|
init_config();
|
|
1236
|
-
import { z as
|
|
1408
|
+
import { z as z13 } from "zod";
|
|
1237
1409
|
import { nanoid as nanoid3 } from "nanoid";
|
|
1238
1410
|
|
|
1239
1411
|
// src/tools/bash.ts
|
|
@@ -4359,6 +4531,59 @@ Context: ${context}` : query;
|
|
|
4359
4531
|
|
|
4360
4532
|
// src/tools/index.ts
|
|
4361
4533
|
init_semantic_search();
|
|
4534
|
+
|
|
4535
|
+
// src/tools/task.ts
|
|
4536
|
+
import { tool as tool11 } from "ai";
|
|
4537
|
+
import { z as z12 } from "zod";
|
|
4538
|
+
import Ajv from "ajv";
|
|
4539
|
+
var ajv = new Ajv({ allErrors: true });
|
|
4540
|
+
function createCompleteTaskTool(options) {
|
|
4541
|
+
const validate = ajv.compile(options.outputSchema);
|
|
4542
|
+
return tool11({
|
|
4543
|
+
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.",
|
|
4544
|
+
inputSchema: z12.object({
|
|
4545
|
+
result: z12.record(z12.string(), z12.unknown()).describe("The task result as a JSON object matching the output schema")
|
|
4546
|
+
}),
|
|
4547
|
+
execute: async (input) => {
|
|
4548
|
+
const valid = validate(input.result);
|
|
4549
|
+
if (!valid) {
|
|
4550
|
+
const errors = validate.errors?.map((e) => ({
|
|
4551
|
+
path: e.instancePath || "/",
|
|
4552
|
+
message: e.message,
|
|
4553
|
+
params: e.params
|
|
4554
|
+
}));
|
|
4555
|
+
return {
|
|
4556
|
+
status: "validation_error",
|
|
4557
|
+
message: "The result does not match the required output schema. Fix the errors and call complete_task again.",
|
|
4558
|
+
errors,
|
|
4559
|
+
expectedSchema: options.outputSchema
|
|
4560
|
+
};
|
|
4561
|
+
}
|
|
4562
|
+
options.onComplete({ status: "completed", result: input.result });
|
|
4563
|
+
return {
|
|
4564
|
+
status: "completed",
|
|
4565
|
+
message: "Task completed successfully."
|
|
4566
|
+
};
|
|
4567
|
+
}
|
|
4568
|
+
});
|
|
4569
|
+
}
|
|
4570
|
+
function createTaskFailedTool(options) {
|
|
4571
|
+
return tool11({
|
|
4572
|
+
description: "Call this tool if you are unable to complete the task. Provide a clear reason explaining why the task cannot be completed.",
|
|
4573
|
+
inputSchema: z12.object({
|
|
4574
|
+
reason: z12.string().describe("Explanation of why the task cannot be completed")
|
|
4575
|
+
}),
|
|
4576
|
+
execute: async (input) => {
|
|
4577
|
+
options.onComplete({ status: "failed", error: input.reason });
|
|
4578
|
+
return {
|
|
4579
|
+
status: "failed",
|
|
4580
|
+
message: `Task marked as failed: ${input.reason}`
|
|
4581
|
+
};
|
|
4582
|
+
}
|
|
4583
|
+
});
|
|
4584
|
+
}
|
|
4585
|
+
|
|
4586
|
+
// src/tools/index.ts
|
|
4362
4587
|
init_semantic();
|
|
4363
4588
|
init_semantic_search();
|
|
4364
4589
|
async function createTools(options) {
|
|
@@ -4410,6 +4635,10 @@ async function createTools(options) {
|
|
|
4410
4635
|
} catch {
|
|
4411
4636
|
}
|
|
4412
4637
|
}
|
|
4638
|
+
if (options.taskTools) {
|
|
4639
|
+
tools.complete_task = createCompleteTaskTool(options.taskTools);
|
|
4640
|
+
tools.task_failed = createTaskFailedTool(options.taskTools);
|
|
4641
|
+
}
|
|
4413
4642
|
return tools;
|
|
4414
4643
|
}
|
|
4415
4644
|
|
|
@@ -4727,6 +4956,30 @@ function formatTodosForContext(todos) {
|
|
|
4727
4956
|
}
|
|
4728
4957
|
return lines.join("\n");
|
|
4729
4958
|
}
|
|
4959
|
+
function buildTaskPromptAddendum(outputSchema) {
|
|
4960
|
+
return `
|
|
4961
|
+
## Task Mode
|
|
4962
|
+
|
|
4963
|
+
You are running in **task mode**. You have been given a specific task to complete autonomously.
|
|
4964
|
+
|
|
4965
|
+
### Rules
|
|
4966
|
+
1. Work independently \u2014 no human will approve tool calls. All tools run without approval.
|
|
4967
|
+
2. Keep working until the task is fully complete.
|
|
4968
|
+
3. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
|
|
4969
|
+
4. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
|
|
4970
|
+
5. Do NOT stop without calling one of these two tools.
|
|
4971
|
+
|
|
4972
|
+
### Output Schema
|
|
4973
|
+
The \`complete_task\` tool expects a \`result\` object matching this JSON Schema:
|
|
4974
|
+
\`\`\`json
|
|
4975
|
+
${JSON.stringify(outputSchema, null, 2)}
|
|
4976
|
+
\`\`\`
|
|
4977
|
+
|
|
4978
|
+
### Completion Tools
|
|
4979
|
+
- **\`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.
|
|
4980
|
+
- **\`task_failed({ reason: "..." })\`** \u2014 Call only if the task truly cannot be completed.
|
|
4981
|
+
`;
|
|
4982
|
+
}
|
|
4730
4983
|
function createSummaryPrompt(conversationHistory) {
|
|
4731
4984
|
return `Please provide a concise summary of the following conversation history. Focus on:
|
|
4732
4985
|
1. The main task or goal being worked on
|
|
@@ -4988,6 +5241,25 @@ ${this.summary}`
|
|
|
4988
5241
|
}
|
|
4989
5242
|
};
|
|
4990
5243
|
|
|
5244
|
+
// src/utils/webhook.ts
|
|
5245
|
+
async function sendWebhook(url, event) {
|
|
5246
|
+
try {
|
|
5247
|
+
const controller = new AbortController();
|
|
5248
|
+
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
5249
|
+
await fetch(url, {
|
|
5250
|
+
method: "POST",
|
|
5251
|
+
headers: {
|
|
5252
|
+
"Content-Type": "application/json",
|
|
5253
|
+
"X-SparkECoder-Event": event.type
|
|
5254
|
+
},
|
|
5255
|
+
body: JSON.stringify(event),
|
|
5256
|
+
signal: controller.signal
|
|
5257
|
+
});
|
|
5258
|
+
clearTimeout(timeout);
|
|
5259
|
+
} catch {
|
|
5260
|
+
}
|
|
5261
|
+
}
|
|
5262
|
+
|
|
4991
5263
|
// src/agent/index.ts
|
|
4992
5264
|
var approvalResolvers = /* @__PURE__ */ new Map();
|
|
4993
5265
|
var Agent = class _Agent {
|
|
@@ -5207,6 +5479,145 @@ ${prompt}` });
|
|
|
5207
5479
|
steps: result.steps
|
|
5208
5480
|
};
|
|
5209
5481
|
}
|
|
5482
|
+
/**
|
|
5483
|
+
* Run the agent in task mode — loops autonomously until the agent calls
|
|
5484
|
+
* complete_task or task_failed (or hits maxIterations).
|
|
5485
|
+
* All tools run without approval. Webhook events are fired throughout.
|
|
5486
|
+
*/
|
|
5487
|
+
async runTask(options) {
|
|
5488
|
+
const config = getConfig();
|
|
5489
|
+
const maxIterations = options.taskConfig.maxIterations ?? 50;
|
|
5490
|
+
const webhookUrl = options.taskConfig.webhookUrl;
|
|
5491
|
+
const fireWebhook = (type, data) => {
|
|
5492
|
+
if (!webhookUrl) return;
|
|
5493
|
+
sendWebhook(webhookUrl, {
|
|
5494
|
+
type,
|
|
5495
|
+
taskId: this.session.id,
|
|
5496
|
+
sessionId: this.session.id,
|
|
5497
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5498
|
+
data
|
|
5499
|
+
});
|
|
5500
|
+
};
|
|
5501
|
+
const completion = { signal: null };
|
|
5502
|
+
const onComplete = (signal) => {
|
|
5503
|
+
completion.signal = signal;
|
|
5504
|
+
};
|
|
5505
|
+
const taskTools = await createTools({
|
|
5506
|
+
sessionId: this.session.id,
|
|
5507
|
+
workingDirectory: this.session.workingDirectory,
|
|
5508
|
+
skillsDirectories: config.resolvedSkillsDirectories,
|
|
5509
|
+
onBashProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "bash", data: progress }) : void 0,
|
|
5510
|
+
onWriteFileProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "write_file", data: progress }) : void 0,
|
|
5511
|
+
onSearchProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "explore_agent", data: progress }) : void 0,
|
|
5512
|
+
taskTools: {
|
|
5513
|
+
outputSchema: options.taskConfig.outputSchema,
|
|
5514
|
+
onComplete
|
|
5515
|
+
}
|
|
5516
|
+
});
|
|
5517
|
+
const baseSystemPrompt = await buildSystemPrompt({
|
|
5518
|
+
workingDirectory: this.session.workingDirectory,
|
|
5519
|
+
skillsDirectories: config.resolvedSkillsDirectories,
|
|
5520
|
+
sessionId: this.session.id,
|
|
5521
|
+
discoveredSkills: config.discoveredSkills,
|
|
5522
|
+
activeFiles: []
|
|
5523
|
+
});
|
|
5524
|
+
const taskAddendum = buildTaskPromptAddendum(options.taskConfig.outputSchema);
|
|
5525
|
+
const systemPrompt = `${baseSystemPrompt}
|
|
5526
|
+
|
|
5527
|
+
${taskAddendum}`;
|
|
5528
|
+
fireWebhook("task.started", { prompt: options.prompt });
|
|
5529
|
+
this.context.addUserMessage(options.prompt);
|
|
5530
|
+
let iteration = 0;
|
|
5531
|
+
while (iteration < maxIterations) {
|
|
5532
|
+
iteration++;
|
|
5533
|
+
if (options.abortSignal?.aborted) {
|
|
5534
|
+
const cancelError = "Task was cancelled";
|
|
5535
|
+
fireWebhook("task.failed", { status: "failed", error: cancelError, iterations: iteration });
|
|
5536
|
+
return { status: "failed", error: cancelError, iterations: iteration };
|
|
5537
|
+
}
|
|
5538
|
+
const messages = await this.context.getMessages();
|
|
5539
|
+
const useAnthropic = isAnthropicModel(this.session.model);
|
|
5540
|
+
const result = await generateText3({
|
|
5541
|
+
model: resolveModel(this.session.model),
|
|
5542
|
+
system: systemPrompt,
|
|
5543
|
+
messages,
|
|
5544
|
+
tools: taskTools,
|
|
5545
|
+
stopWhen: stepCountIs2(500),
|
|
5546
|
+
abortSignal: options.abortSignal,
|
|
5547
|
+
providerOptions: useAnthropic ? {
|
|
5548
|
+
anthropic: {
|
|
5549
|
+
thinking: { type: "enabled", budgetTokens: 1e4 }
|
|
5550
|
+
}
|
|
5551
|
+
} : void 0,
|
|
5552
|
+
onStepFinish: (step) => {
|
|
5553
|
+
options.onStepFinish?.(step);
|
|
5554
|
+
fireWebhook("task.step_finished", { iteration, text: step.text });
|
|
5555
|
+
}
|
|
5556
|
+
});
|
|
5557
|
+
const responseMessages = result.response.messages;
|
|
5558
|
+
this.context.addResponseMessages(responseMessages);
|
|
5559
|
+
if (result.text) {
|
|
5560
|
+
options.onText?.(result.text);
|
|
5561
|
+
fireWebhook("task.message", { iteration, text: result.text });
|
|
5562
|
+
}
|
|
5563
|
+
for (const step of result.steps) {
|
|
5564
|
+
if (step.toolCalls) {
|
|
5565
|
+
for (const tc of step.toolCalls) {
|
|
5566
|
+
options.onToolCall?.({ toolCallId: tc.toolCallId, toolName: tc.toolName, input: tc.args });
|
|
5567
|
+
fireWebhook("task.tool_call", { iteration, toolName: tc.toolName, toolCallId: tc.toolCallId, input: tc.args });
|
|
5568
|
+
}
|
|
5569
|
+
}
|
|
5570
|
+
if (step.toolResults) {
|
|
5571
|
+
for (const tr of step.toolResults) {
|
|
5572
|
+
options.onToolResult?.({ toolCallId: tr.toolCallId, toolName: tr.toolName, output: tr.result });
|
|
5573
|
+
fireWebhook("task.tool_result", { iteration, toolName: tr.toolName, toolCallId: tr.toolCallId, output: tr.result });
|
|
5574
|
+
}
|
|
5575
|
+
}
|
|
5576
|
+
}
|
|
5577
|
+
if (completion.signal) {
|
|
5578
|
+
const sig = completion.signal;
|
|
5579
|
+
const finalStatus = sig.status;
|
|
5580
|
+
const eventType = finalStatus === "completed" ? "task.completed" : "task.failed";
|
|
5581
|
+
fireWebhook(eventType, {
|
|
5582
|
+
status: finalStatus,
|
|
5583
|
+
result: sig.result,
|
|
5584
|
+
error: sig.error,
|
|
5585
|
+
iterations: iteration
|
|
5586
|
+
});
|
|
5587
|
+
const updatedTask2 = {
|
|
5588
|
+
...options.taskConfig,
|
|
5589
|
+
status: finalStatus,
|
|
5590
|
+
result: sig.result,
|
|
5591
|
+
error: sig.error,
|
|
5592
|
+
iterations: iteration
|
|
5593
|
+
};
|
|
5594
|
+
await sessionQueries.update(this.session.id, {
|
|
5595
|
+
config: { ...this.session.config, task: updatedTask2 }
|
|
5596
|
+
});
|
|
5597
|
+
return {
|
|
5598
|
+
status: finalStatus,
|
|
5599
|
+
result: sig.result,
|
|
5600
|
+
error: sig.error,
|
|
5601
|
+
iterations: iteration
|
|
5602
|
+
};
|
|
5603
|
+
}
|
|
5604
|
+
this.context.addUserMessage(
|
|
5605
|
+
"Continue working on the task. When done, call `complete_task` with the result. If you cannot complete it, call `task_failed` with a reason."
|
|
5606
|
+
);
|
|
5607
|
+
}
|
|
5608
|
+
const timeoutError = `Task did not complete within ${maxIterations} iterations`;
|
|
5609
|
+
fireWebhook("task.failed", { status: "failed", error: timeoutError, iterations: iteration });
|
|
5610
|
+
const updatedTask = {
|
|
5611
|
+
...options.taskConfig,
|
|
5612
|
+
status: "failed",
|
|
5613
|
+
error: timeoutError,
|
|
5614
|
+
iterations: iteration
|
|
5615
|
+
};
|
|
5616
|
+
await sessionQueries.update(this.session.id, {
|
|
5617
|
+
config: { ...this.session.config, task: updatedTask }
|
|
5618
|
+
});
|
|
5619
|
+
return { status: "failed", error: timeoutError, iterations: iteration };
|
|
5620
|
+
}
|
|
5210
5621
|
/**
|
|
5211
5622
|
* Wrap tools to add approval checking
|
|
5212
5623
|
*/
|
|
@@ -5220,9 +5631,9 @@ ${prompt}` });
|
|
|
5220
5631
|
wrappedTools[name] = originalTool;
|
|
5221
5632
|
continue;
|
|
5222
5633
|
}
|
|
5223
|
-
wrappedTools[name] =
|
|
5634
|
+
wrappedTools[name] = tool12({
|
|
5224
5635
|
description: originalTool.description || "",
|
|
5225
|
-
inputSchema: originalTool.inputSchema ||
|
|
5636
|
+
inputSchema: originalTool.inputSchema || z13.object({}),
|
|
5226
5637
|
execute: async (input, toolOptions) => {
|
|
5227
5638
|
const toolCallId = toolOptions.toolCallId || nanoid3();
|
|
5228
5639
|
const execution = toolExecutionQueries.create({
|
|
@@ -5333,6 +5744,7 @@ ${prompt}` });
|
|
|
5333
5744
|
export {
|
|
5334
5745
|
Agent,
|
|
5335
5746
|
ContextManager,
|
|
5336
|
-
buildSystemPrompt
|
|
5747
|
+
buildSystemPrompt,
|
|
5748
|
+
buildTaskPromptAddendum
|
|
5337
5749
|
};
|
|
5338
5750
|
//# sourceMappingURL=index.js.map
|