veryfront 0.1.998 → 0.1.1001
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/esm/cli/commands/pull/command.d.ts.map +1 -1
- package/esm/cli/commands/pull/command.js +5 -3
- package/esm/cli/commands/up/command.d.ts.map +1 -1
- package/esm/cli/commands/up/command.js +4 -3
- package/esm/cli/shared/config.d.ts.map +1 -1
- package/esm/cli/shared/config.js +22 -10
- package/esm/cli/shared/constants.d.ts +1 -0
- package/esm/cli/shared/constants.d.ts.map +1 -1
- package/esm/cli/shared/constants.js +16 -1
- package/esm/cli/templates/manifest.d.ts +1 -1
- package/esm/cli/templates/manifest.js +15 -15
- package/esm/deno.js +1 -1
- package/esm/src/discovery/transpiler.d.ts.map +1 -1
- package/esm/src/discovery/transpiler.js +6 -1
- package/esm/src/embedding/index.d.ts +0 -2
- package/esm/src/embedding/index.d.ts.map +1 -1
- package/esm/src/embedding/index.js +0 -1
- package/esm/src/embedding/upload-handler.d.ts +2 -13
- package/esm/src/embedding/upload-handler.d.ts.map +1 -1
- package/esm/src/embedding/upload-handler.js +24 -17
- package/esm/src/internal-agents/run-stream.d.ts +1 -0
- package/esm/src/internal-agents/run-stream.d.ts.map +1 -1
- package/esm/src/internal-agents/run-stream.js +5 -1
- package/esm/src/modules/import-map/default-import-map.d.ts.map +1 -1
- package/esm/src/modules/import-map/default-import-map.js +0 -5
- package/esm/src/server/handlers/request/agent-stream.handler.d.ts +1 -0
- package/esm/src/server/handlers/request/agent-stream.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/agent-stream.handler.js +4 -0
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.d.ts.map +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
- package/esm/src/embedding/react/use-uploads.d.ts +0 -33
- package/esm/src/embedding/react/use-uploads.d.ts.map +0 -1
- package/esm/src/embedding/react/use-uploads.js +0 -76
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/pull/command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/pull/command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAM3E,OAAO,EACL,eAAe,EAIhB,MAAM,wBAAwB,CAAC;AAOhC;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;GAY7B,CAAC;AAEF,eAAO,MAAM,cAAc;;;;;;;;;;GAAgC,CAAC;AAE5D,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAC;AAEzE;;GAEG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;GAUxB,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oDAAoD;IACpD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,CAKlE;AAED,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AA2CD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAWjF;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,EAC1C,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,WAAW,EAAE,CAAC,CAoBxB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAmBjG;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,EAC1C,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,MAAM,CAAC,CAQjB;AA8ID;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuGpE"}
|
|
@@ -9,12 +9,13 @@
|
|
|
9
9
|
import { defineSchema, lazySchema } from "../../../src/schemas/index.js";
|
|
10
10
|
import { dirname, join, normalize, resolve } from "../../../src/platform/compat/path/index.js";
|
|
11
11
|
import { cliLogger } from "../../utils/index.js";
|
|
12
|
+
import { resolveCliApiUrl } from "../../shared/constants.js";
|
|
12
13
|
import { cwd } from "../../../src/platform/index.js";
|
|
13
14
|
import { createFileSystem } from "../../../src/platform/index.js";
|
|
14
15
|
import { createApiClient, readConfigFile, resolveConfigWithAuth, } from "../../shared/config.js";
|
|
15
16
|
import { confirmPrompt, logInfo, logSuccess, logWarning } from "../../utils/index.js";
|
|
16
17
|
import { createNoopSpinner, createSpinner } from "../../ui/index.js";
|
|
17
|
-
import { getApiTokenEnv } from "../../../src/config/index.js";
|
|
18
|
+
import { getApiTokenEnv, getEnvironmentConfig } from "../../../src/config/index.js";
|
|
18
19
|
import { withSpan } from "../../../src/observability/tracing/otlp-setup.js";
|
|
19
20
|
import { CommonArgs, createArgParser } from "../../shared/args.js";
|
|
20
21
|
/**
|
|
@@ -268,12 +269,13 @@ export function pullCommand(options = {}) {
|
|
|
268
269
|
spinner.stop();
|
|
269
270
|
if (!projects?.length)
|
|
270
271
|
throw error;
|
|
271
|
-
const
|
|
272
|
+
const env = getEnvironmentConfig();
|
|
273
|
+
const token = getApiTokenEnv(env) ?? configFile?.apiToken;
|
|
272
274
|
if (!token) {
|
|
273
275
|
throw new Error("VERYFRONT_API_TOKEN environment variable or apiToken in veryfront.json is required when using --projects");
|
|
274
276
|
}
|
|
275
277
|
config = {
|
|
276
|
-
apiUrl: configFile?.apiUrl
|
|
278
|
+
apiUrl: resolveCliApiUrl(env, configFile?.apiUrl),
|
|
277
279
|
apiToken: token,
|
|
278
280
|
projectSlug: "",
|
|
279
281
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/up/command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAO3E,OAAO,EAAE,KAAK,iBAAiB,EAAwB,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/up/command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAO3E,OAAO,EAAE,KAAK,iBAAiB,EAAwB,MAAM,8BAA8B,CAAC;AAS5F,eAAO,MAAM,eAAe;;;GAK3B,CAAC;AAEF,eAAO,MAAM,YAAY;;;GAA8B,CAAC;AAExD,MAAM,MAAM,SAAS,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC;AAExE,eAAO,MAAM,WAAW;;;GAGtB,CAAC;AAyEH,wBAAsB,SAAS,CAC7B,OAAO,GAAE,OAAO,CAAC,SAAS,CAAM,EAChC,GAAG,GAAE,iBAA0C,GAC9C,OAAO,CAAC,IAAI,CAAC,CA+Gf"}
|
|
@@ -10,6 +10,7 @@ import { createSpinner, shouldUseColor } from "../../ui/index.js";
|
|
|
10
10
|
import { isTTY, promptUser } from "../../utils/index.js";
|
|
11
11
|
import { CommonArgs, createArgParser } from "../../shared/args.js";
|
|
12
12
|
import { readConfigFile } from "../../shared/config.js";
|
|
13
|
+
import { resolveCliApiUrl } from "../../shared/constants.js";
|
|
13
14
|
import { pushCommand } from "../push/index.js";
|
|
14
15
|
import { deployCommand } from "../deploy/index.js";
|
|
15
16
|
export const getUpArgsSchema = defineSchema((v) => v.object({
|
|
@@ -77,7 +78,7 @@ export async function upCommand(options = {}, env = getEnvironmentConfig()) {
|
|
|
77
78
|
const useColor = shouldUseColor();
|
|
78
79
|
const c = (fn, s) => (useColor ? fn(s) : s);
|
|
79
80
|
const projectDir = cwd();
|
|
80
|
-
const userInfo = await ensureAuthenticated();
|
|
81
|
+
const userInfo = await ensureAuthenticated(env);
|
|
81
82
|
if (!userInfo)
|
|
82
83
|
return;
|
|
83
84
|
const spinner = createSpinner("Analyzing project...");
|
|
@@ -114,8 +115,8 @@ export async function upCommand(options = {}, env = getEnvironmentConfig()) {
|
|
|
114
115
|
else {
|
|
115
116
|
const projectSpinner = createSpinner(`Creating project "${slug}"...`);
|
|
116
117
|
try {
|
|
117
|
-
const apiUrl = env
|
|
118
|
-
const resolvedToken = env.apiToken ?? (await readToken());
|
|
118
|
+
const apiUrl = resolveCliApiUrl(env);
|
|
119
|
+
const resolvedToken = env.apiToken ?? (await readToken(env));
|
|
119
120
|
if (!resolvedToken) {
|
|
120
121
|
projectSpinner.stop();
|
|
121
122
|
cliLogger.error("Not authenticated");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/cli/shared/config.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAGxE,OAAO,EAAE,KAAK,iBAAiB,EAAwB,MAAM,2BAA2B,CAAC;AA6BzF,eAAO,MAAM,wBAAwB;;IAGjC,mDAAmD;;;;GAKtD,CAAC;AACF,eAAO,MAAM,qBAAqB;;IAN9B,mDAAmD;;;;GAMkB,CAAC;AAC1E,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC,CAAC;AAEvF,eAAO,MAAM,uBAAuB;;;;GAMnC,CAAC;AACF,eAAO,MAAM,oBAAoB;;;;GAAsC,CAAC;AACxE,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC,CAAC;AAErF,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/cli/shared/config.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAGxE,OAAO,EAAE,KAAK,iBAAiB,EAAwB,MAAM,2BAA2B,CAAC;AA6BzF,eAAO,MAAM,wBAAwB;;IAGjC,mDAAmD;;;;GAKtD,CAAC;AACF,eAAO,MAAM,qBAAqB;;IAN9B,mDAAmD;;;;GAMkB,CAAC;AAC1E,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC,CAAC;AAEvF,eAAO,MAAM,uBAAuB;;;;GAMnC,CAAC;AACF,eAAO,MAAM,oBAAoB;;;;GAAsC,CAAC;AACxE,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC,CAAC;AAErF,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA2CxF;AAED,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAatF;AA4ED,eAAO,MAAM,aAAa,gBAJH,MAAM,QAAQ,iBAAiB,KAAG,OAAO,CAAC,cAAc,CAIvB,CAAC;AAEzD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,gBAZX,MAAM,QAAQ,iBAAiB,KAAG,OAAO,CAAC,cAAc,CAYhB,CAAC;AAUhE,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAClE,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAClD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACjD,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACrC;AAED,eAAO,MAAM,iBAAiB;;;;GAM7B,CAAC;AACF,eAAO,MAAM,cAAc;;;;GAAgC,CAAC;AAC5D,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAC;AAEzE,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CA+GjE"}
|
package/esm/cli/shared/config.js
CHANGED
|
@@ -12,7 +12,7 @@ import { getEnvironmentConfig } from "../../src/config/index.js";
|
|
|
12
12
|
import { cliLogger, VERSION } from "../utils/index.js";
|
|
13
13
|
import { readToken } from "../auth/token-store.js";
|
|
14
14
|
import { ensureAuthenticated } from "../auth/login.js";
|
|
15
|
-
import {
|
|
15
|
+
import { resolveCliApiUrl } from "./constants.js";
|
|
16
16
|
import { isRetryableConnectionError } from "../../src/proxy/retry.js";
|
|
17
17
|
// Delays for exponential backoff with jitter: attempt 1 = ~300ms, 2 = ~1s, 3 = ~3s
|
|
18
18
|
const API_RETRY_DELAYS_MS = [300, 1000, 3000];
|
|
@@ -49,6 +49,7 @@ export const getResolvedConfigSchema = defineSchema((v) => v.object({
|
|
|
49
49
|
export const ResolvedConfigSchema = lazySchema(getResolvedConfigSchema);
|
|
50
50
|
export async function readConfigFile(projectDir) {
|
|
51
51
|
const fs = createFileSystem();
|
|
52
|
+
let moduleProjectSlug;
|
|
52
53
|
for (const ext of [".ts", ".js"]) {
|
|
53
54
|
const configPath = join(projectDir, `veryfront.config${ext}`);
|
|
54
55
|
try {
|
|
@@ -56,25 +57,36 @@ export async function readConfigFile(projectDir) {
|
|
|
56
57
|
continue;
|
|
57
58
|
const module = await import(`file://${configPath}`);
|
|
58
59
|
const config = module.default ?? module;
|
|
59
|
-
if (config?.projectSlug)
|
|
60
|
-
|
|
60
|
+
if (config?.projectSlug) {
|
|
61
|
+
moduleProjectSlug = config.projectSlug;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
61
64
|
}
|
|
62
65
|
catch (error) {
|
|
63
66
|
cliLogger.debug(`Failed to import config file ${configPath}:`, error);
|
|
64
67
|
}
|
|
65
68
|
}
|
|
69
|
+
// veryfront.json is always merged in: veryfront.config.ts owns the
|
|
70
|
+
// projectSlug when both define one, but apiUrl/apiToken only live in
|
|
71
|
+
// veryfront.json and must not be dropped because a TS config exists.
|
|
66
72
|
const configJsonPath = join(projectDir, "veryfront.json");
|
|
73
|
+
let jsonConfig = null;
|
|
67
74
|
try {
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
if (await fs.exists(configJsonPath)) {
|
|
76
|
+
const content = await fs.readTextFile(configJsonPath);
|
|
77
|
+
const parsed = VeryfrontConfigSchema.safeParse(JSON.parse(content));
|
|
78
|
+
jsonConfig = parsed.success ? parsed.data : null;
|
|
79
|
+
}
|
|
73
80
|
}
|
|
74
81
|
catch (error) {
|
|
75
82
|
cliLogger.debug(`Failed to read veryfront.json:`, error);
|
|
76
|
-
return null;
|
|
77
83
|
}
|
|
84
|
+
if (!moduleProjectSlug && !jsonConfig)
|
|
85
|
+
return null;
|
|
86
|
+
return {
|
|
87
|
+
...jsonConfig,
|
|
88
|
+
...(moduleProjectSlug ? { projectSlug: moduleProjectSlug } : {}),
|
|
89
|
+
};
|
|
78
90
|
}
|
|
79
91
|
export async function writeProjectSlug(projectDir, slug) {
|
|
80
92
|
const fs = createFileSystem();
|
|
@@ -121,7 +133,7 @@ function resolveTenantProjectReference() {
|
|
|
121
133
|
async function resolveConfigBase(projectDir, env, interactive) {
|
|
122
134
|
const dir = projectDir ?? cwd();
|
|
123
135
|
const configFile = await readConfigFile(dir);
|
|
124
|
-
const apiUrl = env
|
|
136
|
+
const apiUrl = resolveCliApiUrl(env, configFile?.apiUrl);
|
|
125
137
|
let apiToken = env.apiToken ?? configFile?.apiToken ?? (await readToken(env));
|
|
126
138
|
if (!apiToken && interactive) {
|
|
127
139
|
const userInfo = await ensureAuthenticated(env);
|
|
@@ -12,6 +12,7 @@ export declare const DEFAULT_CALLBACK_PORT = 9876;
|
|
|
12
12
|
export declare const MAX_PORT_ATTEMPTS = 100;
|
|
13
13
|
export declare const DEFAULT_API_URL = "https://api.veryfront.com";
|
|
14
14
|
export declare const DEFAULT_LOCAL_API_URL = "https://api.veryfront.com";
|
|
15
|
+
export declare function resolveCliApiUrl(env?: EnvironmentConfig, configApiUrl?: string): string;
|
|
15
16
|
export declare function getApiUrl(env?: EnvironmentConfig): string;
|
|
16
17
|
export declare const DEFAULT_LOGIN_TIMEOUT_MS = 120000;
|
|
17
18
|
export declare const SHUTDOWN_TIMEOUT_MS = 3000;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/cli/shared/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,iBAAiB,EAAwB,MAAM,2BAA2B,CAAC;AAEzF,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,kBAAkB,OAAO,CAAC;AACvC,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,eAAO,MAAM,oBAAoB,QAAyC,CAAC;AAC3E,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC,eAAO,MAAM,eAAe,8BAA8B,CAAC;AAC3D,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/cli/shared/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,iBAAiB,EAAwB,MAAM,2BAA2B,CAAC;AAEzF,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,kBAAkB,OAAO,CAAC;AACvC,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,eAAO,MAAM,oBAAoB,QAAyC,CAAC;AAC3E,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC,eAAO,MAAM,eAAe,8BAA8B,CAAC;AAC3D,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AAOjE,wBAAgB,gBAAgB,CAC9B,GAAG,GAAE,iBAA0C,EAC/C,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CASR;AAED,wBAAgB,SAAS,CAAC,GAAG,GAAE,iBAA0C,GAAG,MAAM,CAEjF;AAED,eAAO,MAAM,wBAAwB,SAAU,CAAC;AAChD,eAAO,MAAM,mBAAmB,OAAQ,CAAC;AACzC,eAAO,MAAM,kBAAkB,OAAQ,CAAC;AAExC,eAAO,MAAM,eAAe,cAAc,CAAC;AAC3C,eAAO,MAAM,eAAe,UAAU,CAAC;AACvC,eAAO,MAAM,sBAAsB,MAAQ,CAAC"}
|
|
@@ -12,8 +12,23 @@ export const DEFAULT_CALLBACK_PORT = 9876;
|
|
|
12
12
|
export const MAX_PORT_ATTEMPTS = 100;
|
|
13
13
|
export const DEFAULT_API_URL = "https://api.veryfront.com";
|
|
14
14
|
export const DEFAULT_LOCAL_API_URL = "https://api.veryfront.com";
|
|
15
|
+
function getExplicitApiBaseUrl(env) {
|
|
16
|
+
if (!env.apiBaseUrl || env.apiBaseUrl === DEFAULT_API_URL)
|
|
17
|
+
return undefined;
|
|
18
|
+
return env.apiBaseUrl;
|
|
19
|
+
}
|
|
20
|
+
export function resolveCliApiUrl(env = getEnvironmentConfig(), configApiUrl) {
|
|
21
|
+
// VERYFRONT_API_URL wins. A non-default VERYFRONT_API_BASE_URL is an
|
|
22
|
+
// operator override, so it wins over a checked-in veryfront.json apiUrl.
|
|
23
|
+
// The default production apiBaseUrl stays below project config.
|
|
24
|
+
return env.apiUrl ??
|
|
25
|
+
getExplicitApiBaseUrl(env) ??
|
|
26
|
+
configApiUrl ??
|
|
27
|
+
env.apiBaseUrl ??
|
|
28
|
+
DEFAULT_API_URL;
|
|
29
|
+
}
|
|
15
30
|
export function getApiUrl(env = getEnvironmentConfig()) {
|
|
16
|
-
return env
|
|
31
|
+
return resolveCliApiUrl(env);
|
|
17
32
|
}
|
|
18
33
|
export const DEFAULT_LOGIN_TIMEOUT_MS = 120_000;
|
|
19
34
|
export const SHUTDOWN_TIMEOUT_MS = 3_000;
|
|
@@ -50,10 +50,10 @@ declare namespace _default {
|
|
|
50
50
|
"agents/rag.ts": string;
|
|
51
51
|
"app/api/ag-ui/route.ts": string;
|
|
52
52
|
"app/api/ingest/route.ts": string;
|
|
53
|
-
"app/api/uploads/[id]/route.ts": string;
|
|
54
53
|
"app/api/uploads/route.ts": string;
|
|
55
54
|
"app/layout.tsx": string;
|
|
56
55
|
"app/page.tsx": string;
|
|
56
|
+
"app/uploads/page.tsx": string;
|
|
57
57
|
"content/architecture.md": string;
|
|
58
58
|
"content/getting-started.md": string;
|
|
59
59
|
"globals.css": string;
|
|
@@ -21,22 +21,22 @@ export default {
|
|
|
21
21
|
},
|
|
22
22
|
"ai-agent": {
|
|
23
23
|
"files": {
|
|
24
|
-
"agents/assistant.ts": "import { agent } from \"veryfront/agent\";\n\nexport default agent({\n id: \"assistant\",\n system: \"You are a helpful assistant. Answer questions clearly and concisely.\",\n tools: true,\n maxSteps: 10,\n});\n",
|
|
24
|
+
"agents/assistant.ts": "import { agent } from \"veryfront/agent\";\n\nexport default agent({\n id: \"assistant\",\n name: \"AI Agent\",\n description: \"Ask questions and use tools.\",\n system: \"You are a helpful assistant. Answer questions clearly and concisely.\",\n tools: true,\n maxSteps: 10,\n suggestions: {\n suggestions: [\n {\n type: \"prompt\",\n title: \"Draft a plan\",\n prompt: \"Help me make a concise plan for \",\n },\n {\n type: \"prompt\",\n title: \"Explain a topic\",\n prompt: \"Explain this clearly: \",\n },\n ],\n },\n});\n",
|
|
25
25
|
"app/api/ag-ui/route.ts": "import { createAgUiHandler } from \"veryfront/agent\";\n\nexport const POST = createAgUiHandler(\"assistant\");\n",
|
|
26
26
|
"app/layout.tsx": "import \"../globals.css\";\nimport { Head } from \"veryfront/head\";\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}): React.ReactNode {\n return (\n <>\n <Head>\n <title>AI Chat</title>\n </Head>\n <div className=\"flex flex-col h-screen bg-white dark:bg-neutral-900\">\n {children}\n </div>\n </>\n );\n}\n",
|
|
27
|
-
"app/page.tsx": "'use client'\n\nimport { Chat
|
|
27
|
+
"app/page.tsx": "'use client'\n\nimport { Chat } from 'veryfront/chat'\n\nexport default function ChatPage(): React.JSX.Element {\n return <Chat agentId=\"assistant\" api=\"/api/ag-ui\" className=\"flex-1 min-h-0\" placeholder=\"Message\" />\n}\n",
|
|
28
28
|
"globals.css": "@import \"tailwindcss\";\n",
|
|
29
|
-
"README.md": "# AI Agent\n\nA simple conversational AI with tool support.\n\n## What's included\n\n- Single assistant agent with streaming chat UI\n- Example calculator tool\n- `
|
|
29
|
+
"README.md": "# AI Agent\n\nA simple conversational AI with tool support.\n\n## What's included\n\n- Single assistant agent with streaming chat UI\n- Example calculator tool\n- App-mode `Chat` component for real-time responses\n\n## Structure\n\n```\nagents/assistant.ts Agent definition\ntools/calculator.ts Example tool\napp/\n api/ag-ui/route.ts AG-UI endpoint\n page.tsx Chat interface\n```\n\nThis starter is not production-ready.\n",
|
|
30
30
|
"tools/calculator.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\n\nexport default tool({\n id: \"calculator\",\n description: \"Perform basic arithmetic operations\",\n inputSchema: defineSchema((v) => v.object({\n operation: v.enum([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n a: v.number(),\n b: v.number(),\n }))(),\n execute: ({ operation, a, b }) => {\n if (operation === \"divide\" && b === 0) {\n throw new Error(\"Cannot divide by zero\");\n }\n\n if (operation === \"add\") return { result: a + b };\n if (operation === \"subtract\") return { result: a - b };\n if (operation === \"multiply\") return { result: a * b };\n return { result: a / b };\n },\n});\n",
|
|
31
31
|
"tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"jsx\": \"react-jsx\",\n \"skipLibCheck\": true,\n \"esModuleInterop\": true,\n \"paths\": {\n \"@/*\": [\"./*\"]\n }\n },\n \"include\": [\"**/*.ts\", \"**/*.tsx\"],\n \"exclude\": [\"node_modules\"]\n}\n"
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
"coding-agent": {
|
|
35
35
|
"files": {
|
|
36
|
-
"agents/coder.ts": "import { agent } from \"veryfront/agent\";\n\nexport default agent({\n id: \"coder\",\n system: `You are an expert coding assistant. You can read, search, and modify code files in the project.\n\nWhen asked to make changes:\n1. First read the relevant files to understand the codebase\n2. Explain what you'll change and why\n3. Make the changes\n4. Verify the result\n\nAlways explain your reasoning before making edits.`,\n tools: true,\n maxSteps: 15,\n});\n",
|
|
36
|
+
"agents/coder.ts": "import { agent } from \"veryfront/agent\";\n\nexport default agent({\n id: \"coder\",\n name: \"Code Agent\",\n description: \"Read, search, and edit project files.\",\n system: `You are an expert coding assistant. You can read, search, and modify code files in the project.\n\nWhen asked to make changes:\n1. First read the relevant files to understand the codebase\n2. Explain what you'll change and why\n3. Make the changes\n4. Verify the result\n\nAlways explain your reasoning before making edits.`,\n tools: true,\n maxSteps: 15,\n suggestions: {\n suggestions: [\n {\n type: \"prompt\",\n title: \"Explain the codebase\",\n prompt: \"Explain how this project is organized.\",\n },\n {\n type: \"prompt\",\n title: \"Make a change\",\n prompt: \"Make this code change: \",\n },\n ],\n },\n});\n",
|
|
37
37
|
"app/api/ag-ui/route.ts": "import { createAgUiHandler } from \"veryfront/agent\";\n\nexport const POST = createAgUiHandler(\"coder\");\n",
|
|
38
38
|
"app/layout.tsx": "import \"../globals.css\";\nimport { Head } from \"veryfront/head\";\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}): React.ReactNode {\n return (\n <>\n <Head>\n <title>Code Agent</title>\n </Head>\n <div className=\"dark\">\n <div className=\"flex flex-col h-screen bg-neutral-950\">\n <header className=\"flex-shrink-0 border-b border-neutral-800\">\n <div className=\"max-w-4xl mx-auto flex items-center gap-3 px-4 py-3\">\n <div className=\"w-8 h-8 rounded-lg bg-emerald-500/10 flex items-center justify-center\">\n <svg\n className=\"w-4 h-4 text-emerald-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5\"\n />\n </svg>\n </div>\n <div>\n <h1 className=\"font-medium text-white text-sm font-mono\">\n code-agent\n </h1>\n <p className=\"text-xs text-neutral-500\">\n read, search, edit project files\n </p>\n </div>\n <div className=\"ml-auto flex items-center gap-1.5\">\n <span className=\"w-2 h-2 rounded-full bg-emerald-400 animate-pulse\" />\n <span className=\"text-xs text-neutral-500 font-mono\">ready</span>\n </div>\n </div>\n </header>\n {children}\n </div>\n </div>\n </>\n );\n}\n",
|
|
39
|
-
"app/page.tsx": "'use client'\n\nimport { Chat
|
|
39
|
+
"app/page.tsx": "'use client'\n\nimport { Chat } from 'veryfront/chat'\n\nexport default function CodeAgent(): React.JSX.Element {\n return (\n <Chat\n agentId=\"coder\"\n api=\"/api/ag-ui\"\n className=\"flex-1 min-h-0\"\n placeholder=\"Describe what you want to build or fix...\"\n />\n )\n}\n",
|
|
40
40
|
"globals.css": "@import \"tailwindcss\";\n",
|
|
41
41
|
"README.md": "# Coding Agent\n\nAn AI assistant that can read, understand, and modify project files.\n\n## What's included\n\n- Coder agent with file system tools\n- Read, list, and edit files through conversation\n- Safe search/replace editing pattern\n\n## Structure\n\n```\nagents/coder.ts Agent with coding instructions\ntools/\n read-file.ts Read file contents\n list-files.ts List directory contents\n edit-file.ts Search and replace in files\napp/\n api/ag-ui/route.ts AG-UI endpoint\n page.tsx Chat interface\n```\n\nThis starter is not production-ready.\n",
|
|
42
42
|
"tools/edit-file.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { cwd, readTextFile, realPath, resolve, writeTextFile } from \"veryfront/fs\";\n\n/** True when `target` is the same as, or nested under, `root` (both canonical). */\nfunction isWithin(root: string, target: string): boolean {\n const r = root.replace(/\\\\/g, \"/\");\n const t = target.replace(/\\\\/g, \"/\");\n return t === r || t.startsWith(`${r}/`);\n}\n\nexport default tool({\n id: \"edit-file\",\n description: \"Edit a file by replacing a specific string with new content\",\n inputSchema: defineSchema((v) => v.object({\n path: v.string().describe(\"File path relative to the project root\"),\n search: v.string().describe(\"Exact string to find in the file\"),\n replace: v.string().describe(\"String to replace it with\"),\n }))(),\n execute: async ({ path, search, replace }) => {\n let projectDir: string;\n let absolute: string;\n try {\n // Canonicalize both sides so a symlink that points outside the project\n // is resolved to its real target before the containment check.\n projectDir = await realPath(cwd());\n absolute = await realPath(resolve(projectDir, path));\n } catch {\n return { error: `File not found: ${path}` };\n }\n if (!isWithin(projectDir, absolute)) {\n return { error: `Path escapes project directory: ${path}` };\n }\n\n const content = await readTextFile(absolute);\n if (!content.includes(search)) {\n return { error: \"Search string not found in file\" };\n }\n\n const updated = content.replace(search, replace);\n await writeTextFile(absolute, updated);\n return { path, success: true };\n },\n});\n",
|
|
@@ -47,17 +47,17 @@ export default {
|
|
|
47
47
|
},
|
|
48
48
|
"docs-agent": {
|
|
49
49
|
"files": {
|
|
50
|
-
"agents/rag.ts": "import { agent } from \"veryfront/agent\";\n\nexport default agent({\n id: \"rag\",\n system:\n `You answer questions using the provided documents. ` +\n `Always cite your sources by referencing the document title. ` +\n `If the search results don't contain a clear answer, say so honestly.`,\n});\n",
|
|
50
|
+
"agents/rag.ts": "import { agent } from \"veryfront/agent\";\n\nexport default agent({\n id: \"rag\",\n name: \"Docs Agent\",\n description: \"Upload files and ask questions.\",\n system:\n `You answer questions using the provided documents. ` +\n `Always cite your sources by referencing the document title. ` +\n `If the search results don't contain a clear answer, say so honestly.`,\n suggestions: {\n suggestions: [\n {\n type: \"prompt\",\n title: \"Ask Question\",\n prompt: \"I have a question about this document: \",\n },\n {\n type: \"prompt\",\n title: \"Extract Insights\",\n prompt: \"Extract the key insights from the uploaded documents.\",\n },\n {\n type: \"prompt\",\n title: \"Find Sources\",\n prompt: \"Find relevant sources and references in the documents for: \",\n },\n ],\n },\n});\n",
|
|
51
51
|
"app/api/ag-ui/route.ts": "import { createAgUiHandler } from \"veryfront/agent\";\nimport { store } from \"../../../store.ts\";\n\nexport const POST = createAgUiHandler(\"rag\", {\n beforeStream: async ({ lastUserText }) => {\n const query = lastUserText.trim();\n if (!query) return;\n\n try {\n const results = await store.search(query, { topK: 5 });\n if (results.length === 0) return;\n\n const contextBlock = results\n .map(\n (result) =>\n `[${result.title}] (score: ${\n result.score.toFixed(2)\n })\\n${result.text}`,\n )\n .join(\"\\n\\n---\\n\\n\");\n\n return {\n prepend: [\n {\n role: \"system\",\n parts: [\n {\n type: \"text\",\n text:\n `Here are relevant documents retrieved for your question:\\n\\n${contextBlock}\\n\\n` +\n \"Use these documents to answer. Cite the document title when referencing information.\",\n },\n ],\n },\n ],\n };\n } catch (e) {\n console.error(\"[RAG] Retrieval failed:\", e);\n return;\n }\n },\n});\n",
|
|
52
52
|
"app/api/ingest/route.ts": "import { store } from \"../../../store.ts\";\n\nexport async function POST() {\n await store.indexContentDir();\n return Response.json({ ok: true });\n}\n",
|
|
53
|
-
"app/api/uploads/
|
|
54
|
-
"app/
|
|
55
|
-
"app/
|
|
56
|
-
"app/page.tsx": "'use client'\n\nimport {
|
|
53
|
+
"app/api/uploads/route.ts": "import { createUploadHandler } from \"veryfront/embedding\";\nimport { store } from \"../../../store.ts\";\n\nexport const { POST, GET, DELETE } = createUploadHandler(store, {\n auth: { type: \"none\", allowUnauthenticated: true },\n});\n",
|
|
54
|
+
"app/layout.tsx": "'use client'\n\nimport \"../globals.css\";\nimport {\n AppShell,\n ChatSidebar,\n ChatThemeScope,\n ConversationsProvider,\n Tabs,\n TabsItem,\n} from \"veryfront/chat\";\nimport { Head } from \"veryfront/head\";\nimport { useRouter } from \"veryfront/router\";\n\nexport default function RootLayout({ children }: { children: React.ReactNode }): React.ReactNode {\n const router = useRouter();\n const activeTab = router.pathname.startsWith(\"/uploads\") ? \"uploads\" : \"chat\";\n\n return (\n <>\n <Head><title>Docs Agent</title></Head>\n <ChatThemeScope className=\"flex flex-col h-screen\">\n <ConversationsProvider storageKey=\"rag-conversations\">\n <AppShell className=\"flex-1 min-h-0\">\n <AppShell.Sidebar side=\"left\" className=\"border-r border-[var(--outline-border)]\">\n <AppShell.SidebarContent className=\"p-0\">\n <ChatSidebar fill />\n </AppShell.SidebarContent>\n </AppShell.Sidebar>\n <AppShell.Main>\n <AppShell.Header border className=\"h-16 gap-3 px-3\">\n <AppShell.Trigger side=\"left\" />\n <div className=\"flex flex-1 justify-center\">\n <Tabs\n value={activeTab}\n onValueChange={(value) => router.push(value === \"uploads\" ? \"/uploads\" : \"/\")}\n >\n <TabsItem value=\"chat\">Chat</TabsItem>\n <TabsItem value=\"uploads\">Uploads</TabsItem>\n </Tabs>\n </div>\n </AppShell.Header>\n <AppShell.Content className=\"flex flex-col min-h-0 pt-3\">\n {children}\n </AppShell.Content>\n </AppShell.Main>\n </AppShell>\n </ConversationsProvider>\n </ChatThemeScope>\n </>\n );\n}\n",
|
|
55
|
+
"app/page.tsx": "'use client'\n\nimport { Chat } from 'veryfront/chat'\n\nconst ACCEPT = '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.csv,.txt,.md,.mdx,.html,.rtf,.epub,.json,.xml'\n\nexport default function DocsChat() {\n return (\n <Chat\n agentId=\"rag\"\n api=\"/api/ag-ui\"\n uploadApi=\"/api/uploads\"\n showSteps\n showSources\n attachAccept={ACCEPT}\n className=\"flex-1 min-h-0\"\n placeholder=\"Ask anything about your documents...\"\n />\n )\n}\n",
|
|
56
|
+
"app/uploads/page.tsx": "'use client'\n\nimport { AttachmentsPanel, useUploadsRegistry } from 'veryfront/chat'\n\nconst UPLOAD_API = '/api/uploads'\nconst ACCEPT = '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.csv,.txt,.md,.mdx,.html,.rtf,.epub,.json,.xml'\n\nexport default function UploadsPage(): React.JSX.Element {\n const uploads = useUploadsRegistry({ url: UPLOAD_API, storageKey: 'rag-uploads' })\n\n return (\n <AttachmentsPanel\n uploads={uploads.items}\n loading={uploads.isLoading}\n onAttach={uploads.upload}\n onRemoveUpload={uploads.remove}\n attachAccept={ACCEPT}\n className=\"flex-1 min-h-0\"\n />\n )\n}\n",
|
|
57
57
|
"content/architecture.md": "# Architecture\n\nAcme Platform uses a modular, event-driven architecture.\n\n## Core Components\n\n### API Gateway\nRoutes incoming requests to the appropriate microservice. Handles authentication, rate limiting, and request validation.\n\n### Event Bus\nAsynchronous message broker connecting all services. Supports pub/sub and point-to-point messaging patterns.\n\n### Data Layer\nMulti-tenant data storage with automatic sharding. Supports PostgreSQL for relational data and Redis for caching.\n\n## Request Flow\n\n1. Client sends request to API Gateway\n2. Gateway validates authentication token\n3. Request is routed to the target service\n4. Service processes request and publishes events\n5. Response is returned through the gateway\n\n## Scaling\n\nEach component scales independently. The API Gateway uses horizontal scaling with load balancing. Services auto-scale based on queue depth and CPU utilization.\n\n## Security\n\n- All inter-service communication uses mTLS\n- API tokens are rotated every 24 hours\n- Data at rest is encrypted with AES-256\n- Audit logs are retained for 90 days\n",
|
|
58
58
|
"content/getting-started.md": "# Getting Started\n\nWelcome to Acme Platform. This guide covers initial setup and core concepts.\n\n## Installation\n\nInstall the CLI globally:\n\n```bash\nnpm install -g @acme/cli\n```\n\n## Creating a Project\n\nRun the init command to scaffold a new project:\n\n```bash\nacme init my-project\ncd my-project\n```\n\n## Project Structure\n\n- `src/`: Application source code\n- `config/`: Configuration files\n- `tests/`: Test suite\n- `docs/`: Documentation\n\n## Configuration\n\nCreate an `acme.config.ts` file in your project root:\n\n```ts\nexport default {\n name: \"my-project\",\n region: \"us-east-1\",\n features: [\"auth\", \"storage\"],\n};\n```\n\n## Next Steps\n\n- Read the [Architecture Guide](./architecture) to understand the system design\n- Check [API Reference](./api-reference) for available endpoints\n- Join our Discord community for support\n",
|
|
59
59
|
"globals.css": "@import \"tailwindcss\";\n",
|
|
60
|
-
"README.md": "# Docs Agent\n\nA chatbot that answers questions from your own documents using Retrieval-Augmented Generation (RAG).\n\n## What's included\n\n- Q&A agent with source citation\n- Embedding-based semantic search with convention-based model selection\n- Document upload supporting PDF, DOCX, XLSX, PPTX, CSV, HTML, RTF, EPUB, TXT, and Markdown\n- `ragStore()` with local JSON storage by default, and Veryfront Cloud RAG when bootstrap is present\n- Veryfront Cloud AI Gateway routing for generation and embeddings when bootstrap is present\n- Original uploaded files stored in Veryfront Cloud project uploads when cloud bootstrap is present\n- Sample content in `/content` indexed through a dedicated ingestion route\n\n## Getting started\n\n1. Set your Veryfront Cloud bootstrap vars:\n\n ```bash\n export VERYFRONT_API_TOKEN=vf_...\n export VERYFRONT_PROJECT_SLUG=my-project\n ```\n\n2. Start the dev server:\n\n ```bash\n npx veryfront dev\n ```\n\n3. Index the sample docs in `content/`:\n\n ```bash\n curl -X POST http://localhost:3000/api/ingest\n ```\n\n4. Open the app and upload a document or ask a question.\n\nIf you are using a self-hosted Veryfront API, also set `VERYFRONT_API_URL`.\n\n## Cloud mode\n\nWith `VERYFRONT_API_TOKEN` and `VERYFRONT_PROJECT_SLUG` set, the template uses\nVeryfront Cloud automatically:\n\n- Agent generation routes through Veryfront Cloud model routing.\n- Query and document embeddings route through Veryfront Cloud embedding routing.\n- `veryfront-cloud/openai/...` and `veryfront-cloud/google/...` models use AI Gateway.\n- RAG documents, chunks, and embeddings are stored in the target project.\n\nThe default cloud embedding model is\n`veryfront-cloud/openai/text-embedding-3-small`. Set\n`VERYFRONT_DEFAULT_EMBEDDING_MODEL` only when you need a different embedding\nmodel.\n\n## Architecture\n\nRAG grounds LLM responses in your documents through three pipelines: **Ingestion**, **Query**, and **RAG**. These pipelines are orchestrated around a shared vector store.\n\n```mermaid\nflowchart LR\n ChatUI_L[\"Chat UI\"]\n\n subgraph IngestionFlow[\"Ingestion Pipeline\"]\n D[\"Documents\"] --> EXT[\"Extraction\"] --> DC[\"Chunking\"] --> DE[\"Document\\nEmbedding\"] --> ING[\"Storage\"]\n end\n\n subgraph QueryFlow[\"Query Pipeline\"]\n Q[\"Query\"] --> QE[\"Query\\nEmbedding\"] --> SS[\"Similarity\\nSearch\"]\n end\n\n subgraph RAGFlow[\"RAG Pipeline\"]\n BF[\"beforeStream\\nHook\"] --> RET[\"Retrieval\"] --> AUG[\"Augmentation\"] --> AG[\"Agent\"] --> GEN[\"Generation\"]\n end\n\n EMB((\"Embedding\\nModel\"))\n GEN_LLM((\"Generative\\nModel\"))\n VS[(\"Vector\\nStore\")]\n ChatUI_R[\"Chat UI\"]\n\n ChatUI_L --> D\n ChatUI_L --> Q\n\n QE -.- EMB\n DE -.- EMB\n\n SS --> VS\n ING --> VS\n\n Q --> BF\n VS --> RET\n AG -.- GEN_LLM\n GEN -.- GEN_LLM\n GEN --> ChatUI_R\n```\n\n### Pipelines\n\n**Ingestion**: Documents are parsed into plain text via the built-in kreuzberg extraction engine (supporting PDF, DOCX, XLSX, PPTX, HTML, RTF, EPUB, and 76+ formats), split into overlapping chunks (~1000 chars, 200 char overlap), and stored in the default `ragStore()`. In local mode that means `data/index.json`; with Veryfront Cloud bootstrap it upgrades to the cloud RAG backend automatically. The original uploaded binary is also stored in the project's Veryfront Cloud uploads store so remote projects retain the source file, not just the extracted text. Uploaded files are ingested by the upload route. Bundled files in `content/` are ingested by the `/api/ingest` route.\n\n**Query**: The user's query is embedded into the same vector space as the documents, then compared against all stored chunks using cosine similarity to find the top-*k* most relevant results.\n\n**RAG**: The `beforeStream` hook in the AG-UI route intercepts each message before it reaches the agent. It searches the document store for relevant chunks, assembles them into context, and prepends them as retrieved reference data. The agent then generates a cited response streamed back to the user.\n\n## Structure\n\n```\nstore.ts RAG store config\nagents/rag.ts Q&A agent with citation instructions\ncontent/\n getting-started.md Sample document\n architecture.md Sample document\napp/\n api/ag-ui/route.ts AG-UI endpoint\n api/ingest/route.ts Bundled content ingestion\n api/uploads/route.ts Upload
|
|
60
|
+
"README.md": "# Docs Agent\n\nA chatbot that answers questions from your own documents using Retrieval-Augmented Generation (RAG).\n\n## What's included\n\n- Q&A agent with source citation\n- Embedding-based semantic search with convention-based model selection\n- Document upload supporting PDF, DOCX, XLSX, PPTX, CSV, HTML, RTF, EPUB, TXT, and Markdown\n- `ragStore()` with local JSON storage by default, and Veryfront Cloud RAG when bootstrap is present\n- Veryfront Cloud AI Gateway routing for generation and embeddings when bootstrap is present\n- Original uploaded files stored in Veryfront Cloud project uploads when cloud bootstrap is present\n- Sample content in `/content` indexed through a dedicated ingestion route\n\n## Getting started\n\n1. Set your Veryfront Cloud bootstrap vars:\n\n ```bash\n export VERYFRONT_API_TOKEN=vf_...\n export VERYFRONT_PROJECT_SLUG=my-project\n ```\n\n2. Start the dev server:\n\n ```bash\n npx veryfront dev\n ```\n\n3. Index the sample docs in `content/`:\n\n ```bash\n curl -X POST http://localhost:3000/api/ingest\n ```\n\n4. Open the app and upload a document or ask a question.\n\nIf you are using a self-hosted Veryfront API, also set `VERYFRONT_API_URL`.\n\n## Cloud mode\n\nWith `VERYFRONT_API_TOKEN` and `VERYFRONT_PROJECT_SLUG` set, the template uses\nVeryfront Cloud automatically:\n\n- Agent generation routes through Veryfront Cloud model routing.\n- Query and document embeddings route through Veryfront Cloud embedding routing.\n- `veryfront-cloud/openai/...` and `veryfront-cloud/google/...` models use AI Gateway.\n- RAG documents, chunks, and embeddings are stored in the target project.\n\nThe default cloud embedding model is\n`veryfront-cloud/openai/text-embedding-3-small`. Set\n`VERYFRONT_DEFAULT_EMBEDDING_MODEL` only when you need a different embedding\nmodel.\n\n## Architecture\n\nRAG grounds LLM responses in your documents through three pipelines: **Ingestion**, **Query**, and **RAG**. These pipelines are orchestrated around a shared vector store.\n\n```mermaid\nflowchart LR\n ChatUI_L[\"Chat UI\"]\n\n subgraph IngestionFlow[\"Ingestion Pipeline\"]\n D[\"Documents\"] --> EXT[\"Extraction\"] --> DC[\"Chunking\"] --> DE[\"Document\\nEmbedding\"] --> ING[\"Storage\"]\n end\n\n subgraph QueryFlow[\"Query Pipeline\"]\n Q[\"Query\"] --> QE[\"Query\\nEmbedding\"] --> SS[\"Similarity\\nSearch\"]\n end\n\n subgraph RAGFlow[\"RAG Pipeline\"]\n BF[\"beforeStream\\nHook\"] --> RET[\"Retrieval\"] --> AUG[\"Augmentation\"] --> AG[\"Agent\"] --> GEN[\"Generation\"]\n end\n\n EMB((\"Embedding\\nModel\"))\n GEN_LLM((\"Generative\\nModel\"))\n VS[(\"Vector\\nStore\")]\n ChatUI_R[\"Chat UI\"]\n\n ChatUI_L --> D\n ChatUI_L --> Q\n\n QE -.- EMB\n DE -.- EMB\n\n SS --> VS\n ING --> VS\n\n Q --> BF\n VS --> RET\n AG -.- GEN_LLM\n GEN -.- GEN_LLM\n GEN --> ChatUI_R\n```\n\n### Pipelines\n\n**Ingestion**: Documents are parsed into plain text via the built-in kreuzberg extraction engine (supporting PDF, DOCX, XLSX, PPTX, HTML, RTF, EPUB, and 76+ formats), split into overlapping chunks (~1000 chars, 200 char overlap), and stored in the default `ragStore()`. In local mode that means `data/index.json`; with Veryfront Cloud bootstrap it upgrades to the cloud RAG backend automatically. The original uploaded binary is also stored in the project's Veryfront Cloud uploads store so remote projects retain the source file, not just the extracted text. Uploaded files are ingested by the upload route. Bundled files in `content/` are ingested by the `/api/ingest` route.\n\n**Query**: The user's query is embedded into the same vector space as the documents, then compared against all stored chunks using cosine similarity to find the top-*k* most relevant results.\n\n**RAG**: The `beforeStream` hook in the AG-UI route intercepts each message before it reaches the agent. It searches the document store for relevant chunks, assembles them into context, and prepends them as retrieved reference data. The agent then generates a cited response streamed back to the user.\n\n## Structure\n\n```\nstore.ts RAG store config\nagents/rag.ts Q&A agent with citation instructions\ncontent/\n getting-started.md Sample document\n architecture.md Sample document\napp/\n api/ag-ui/route.ts AG-UI endpoint\n api/ingest/route.ts Bundled content ingestion\n api/uploads/route.ts Upload, list, and delete uploads\n uploads/page.tsx Upload management panel\n page.tsx Chat UI\n layout.tsx Chat shell with sidebar and tabs\n```\n\n## Framework usage\n\n| What | Framework | Template code |\n|------|-----------|---------------|\n| Chat UI + streaming | app-mode `Chat` | `page.tsx` |\n| Upload management | `AttachmentsPanel`, `useUploadsRegistry` | `uploads/page.tsx` |\n| Source display | `showSources` prop on `Chat` | `page.tsx` |\n| Upload API route | `createUploadHandler` | 1 line in `route.ts` |\n| AG-UI route | `createAgUiHandler` | 1 line in `route.ts` |\n| Agent definition | `agent()` | Config object in `agents/rag.ts` |\n| RAG retrieval | `beforeStream` hook | Context injection in `api/ag-ui/route.ts` |\n| Vector store | `ragStore()` | Config in `store.ts` |\n\n## Adding documents\n\n- Drop files into `content/`, then run `curl -X POST http://localhost:3000/api/ingest`\n- Or use the upload panel in the UI for PDF, DOCX, XLSX, PPTX, CSV, HTML, RTF, EPUB, TXT, and MD files\n\n## Production notes\n\nThis is a starter template, not a production-ready setup. For production, consider:\n\n- **Vector store**: Replace the default store with pgvector, Pinecone, or Qdrant for datasets beyond ~10k chunks\n- **Reranking**: Add a cross-encoder reranker (e.g. Cohere Rerank) after retrieval to improve precision\n- **Hybrid search**: Combine dense vectors with BM25 keyword matching for better recall\n",
|
|
61
61
|
"store.ts": "import { ragStore } from \"veryfront/embedding\";\n\nexport const store = ragStore({\n storagePath: \"data/index.json\",\n contentDir: \"content\",\n});\n",
|
|
62
62
|
"tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"jsx\": \"react-jsx\",\n \"skipLibCheck\": true,\n \"esModuleInterop\": true,\n \"paths\": {\n \"@/*\": [\"./*\"]\n }\n },\n \"include\": [\"**/*.ts\", \"**/*.tsx\"],\n \"exclude\": [\"node_modules\"]\n}\n"
|
|
63
63
|
}
|
|
@@ -72,12 +72,12 @@ export default {
|
|
|
72
72
|
},
|
|
73
73
|
"multi-agent-system": {
|
|
74
74
|
"files": {
|
|
75
|
-
"agents/orchestrator.ts": "import { agent, getAgentsAsTools } from \"veryfront/agent\";\n\nexport default agent({\n id: \"orchestrator\",\n system:\n \"You coordinate a team of AI agents. \" +\n \"Delegate research tasks to the researcher and writing tasks to the writer. \" +\n \"Combine their outputs into a polished response.\",\n tools: getAgentsAsTools([\"researcher\", \"writer\"]),\n maxSteps: 10,\n});\n",
|
|
75
|
+
"agents/orchestrator.ts": "import { agent, getAgentsAsTools } from \"veryfront/agent\";\n\nexport default agent({\n id: \"orchestrator\",\n name: \"Agent Team\",\n description: \"Coordinate research and writing agents.\",\n system:\n \"You coordinate a team of AI agents. \" +\n \"Delegate research tasks to the researcher and writing tasks to the writer. \" +\n \"Combine their outputs into a polished response.\",\n tools: getAgentsAsTools([\"researcher\", \"writer\"]),\n maxSteps: 10,\n suggestions: {\n suggestions: [\n {\n type: \"prompt\",\n title: \"Research a topic\",\n prompt: \"Research this topic and summarize the key findings: \",\n },\n {\n type: \"prompt\",\n title: \"Write a brief\",\n prompt: \"Research and write a concise brief about \",\n },\n ],\n },\n});\n",
|
|
76
76
|
"agents/researcher.ts": "import { agent } from \"veryfront/agent\";\n\nexport default agent({\n id: \"researcher\",\n system:\n \"You are a research specialist. \" +\n \"Gather comprehensive information on the given topic. \" +\n \"Present findings as structured bullet points with key facts and data.\",\n tools: true,\n maxSteps: 5,\n});\n",
|
|
77
77
|
"agents/writer.ts": "import { agent } from \"veryfront/agent\";\n\nexport default agent({\n id: \"writer\",\n system:\n \"You are a writing specialist. \" +\n \"Take research notes and transform them into clear, engaging prose. \" +\n \"Use a professional but approachable tone.\",\n maxSteps: 3,\n});\n",
|
|
78
78
|
"app/api/ag-ui/route.ts": "import { createAgUiHandler } from \"veryfront/agent\";\n\nexport const POST = createAgUiHandler(\"orchestrator\");\n",
|
|
79
79
|
"app/layout.tsx": "import \"../globals.css\";\nimport { Head } from \"veryfront/head\";\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}): React.ReactNode {\n return (\n <>\n <Head>\n <title>Multi-Agent System</title>\n </Head>\n <div className=\"flex flex-col h-screen bg-white dark:bg-neutral-950\">\n <header className=\"flex-shrink-0 border-b border-neutral-200 dark:border-neutral-800\">\n <div className=\"max-w-3xl mx-auto flex items-center gap-3 px-4 py-3\">\n <div className=\"flex -space-x-2\">\n <div className=\"w-7 h-7 rounded-full bg-blue-500 ring-2 ring-white dark:ring-neutral-950 flex items-center justify-center text-[10px] font-bold text-white\">\n O\n </div>\n <div className=\"w-7 h-7 rounded-full bg-amber-500 ring-2 ring-white dark:ring-neutral-950 flex items-center justify-center text-[10px] font-bold text-white\">\n R\n </div>\n <div className=\"w-7 h-7 rounded-full bg-violet-500 ring-2 ring-white dark:ring-neutral-950 flex items-center justify-center text-[10px] font-bold text-white\">\n W\n </div>\n </div>\n <div>\n <h1 className=\"font-medium text-neutral-900 dark:text-white text-sm\">\n Agent Team\n </h1>\n <p className=\"text-xs text-neutral-500 dark:text-neutral-400\">\n Orchestrator, Researcher, Writer\n </p>\n </div>\n </div>\n </header>\n {children}\n </div>\n </>\n );\n}\n",
|
|
80
|
-
"app/page.tsx": "'use client'\n\nimport { Chat
|
|
80
|
+
"app/page.tsx": "'use client'\n\nimport { Chat } from 'veryfront/chat'\n\nexport default function MultiAgentChat(): React.JSX.Element {\n return (\n <Chat\n agentId=\"orchestrator\"\n api=\"/api/ag-ui\"\n className=\"flex-1 min-h-0\"\n placeholder=\"Give the team a task...\"\n />\n )\n}\n",
|
|
81
81
|
"globals.css": "@import \"tailwindcss\";\n",
|
|
82
82
|
"README.md": "# Multi-Agent System\n\nA team of specialized agents that collaborate on tasks.\n\n## What's included\n\n- Orchestrator that delegates to researcher and writer agents\n- Agent-as-tool composition via `getAgentsAsTools()`\n- Web search tool (placeholder, configure your own API)\n\n## Structure\n\n```\nagents/\n orchestrator.ts Coordinates the team\n researcher.ts Gathers information\n writer.ts Produces polished content\ntools/web-search.ts Placeholder search tool\napp/\n api/ag-ui/route.ts AG-UI endpoint\n page.tsx Chat interface\n```\n\nThis starter is not production-ready.\n",
|
|
83
83
|
"tools/web-search.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\n\nexport default tool({\n id: \"web-search\",\n description: \"Search the web for information on a topic\",\n inputSchema: defineSchema((v) => v.object({\n query: v.string().describe(\"Search query\"),\n }))(),\n execute: async ({ query: _query }) => {\n // Connect a real search API to use this tool.\n // Popular options: Tavily, SerpAPI, Brave Search\n throw new Error(\n \"No search API configured. \" +\n \"See https://veryfront.com/docs/code/guides/tools for setup instructions.\",\n );\n },\n});\n",
|
|
@@ -86,9 +86,9 @@ export default {
|
|
|
86
86
|
},
|
|
87
87
|
"saas-starter": {
|
|
88
88
|
"files": {
|
|
89
|
-
"agents/assistant.ts": "import { agent } from \"veryfront/agent\";\n\nexport default agent({\n id: \"assistant\",\n system: \"You are a helpful AI assistant. Be concise and direct.\",\n tools: true,\n memory: { type: \"conversation\", maxMessages: 50 },\n maxSteps: 10,\n});\n",
|
|
89
|
+
"agents/assistant.ts": "import { agent } from \"veryfront/agent\";\n\nexport default agent({\n id: \"assistant\",\n name: \"SaaS Assistant\",\n description: \"Answer product and customer questions.\",\n system: \"You are a helpful AI assistant. Be concise and direct.\",\n tools: true,\n memory: { type: \"conversation\", maxMessages: 50 },\n maxSteps: 10,\n suggestions: {\n suggestions: [\n {\n type: \"prompt\",\n title: \"Summarize account\",\n prompt: \"Summarize the latest account activity.\",\n },\n {\n type: \"prompt\",\n title: \"Find customers\",\n prompt: \"Find customers who need attention.\",\n },\n ],\n },\n});\n",
|
|
90
90
|
"app/api/ag-ui/route.ts": "import { createAgUiHandler } from \"veryfront/agent\";\n\nexport const POST = createAgUiHandler(\"assistant\");\n",
|
|
91
|
-
"app/dashboard/page.tsx": "\"use client\";\n\nimport { useState } from \"react\";\nimport { Chat
|
|
91
|
+
"app/dashboard/page.tsx": "\"use client\";\n\nimport { useState } from \"react\";\nimport { Chat } from \"veryfront/chat\";\n\ninterface Conversation {\n id: string;\n title: string;\n updatedAt: string;\n}\n\nconst INITIAL_CONVERSATIONS: Conversation[] = [\n { id: \"1\", title: \"Getting started\", updatedAt: \"Just now\" },\n];\n\nexport default function Dashboard(): React.JSX.Element {\n const [conversations] = useState<Conversation[]>(INITIAL_CONVERSATIONS);\n const [activeId, setActiveId] = useState(\"1\");\n\n return (\n <div className=\"flex h-screen bg-white dark:bg-neutral-950\">\n {/* Sidebar */}\n <aside className=\"w-64 border-r border-neutral-200 dark:border-neutral-800 flex flex-col bg-neutral-50 dark:bg-neutral-900\">\n <div className=\"p-4 border-b border-neutral-200 dark:border-neutral-800\">\n <button className=\"w-full flex items-center gap-2 px-3 py-2 text-sm font-medium text-neutral-700 dark:text-neutral-300 bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 rounded-lg hover:bg-neutral-50 dark:hover:bg-neutral-700 transition-colors\">\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M12 4.5v15m7.5-7.5h-15\"\n />\n </svg>\n New chat\n </button>\n </div>\n\n <nav className=\"flex-1 overflow-y-auto p-2 space-y-0.5\">\n {conversations.map((conv) => (\n <button\n key={conv.id}\n onClick={() => setActiveId(conv.id)}\n className={`w-full text-left px-3 py-2 rounded-lg text-sm transition-colors ${\n activeId === conv.id\n ? \"bg-neutral-200 dark:bg-neutral-800 text-neutral-900 dark:text-white\"\n : \"text-neutral-600 dark:text-neutral-400 hover:bg-neutral-100 dark:hover:bg-neutral-800/50\"\n }`}\n >\n <p className=\"truncate\">{conv.title}</p>\n <p className=\"text-xs text-neutral-400 mt-0.5\">\n {conv.updatedAt}\n </p>\n </button>\n ))}\n </nav>\n\n <div className=\"p-4 border-t border-neutral-200 dark:border-neutral-800\">\n <div className=\"flex items-center gap-2\">\n <div className=\"w-8 h-8 rounded-full bg-neutral-200 dark:bg-neutral-700 flex items-center justify-center text-xs font-medium text-neutral-600 dark:text-neutral-300\">\n U\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-neutral-900 dark:text-white truncate\">\n User\n </p>\n <p className=\"text-xs text-neutral-500 truncate\">\n user@example.com\n </p>\n </div>\n </div>\n </div>\n </aside>\n\n {/* Chat */}\n <main className=\"flex-1 flex flex-col\">\n <Chat\n agentId=\"assistant\"\n api=\"/api/ag-ui\"\n className=\"flex-1 min-h-0\"\n placeholder=\"Message...\"\n />\n </main>\n </div>\n );\n}\n",
|
|
92
92
|
"app/layout.tsx": "import \"../globals.css\";\nimport { Head } from \"veryfront/head\";\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}): React.ReactNode {\n return (\n <>\n <Head>\n <title>AI SaaS</title>\n </Head>\n <div className=\"antialiased\">\n {children}\n </div>\n </>\n );\n}\n",
|
|
93
93
|
"app/login/page.tsx": "\"use client\";\n\n// Demo sign-in: the buttons below pass straight through to /dashboard so the\n// starter is usable out of the box. To wire up real OAuth, scaffold provider\n// routes at app/api/auth/google/route.ts and app/api/auth/github/route.ts and\n// point the hrefs there. See https://veryfront.com/docs/code/guides/oauth.\nexport default function LoginPage(): React.JSX.Element {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-neutral-50 dark:bg-neutral-950 px-4\">\n <div className=\"w-full max-w-sm\">\n <div className=\"text-center mb-8\">\n <h1 className=\"text-xl font-bold text-neutral-900 dark:text-white\">\n Welcome back\n </h1>\n <p className=\"text-sm text-neutral-500 dark:text-neutral-400 mt-1\">\n Sign in to continue\n </p>\n </div>\n\n <div className=\"bg-white dark:bg-neutral-900 rounded-2xl border border-neutral-200 dark:border-neutral-800 p-6 space-y-3\">\n <a\n href=\"/dashboard\"\n className=\"flex items-center justify-center gap-2 w-full px-4 py-2.5 border border-neutral-200 dark:border-neutral-800 rounded-xl text-sm font-medium text-neutral-700 dark:text-neutral-300 hover:bg-neutral-50 dark:hover:bg-neutral-800 transition-colors\"\n >\n <svg className=\"w-4 h-4\" viewBox=\"0 0 24 24\">\n <path\n fill=\"#4285F4\"\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.76h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"\n />\n <path\n fill=\"#34A853\"\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"\n />\n <path\n fill=\"#FBBC05\"\n d=\"M5.84 14.09a7.12 7.12 0 010-4.18V7.07H2.18A11.99 11.99 0 001 12c0 1.94.46 3.77 1.18 5.43l3.66-3.34z\"\n />\n <path\n fill=\"#EA4335\"\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"\n />\n </svg>\n Continue with Google\n </a>\n <a\n href=\"/dashboard\"\n className=\"flex items-center justify-center gap-2 w-full px-4 py-2.5 border border-neutral-200 dark:border-neutral-800 rounded-xl text-sm font-medium text-neutral-700 dark:text-neutral-300 hover:bg-neutral-50 dark:hover:bg-neutral-800 transition-colors\"\n >\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.51 11.51 0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z\" />\n </svg>\n Continue with GitHub\n </a>\n </div>\n\n <p className=\"mt-6 text-center text-xs text-neutral-400\">\n <a\n href=\"/\"\n className=\"hover:text-neutral-600 dark:hover:text-neutral-300\"\n >\n ← Back to home\n </a>\n </p>\n </div>\n </div>\n );\n}\n",
|
|
94
94
|
"app/page.tsx": "export default function LandingPage(): React.JSX.Element {\n return (\n <div className=\"min-h-screen bg-white dark:bg-neutral-950\">\n {/* Nav */}\n <nav className=\"border-b border-neutral-100 dark:border-neutral-900\">\n <div className=\"max-w-5xl mx-auto flex items-center justify-between px-6 h-14\">\n <span className=\"font-semibold text-neutral-900 dark:text-white\">\n AI SaaS\n </span>\n <div className=\"flex items-center gap-4\">\n <a\n href=\"/login\"\n className=\"text-sm text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-white transition-colors\"\n >\n Sign in\n </a>\n <a\n href=\"/login\"\n className=\"text-sm px-4 py-1.5 bg-neutral-900 dark:bg-white text-white dark:text-neutral-900 rounded-full font-medium hover:opacity-90 transition-opacity\"\n >\n Get started\n </a>\n </div>\n </div>\n </nav>\n\n {/* Hero */}\n <main className=\"max-w-5xl mx-auto px-6\">\n <div className=\"pt-24 pb-16 text-center\">\n <h1 className=\"text-4xl md:text-5xl font-bold tracking-tight text-neutral-900 dark:text-white\">\n Your AI-powered platform\n </h1>\n <p className=\"mt-4 text-lg text-neutral-500 dark:text-neutral-400 max-w-lg mx-auto\">\n Built with Veryfront. Agents, tools, and memory are ready for\n production.\n </p>\n <div className=\"mt-8 flex gap-3 justify-center\">\n <a\n href=\"/login\"\n className=\"px-6 py-2.5 bg-neutral-900 dark:bg-white text-white dark:text-neutral-900 rounded-full font-medium hover:opacity-90 transition-opacity\"\n >\n Start free\n </a>\n <a\n href=\"https://veryfront.com/docs/code/guides\"\n className=\"px-6 py-2.5 border border-neutral-200 dark:border-neutral-800 text-neutral-700 dark:text-neutral-300 rounded-full font-medium hover:bg-neutral-50 dark:hover:bg-neutral-900 transition-colors\"\n >\n Documentation\n </a>\n </div>\n </div>\n\n {/* Features */}\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6 py-16 border-t border-neutral-100 dark:border-neutral-900\">\n {[\n {\n title: \"AI Agents\",\n desc: \"Define agents with tools, memory, and streaming. Veryfront auto-discovers them from your project.\",\n },\n {\n title: \"Per-User Memory\",\n desc: \"Each user gets their own conversation history, persisted across sessions.\",\n },\n {\n title: \"Production Ready\",\n desc: \"Use auth, rate limiting, and deployment to ship to production with one command.\",\n },\n ].map(({ title, desc }) => (\n <div key={title}>\n <h3 className=\"font-medium text-neutral-900 dark:text-white\">\n {title}\n </h3>\n <p className=\"mt-1 text-sm text-neutral-500 dark:text-neutral-400\">\n {desc}\n </p>\n </div>\n ))}\n </div>\n </main>\n </div>\n );\n}\n",
|
package/esm/deno.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transpiler.d.ts","sourceRoot":"","sources":["../../../src/src/discovery/transpiler.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AA6IvD;;GAEG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"transpiler.d.ts","sourceRoot":"","sources":["../../../src/src/discovery/transpiler.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AA6IvD;;GAEG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,OAAO,CAAC,CAuGlB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
|
|
@@ -191,7 +191,12 @@ export async function importModule(file, context) {
|
|
|
191
191
|
contents: source,
|
|
192
192
|
loader,
|
|
193
193
|
resolveDir: fileDir,
|
|
194
|
-
|
|
194
|
+
// Must be a basename: esbuild joins resolveDir + sourcefile to form the
|
|
195
|
+
// entry module path when sourcefile is relative. Passing the full
|
|
196
|
+
// relative filePath (e.g. "tools/foo.ts") on VFS runs (baseDir === "")
|
|
197
|
+
// doubles the prefix to "tools/tools/foo.ts", which anchors ../ imports
|
|
198
|
+
// one directory too deep.
|
|
199
|
+
sourcefile: pathHelper.basename(filePath),
|
|
195
200
|
},
|
|
196
201
|
});
|
|
197
202
|
if (result.errors.length > 0) {
|
|
@@ -21,8 +21,6 @@ export { vectorStore } from "./vector-store.js";
|
|
|
21
21
|
export { ragStore } from "./rag-store.js";
|
|
22
22
|
export { createUploadHandler } from "./upload-handler.js";
|
|
23
23
|
export { loadUpload } from "./upload-loader.js";
|
|
24
|
-
export { useUploads } from "./react/use-uploads.js";
|
|
25
|
-
export type { UseUploadsOptions, UseUploadsResult } from "./react/use-uploads.js";
|
|
26
24
|
export { clearEmbeddingProviders, registerEmbeddingProvider, resolveEmbeddingModel, } from "./resolve.js";
|
|
27
25
|
export type { ChunkOptions, Embedding, EmbeddingConfig, RagChunk, RagDocumentMeta, RagRefreshOptions, RagSearchOptions, RagSearchResult, RagStore, RagStoreBackend, RagStoreConfig, RagStoreData, SearchOptions, SearchResult, VectorStore, VectorStoreConfig, } from "./types.js";
|
|
28
26
|
export type { UploadAuthorizationResult, UploadAuthorize, UploadHandlerAuthConfig, UploadHandlerConfig, } from "./upload-handler.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,yBAAyB,CAAC;AAGjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,gBAAgB,IAAI,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,yBAAyB,CAAC;AAGjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,gBAAgB,IAAI,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,YAAY,EACZ,SAAS,EACT,eAAe,EACf,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,eAAe,EACf,cAAc,EACd,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,yBAAyB,EACzB,eAAe,EACf,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC"}
|
|
@@ -21,5 +21,4 @@ export { vectorStore } from "./vector-store.js";
|
|
|
21
21
|
export { ragStore } from "./rag-store.js";
|
|
22
22
|
export { createUploadHandler } from "./upload-handler.js";
|
|
23
23
|
export { loadUpload } from "./upload-loader.js";
|
|
24
|
-
export { useUploads } from "./react/use-uploads.js";
|
|
25
24
|
export { clearEmbeddingProviders, registerEmbeddingProvider, resolveEmbeddingModel, } from "./resolve.js";
|
|
@@ -25,7 +25,7 @@ export interface UploadHandlerConfig {
|
|
|
25
25
|
* `loadUpload`, and ingests into the provided RAG store. When Veryfront Cloud
|
|
26
26
|
* bootstrap is present, the original binary is also stored in the project's
|
|
27
27
|
* uploads store via the cloud adapter. GET returns the upload list. DELETE
|
|
28
|
-
* removes an upload by ID from route params.
|
|
28
|
+
* removes an upload by ID from the `id` query parameter or route params.
|
|
29
29
|
*
|
|
30
30
|
* @example
|
|
31
31
|
* ```ts
|
|
@@ -34,7 +34,7 @@ export interface UploadHandlerConfig {
|
|
|
34
34
|
* import { getEnv } from "veryfront";
|
|
35
35
|
* import { store } from "lib/store.ts";
|
|
36
36
|
*
|
|
37
|
-
* export const { POST, GET } = createUploadHandler(store, {
|
|
37
|
+
* export const { POST, GET, DELETE } = createUploadHandler(store, {
|
|
38
38
|
* auth: {
|
|
39
39
|
* authorize: (request) => {
|
|
40
40
|
* const token = getEnv("UPLOAD_TOKEN");
|
|
@@ -44,17 +44,6 @@ export interface UploadHandlerConfig {
|
|
|
44
44
|
* },
|
|
45
45
|
* });
|
|
46
46
|
* ```
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* ```ts
|
|
50
|
-
* // app/api/uploads/[id]/route.ts
|
|
51
|
-
* import { createUploadHandler } from "veryfront/embedding";
|
|
52
|
-
* import { store } from "lib/store.ts";
|
|
53
|
-
*
|
|
54
|
-
* export const { DELETE } = createUploadHandler(store, {
|
|
55
|
-
* auth: { type: "none", allowUnauthenticated: true },
|
|
56
|
-
* });
|
|
57
|
-
* ```
|
|
58
47
|
*/
|
|
59
48
|
export declare function createUploadHandler(store: RagStore, config?: UploadHandlerConfig): {
|
|
60
49
|
POST: (request: Request) => Promise<Response>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-handler.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/upload-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"upload-handler.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/upload-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAmB,QAAQ,EAAE,MAAM,YAAY,CAAC;AAqF5D,MAAM,MAAM,yBAAyB,GAAG,OAAO,GAAG,QAAQ,GAAG,IAAI,GAAG,SAAS,CAAC;AAE9E,MAAM,MAAM,eAAe,GAAG,CAC5B,OAAO,EAAE,OAAO,KACb,yBAAyB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;AAEpE,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,oBAAoB,EAAE,IAAI,CAAA;CAAE,GAC5C;IAAE,SAAS,EAAE,eAAe,CAAA;CAAE,CAAC;AAEnC,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,uBAAuB,CAAC;CAChC;AAuHD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,QAAQ,EACf,MAAM,CAAC,EAAE,mBAAmB;oBAKC,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;oBAmF3B,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;sBAc7C,OAAO,WACP;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,KAC1C,OAAO,CAAC,QAAQ,CAAC;EA6BrB"}
|
|
@@ -145,6 +145,22 @@ function getSourceBlobStorage() {
|
|
|
145
145
|
? new VeryfrontCloudBlobStorage({ prefix: CLOUD_UPLOAD_PREFIX })
|
|
146
146
|
: null;
|
|
147
147
|
}
|
|
148
|
+
function toUploadRegistryItem(upload) {
|
|
149
|
+
return {
|
|
150
|
+
id: upload.id,
|
|
151
|
+
name: upload.title,
|
|
152
|
+
mediaType: typeToMime(upload.type),
|
|
153
|
+
size: 0,
|
|
154
|
+
...(upload.url ? { url: upload.url } : {}),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function resolveDeleteId(request, context) {
|
|
158
|
+
const fromParams = context.params.id;
|
|
159
|
+
if (fromParams)
|
|
160
|
+
return fromParams;
|
|
161
|
+
const fromQuery = new URL(request.url).searchParams.get("id");
|
|
162
|
+
return fromQuery ?? "";
|
|
163
|
+
}
|
|
148
164
|
/**
|
|
149
165
|
* Creates HTTP route handlers for upload, listing, and deletion.
|
|
150
166
|
*
|
|
@@ -159,7 +175,7 @@ function getSourceBlobStorage() {
|
|
|
159
175
|
* `loadUpload`, and ingests into the provided RAG store. When Veryfront Cloud
|
|
160
176
|
* bootstrap is present, the original binary is also stored in the project's
|
|
161
177
|
* uploads store via the cloud adapter. GET returns the upload list. DELETE
|
|
162
|
-
* removes an upload by ID from route params.
|
|
178
|
+
* removes an upload by ID from the `id` query parameter or route params.
|
|
163
179
|
*
|
|
164
180
|
* @example
|
|
165
181
|
* ```ts
|
|
@@ -168,7 +184,7 @@ function getSourceBlobStorage() {
|
|
|
168
184
|
* import { getEnv } from "veryfront";
|
|
169
185
|
* import { store } from "lib/store.ts";
|
|
170
186
|
*
|
|
171
|
-
* export const { POST, GET } = createUploadHandler(store, {
|
|
187
|
+
* export const { POST, GET, DELETE } = createUploadHandler(store, {
|
|
172
188
|
* auth: {
|
|
173
189
|
* authorize: (request) => {
|
|
174
190
|
* const token = getEnv("UPLOAD_TOKEN");
|
|
@@ -178,17 +194,6 @@ function getSourceBlobStorage() {
|
|
|
178
194
|
* },
|
|
179
195
|
* });
|
|
180
196
|
* ```
|
|
181
|
-
*
|
|
182
|
-
* @example
|
|
183
|
-
* ```ts
|
|
184
|
-
* // app/api/uploads/[id]/route.ts
|
|
185
|
-
* import { createUploadHandler } from "veryfront/embedding";
|
|
186
|
-
* import { store } from "lib/store.ts";
|
|
187
|
-
*
|
|
188
|
-
* export const { DELETE } = createUploadHandler(store, {
|
|
189
|
-
* auth: { type: "none", allowUnauthenticated: true },
|
|
190
|
-
* });
|
|
191
|
-
* ```
|
|
192
197
|
*/
|
|
193
198
|
export function createUploadHandler(store, config) {
|
|
194
199
|
const maxSize = config?.maxFileSize ?? MAX_FILE_SIZE;
|
|
@@ -247,8 +252,10 @@ export function createUploadHandler(store, config) {
|
|
|
247
252
|
}
|
|
248
253
|
}
|
|
249
254
|
return Response.json({
|
|
250
|
-
|
|
251
|
-
|
|
255
|
+
id,
|
|
256
|
+
name: safeName,
|
|
257
|
+
mediaType: file.type || typeToMime(fileType),
|
|
258
|
+
size: file.size,
|
|
252
259
|
});
|
|
253
260
|
}
|
|
254
261
|
catch (error) {
|
|
@@ -262,7 +269,7 @@ export function createUploadHandler(store, config) {
|
|
|
262
269
|
if (unauthorized)
|
|
263
270
|
return unauthorized;
|
|
264
271
|
const uploads = await enrichUploadsWithSourceUrls(await store.listDocuments());
|
|
265
|
-
return Response.json({ uploads });
|
|
272
|
+
return Response.json({ items: uploads.map(toUploadRegistryItem) });
|
|
266
273
|
}
|
|
267
274
|
catch (error) {
|
|
268
275
|
serverLogger.error("Upload list failed:", error);
|
|
@@ -274,7 +281,7 @@ export function createUploadHandler(store, config) {
|
|
|
274
281
|
const unauthorized = await authorizeUploadRequest(request, authorize);
|
|
275
282
|
if (unauthorized)
|
|
276
283
|
return unauthorized;
|
|
277
|
-
const id = context
|
|
284
|
+
const id = resolveDeleteId(request, context);
|
|
278
285
|
if (!id) {
|
|
279
286
|
return Response.json({ error: "Missing upload ID" }, { status: 400 });
|
|
280
287
|
}
|
|
@@ -5,6 +5,7 @@ import { type AgentRunSessionManager } from "./session-manager.js";
|
|
|
5
5
|
import type { RuntimeRunAgentInput } from "./schema.js";
|
|
6
6
|
export interface RuntimeAgentStreamExecutionDeps {
|
|
7
7
|
sessionManager: AgentRunSessionManager;
|
|
8
|
+
localTools?: Record<string, Tool | boolean>;
|
|
8
9
|
projectAgentSandbox?: {
|
|
9
10
|
apiUrl?: string;
|
|
10
11
|
authToken?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/run-stream.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,KAAK,EACV,KAAK,YAAY,IAAI,OAAO,EAC5B,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAC;AAQ3B,OAAO,KAAK,EACV,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAmB,KAAK,IAAI,EAAgB,MAAM,kBAAkB,CAAC;AAU5E,OAAO,EAA0B,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAsCxD,MAAM,WAAW,+BAA+B;IAC9C,cAAc,EAAE,sBAAsB,CAAC;IACvC,mBAAmB,CAAC,EAAE;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,cAAc,CAAC,EAAE,+BAA+B,CAAC,gBAAgB,CAAC,CAAC;IACnE,8BAA8B,CAAC,EAAE,CAC/B,KAAK,EAAE,+BAA+B,KACnC,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC7C,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAClC;QACH,MAAM,EAAE,CACN,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;YACV,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;SAC9C,EACD,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,CAAC,EAAE,MAAM,EAChC,WAAW,CAAC,EAAE,WAAW,KACtB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;KAC1C,CAAC;CACH;AAoCD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,oBAAoB,EAC3B,cAAc,EAAE,sBAAsB,EACtC,2BAA2B,CAAC,EAAE,MAAM,EAAE,EACtC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;;cAsFrD;AA2KD,wBAAsB,gCAAgC,CACpD,KAAK,EAAE,oBAAoB,EAC3B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,+BAA+B,GACpC,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/run-stream.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,KAAK,EACV,KAAK,YAAY,IAAI,OAAO,EAC5B,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAC;AAQ3B,OAAO,KAAK,EACV,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAmB,KAAK,IAAI,EAAgB,MAAM,kBAAkB,CAAC;AAU5E,OAAO,EAA0B,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAsCxD,MAAM,WAAW,+BAA+B;IAC9C,cAAc,EAAE,sBAAsB,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC;IAC5C,mBAAmB,CAAC,EAAE;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,cAAc,CAAC,EAAE,+BAA+B,CAAC,gBAAgB,CAAC,CAAC;IACnE,8BAA8B,CAAC,EAAE,CAC/B,KAAK,EAAE,+BAA+B,KACnC,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC7C,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAClC;QACH,MAAM,EAAE,CACN,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;YACV,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;SAC9C,EACD,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,CAAC,EAAE,MAAM,EAChC,WAAW,CAAC,EAAE,WAAW,KACtB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;KAC1C,CAAC;CACH;AAoCD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,oBAAoB,EAC3B,cAAc,EAAE,sBAAsB,EACtC,2BAA2B,CAAC,EAAE,MAAM,EAAE,EACtC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;;cAsFrD;AA2KD,wBAAsB,gCAAgC,CACpD,KAAK,EAAE,oBAAoB,EAC3B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,+BAA+B,GACpC,OAAO,CAAC,QAAQ,CAAC,CAkUnB"}
|
|
@@ -263,7 +263,11 @@ export async function createRuntimeAgentStreamResponse(input, agent, deps) {
|
|
|
263
263
|
const forwardedIntegrationToolDefs = getForwardedIntegrationToolDefinitions(input.forwardedProps);
|
|
264
264
|
const availableForwardedToolNames = forwardedIntegrationToolDefs?.map((tool) => tool.name);
|
|
265
265
|
const sandboxTools = await buildProjectAgentSandboxTools({ agent, deps });
|
|
266
|
-
const
|
|
266
|
+
const availableLocalTools = {
|
|
267
|
+
...(deps.localTools ?? {}),
|
|
268
|
+
...(sandboxTools.tools ?? {}),
|
|
269
|
+
};
|
|
270
|
+
const mergedTools = buildMergedTools(agent, input, deps.sessionManager, availableForwardedToolNames, Object.keys(availableLocalTools).length > 0 ? availableLocalTools : undefined);
|
|
267
271
|
const runtimeAgent = {
|
|
268
272
|
...agent,
|
|
269
273
|
config: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-import-map.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/import-map/default-import-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"default-import-map.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/import-map/default-import-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAmDlD,wBAAgB,mBAAmB,IAAI,eAAe,CAIrD"}
|
|
@@ -25,10 +25,6 @@ function getVeryfrontSsrImportMap() {
|
|
|
25
25
|
const workflowReact = `${base}/workflow/react/index.js${ssr}`;
|
|
26
26
|
// veryfront/react is a barrel that re-exports all browser-side modules.
|
|
27
27
|
const react = `${base}/react/public.js${ssr}`;
|
|
28
|
-
// Map veryfront/embedding to the React hooks submodule for SSR.
|
|
29
|
-
// The full embedding/index.ts imports heavy server-side code (vectorStore, ragStore)
|
|
30
|
-
// that fails to transform. SSR only needs the React hook (useUploads).
|
|
31
|
-
const embedding = `${base}/embedding/react/index.js${ssr}`;
|
|
32
28
|
return {
|
|
33
29
|
"veryfront/react": react,
|
|
34
30
|
"veryfront/head": head,
|
|
@@ -38,7 +34,6 @@ function getVeryfrontSsrImportMap() {
|
|
|
38
34
|
"veryfront/markdown": markdown,
|
|
39
35
|
"veryfront/chat": chat,
|
|
40
36
|
"veryfront/mdx": mdx,
|
|
41
|
-
"veryfront/embedding": embedding,
|
|
42
37
|
"veryfront/workflow": workflowReact,
|
|
43
38
|
"veryfront/react/head": head,
|
|
44
39
|
"veryfront/react/router": router,
|
|
@@ -5,6 +5,7 @@ import { BaseHandler } from "../response/base.js";
|
|
|
5
5
|
import type { HandlerContext, HandlerMetadata, HandlerResult } from "../types.js";
|
|
6
6
|
export interface AgentStreamHandlerDeps extends RuntimeAgentDiscoveryDeps, RuntimeAgentStreamExecutionDeps {
|
|
7
7
|
resolveRuntimeOwnerInvokeUrl?: typeof resolveRuntimeOwnerInvokeUrl;
|
|
8
|
+
getLocalTools?: (agentId: string) => RuntimeAgentStreamExecutionDeps["localTools"];
|
|
8
9
|
}
|
|
9
10
|
export declare class AgentStreamHandler extends BaseHandler {
|
|
10
11
|
private readonly deps;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-stream.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/agent-stream.handler.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-stream.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/agent-stream.handler.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAEpF,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,wCAAwC,CAAC;AAQhD,OAAO,EACL,4BAA4B,EAE7B,MAAM,2CAA2C,CAAC;AAyBnD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAanG,MAAM,WAAW,sBACf,SAAQ,yBAAyB,EAAE,+BAA+B;IAClE,4BAA4B,CAAC,EAAE,OAAO,4BAA4B,CAAC;IACnE,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,+BAA+B,CAAC,YAAY,CAAC,CAAC;CACpF;AAofD,qBAAa,kBAAmB,SAAQ,WAAW;IASrC,OAAO,CAAC,QAAQ,CAAC,IAAI;IARjC,QAAQ,EAAE,eAAe,CAMvB;gBAE2B,IAAI,GAAE,sBAAoC;IAIvE,OAAO,CAAC,sBAAsB;IAwBxB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CA4LxE"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createRemoteMCPToolSource, toolRegistry, } from "../../../tool/index.js";
|
|
2
2
|
import { defaultChannelInvokeDeps } from "../../../channels/invoke.js";
|
|
3
|
+
import { getDiscoveredHostTools } from "../../../agent/hosted/veryfront-cloud-agent-service.js";
|
|
3
4
|
import { createRuntimeAgentStreamResponse, } from "../../../internal-agents/run-stream.js";
|
|
4
5
|
import { createRuntimeAgentFromMarkdownDefinition } from "../../../agent/runtime/agent-markdown-adapter.js";
|
|
5
6
|
import { buildStudioMcpHeaders } from "../../../agent/project/live-studio-mcp-tools.js";
|
|
@@ -21,6 +22,7 @@ const defaultDeps = {
|
|
|
21
22
|
...defaultChannelInvokeDeps,
|
|
22
23
|
sessionManager: agentRunSessionManager,
|
|
23
24
|
resolveRuntimeOwnerInvokeUrl,
|
|
25
|
+
getLocalTools: (agentId) => getDiscoveredHostTools({ agentId }),
|
|
24
26
|
};
|
|
25
27
|
const logger = serverLogger.component("agent-stream-handler");
|
|
26
28
|
const RUN_STREAM_PATH_REGEX = /^\/api\/control-plane\/runs\/([^/]+)\/stream$/;
|
|
@@ -450,6 +452,7 @@ export class AgentStreamHandler extends BaseHandler {
|
|
|
450
452
|
? createRuntimeAgentFromMarkdownDefinition(payload.agentConfig)
|
|
451
453
|
: agent;
|
|
452
454
|
const runtimeInput = sanitizeRuntimeRunAgentInput(toRuntimeRunAgentInput(payload));
|
|
455
|
+
const localTools = this.deps.getLocalTools?.(runtimeBaseAgent.id);
|
|
453
456
|
const apiAuthToken = payload.credentials?.authToken || ctx.proxyToken ||
|
|
454
457
|
getHostEnv("VERYFRONT_API_TOKEN") || "";
|
|
455
458
|
const platformRuntimeAgent = await withVeryfrontPlatformRemoteTools({
|
|
@@ -486,6 +489,7 @@ export class AgentStreamHandler extends BaseHandler {
|
|
|
486
489
|
}
|
|
487
490
|
const runAgentStream = () => createRuntimeAgentStreamResponse(runtimeInput, runtimeAgent, {
|
|
488
491
|
...this.deps,
|
|
492
|
+
localTools,
|
|
489
493
|
projectAgentSandbox: {
|
|
490
494
|
apiUrl: getHostEnv("VERYFRONT_API_URL") ?? "https://api.veryfront.com",
|
|
491
495
|
authToken: apiAuthToken || undefined,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-constant.d.ts","sourceRoot":"","sources":["../../../src/src/utils/version-constant.ts"],"names":[],"mappings":"AAEA,4BAA4B;AAC5B,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"version-constant.d.ts","sourceRoot":"","sources":["../../../src/src/utils/version-constant.ts"],"names":[],"mappings":"AAEA,4BAA4B;AAC5B,eAAO,MAAM,OAAO,aAAa,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useUploads Hook
|
|
3
|
-
*
|
|
4
|
-
* Manages upload, deletion, and listing for RAG applications.
|
|
5
|
-
* Pairs with `createUploadHandler` on the server side.
|
|
6
|
-
*/
|
|
7
|
-
import type { RagDocumentMeta } from "../types.js";
|
|
8
|
-
/** Options accepted by use uploads. */
|
|
9
|
-
export interface UseUploadsOptions {
|
|
10
|
-
/** API endpoint, e.g. "/API/uploads" */
|
|
11
|
-
api: string;
|
|
12
|
-
}
|
|
13
|
-
/** Result returned from use uploads. */
|
|
14
|
-
export interface UseUploadsResult {
|
|
15
|
-
/** All uploads from the server */
|
|
16
|
-
uploads: RagDocumentMeta[];
|
|
17
|
-
/** True while an upload is in progress */
|
|
18
|
-
uploading: boolean;
|
|
19
|
-
/** User-facing error message, cleared on next action */
|
|
20
|
-
error: string | null;
|
|
21
|
-
/** Upload a file (multipart POST) */
|
|
22
|
-
upload: (file: File) => Promise<void>;
|
|
23
|
-
/** Delete an upload by ID */
|
|
24
|
-
remove: (id: string) => Promise<void>;
|
|
25
|
-
/** Re-fetch the upload list */
|
|
26
|
-
refresh: () => Promise<void>;
|
|
27
|
-
}
|
|
28
|
-
export declare function buildUploadResourceUrl(api: string, id: string): string;
|
|
29
|
-
/**
|
|
30
|
-
* useUploads hook for managing RAG upload lifecycle.
|
|
31
|
-
*/
|
|
32
|
-
export declare function useUploads(options: UseUploadsOptions): UseUploadsResult;
|
|
33
|
-
//# sourceMappingURL=use-uploads.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-uploads.d.ts","sourceRoot":"","sources":["../../../../src/src/embedding/react/use-uploads.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD,uCAAuC;AACvC,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wCAAwC;AACxC,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,0CAA0C;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qCAAqC;IACrC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,6BAA6B;IAC7B,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,+BAA+B;IAC/B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAmEvE"}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useUploads Hook
|
|
3
|
-
*
|
|
4
|
-
* Manages upload, deletion, and listing for RAG applications.
|
|
5
|
-
* Pairs with `createUploadHandler` on the server side.
|
|
6
|
-
*/
|
|
7
|
-
import { useCallback, useEffect, useRef, useState } from "../../../react/react.js";
|
|
8
|
-
import { API_ERROR } from "../../errors/index.js";
|
|
9
|
-
export function buildUploadResourceUrl(api, id) {
|
|
10
|
-
return `${api}/${encodeURIComponent(id)}`;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* useUploads hook for managing RAG upload lifecycle.
|
|
14
|
-
*/
|
|
15
|
-
export function useUploads(options) {
|
|
16
|
-
const [uploads, setUploads] = useState([]);
|
|
17
|
-
const [uploading, setUploading] = useState(false);
|
|
18
|
-
const [error, setError] = useState(null);
|
|
19
|
-
const abortControllerRef = useRef(null);
|
|
20
|
-
const refresh = useCallback(async () => {
|
|
21
|
-
try {
|
|
22
|
-
const res = await fetch(options.api);
|
|
23
|
-
if (!res.ok)
|
|
24
|
-
return;
|
|
25
|
-
const data = await res.json();
|
|
26
|
-
setUploads(data.uploads ?? []);
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
console.debug("useUploads: failed to load uploads", error);
|
|
30
|
-
setError("Failed to load uploads");
|
|
31
|
-
}
|
|
32
|
-
}, [options.api]);
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
refresh();
|
|
35
|
-
}, [refresh]);
|
|
36
|
-
const upload = useCallback(async (file) => {
|
|
37
|
-
setError(null);
|
|
38
|
-
setUploading(true);
|
|
39
|
-
const abortController = new AbortController();
|
|
40
|
-
abortControllerRef.current = abortController;
|
|
41
|
-
try {
|
|
42
|
-
const formData = new FormData();
|
|
43
|
-
formData.append("file", file);
|
|
44
|
-
const res = await fetch(options.api, {
|
|
45
|
-
method: "POST",
|
|
46
|
-
body: formData,
|
|
47
|
-
signal: abortController.signal,
|
|
48
|
-
});
|
|
49
|
-
const data = await res.json();
|
|
50
|
-
if (!res.ok)
|
|
51
|
-
throw API_ERROR.create({ detail: data.error ?? "Upload failed" });
|
|
52
|
-
await refresh();
|
|
53
|
-
}
|
|
54
|
-
catch (err) {
|
|
55
|
-
if (err instanceof Error && err.name === "AbortError")
|
|
56
|
-
return;
|
|
57
|
-
setError(err instanceof Error ? err.message : "Upload failed");
|
|
58
|
-
}
|
|
59
|
-
finally {
|
|
60
|
-
setUploading(false);
|
|
61
|
-
abortControllerRef.current = null;
|
|
62
|
-
}
|
|
63
|
-
}, [options.api, refresh]);
|
|
64
|
-
const remove = useCallback(async (id) => {
|
|
65
|
-
setError(null);
|
|
66
|
-
try {
|
|
67
|
-
await fetch(buildUploadResourceUrl(options.api, id), { method: "DELETE" });
|
|
68
|
-
await refresh();
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
console.debug("useUploads: failed to delete upload", error);
|
|
72
|
-
setError("Failed to delete upload");
|
|
73
|
-
}
|
|
74
|
-
}, [options.api, refresh]);
|
|
75
|
-
return { uploads, uploading, error, upload, remove, refresh };
|
|
76
|
-
}
|