@truefoundry/trueforge 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/dist/_frontend/assets/{ConnectorSettings-H37ZFC6Z-BoDzRBt-.js → ConnectorSettings-4CYGRWPH-EWp5lwOt.js} +1 -1
- package/dist/_frontend/assets/ConnectorSettings-4CYGRWPH-EWp5lwOt.js.br +0 -0
- package/dist/_frontend/assets/ConnectorSettings-4CYGRWPH-EWp5lwOt.js.gz +0 -0
- package/dist/_frontend/assets/{DockLayout-KEMFRWIR-2H2_fGVk.js → DockLayout-FEDQX2UT-DbN-pvPO.js} +1 -1
- package/dist/_frontend/assets/{DrawerLayout-ZVWCKEIS-DFGUqK6q.js → DrawerLayout-NMA7P64K-0IGRaUAW.js} +2 -2
- package/dist/_frontend/assets/DrawerLayout-NMA7P64K-0IGRaUAW.js.br +0 -0
- package/dist/_frontend/assets/DrawerLayout-NMA7P64K-0IGRaUAW.js.gz +0 -0
- package/dist/_frontend/assets/{ModelSettings-QJMYHCMD-DaR_pzAb.js → ModelSettings-H5FKRZLK-CEQWPDWn.js} +1 -1
- package/dist/_frontend/assets/ModelSettings-H5FKRZLK-CEQWPDWn.js.br +0 -0
- package/dist/_frontend/assets/ModelSettings-H5FKRZLK-CEQWPDWn.js.gz +0 -0
- package/dist/_frontend/assets/{SandboxSettings-BUBMLW7Q-ChiNe2Y8.js → SandboxSettings-CBSC3C3G-PWbj0tIQ.js} +1 -1
- package/dist/_frontend/assets/SandboxSettings-CBSC3C3G-PWbj0tIQ.js.br +0 -0
- package/dist/_frontend/assets/SandboxSettings-CBSC3C3G-PWbj0tIQ.js.gz +0 -0
- package/dist/_frontend/assets/SettingsBuilder-EGSH7BUA-Cvx-hLzU.js +2 -0
- package/dist/_frontend/assets/SettingsBuilder-EGSH7BUA-Cvx-hLzU.js.br +0 -0
- package/dist/_frontend/assets/SettingsBuilder-EGSH7BUA-Cvx-hLzU.js.gz +0 -0
- package/dist/_frontend/assets/ShellRouteSync-53FTXNZZ-BIksLzSL.js +1 -0
- package/dist/_frontend/assets/ShellRouteSync-53FTXNZZ-BIksLzSL.js.br +0 -0
- package/dist/_frontend/assets/ShellRouteSync-53FTXNZZ-BIksLzSL.js.gz +0 -0
- package/dist/_frontend/assets/{SidebarLayout-F3XFXW7B-BQV8bkzL.js → SidebarLayout-5WM2BHZG-Ceb_9WvC.js} +2 -2
- package/dist/_frontend/assets/SidebarLayout-5WM2BHZG-Ceb_9WvC.js.br +0 -0
- package/dist/_frontend/assets/SidebarLayout-5WM2BHZG-Ceb_9WvC.js.gz +0 -0
- package/dist/_frontend/assets/{SkillSettings-IRMGDFRG-ChKre3S8.js → SkillSettings-A2OQSQUT-C-AShr7L.js} +1 -1
- package/dist/_frontend/assets/SkillSettings-A2OQSQUT-C-AShr7L.js.br +0 -0
- package/dist/_frontend/assets/SkillSettings-A2OQSQUT-C-AShr7L.js.gz +0 -0
- package/dist/_frontend/assets/TrueForgeUIWithRouter-2AQ3HW6L-DexVXzlD.js +1 -0
- package/dist/_frontend/assets/{WidgetLayout-SZMABKIR-BRKArpEm.js → WidgetLayout-IKGVAZFV-Q2dDfnNQ.js} +1 -1
- package/dist/_frontend/assets/WidgetLayout-IKGVAZFV-Q2dDfnNQ.js.br +0 -0
- package/dist/_frontend/assets/WidgetLayout-IKGVAZFV-Q2dDfnNQ.js.gz +0 -0
- package/dist/_frontend/assets/{chunk-7EEOWDLE-BIwInB6G.js → chunk-4STVL6W6-DO6mK5-E.js} +2 -2
- package/dist/_frontend/assets/chunk-4STVL6W6-DO6mK5-E.js.br +0 -0
- package/dist/_frontend/assets/chunk-4STVL6W6-DO6mK5-E.js.gz +0 -0
- package/dist/_frontend/assets/chunk-62JRHF6Z-BpHQergm.js +12 -0
- package/dist/_frontend/assets/chunk-62JRHF6Z-BpHQergm.js.br +0 -0
- package/dist/_frontend/assets/chunk-62JRHF6Z-BpHQergm.js.gz +0 -0
- package/dist/_frontend/assets/chunk-BMLCISMH-BtIzChti.js +4 -0
- package/dist/_frontend/assets/chunk-BMLCISMH-BtIzChti.js.br +0 -0
- package/dist/_frontend/assets/chunk-BMLCISMH-BtIzChti.js.gz +0 -0
- package/dist/_frontend/assets/{cssMode-Bb1lR8Ti.js → cssMode-tBxiXBbi.js} +1 -1
- package/dist/_frontend/assets/cssMode-tBxiXBbi.js.br +0 -0
- package/dist/_frontend/assets/cssMode-tBxiXBbi.js.gz +0 -0
- package/dist/_frontend/assets/{freemarker2-BrrF7mKG.js → freemarker2-C8-_g6KH.js} +1 -1
- package/dist/_frontend/assets/freemarker2-C8-_g6KH.js.br +0 -0
- package/dist/_frontend/assets/freemarker2-C8-_g6KH.js.gz +0 -0
- package/dist/_frontend/assets/{handlebars-WQ7HMT1b.js → handlebars-CVTAyJx2.js} +1 -1
- package/dist/_frontend/assets/handlebars-CVTAyJx2.js.br +0 -0
- package/dist/_frontend/assets/handlebars-CVTAyJx2.js.gz +0 -0
- package/dist/_frontend/assets/{html-CoOPnhCb.js → html-CFO-PVK6.js} +1 -1
- package/dist/_frontend/assets/html-CFO-PVK6.js.br +0 -0
- package/dist/_frontend/assets/html-CFO-PVK6.js.gz +0 -0
- package/dist/_frontend/assets/{htmlMode-BW7taYty.js → htmlMode-CFCanlO-.js} +1 -1
- package/dist/_frontend/assets/htmlMode-CFCanlO-.js.br +0 -0
- package/dist/_frontend/assets/htmlMode-CFCanlO-.js.gz +0 -0
- package/dist/_frontend/assets/{index-DFQqb6R1.js → index-BIWWiCC7.js} +3 -3
- package/dist/_frontend/assets/index-BIWWiCC7.js.br +0 -0
- package/dist/_frontend/assets/index-BIWWiCC7.js.gz +0 -0
- package/dist/_frontend/assets/{index-ChCGltYc.js → index-CSSyjy0I.js} +262 -265
- package/dist/_frontend/assets/index-CSSyjy0I.js.br +0 -0
- package/dist/_frontend/assets/index-CSSyjy0I.js.gz +0 -0
- package/dist/_frontend/assets/{javascript-CPINtbIt.js → javascript-MIQGaM22.js} +1 -1
- package/dist/_frontend/assets/{jsonMode-C8qDzOfb.js → jsonMode-D5gVPPeB.js} +1 -1
- package/dist/_frontend/assets/jsonMode-D5gVPPeB.js.br +0 -0
- package/dist/_frontend/assets/jsonMode-D5gVPPeB.js.gz +0 -0
- package/dist/_frontend/assets/{liquid-zGC9H1Dt.js → liquid-DHNaEubO.js} +1 -1
- package/dist/_frontend/assets/liquid-DHNaEubO.js.br +0 -0
- package/dist/_frontend/assets/liquid-DHNaEubO.js.gz +0 -0
- package/dist/_frontend/assets/{lspLanguageFeatures-B6VPH2Sv.js → lspLanguageFeatures-QCSfugnT.js} +1 -1
- package/dist/_frontend/assets/lspLanguageFeatures-QCSfugnT.js.br +0 -0
- package/dist/_frontend/assets/lspLanguageFeatures-QCSfugnT.js.gz +0 -0
- package/dist/_frontend/assets/{mdx-BrQrGCP9.js → mdx-BXTfxgKC.js} +1 -1
- package/dist/_frontend/assets/mdx-BXTfxgKC.js.br +0 -0
- package/dist/_frontend/assets/mdx-BXTfxgKC.js.gz +0 -0
- package/dist/_frontend/assets/{python-zKGpYLwR.js → python-2xJ5-a_I.js} +1 -1
- package/dist/_frontend/assets/python-2xJ5-a_I.js.br +0 -0
- package/dist/_frontend/assets/python-2xJ5-a_I.js.gz +0 -0
- package/dist/_frontend/assets/{razor-BJ38lYsd.js → razor-pc2nnHiH.js} +1 -1
- package/dist/_frontend/assets/razor-pc2nnHiH.js.br +0 -0
- package/dist/_frontend/assets/razor-pc2nnHiH.js.gz +0 -0
- package/dist/_frontend/assets/{tsMode-dPLqGMg8.js → tsMode-DDOTqjiA.js} +1 -1
- package/dist/_frontend/assets/tsMode-DDOTqjiA.js.br +0 -0
- package/dist/_frontend/assets/tsMode-DDOTqjiA.js.gz +0 -0
- package/dist/_frontend/assets/{typescript-BJlivWry.js → typescript-B8kVUDuw.js} +1 -1
- package/dist/_frontend/assets/typescript-B8kVUDuw.js.br +0 -0
- package/dist/_frontend/assets/typescript-B8kVUDuw.js.gz +0 -0
- package/dist/_frontend/assets/{workers-fMwav4jB.js → workers-BKOSx8Az.js} +1 -1
- package/dist/_frontend/assets/workers-BKOSx8Az.js.br +0 -0
- package/dist/_frontend/assets/workers-BKOSx8Az.js.gz +0 -0
- package/dist/_frontend/assets/{xml-DZW470wi.js → xml--HuG4XfW.js} +1 -1
- package/dist/_frontend/assets/xml--HuG4XfW.js.br +0 -0
- package/dist/_frontend/assets/xml--HuG4XfW.js.gz +0 -0
- package/dist/_frontend/assets/{yaml-Bs1DumYp.js → yaml-BM2qwYh9.js} +1 -1
- package/dist/_frontend/assets/yaml-BM2qwYh9.js.br +0 -0
- package/dist/_frontend/assets/yaml-BM2qwYh9.js.gz +0 -0
- package/dist/_frontend/index.html +1 -1
- package/dist/_frontend/index.html.br +0 -0
- package/dist/_frontend/index.html.gz +0 -0
- package/dist/cli.js +23 -1
- package/dist/cli.js.map +1 -1
- package/dist/main.js +388 -77
- package/dist/main.js.map +1 -1
- package/package.json +11 -7
- package/dist/_frontend/assets/ConnectorSettings-H37ZFC6Z-BoDzRBt-.js.br +0 -0
- package/dist/_frontend/assets/ConnectorSettings-H37ZFC6Z-BoDzRBt-.js.gz +0 -0
- package/dist/_frontend/assets/DrawerLayout-ZVWCKEIS-DFGUqK6q.js.br +0 -0
- package/dist/_frontend/assets/DrawerLayout-ZVWCKEIS-DFGUqK6q.js.gz +0 -0
- package/dist/_frontend/assets/ModelSettings-QJMYHCMD-DaR_pzAb.js.br +0 -0
- package/dist/_frontend/assets/ModelSettings-QJMYHCMD-DaR_pzAb.js.gz +0 -0
- package/dist/_frontend/assets/SandboxSettings-BUBMLW7Q-ChiNe2Y8.js.br +0 -0
- package/dist/_frontend/assets/SandboxSettings-BUBMLW7Q-ChiNe2Y8.js.gz +0 -0
- package/dist/_frontend/assets/SettingsBuilder-26XSGIHK-DmgjXL0m.js +0 -2
- package/dist/_frontend/assets/SettingsBuilder-26XSGIHK-DmgjXL0m.js.br +0 -0
- package/dist/_frontend/assets/SettingsBuilder-26XSGIHK-DmgjXL0m.js.gz +0 -0
- package/dist/_frontend/assets/SidebarLayout-F3XFXW7B-BQV8bkzL.js.br +0 -0
- package/dist/_frontend/assets/SidebarLayout-F3XFXW7B-BQV8bkzL.js.gz +0 -0
- package/dist/_frontend/assets/SkillSettings-IRMGDFRG-ChKre3S8.js.br +0 -0
- package/dist/_frontend/assets/SkillSettings-IRMGDFRG-ChKre3S8.js.gz +0 -0
- package/dist/_frontend/assets/WidgetLayout-SZMABKIR-BRKArpEm.js.br +0 -0
- package/dist/_frontend/assets/WidgetLayout-SZMABKIR-BRKArpEm.js.gz +0 -0
- package/dist/_frontend/assets/chunk-7EEOWDLE-BIwInB6G.js.br +0 -0
- package/dist/_frontend/assets/chunk-7EEOWDLE-BIwInB6G.js.gz +0 -0
- package/dist/_frontend/assets/chunk-LRQHHZDX-eb14Z2nA.js +0 -1
- package/dist/_frontend/assets/chunk-LRQHHZDX-eb14Z2nA.js.br +0 -0
- package/dist/_frontend/assets/chunk-LRQHHZDX-eb14Z2nA.js.gz +0 -0
- package/dist/_frontend/assets/cssMode-Bb1lR8Ti.js.br +0 -0
- package/dist/_frontend/assets/cssMode-Bb1lR8Ti.js.gz +0 -0
- package/dist/_frontend/assets/freemarker2-BrrF7mKG.js.br +0 -0
- package/dist/_frontend/assets/freemarker2-BrrF7mKG.js.gz +0 -0
- package/dist/_frontend/assets/handlebars-WQ7HMT1b.js.br +0 -0
- package/dist/_frontend/assets/handlebars-WQ7HMT1b.js.gz +0 -0
- package/dist/_frontend/assets/html-CoOPnhCb.js.br +0 -0
- package/dist/_frontend/assets/html-CoOPnhCb.js.gz +0 -0
- package/dist/_frontend/assets/htmlMode-BW7taYty.js.br +0 -0
- package/dist/_frontend/assets/htmlMode-BW7taYty.js.gz +0 -0
- package/dist/_frontend/assets/index-ChCGltYc.js.br +0 -0
- package/dist/_frontend/assets/index-ChCGltYc.js.gz +0 -0
- package/dist/_frontend/assets/index-DFQqb6R1.js.br +0 -0
- package/dist/_frontend/assets/index-DFQqb6R1.js.gz +0 -0
- package/dist/_frontend/assets/jsonMode-C8qDzOfb.js.br +0 -0
- package/dist/_frontend/assets/jsonMode-C8qDzOfb.js.gz +0 -0
- package/dist/_frontend/assets/liquid-zGC9H1Dt.js.br +0 -0
- package/dist/_frontend/assets/liquid-zGC9H1Dt.js.gz +0 -0
- package/dist/_frontend/assets/lspLanguageFeatures-B6VPH2Sv.js.br +0 -0
- package/dist/_frontend/assets/lspLanguageFeatures-B6VPH2Sv.js.gz +0 -0
- package/dist/_frontend/assets/mdx-BrQrGCP9.js.br +0 -0
- package/dist/_frontend/assets/mdx-BrQrGCP9.js.gz +0 -0
- package/dist/_frontend/assets/python-zKGpYLwR.js.br +0 -0
- package/dist/_frontend/assets/python-zKGpYLwR.js.gz +0 -0
- package/dist/_frontend/assets/razor-BJ38lYsd.js.br +0 -0
- package/dist/_frontend/assets/razor-BJ38lYsd.js.gz +0 -0
- package/dist/_frontend/assets/tsMode-dPLqGMg8.js.br +0 -0
- package/dist/_frontend/assets/tsMode-dPLqGMg8.js.gz +0 -0
- package/dist/_frontend/assets/typescript-BJlivWry.js.br +0 -0
- package/dist/_frontend/assets/typescript-BJlivWry.js.gz +0 -0
- package/dist/_frontend/assets/workers-fMwav4jB.js.br +0 -0
- package/dist/_frontend/assets/workers-fMwav4jB.js.gz +0 -0
- package/dist/_frontend/assets/xml-DZW470wi.js.br +0 -0
- package/dist/_frontend/assets/xml-DZW470wi.js.gz +0 -0
- package/dist/_frontend/assets/yaml-Bs1DumYp.js.br +0 -0
- package/dist/_frontend/assets/yaml-Bs1DumYp.js.gz +0 -0
package/dist/main.js
CHANGED
|
@@ -92,8 +92,12 @@ function parseBoolean(options) {
|
|
|
92
92
|
return defaultValue;
|
|
93
93
|
}
|
|
94
94
|
const value = raw.trim().toLowerCase();
|
|
95
|
-
if (value === "true")
|
|
96
|
-
|
|
95
|
+
if (value === "true") {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
if (value === "false") {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
97
101
|
throw new Error(`Environment variable ${envKey} must be "true" or "false", got "${raw}"`);
|
|
98
102
|
}
|
|
99
103
|
function resolveDefaultFrontendDir() {
|
|
@@ -192,11 +196,13 @@ function getPublicBaseUrl(config = configuration) {
|
|
|
192
196
|
}
|
|
193
197
|
return config.PUBLIC_BASE_URL;
|
|
194
198
|
}
|
|
195
|
-
var DEFAULT_PORT, PACKAGE_ROOT, LOCAL_EXECUTOR_ID, ENV_PATHS_APP_NAME, DEFAULT_POSTGRES_USER, DEFAULT_POSTGRES_PASSWORD, DEFAULT_POSTGRES_DB, DEFAULT_POSTGRES_HOST, DEFAULT_POSTGRES_PORT, DEFAULT_REDIS_URL, DEFAULT_OIDC_USER_REFERENCE_CLAIM, DEFAULT_OIDC_USER_ROLE_CLAIM, DEFAULT_OIDC_ADMIN_ROLE_VALUE, DEFAULT_OIDC_SCOPES, serverExecutionTimeoutSeconds, standalone, port, shared, configuration, config_default;
|
|
199
|
+
var DEFAULT_PORT, DEFAULT_HOST, DEFAULT_MAX_REQUEST_BODY_BYTES, PACKAGE_ROOT, LOCAL_EXECUTOR_ID, ENV_PATHS_APP_NAME, DEFAULT_POSTGRES_USER, DEFAULT_POSTGRES_PASSWORD, DEFAULT_POSTGRES_DB, DEFAULT_POSTGRES_HOST, DEFAULT_POSTGRES_PORT, DEFAULT_REDIS_URL, DEFAULT_OIDC_USER_REFERENCE_CLAIM, DEFAULT_OIDC_USER_ROLE_CLAIM, DEFAULT_OIDC_ADMIN_ROLE_VALUE, DEFAULT_OIDC_SCOPES, serverExecutionTimeoutSeconds, standalone, port, host, shared, configuration, config_default;
|
|
196
200
|
var init_config = __esm({
|
|
197
201
|
"src/config.ts"() {
|
|
198
202
|
"use strict";
|
|
199
203
|
DEFAULT_PORT = 8790;
|
|
204
|
+
DEFAULT_HOST = "localhost";
|
|
205
|
+
DEFAULT_MAX_REQUEST_BODY_BYTES = 30 * 1024 * 1024;
|
|
200
206
|
PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
201
207
|
LOCAL_EXECUTOR_ID = "local";
|
|
202
208
|
ENV_PATHS_APP_NAME = "trueforge";
|
|
@@ -221,10 +227,12 @@ var init_config = __esm({
|
|
|
221
227
|
defaultValue: true
|
|
222
228
|
});
|
|
223
229
|
port = parsePort(getEnv("PORT"));
|
|
230
|
+
host = getEnv("HOST", { defaultValue: DEFAULT_HOST }) ?? DEFAULT_HOST;
|
|
224
231
|
shared = {
|
|
225
232
|
LOG_LEVEL: getEnv("LOG_LEVEL", { defaultValue: "info" }) ?? "info",
|
|
226
233
|
NODE_ENV: getEnv("NODE_ENV"),
|
|
227
234
|
PORT: port,
|
|
235
|
+
HOST: host,
|
|
228
236
|
EXECUTOR_ID: standalone ? LOCAL_EXECUTOR_ID : randomAlphanumeric(6),
|
|
229
237
|
MODEL_CATALOG_PATH: resolveOptionalPathEnv("MODEL_CATALOG_PATH"),
|
|
230
238
|
MCP_CATALOG_PATH: resolveOptionalPathEnv("MCP_CATALOG_PATH"),
|
|
@@ -247,6 +255,11 @@ var init_config = __esm({
|
|
|
247
255
|
raw: getEnv("SANDBOX_FILE_MAX_BYTES_FOR_DOWNLOAD"),
|
|
248
256
|
defaultValue: 20971520
|
|
249
257
|
}),
|
|
258
|
+
MAX_REQUEST_BODY_BYTES: parsePositiveInt({
|
|
259
|
+
envKey: "MAX_REQUEST_BODY_BYTES",
|
|
260
|
+
raw: getEnv("MAX_REQUEST_BODY_BYTES"),
|
|
261
|
+
defaultValue: DEFAULT_MAX_REQUEST_BODY_BYTES
|
|
262
|
+
}),
|
|
250
263
|
GRACEFUL_TIMEOUT_SECONDS: parsePositiveInt({
|
|
251
264
|
envKey: "GRACEFUL_TIMEOUT_SECONDS",
|
|
252
265
|
raw: getEnv("GRACEFUL_TIMEOUT_SECONDS"),
|
|
@@ -576,15 +589,15 @@ __export(migrateSqlite_exports, {
|
|
|
576
589
|
migrateSqliteToLatest: () => migrateSqliteToLatest
|
|
577
590
|
});
|
|
578
591
|
import { promises as fs2 } from "fs";
|
|
579
|
-
import
|
|
592
|
+
import path4 from "path";
|
|
580
593
|
import { FileMigrationProvider, Migrator } from "kysely/migration";
|
|
581
594
|
async function migrateSqliteToLatest(db) {
|
|
582
595
|
const migrator = new Migrator({
|
|
583
596
|
db,
|
|
584
597
|
provider: new FileMigrationProvider({
|
|
585
598
|
fs: fs2,
|
|
586
|
-
path:
|
|
587
|
-
migrationFolder:
|
|
599
|
+
path: path4,
|
|
600
|
+
migrationFolder: path4.join(import.meta.dirname, "sqlite", "migrations")
|
|
588
601
|
})
|
|
589
602
|
});
|
|
590
603
|
const { error, results } = await migrator.migrateToLatest();
|
|
@@ -613,8 +626,8 @@ import { sql } from "kysely";
|
|
|
613
626
|
function jsonbBind(value) {
|
|
614
627
|
return sql`jsonb(${JSON.stringify(value)})`;
|
|
615
628
|
}
|
|
616
|
-
function jsonbSet(column,
|
|
617
|
-
return sql`jsonb_set(${column}, ${
|
|
629
|
+
function jsonbSet(column, path7, value) {
|
|
630
|
+
return sql`jsonb_set(${column}, ${path7}, ${jsonbBind(value)})`;
|
|
618
631
|
}
|
|
619
632
|
function jsonText(column) {
|
|
620
633
|
return sql`json(${column})`;
|
|
@@ -724,7 +737,9 @@ async function assembleTurnRecord(db, args) {
|
|
|
724
737
|
"created_at",
|
|
725
738
|
"updated_at"
|
|
726
739
|
]).where("session_id", "=", args.session_id).where("turn_id", "=", args.turn_id).executeTakeFirst();
|
|
727
|
-
if (!turn)
|
|
740
|
+
if (!turn) {
|
|
741
|
+
return void 0;
|
|
742
|
+
}
|
|
728
743
|
const contextRows = await db.selectFrom("turn_thread as tt").leftJoin(
|
|
729
744
|
"turn_thread_context as ttc",
|
|
730
745
|
(join) => join.on("ttc.session_id", "=", args.session_id).on("ttc.turn_id", "=", args.turn_id).onRef("ttc.thread_id", "=", "tt.thread_id")
|
|
@@ -806,7 +821,9 @@ async function createTurn(db, input) {
|
|
|
806
821
|
try {
|
|
807
822
|
await db.transaction().execute(async (trx) => {
|
|
808
823
|
const locked = await trx.selectFrom("session").select(["last_turn_id"]).where("session_id", "=", input.session_id).executeTakeFirst();
|
|
809
|
-
if (!locked)
|
|
824
|
+
if (!locked) {
|
|
825
|
+
throw new SessionNotFoundError(input.session_id);
|
|
826
|
+
}
|
|
810
827
|
let sessionUpdate = trx.updateTable("session").set({
|
|
811
828
|
last_turn_id: input.turn.turn_id,
|
|
812
829
|
updated_at: nowIso(),
|
|
@@ -845,7 +862,9 @@ async function createTurn(db, input) {
|
|
|
845
862
|
}
|
|
846
863
|
prevCheckpoint = first.turn_checkpoint;
|
|
847
864
|
for (const row of prevRows) {
|
|
848
|
-
if (row.thread_id === null)
|
|
865
|
+
if (row.thread_id === null) {
|
|
866
|
+
continue;
|
|
867
|
+
}
|
|
849
868
|
if (row.thread_checkpoint === null || row.current_context_usage === null) {
|
|
850
869
|
throw new SessionStoreInvariantError2(`previous turn_thread row for ${row.thread_id} is incomplete`);
|
|
851
870
|
}
|
|
@@ -997,7 +1016,9 @@ async function createTurn(db, input) {
|
|
|
997
1016
|
}
|
|
998
1017
|
const capabilityStateRows = [];
|
|
999
1018
|
for (const capability of input.capability_states) {
|
|
1000
|
-
if (capability.capability_state === null)
|
|
1019
|
+
if (capability.capability_state === null) {
|
|
1020
|
+
continue;
|
|
1021
|
+
}
|
|
1001
1022
|
for (const [key, state] of Object.entries(capability.capability_state)) {
|
|
1002
1023
|
capabilityStateRows.push({
|
|
1003
1024
|
session_id: input.session_id,
|
|
@@ -1014,8 +1035,12 @@ async function createTurn(db, input) {
|
|
|
1014
1035
|
}
|
|
1015
1036
|
});
|
|
1016
1037
|
} catch (err) {
|
|
1017
|
-
if (err instanceof SessionStoreNotFoundError3 || err instanceof SessionStoreConflictError3)
|
|
1018
|
-
|
|
1038
|
+
if (err instanceof SessionStoreNotFoundError3 || err instanceof SessionStoreConflictError3) {
|
|
1039
|
+
throw err;
|
|
1040
|
+
}
|
|
1041
|
+
if (isUniqueViolation(err)) {
|
|
1042
|
+
throw new TurnAlreadyExistsError(input.turn.turn_id, { cause: err });
|
|
1043
|
+
}
|
|
1019
1044
|
throw err;
|
|
1020
1045
|
}
|
|
1021
1046
|
}
|
|
@@ -1040,7 +1065,9 @@ async function freezeAndGetTurn(db, input) {
|
|
|
1040
1065
|
}).execute();
|
|
1041
1066
|
}
|
|
1042
1067
|
const record = await assembleTurnRecord(trx, input);
|
|
1043
|
-
if (!record)
|
|
1068
|
+
if (!record) {
|
|
1069
|
+
throw new TurnNotFoundError(input.turn_id);
|
|
1070
|
+
}
|
|
1044
1071
|
return record;
|
|
1045
1072
|
});
|
|
1046
1073
|
}
|
|
@@ -1088,7 +1115,9 @@ async function updateTurnState(db, input) {
|
|
|
1088
1115
|
const numUpdated = Number(result.numUpdatedRows);
|
|
1089
1116
|
if (numUpdated === 0) {
|
|
1090
1117
|
const existing = await trx.selectFrom("turn").select([jsonText(sql2.ref("state")).as("state")]).where("session_id", "=", input.session_id).where("turn_id", "=", input.turn_id).executeTakeFirst();
|
|
1091
|
-
if (!existing)
|
|
1118
|
+
if (!existing) {
|
|
1119
|
+
throw new TurnNotFoundError(input.turn_id);
|
|
1120
|
+
}
|
|
1092
1121
|
throw new TurnNotRunningError(input.turn_id, terminalTurnState(existing.state, input.turn_id));
|
|
1093
1122
|
}
|
|
1094
1123
|
await trx.insertInto("session_event").values({
|
|
@@ -1157,7 +1186,9 @@ import {
|
|
|
1157
1186
|
} from "@truefoundry/trueforge-core/agent-session/store/SessionStoreErrors";
|
|
1158
1187
|
import { sql as sql4 } from "kysely";
|
|
1159
1188
|
async function appendToEvents(db, input) {
|
|
1160
|
-
if (input.events.length === 0)
|
|
1189
|
+
if (input.events.length === 0) {
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1161
1192
|
const keys = {
|
|
1162
1193
|
session_id: input.session_id,
|
|
1163
1194
|
turn_id: input.turn_id
|
|
@@ -1202,11 +1233,17 @@ async function resolveAncestorChain(db, sessionId, anchor) {
|
|
|
1202
1233
|
let oldestId = chain[0];
|
|
1203
1234
|
while (oldestId && oldestId !== anchor.turn_id) {
|
|
1204
1235
|
const oldest = await db.selectFrom("turn").select([jsonText(sql4.ref("ancestor_ids")).as("ancestor_ids")]).where("session_id", "=", sessionId).where("turn_id", "=", oldestId).executeTakeFirst();
|
|
1205
|
-
if (!oldest)
|
|
1236
|
+
if (!oldest) {
|
|
1237
|
+
break;
|
|
1238
|
+
}
|
|
1206
1239
|
const older = oldest.ancestor_ids.filter((id) => !seen.has(id));
|
|
1207
|
-
if (older.length === 0)
|
|
1240
|
+
if (older.length === 0) {
|
|
1241
|
+
break;
|
|
1242
|
+
}
|
|
1208
1243
|
chain.unshift(...older);
|
|
1209
|
-
for (const id of older)
|
|
1244
|
+
for (const id of older) {
|
|
1245
|
+
seen.add(id);
|
|
1246
|
+
}
|
|
1210
1247
|
oldestId = older[0];
|
|
1211
1248
|
}
|
|
1212
1249
|
return chain;
|
|
@@ -2448,15 +2485,15 @@ __export(migratePostgres_exports, {
|
|
|
2448
2485
|
migrateToLatest: () => migrateToLatest
|
|
2449
2486
|
});
|
|
2450
2487
|
import { promises as fs3 } from "fs";
|
|
2451
|
-
import
|
|
2488
|
+
import path5 from "path";
|
|
2452
2489
|
import { FileMigrationProvider as FileMigrationProvider2, Migrator as Migrator2 } from "kysely/migration";
|
|
2453
2490
|
async function migrateToLatest(db) {
|
|
2454
2491
|
const migrator = new Migrator2({
|
|
2455
2492
|
db,
|
|
2456
2493
|
provider: new FileMigrationProvider2({
|
|
2457
2494
|
fs: fs3,
|
|
2458
|
-
path:
|
|
2459
|
-
migrationFolder:
|
|
2495
|
+
path: path5,
|
|
2496
|
+
migrationFolder: path5.join(import.meta.dirname, "postgres", "migrations")
|
|
2460
2497
|
})
|
|
2461
2498
|
});
|
|
2462
2499
|
const { error, results } = await migrator.migrateToLatest();
|
|
@@ -2506,8 +2543,8 @@ import { sql as sql9 } from "kysely";
|
|
|
2506
2543
|
function json(value) {
|
|
2507
2544
|
return sql9`${JSON.stringify(value)}::jsonb`;
|
|
2508
2545
|
}
|
|
2509
|
-
function jsonbSet2(target,
|
|
2510
|
-
return sql9`jsonb_set(${target}, ${
|
|
2546
|
+
function jsonbSet2(target, path7, newValue) {
|
|
2547
|
+
return sql9`jsonb_set(${target}, ${path7}, ${newValue})`;
|
|
2511
2548
|
}
|
|
2512
2549
|
function now() {
|
|
2513
2550
|
return sql9`now()`;
|
|
@@ -2621,7 +2658,9 @@ async function assertTurnRunning2(db, keys) {
|
|
|
2621
2658
|
}
|
|
2622
2659
|
async function assembleTurnRecord2(db, args) {
|
|
2623
2660
|
const turn = await db.selectFrom("turn").selectAll().where("session_id", "=", args.session_id).where("turn_id", "=", args.turn_id).executeTakeFirst();
|
|
2624
|
-
if (!turn)
|
|
2661
|
+
if (!turn) {
|
|
2662
|
+
return void 0;
|
|
2663
|
+
}
|
|
2625
2664
|
const contextRows = await db.selectFrom("turn_thread as tt").leftJoin(lateralUnnestBigintArrayWithOrdinality(sql11`tt.context_ids`, "c"), (join) => join.onTrue()).leftJoin(
|
|
2626
2665
|
"thread_context_log as l",
|
|
2627
2666
|
(join) => join.on("l.session_id", "=", args.session_id).onRef("l.thread_id", "=", "tt.thread_id").onRef("l.append_id", "=", "c.append_id")
|
|
@@ -2690,7 +2729,9 @@ async function createTurn2(db, input) {
|
|
|
2690
2729
|
try {
|
|
2691
2730
|
await db.transaction().execute(async (trx) => {
|
|
2692
2731
|
const locked = await trx.selectFrom("session").select(["last_turn_id"]).where("session_id", "=", input.session_id).forUpdate().executeTakeFirst();
|
|
2693
|
-
if (!locked)
|
|
2732
|
+
if (!locked) {
|
|
2733
|
+
throw new SessionNotFoundError4(input.session_id);
|
|
2734
|
+
}
|
|
2694
2735
|
await trx.updateTable("session").set({
|
|
2695
2736
|
last_turn_id: input.turn.turn_id,
|
|
2696
2737
|
updated_at: sql11`now()`,
|
|
@@ -2722,7 +2763,9 @@ async function createTurn2(db, input) {
|
|
|
2722
2763
|
}
|
|
2723
2764
|
prevCheckpoint = first.turn_checkpoint;
|
|
2724
2765
|
for (const row of prevRows) {
|
|
2725
|
-
if (row.thread_id === null)
|
|
2766
|
+
if (row.thread_id === null) {
|
|
2767
|
+
continue;
|
|
2768
|
+
}
|
|
2726
2769
|
if (row.thread_checkpoint === null || row.current_context_usage === null || row.context_ids === null) {
|
|
2727
2770
|
throw new SessionStoreInvariantError4(`previous turn_thread row for ${row.thread_id} is incomplete`);
|
|
2728
2771
|
}
|
|
@@ -2830,7 +2873,9 @@ async function createTurn2(db, input) {
|
|
|
2830
2873
|
}
|
|
2831
2874
|
const capabilityStateRows = [];
|
|
2832
2875
|
for (const capability of input.capability_states) {
|
|
2833
|
-
if (capability.capability_state === null)
|
|
2876
|
+
if (capability.capability_state === null) {
|
|
2877
|
+
continue;
|
|
2878
|
+
}
|
|
2834
2879
|
for (const [key, state] of Object.entries(capability.capability_state)) {
|
|
2835
2880
|
capabilityStateRows.push({
|
|
2836
2881
|
session_id: input.session_id,
|
|
@@ -2847,8 +2892,12 @@ async function createTurn2(db, input) {
|
|
|
2847
2892
|
}
|
|
2848
2893
|
});
|
|
2849
2894
|
} catch (err) {
|
|
2850
|
-
if (err instanceof SessionStoreNotFoundError4 || err instanceof SessionStoreConflictError4)
|
|
2851
|
-
|
|
2895
|
+
if (err instanceof SessionStoreNotFoundError4 || err instanceof SessionStoreConflictError4) {
|
|
2896
|
+
throw err;
|
|
2897
|
+
}
|
|
2898
|
+
if (isUniqueViolation2(err)) {
|
|
2899
|
+
throw new TurnAlreadyExistsError2(input.turn.turn_id, { cause: err });
|
|
2900
|
+
}
|
|
2852
2901
|
throw err;
|
|
2853
2902
|
}
|
|
2854
2903
|
}
|
|
@@ -2873,7 +2922,9 @@ async function freezeAndGetTurn2(db, input) {
|
|
|
2873
2922
|
}).execute();
|
|
2874
2923
|
}
|
|
2875
2924
|
const record = await assembleTurnRecord2(trx, input);
|
|
2876
|
-
if (!record)
|
|
2925
|
+
if (!record) {
|
|
2926
|
+
throw new TurnNotFoundError3(input.turn_id);
|
|
2927
|
+
}
|
|
2877
2928
|
return record;
|
|
2878
2929
|
});
|
|
2879
2930
|
}
|
|
@@ -2912,7 +2963,9 @@ async function updateTurnState2(db, input) {
|
|
|
2912
2963
|
const numUpdated = Number(result.numUpdatedRows);
|
|
2913
2964
|
if (numUpdated === 0) {
|
|
2914
2965
|
const existing = await trx.selectFrom("turn").select("state").where("session_id", "=", input.session_id).where("turn_id", "=", input.turn_id).executeTakeFirst();
|
|
2915
|
-
if (!existing)
|
|
2966
|
+
if (!existing) {
|
|
2967
|
+
throw new TurnNotFoundError3(input.turn_id);
|
|
2968
|
+
}
|
|
2916
2969
|
throw new TurnNotRunningError2(input.turn_id, terminalTurnState2(existing.state, input.turn_id));
|
|
2917
2970
|
}
|
|
2918
2971
|
await trx.insertInto("session_event").values({
|
|
@@ -2983,7 +3036,9 @@ import {
|
|
|
2983
3036
|
} from "@truefoundry/trueforge-core/agent-session/store/SessionStoreErrors";
|
|
2984
3037
|
import { sql as sql13 } from "kysely";
|
|
2985
3038
|
async function appendToEvents2(db, input) {
|
|
2986
|
-
if (input.events.length === 0)
|
|
3039
|
+
if (input.events.length === 0) {
|
|
3040
|
+
return;
|
|
3041
|
+
}
|
|
2987
3042
|
const keys = {
|
|
2988
3043
|
session_id: input.session_id,
|
|
2989
3044
|
turn_id: input.turn_id
|
|
@@ -3058,11 +3113,17 @@ async function resolveAncestorChain2(db, sessionId, anchor) {
|
|
|
3058
3113
|
let oldestId = chain[0];
|
|
3059
3114
|
while (oldestId && oldestId !== anchor.turn_id) {
|
|
3060
3115
|
const oldest = await db.selectFrom("turn").select(["ancestor_ids"]).where("session_id", "=", sessionId).where("turn_id", "=", oldestId).executeTakeFirst();
|
|
3061
|
-
if (!oldest)
|
|
3116
|
+
if (!oldest) {
|
|
3117
|
+
break;
|
|
3118
|
+
}
|
|
3062
3119
|
const older = oldest.ancestor_ids.filter((id) => !seen.has(id));
|
|
3063
|
-
if (older.length === 0)
|
|
3120
|
+
if (older.length === 0) {
|
|
3121
|
+
break;
|
|
3122
|
+
}
|
|
3064
3123
|
chain.unshift(...older);
|
|
3065
|
-
for (const id of older)
|
|
3124
|
+
for (const id of older) {
|
|
3125
|
+
seen.add(id);
|
|
3126
|
+
}
|
|
3066
3127
|
oldestId = older[0];
|
|
3067
3128
|
}
|
|
3068
3129
|
return chain;
|
|
@@ -4138,19 +4199,19 @@ var init_PostgresAgentStore = __esm({
|
|
|
4138
4199
|
// src/main.ts
|
|
4139
4200
|
import { extractErrorLogFields as extractErrorLogFields8 } from "@truefoundry/trueforge-core/core";
|
|
4140
4201
|
import { mkdir } from "fs/promises";
|
|
4141
|
-
import
|
|
4202
|
+
import path6 from "path";
|
|
4142
4203
|
import { serve } from "@hono/node-server";
|
|
4143
4204
|
import {
|
|
4144
4205
|
CancellationReason as CancellationReason6,
|
|
4145
4206
|
Sessions
|
|
4146
4207
|
} from "@truefoundry/trueforge-core/agent-session";
|
|
4147
4208
|
import { RequestReplyExecutor, RequestReplyRouter } from "@truefoundry/trueforge-core/request-reply";
|
|
4148
|
-
import winston from "winston";
|
|
4149
4209
|
|
|
4150
4210
|
// src/app.ts
|
|
4151
4211
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
4152
4212
|
import { OpenAPIHono as OpenAPIHono14, z as z24 } from "@hono/zod-openapi";
|
|
4153
4213
|
import { extractErrorLogFields as extractErrorLogFields6 } from "@truefoundry/trueforge-core/core";
|
|
4214
|
+
import { bodyLimit } from "hono/body-limit";
|
|
4154
4215
|
import { HTTPException as HTTPException6 } from "hono/http-exception";
|
|
4155
4216
|
|
|
4156
4217
|
// src/apis/agents.ts
|
|
@@ -4744,6 +4805,7 @@ function toDaytonaSandboxProvider({
|
|
|
4744
4805
|
const { apiKey, ...settings } = toDaytonaSandboxProviderInput(manifest);
|
|
4745
4806
|
return new DaytonaSandboxProvider({
|
|
4746
4807
|
client: new Daytona({ apiKey }),
|
|
4808
|
+
apiKey,
|
|
4747
4809
|
...settings,
|
|
4748
4810
|
tenantName: tenant_id,
|
|
4749
4811
|
sandboxImage: build_metadata?.["image_uri"] ?? SANDBOX_IMAGE_URI,
|
|
@@ -4759,6 +4821,13 @@ function toSandboxStatus(build) {
|
|
|
4759
4821
|
build_metadata: build.metadata
|
|
4760
4822
|
};
|
|
4761
4823
|
}
|
|
4824
|
+
function sandboxStatusFromRecord(record) {
|
|
4825
|
+
return {
|
|
4826
|
+
status: record.status,
|
|
4827
|
+
status_reason: record.status_reason,
|
|
4828
|
+
build_metadata: record.build_metadata
|
|
4829
|
+
};
|
|
4830
|
+
}
|
|
4762
4831
|
var READY_REVALIDATE_INTERVAL_MS = 13 * 24 * 60 * 60 * 1e3;
|
|
4763
4832
|
async function checkSnapshotStatus({
|
|
4764
4833
|
store,
|
|
@@ -4769,11 +4838,7 @@ async function checkSnapshotStatus({
|
|
|
4769
4838
|
if (!record) {
|
|
4770
4839
|
return void 0;
|
|
4771
4840
|
}
|
|
4772
|
-
const persisted =
|
|
4773
|
-
status: record.status,
|
|
4774
|
-
status_reason: record.status_reason,
|
|
4775
|
-
build_metadata: record.build_metadata
|
|
4776
|
-
};
|
|
4841
|
+
const persisted = sandboxStatusFromRecord(record);
|
|
4777
4842
|
const readyIsFresh = record.status === "ready" && Date.now() - Date.parse(record.updated_at) < READY_REVALIDATE_INTERVAL_MS;
|
|
4778
4843
|
if (record.status === "failed" || readyIsFresh) {
|
|
4779
4844
|
return persisted;
|
|
@@ -4791,8 +4856,8 @@ async function checkSnapshotStatus({
|
|
|
4791
4856
|
build = await provider.getImageBuildStatus();
|
|
4792
4857
|
}
|
|
4793
4858
|
const next = toSandboxStatus(build);
|
|
4794
|
-
await store.updateSandboxStatus({ tenant_id, ...next });
|
|
4795
|
-
return next;
|
|
4859
|
+
const updated = await store.updateSandboxStatus({ tenant_id, ...next });
|
|
4860
|
+
return updated ? sandboxStatusFromRecord(updated) : next;
|
|
4796
4861
|
}
|
|
4797
4862
|
|
|
4798
4863
|
// src/schemas/mcpServer.ts
|
|
@@ -8210,6 +8275,10 @@ Use \`previous_turn_id\` to chain to the session's last turn (defaults to \`auto
|
|
|
8210
8275
|
content: { "application/json": { schema: RequestErrorResponseSchema } },
|
|
8211
8276
|
description: "Requested action cannot be performed on the session because it is no longer usable."
|
|
8212
8277
|
},
|
|
8278
|
+
413: {
|
|
8279
|
+
content: { "application/json": { schema: RequestErrorResponseSchema } },
|
|
8280
|
+
description: "Request body exceeds the configured maximum size (MAX_REQUEST_BODY_BYTES)."
|
|
8281
|
+
},
|
|
8213
8282
|
422: {
|
|
8214
8283
|
content: { "application/json": { schema: RequestErrorResponseSchema } },
|
|
8215
8284
|
description: "The request is well-formed but cannot be processed: a referenced resource is missing (named agent, model, MCP server, skill, or sandbox provider), sandbox is required but unavailable (e.g. file uploads), or the turn input conflicts with current state (e.g. unresolved tool calls or approvals, tool name collision)."
|
|
@@ -8503,30 +8572,30 @@ var StreamGoneError = class extends Error {
|
|
|
8503
8572
|
import { SandboxError, validateNoPathTraversal } from "@truefoundry/trueforge-core/core";
|
|
8504
8573
|
var SandboxInvalidPathError = class extends SandboxError {
|
|
8505
8574
|
statusCode = 400;
|
|
8506
|
-
constructor({ path:
|
|
8507
|
-
super(`Path ${reason}: ${
|
|
8575
|
+
constructor({ path: path7, reason }) {
|
|
8576
|
+
super(`Path ${reason}: ${path7}`);
|
|
8508
8577
|
this.name = "SandboxInvalidPathError";
|
|
8509
8578
|
}
|
|
8510
8579
|
};
|
|
8511
8580
|
var MAX_PATH_BYTES = 4095;
|
|
8512
8581
|
var MAX_SEGMENT_BYTES = 255;
|
|
8513
|
-
function validateSandboxFilePath(
|
|
8514
|
-
if (!
|
|
8515
|
-
throw new SandboxInvalidPathError({ path:
|
|
8582
|
+
function validateSandboxFilePath(path7) {
|
|
8583
|
+
if (!path7.startsWith("/")) {
|
|
8584
|
+
throw new SandboxInvalidPathError({ path: path7, reason: "must be absolute" });
|
|
8516
8585
|
}
|
|
8517
|
-
if (
|
|
8518
|
-
throw new SandboxInvalidPathError({ path:
|
|
8586
|
+
if (path7.includes("\0")) {
|
|
8587
|
+
throw new SandboxInvalidPathError({ path: path7, reason: "must not contain a NUL byte" });
|
|
8519
8588
|
}
|
|
8520
|
-
if (Buffer.byteLength(
|
|
8521
|
-
throw new SandboxInvalidPathError({ path:
|
|
8589
|
+
if (Buffer.byteLength(path7) > MAX_PATH_BYTES) {
|
|
8590
|
+
throw new SandboxInvalidPathError({ path: path7, reason: `must be at most ${String(MAX_PATH_BYTES)} bytes` });
|
|
8522
8591
|
}
|
|
8523
|
-
if (
|
|
8592
|
+
if (path7.split("/").some((segment) => Buffer.byteLength(segment) > MAX_SEGMENT_BYTES)) {
|
|
8524
8593
|
throw new SandboxInvalidPathError({
|
|
8525
|
-
path:
|
|
8594
|
+
path: path7,
|
|
8526
8595
|
reason: `must not have a segment longer than ${String(MAX_SEGMENT_BYTES)} bytes`
|
|
8527
8596
|
});
|
|
8528
8597
|
}
|
|
8529
|
-
validateNoPathTraversal(
|
|
8598
|
+
validateNoPathTraversal(path7);
|
|
8530
8599
|
}
|
|
8531
8600
|
|
|
8532
8601
|
// src/apis/turns.ts
|
|
@@ -8545,8 +8614,8 @@ function toArrayBuffer(content) {
|
|
|
8545
8614
|
new Uint8Array(buffer).set(content);
|
|
8546
8615
|
return buffer;
|
|
8547
8616
|
}
|
|
8548
|
-
function toContentDisposition(
|
|
8549
|
-
const fileName =
|
|
8617
|
+
function toContentDisposition(path7) {
|
|
8618
|
+
const fileName = path7.split("/").filter(Boolean).pop() ?? "download";
|
|
8550
8619
|
const encoded = encodeURIComponent(fileName).replace(
|
|
8551
8620
|
/['()*]/g,
|
|
8552
8621
|
(char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`
|
|
@@ -8758,10 +8827,10 @@ function createTurnsRouter(deps) {
|
|
|
8758
8827
|
};
|
|
8759
8828
|
const downloadSandboxFileHandler = async (c) => {
|
|
8760
8829
|
const { session_id: sessionId, turn_id: turnId } = c.req.valid("param");
|
|
8761
|
-
const { path:
|
|
8830
|
+
const { path: path7 } = c.req.valid("query");
|
|
8762
8831
|
let sandboxId;
|
|
8763
8832
|
try {
|
|
8764
|
-
validateSandboxFilePath(
|
|
8833
|
+
validateSandboxFilePath(path7);
|
|
8765
8834
|
const session = await deps.sessions.get({ tenant_id: TENANT_ID, session_id: sessionId });
|
|
8766
8835
|
if (!session) {
|
|
8767
8836
|
return c.json({ error: { message: `Session not found: ${sessionId}` } }, 404);
|
|
@@ -8786,11 +8855,11 @@ function createTurnsRouter(deps) {
|
|
|
8786
8855
|
return c.json({ error: { message: "No sandbox provider configured" } }, 412);
|
|
8787
8856
|
}
|
|
8788
8857
|
validateSandboxOwnedByTenant(sandboxId, TENANT_ID);
|
|
8789
|
-
const content = await provider.downloadFile({ sandboxId, path:
|
|
8858
|
+
const content = await provider.downloadFile({ sandboxId, path: path7 });
|
|
8790
8859
|
return c.body(toArrayBuffer(content), 200, {
|
|
8791
8860
|
"Content-Type": "application/octet-stream",
|
|
8792
8861
|
"Content-Length": String(content.byteLength),
|
|
8793
|
-
"Content-Disposition": toContentDisposition(
|
|
8862
|
+
"Content-Disposition": toContentDisposition(path7),
|
|
8794
8863
|
"Cache-Control": "private, no-store"
|
|
8795
8864
|
});
|
|
8796
8865
|
} catch (error) {
|
|
@@ -8802,7 +8871,7 @@ function createTurnsRouter(deps) {
|
|
|
8802
8871
|
sessionId,
|
|
8803
8872
|
turnId,
|
|
8804
8873
|
sandboxId,
|
|
8805
|
-
path:
|
|
8874
|
+
path: path7
|
|
8806
8875
|
});
|
|
8807
8876
|
return c.json({ error: { message: "Failed to download file from sandbox" } }, 424);
|
|
8808
8877
|
}
|
|
@@ -9012,6 +9081,28 @@ function createTurnsRouter(deps) {
|
|
|
9012
9081
|
return router;
|
|
9013
9082
|
}
|
|
9014
9083
|
|
|
9084
|
+
// src/app.ts
|
|
9085
|
+
init_config();
|
|
9086
|
+
|
|
9087
|
+
// src/packageVersion.ts
|
|
9088
|
+
import { readFileSync } from "fs";
|
|
9089
|
+
import path2 from "path";
|
|
9090
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9091
|
+
var PACKAGE_ROOT2 = path2.resolve(path2.dirname(fileURLToPath2(import.meta.url)), "..");
|
|
9092
|
+
function readPackageVersion() {
|
|
9093
|
+
const packageJsonPath = path2.join(PACKAGE_ROOT2, "package.json");
|
|
9094
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
9095
|
+
if (typeof parsed !== "object" || parsed === null || !("version" in parsed)) {
|
|
9096
|
+
throw new Error(`${packageJsonPath} is missing a version field`);
|
|
9097
|
+
}
|
|
9098
|
+
const { version } = parsed;
|
|
9099
|
+
if (typeof version !== "string" || version.length === 0) {
|
|
9100
|
+
throw new Error(`${packageJsonPath} version must be a non-empty string`);
|
|
9101
|
+
}
|
|
9102
|
+
return version;
|
|
9103
|
+
}
|
|
9104
|
+
var PACKAGE_VERSION = readPackageVersion();
|
|
9105
|
+
|
|
9015
9106
|
// src/zodErrorResponse.ts
|
|
9016
9107
|
import { z as z23 } from "@hono/zod-openapi";
|
|
9017
9108
|
function zodErrorResponse(c, error) {
|
|
@@ -9026,6 +9117,12 @@ var zodValidationHook = (result, c) => {
|
|
|
9026
9117
|
|
|
9027
9118
|
// src/app.ts
|
|
9028
9119
|
var BEARER_AUTH_SCHEME = "BearerAuth";
|
|
9120
|
+
function createRequestBodyLimitMiddleware(maxSize) {
|
|
9121
|
+
return bodyLimit({
|
|
9122
|
+
maxSize,
|
|
9123
|
+
onError: (c) => c.json({ error: { message: `Request body exceeds the maximum size of ${String(maxSize)} bytes` } }, 413)
|
|
9124
|
+
});
|
|
9125
|
+
}
|
|
9029
9126
|
function createAppErrorHandler(params) {
|
|
9030
9127
|
return (error, c) => {
|
|
9031
9128
|
if (error instanceof z24.ZodError) {
|
|
@@ -9049,7 +9146,7 @@ var openApiDocConfig = {
|
|
|
9049
9146
|
info: {
|
|
9050
9147
|
title: "TrueForge API",
|
|
9051
9148
|
description: "HTTP API for the TrueForge agent server (`/api/v1`). Interactive docs are served at `/api/v1/docs` (OpenAPI JSON at `/api/v1/openapi.json`).\n\n**Authentication:** Standalone deployments (no OIDC) accept requests without credentials \u2014 middleware stamps a local default user. When OIDC is configured, protected routes require a valid `id_token` cookie or `Authorization: Bearer` ID token. There is no built-in API-key scheme; pass custom headers only if your reverse proxy or IdP layer requires them.\n\nCovers DB-backed sessions, the agent registry, settings catalogs, and model/MCP/skill/sandbox providers.",
|
|
9052
|
-
version:
|
|
9149
|
+
version: PACKAGE_VERSION
|
|
9053
9150
|
}
|
|
9054
9151
|
};
|
|
9055
9152
|
function registerOpenApiBearerAuth(app) {
|
|
@@ -9088,6 +9185,7 @@ function withAdminAuth(router) {
|
|
|
9088
9185
|
function createServerApp(deps) {
|
|
9089
9186
|
const app = new OpenAPIHono14({ defaultHook: zodValidationHook });
|
|
9090
9187
|
const authEnabled = deps.oidcClient != null;
|
|
9188
|
+
app.use("*", createRequestBodyLimitMiddleware(config_default.MAX_REQUEST_BODY_BYTES));
|
|
9091
9189
|
app.get("/healthz", (c) => c.text("OK!"));
|
|
9092
9190
|
app.route("/api/v1/auth", createAuthRouter({ oidcClient: deps.oidcClient, logger: deps.logger }));
|
|
9093
9191
|
app.route(
|
|
@@ -9480,7 +9578,7 @@ import { serveStatic } from "@hono/node-server/serve-static";
|
|
|
9480
9578
|
import { every } from "hono/combine";
|
|
9481
9579
|
import { compress } from "hono/compress";
|
|
9482
9580
|
import { existsSync as existsSync2 } from "fs";
|
|
9483
|
-
import
|
|
9581
|
+
import path3 from "path";
|
|
9484
9582
|
var SERVER_PATH_PREFIXES = ["/api", "/healthz"];
|
|
9485
9583
|
var HASHED_ASSET_PREFIX = "/assets/";
|
|
9486
9584
|
var IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
@@ -9489,7 +9587,7 @@ function isServerPath(pathname) {
|
|
|
9489
9587
|
return SERVER_PATH_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`));
|
|
9490
9588
|
}
|
|
9491
9589
|
function mountFrontend(app, dir) {
|
|
9492
|
-
if (!existsSync2(
|
|
9590
|
+
if (!existsSync2(path3.join(dir, "index.html"))) {
|
|
9493
9591
|
return false;
|
|
9494
9592
|
}
|
|
9495
9593
|
const serveFile = serveStatic({ root: dir, precompressed: true });
|
|
@@ -9504,14 +9602,108 @@ function mountFrontend(app, dir) {
|
|
|
9504
9602
|
};
|
|
9505
9603
|
const serveCompressed = every(compress(), serveWithCacheHeaders);
|
|
9506
9604
|
const serveBuild = async (c, next) => {
|
|
9507
|
-
if (isServerPath(c.req.path))
|
|
9508
|
-
|
|
9605
|
+
if (isServerPath(c.req.path)) {
|
|
9606
|
+
return next();
|
|
9607
|
+
}
|
|
9608
|
+
if (c.req.method !== "GET" && c.req.method !== "HEAD") {
|
|
9609
|
+
return next();
|
|
9610
|
+
}
|
|
9509
9611
|
return serveCompressed(c, next);
|
|
9510
9612
|
};
|
|
9613
|
+
const serveAppShell = serveStatic({ root: dir, rewriteRequestPath: () => "/index.html", precompressed: true });
|
|
9614
|
+
const serveSpaFallback = async (c, next) => {
|
|
9615
|
+
if (isServerPath(c.req.path)) {
|
|
9616
|
+
return next();
|
|
9617
|
+
}
|
|
9618
|
+
if (c.req.method !== "GET" && c.req.method !== "HEAD") {
|
|
9619
|
+
return next();
|
|
9620
|
+
}
|
|
9621
|
+
if (c.req.header("accept")?.includes("text/html") !== true) {
|
|
9622
|
+
return next();
|
|
9623
|
+
}
|
|
9624
|
+
const response = await serveAppShell(c, next);
|
|
9625
|
+
if (response instanceof Response) {
|
|
9626
|
+
response.headers.set("Cache-Control", REVALIDATE_CACHE_CONTROL);
|
|
9627
|
+
response.headers.set("Vary", "Accept-Encoding");
|
|
9628
|
+
}
|
|
9629
|
+
return response;
|
|
9630
|
+
};
|
|
9511
9631
|
app.use("/*", serveBuild);
|
|
9632
|
+
app.use("/*", serveSpaFallback);
|
|
9512
9633
|
return true;
|
|
9513
9634
|
}
|
|
9514
9635
|
|
|
9636
|
+
// src/logger.ts
|
|
9637
|
+
import winston from "winston";
|
|
9638
|
+
var STANDALONE_META_SKIP = /* @__PURE__ */ new Set(["level", "message", "timestamp", "version", "stack", "splat"]);
|
|
9639
|
+
function shouldColorize() {
|
|
9640
|
+
const noColor = process.env["NO_COLOR"];
|
|
9641
|
+
if (noColor !== void 0 && noColor !== "") {
|
|
9642
|
+
return false;
|
|
9643
|
+
}
|
|
9644
|
+
const forceColor = process.env["FORCE_COLOR"];
|
|
9645
|
+
if (forceColor === "0") {
|
|
9646
|
+
return false;
|
|
9647
|
+
}
|
|
9648
|
+
if (forceColor !== void 0 && forceColor !== "") {
|
|
9649
|
+
return true;
|
|
9650
|
+
}
|
|
9651
|
+
return process.stderr.isTTY;
|
|
9652
|
+
}
|
|
9653
|
+
function standaloneMeta(info) {
|
|
9654
|
+
const copied = { ...info };
|
|
9655
|
+
const meta = {};
|
|
9656
|
+
for (const key of Object.keys(copied)) {
|
|
9657
|
+
if (STANDALONE_META_SKIP.has(key)) {
|
|
9658
|
+
continue;
|
|
9659
|
+
}
|
|
9660
|
+
meta[key] = copied[key];
|
|
9661
|
+
}
|
|
9662
|
+
if (Object.keys(meta).length === 0) {
|
|
9663
|
+
return "";
|
|
9664
|
+
}
|
|
9665
|
+
return ` ${JSON.stringify(meta)}`;
|
|
9666
|
+
}
|
|
9667
|
+
function standaloneFormat(color) {
|
|
9668
|
+
const parts = [
|
|
9669
|
+
winston.format.timestamp({ format: "HH:mm:ss" }),
|
|
9670
|
+
winston.format.errors({ stack: true })
|
|
9671
|
+
];
|
|
9672
|
+
if (color) {
|
|
9673
|
+
parts.push(winston.format.colorize({ level: true }));
|
|
9674
|
+
}
|
|
9675
|
+
parts.push(
|
|
9676
|
+
winston.format.printf((info) => {
|
|
9677
|
+
const extra = standaloneMeta(info);
|
|
9678
|
+
const stack = typeof info["stack"] === "string" ? `
|
|
9679
|
+
${info["stack"]}` : "";
|
|
9680
|
+
return `${String(info["timestamp"])} ${info.level} ${String(info.message)}${extra}${stack}`;
|
|
9681
|
+
})
|
|
9682
|
+
);
|
|
9683
|
+
return winston.format.combine(...parts);
|
|
9684
|
+
}
|
|
9685
|
+
function jsonFormat() {
|
|
9686
|
+
return winston.format.combine(
|
|
9687
|
+
winston.format.timestamp(),
|
|
9688
|
+
winston.format.errors({ stack: true }),
|
|
9689
|
+
winston.format.json()
|
|
9690
|
+
);
|
|
9691
|
+
}
|
|
9692
|
+
function serverLogFormat(options) {
|
|
9693
|
+
if (options.standalone) {
|
|
9694
|
+
return standaloneFormat(shouldColorize());
|
|
9695
|
+
}
|
|
9696
|
+
return jsonFormat();
|
|
9697
|
+
}
|
|
9698
|
+
function createServerLogger(options) {
|
|
9699
|
+
return winston.createLogger({
|
|
9700
|
+
level: options.level,
|
|
9701
|
+
defaultMeta: { version: options.version },
|
|
9702
|
+
format: serverLogFormat({ standalone: options.standalone }),
|
|
9703
|
+
transports: [new winston.transports.Console()]
|
|
9704
|
+
});
|
|
9705
|
+
}
|
|
9706
|
+
|
|
9515
9707
|
// src/runtime/activeTurns.ts
|
|
9516
9708
|
import "@truefoundry/trueforge-core/agent-session";
|
|
9517
9709
|
function activeTurnKey(sessionId, turnId) {
|
|
@@ -9594,6 +9786,118 @@ var ActiveTurnRegistry = class {
|
|
|
9594
9786
|
}
|
|
9595
9787
|
};
|
|
9596
9788
|
|
|
9789
|
+
// src/startupBanner.ts
|
|
9790
|
+
var STANDALONE_MODE_DISCLAIMER = "Standalone mode is intended for local use on your own machine. It is not hardened for production or shared internet access \u2014 please keep it on localhost. We cannot take responsibility for data loss or unauthorized access if this mode is used beyond that.";
|
|
9791
|
+
var ANSI_SHADOW = {
|
|
9792
|
+
T: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D", " \u2588\u2588\u2551 ", " \u2588\u2588\u2551 ", " \u2588\u2588\u2551 ", " \u255A\u2550\u255D "],
|
|
9793
|
+
R: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557", "\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D", "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2550\u255D \u255A\u2550\u255D"],
|
|
9794
|
+
U: ["\u2588\u2588\u2557 \u2588\u2588\u2557", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D", " \u255A\u2550\u2550\u2550\u2550\u2550\u255D "],
|
|
9795
|
+
E: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D", "\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u255D ", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"],
|
|
9796
|
+
F: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D", "\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u255D ", "\u2588\u2588\u2551 ", "\u255A\u2550\u255D "],
|
|
9797
|
+
O: [" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D", " \u255A\u2550\u2550\u2550\u2550\u2550\u255D "],
|
|
9798
|
+
G: [" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D ", "\u2588\u2588\u2551 \u2588\u2588\u2588\u2557", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D", " \u255A\u2550\u2550\u2550\u2550\u2550\u255D "]
|
|
9799
|
+
};
|
|
9800
|
+
var WORDMARK_TEXT = "TRUEFORGE";
|
|
9801
|
+
var WARNING_INNER_WIDTH = 72;
|
|
9802
|
+
var BRAND_COLOR = "\x1B[38;5;99m";
|
|
9803
|
+
var YELLOW = "\x1B[33m";
|
|
9804
|
+
var BOLD = "\x1B[1m";
|
|
9805
|
+
var DIM = "\x1B[2m";
|
|
9806
|
+
var RESET = "\x1B[0m";
|
|
9807
|
+
function glyphFor(ch) {
|
|
9808
|
+
const glyph = ANSI_SHADOW[ch];
|
|
9809
|
+
if (glyph === void 0) {
|
|
9810
|
+
throw new Error(`No ASCII glyph for ${JSON.stringify(ch)}`);
|
|
9811
|
+
}
|
|
9812
|
+
return glyph;
|
|
9813
|
+
}
|
|
9814
|
+
function rowOf(glyph, row) {
|
|
9815
|
+
const cell = glyph[row];
|
|
9816
|
+
if (cell === void 0) {
|
|
9817
|
+
throw new Error(`Glyph is missing row ${String(row)}`);
|
|
9818
|
+
}
|
|
9819
|
+
return cell;
|
|
9820
|
+
}
|
|
9821
|
+
function renderTrueForgeWordmark() {
|
|
9822
|
+
const glyphs = [];
|
|
9823
|
+
for (let i = 0; i < WORDMARK_TEXT.length; i += 1) {
|
|
9824
|
+
const ch = WORDMARK_TEXT[i];
|
|
9825
|
+
if (ch === void 0) {
|
|
9826
|
+
throw new Error(`Missing character at index ${String(i)}`);
|
|
9827
|
+
}
|
|
9828
|
+
glyphs.push(glyphFor(ch));
|
|
9829
|
+
}
|
|
9830
|
+
const rowCount = glyphs[0]?.length;
|
|
9831
|
+
if (rowCount === void 0) {
|
|
9832
|
+
throw new Error("Wordmark text must not be empty");
|
|
9833
|
+
}
|
|
9834
|
+
const rows = [];
|
|
9835
|
+
for (let row = 0; row < rowCount; row += 1) {
|
|
9836
|
+
rows.push(glyphs.map((glyph) => rowOf(glyph, row)).join(""));
|
|
9837
|
+
}
|
|
9838
|
+
return rows.join("\n");
|
|
9839
|
+
}
|
|
9840
|
+
function wrapText(text, width) {
|
|
9841
|
+
const words = text.split(/\s+/).filter((word) => word.length > 0);
|
|
9842
|
+
const lines = [];
|
|
9843
|
+
let current = "";
|
|
9844
|
+
for (const word of words) {
|
|
9845
|
+
if (current.length === 0) {
|
|
9846
|
+
if (word.length > width) {
|
|
9847
|
+
lines.push(word);
|
|
9848
|
+
} else {
|
|
9849
|
+
current = word;
|
|
9850
|
+
}
|
|
9851
|
+
continue;
|
|
9852
|
+
}
|
|
9853
|
+
const next = `${current} ${word}`;
|
|
9854
|
+
if (next.length <= width) {
|
|
9855
|
+
current = next;
|
|
9856
|
+
} else {
|
|
9857
|
+
lines.push(current);
|
|
9858
|
+
current = word.length > width ? "" : word;
|
|
9859
|
+
if (word.length > width) {
|
|
9860
|
+
lines.push(word);
|
|
9861
|
+
}
|
|
9862
|
+
}
|
|
9863
|
+
}
|
|
9864
|
+
if (current.length > 0) {
|
|
9865
|
+
lines.push(current);
|
|
9866
|
+
}
|
|
9867
|
+
return lines;
|
|
9868
|
+
}
|
|
9869
|
+
function paint(options) {
|
|
9870
|
+
if (!options.enabled) {
|
|
9871
|
+
return options.text;
|
|
9872
|
+
}
|
|
9873
|
+
return `${options.color}${options.text}${RESET}`;
|
|
9874
|
+
}
|
|
9875
|
+
function warningBox(message) {
|
|
9876
|
+
const label = " WARNING ";
|
|
9877
|
+
const inner = wrapText(message, WARNING_INNER_WIDTH);
|
|
9878
|
+
const width = Math.max(WARNING_INNER_WIDTH, ...inner.map((line) => line.length), label.length);
|
|
9879
|
+
const topPad = width + 1 - label.length;
|
|
9880
|
+
const top = `\u250C\u2500${label}${"\u2500".repeat(topPad)}\u2510`;
|
|
9881
|
+
const body = inner.map((line) => `\u2502 ${line.padEnd(width)} \u2502`);
|
|
9882
|
+
const bottom = `\u2514${"\u2500".repeat(width + 2)}\u2518`;
|
|
9883
|
+
return [top, ...body, bottom].join("\n");
|
|
9884
|
+
}
|
|
9885
|
+
function formatStandaloneStartupBanner(options) {
|
|
9886
|
+
const { version, color } = options;
|
|
9887
|
+
const wordmark = paint({ text: renderTrueForgeWordmark(), color: `${BOLD}${BRAND_COLOR}`, enabled: color });
|
|
9888
|
+
const subtitle = paint({ text: ` TrueForge v${version} \xB7 standalone`, color: DIM, enabled: color });
|
|
9889
|
+
const warning = paint({ text: warningBox(STANDALONE_MODE_DISCLAIMER), color: `${BOLD}${YELLOW}`, enabled: color });
|
|
9890
|
+
return { wordmark: `
|
|
9891
|
+
${wordmark}
|
|
9892
|
+
${subtitle}
|
|
9893
|
+
`, warning };
|
|
9894
|
+
}
|
|
9895
|
+
function printStandaloneStartupBanner(options) {
|
|
9896
|
+
const { wordmark, warning } = formatStandaloneStartupBanner(options);
|
|
9897
|
+
console.log(wordmark);
|
|
9898
|
+
console.warn(warning);
|
|
9899
|
+
}
|
|
9900
|
+
|
|
9597
9901
|
// src/main.ts
|
|
9598
9902
|
var configuration2;
|
|
9599
9903
|
var isOidcConfigured2;
|
|
@@ -9608,7 +9912,7 @@ try {
|
|
|
9608
9912
|
}
|
|
9609
9913
|
async function createStandalonePersistence(options) {
|
|
9610
9914
|
const { sqlitePath, logger } = options;
|
|
9611
|
-
await mkdir(
|
|
9915
|
+
await mkdir(path6.dirname(sqlitePath), { recursive: true });
|
|
9612
9916
|
const [{ createSqliteDb: createSqliteDb2 }, { migrateSqliteToLatest: migrateSqliteToLatest2 }, sqliteStores] = await Promise.all([
|
|
9613
9917
|
Promise.resolve().then(() => (init_client(), client_exports)),
|
|
9614
9918
|
Promise.resolve().then(() => (init_migrateSqlite(), migrateSqlite_exports)),
|
|
@@ -9750,11 +10054,16 @@ async function createServerRuntime(persistence, logger) {
|
|
|
9750
10054
|
return { activeTurns, app, destroyDb, redis, requestReplyRouter };
|
|
9751
10055
|
}
|
|
9752
10056
|
try {
|
|
9753
|
-
const logger =
|
|
10057
|
+
const logger = createServerLogger({
|
|
9754
10058
|
level: configuration2.LOG_LEVEL,
|
|
9755
|
-
|
|
9756
|
-
|
|
10059
|
+
standalone: configuration2.STANDALONE,
|
|
10060
|
+
version: PACKAGE_VERSION
|
|
9757
10061
|
});
|
|
10062
|
+
if (configuration2.STANDALONE) {
|
|
10063
|
+
printStandaloneStartupBanner({ version: PACKAGE_VERSION, color: shouldColorize() });
|
|
10064
|
+
} else {
|
|
10065
|
+
logger.info("TrueForge starting", { mode: "distributed" });
|
|
10066
|
+
}
|
|
9758
10067
|
const { activeTurns, app, destroyDb, redis, requestReplyRouter } = configuration2.STANDALONE ? await createServerRuntime(
|
|
9759
10068
|
await createStandalonePersistence({ sqlitePath: configuration2.SQLITE_PATH, logger }),
|
|
9760
10069
|
logger
|
|
@@ -9787,8 +10096,8 @@ try {
|
|
|
9787
10096
|
});
|
|
9788
10097
|
await requestReplyExecutor.init();
|
|
9789
10098
|
}
|
|
9790
|
-
const server = serve({ fetch: app.fetch, port: configuration2.PORT }, (info) => {
|
|
9791
|
-
|
|
10099
|
+
const server = serve({ fetch: app.fetch, port: configuration2.PORT, hostname: configuration2.HOST }, (info) => {
|
|
10100
|
+
logger.info(`Agent server listening on http://${configuration2.HOST}:${String(info.port)} (docs at /api/v1/docs)`);
|
|
9792
10101
|
});
|
|
9793
10102
|
server.on("error", (error) => {
|
|
9794
10103
|
console.error("Failed to start server:", error instanceof Error ? error.message : error);
|
|
@@ -9797,7 +10106,9 @@ try {
|
|
|
9797
10106
|
if (configuration2.NODE_ENV !== "development") {
|
|
9798
10107
|
let shuttingDown = false;
|
|
9799
10108
|
const shutdown = async (signal) => {
|
|
9800
|
-
if (shuttingDown)
|
|
10109
|
+
if (shuttingDown) {
|
|
10110
|
+
return;
|
|
10111
|
+
}
|
|
9801
10112
|
shuttingDown = true;
|
|
9802
10113
|
logger.info(`Received ${signal}, draining connections before shutdown`);
|
|
9803
10114
|
setTimeout(() => {
|