@circuitwall/jarela 0.9.3 → 0.10.0
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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +2 -2
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +2 -2
- package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/v1/dashboard/metrics/route.js +72 -5
- package/.next/standalone/.next/server/app/api/v1/dashboard/metrics/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/extensions/route.js +2 -2
- package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/secrets/route.js +2 -2
- package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/run/route.js +136 -26
- package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/run/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/tools/route.js +2 -2
- package/.next/standalone/.next/server/app/index.html +2 -2
- package/.next/standalone/.next/server/app/index.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page.js +266 -40
- package/.next/standalone/.next/server/app/page.js.map +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/setup.html +1 -1
- package/.next/standalone/.next/server/app/setup.rsc +2 -2
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/setup.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/setup.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/setup.segments/setup.segment.rsc +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +2 -2
- package/.next/standalone/.next/server/chunks/210.js +1 -1
- package/.next/standalone/.next/server/chunks/2151.js +60 -2
- package/.next/standalone/.next/server/chunks/2151.js.map +1 -1
- package/.next/standalone/.next/server/chunks/614.js +336 -93
- package/.next/standalone/.next/server/chunks/614.js.map +1 -1
- package/.next/standalone/.next/server/chunks/6765.js +35 -0
- package/.next/standalone/.next/server/chunks/6765.js.map +1 -1
- package/.next/standalone/.next/server/chunks/8697.js +15246 -15002
- package/.next/standalone/.next/server/chunks/8697.js.map +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +2 -2
- package/.next/standalone/.next/server/pages/404.html +2 -2
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/{3741-344e2bfc5028b9c8.js → 3741-2d64471ff763b8fa.js} +36 -1
- package/.next/standalone/.next/static/chunks/3741-2d64471ff763b8fa.js.map +1 -0
- package/.next/standalone/.next/static/chunks/app/{page-c77ab600642bbfc2.js → page-318743bf47fac345.js} +267 -41
- package/.next/standalone/.next/static/chunks/app/page-318743bf47fac345.js.map +1 -0
- package/.next/standalone/.next/static/css/b6b85b0f13bc0e98.css +5 -0
- package/.next/standalone/.next/static/css/b6b85b0f13bc0e98.css.map +1 -0
- package/.next/standalone/package.json +1 -1
- package/CHANGELOG.md +48 -0
- package/README.md +2 -0
- package/api/client.ts +37 -1
- package/api/types.ts +18 -0
- package/app/api/v1/threads/[thread_id]/run/route.ts +69 -22
- package/components/agents/AgentEditor.tsx +7 -4
- package/components/chat/MessageBubble.tsx +108 -1
- package/components/dashboard/DashboardPanel.tsx +79 -21
- package/hooks/useSSE.ts +22 -9
- package/lib/agents/prepare/system-prompt.ts +30 -0
- package/lib/agents/run-registry.test.ts +94 -0
- package/lib/agents/run-registry.ts +60 -1
- package/lib/stores/dashboard-metrics.test.ts +33 -0
- package/lib/stores/dashboard-metrics.ts +93 -1
- package/lib/tools/exec.ts +9 -5
- package/lib/tools/files.ts +6 -0
- package/lib/tools/safety.test.ts +95 -0
- package/lib/tools/safety.ts +147 -0
- package/package.json +1 -1
- package/.next/standalone/.next/static/chunks/3741-344e2bfc5028b9c8.js.map +0 -1
- package/.next/standalone/.next/static/chunks/app/page-c77ab600642bbfc2.js.map +0 -1
- package/.next/standalone/.next/static/css/53f85613a5500253.css +0 -5
- package/.next/standalone/.next/static/css/53f85613a5500253.css.map +0 -1
- /package/.next/standalone/.next/static/{6uLoytvvEtLKIblEB53e0 → 8qTBpUDFnSMYwe3Zc0bGV}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{6uLoytvvEtLKIblEB53e0 → 8qTBpUDFnSMYwe3Zc0bGV}/_ssgManifest.js +0 -0
|
@@ -1562,95 +1562,7 @@ function loadExternalTools(builtinNames) {
|
|
|
1562
1562
|
|
|
1563
1563
|
/***/ }),
|
|
1564
1564
|
|
|
1565
|
-
/***/
|
|
1566
|
-
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
1567
|
-
|
|
1568
|
-
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1569
|
-
/* harmony export */ V: () => (/* binding */ collectStream)
|
|
1570
|
-
/* harmony export */ });
|
|
1571
|
-
// Shared collector for agent stream consumers.
|
|
1572
|
-
//
|
|
1573
|
-
// Previously three near-identical drain loops lived in:
|
|
1574
|
-
// - app/api/v1/threads/[thread_id]/run/route.ts (HTTP run)
|
|
1575
|
-
// - lib/scheduler/index.ts (cron tasks)
|
|
1576
|
-
// - lib/bridges/dispatcher.ts (WhatsApp / bridges)
|
|
1577
|
-
//
|
|
1578
|
-
// They all read `prepared.stream`, accumulate `text_delta` into a single
|
|
1579
|
-
// assistant string, record `tool_call`/`tool_result` events, stop on
|
|
1580
|
-
// `done`/`error`, and surface the terminal state. This helper unifies that.
|
|
1581
|
-
/** Drain an async stream of `StreamChunk` into a single `CollectedRun`. */ async function collectStream(stream, opts = {}) {
|
|
1582
|
-
const result = {
|
|
1583
|
-
assistantContent: "",
|
|
1584
|
-
usedTools: [],
|
|
1585
|
-
toolEvents: [],
|
|
1586
|
-
terminal: "done"
|
|
1587
|
-
};
|
|
1588
|
-
try {
|
|
1589
|
-
for await (const chunk of stream){
|
|
1590
|
-
opts.onChunk?.(chunk);
|
|
1591
|
-
switch(chunk.type){
|
|
1592
|
-
case "text_delta":
|
|
1593
|
-
{
|
|
1594
|
-
result.assistantContent += chunk.data.delta ?? "";
|
|
1595
|
-
break;
|
|
1596
|
-
}
|
|
1597
|
-
case "tool_call":
|
|
1598
|
-
{
|
|
1599
|
-
const d = chunk.data;
|
|
1600
|
-
if (d.name) result.usedTools.push(d.name);
|
|
1601
|
-
result.toolEvents.push({
|
|
1602
|
-
id: d.id ?? `call-${result.toolEvents.length}`,
|
|
1603
|
-
phase: "call",
|
|
1604
|
-
name: d.name ?? "",
|
|
1605
|
-
payload: d.arguments
|
|
1606
|
-
});
|
|
1607
|
-
break;
|
|
1608
|
-
}
|
|
1609
|
-
case "tool_result":
|
|
1610
|
-
{
|
|
1611
|
-
const d = chunk.data;
|
|
1612
|
-
result.toolEvents.push({
|
|
1613
|
-
id: d.id ?? `result-${result.toolEvents.length}`,
|
|
1614
|
-
phase: "result",
|
|
1615
|
-
name: d.name ?? "",
|
|
1616
|
-
payload: d.result
|
|
1617
|
-
});
|
|
1618
|
-
break;
|
|
1619
|
-
}
|
|
1620
|
-
case "error":
|
|
1621
|
-
{
|
|
1622
|
-
result.terminal = "error";
|
|
1623
|
-
const msg = chunk.data?.message;
|
|
1624
|
-
if (typeof msg === "string") result.errorMessage = msg;
|
|
1625
|
-
return result;
|
|
1626
|
-
}
|
|
1627
|
-
case "done":
|
|
1628
|
-
{
|
|
1629
|
-
const d = chunk.data;
|
|
1630
|
-
if (d?.usage && d.provider && d.model_id && d.usage.source === "provider") {
|
|
1631
|
-
result.usage = {
|
|
1632
|
-
input_tokens: d.usage.input_tokens ?? 0,
|
|
1633
|
-
output_tokens: d.usage.output_tokens ?? 0,
|
|
1634
|
-
provider: d.provider,
|
|
1635
|
-
model_id: d.model_id,
|
|
1636
|
-
model_config_name: d.model_config_name ?? null
|
|
1637
|
-
};
|
|
1638
|
-
}
|
|
1639
|
-
return result;
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
}
|
|
1643
|
-
} catch (err) {
|
|
1644
|
-
result.terminal = "error";
|
|
1645
|
-
result.errorMessage = err instanceof Error ? err.message : String(err);
|
|
1646
|
-
}
|
|
1647
|
-
return result;
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
/***/ }),
|
|
1652
|
-
|
|
1653
|
-
/***/ 33934:
|
|
1565
|
+
/***/ 23696:
|
|
1654
1566
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
1655
1567
|
|
|
1656
1568
|
|
|
@@ -2037,12 +1949,211 @@ const documentsIndexUrl = (0,tools/* tool */.z6)(async ({ input })=>{
|
|
|
2037
1949
|
var external_node_child_process_ = __webpack_require__(31421);
|
|
2038
1950
|
// EXTERNAL MODULE: ./lib/env/allowlist.ts
|
|
2039
1951
|
var allowlist = __webpack_require__(23593);
|
|
1952
|
+
;// ./lib/tools/safety.ts
|
|
1953
|
+
// Safety mode for destructive built-in tools (exec + filesystem writes).
|
|
1954
|
+
//
|
|
1955
|
+
// Resolved once per call from `JARELA_TOOL_SAFETY`. Three tiers:
|
|
1956
|
+
//
|
|
1957
|
+
// "safe" — read-only. Exec accepts only an allowlisted set of
|
|
1958
|
+
// inspection commands (ls, git status, …); filesystem
|
|
1959
|
+
// tools refuse every write, edit, move, copy, delete,
|
|
1960
|
+
// or mkdir. Per-call `allow_unsafe` is IGNORED.
|
|
1961
|
+
// "mostly_safe" — default. Exec blocks the obviously-dangerous pattern
|
|
1962
|
+
// list (rm -rf /, shutdown, fork bomb, …); filesystem
|
|
1963
|
+
// tools refuse credential paths and the Jarela data dir.
|
|
1964
|
+
// Per-call `allow_unsafe=true` lifts the exec block for
|
|
1965
|
+
// that single call.
|
|
1966
|
+
// "bypass" — every guard off. For local development on a machine
|
|
1967
|
+
// you control and trust completely. NOT for use behind
|
|
1968
|
+
// a tunnel or with untrusted prompt sources.
|
|
1969
|
+
//
|
|
1970
|
+
// The mode is process-wide so prompt injection cannot escalate by
|
|
1971
|
+
// passing arguments — the LLM can only ever *downgrade* (via
|
|
1972
|
+
// `allow_unsafe=false` semantics, which is just "don't try to bypass").
|
|
1973
|
+
function resolveSafetyMode() {
|
|
1974
|
+
const raw = (process.env.JARELA_TOOL_SAFETY ?? "").trim().toLowerCase();
|
|
1975
|
+
if (raw === "safe") return "safe";
|
|
1976
|
+
if (raw === "bypass" || raw === "unsafe") return "bypass";
|
|
1977
|
+
return "mostly_safe";
|
|
1978
|
+
}
|
|
1979
|
+
// Inspection-only commands allowed in `safe` mode. Matched as the FIRST
|
|
1980
|
+
// token (after stripping leading whitespace) — pipelines, redirections,
|
|
1981
|
+
// command substitution, &&, ;, etc. are all rejected because we cannot
|
|
1982
|
+
// reason about what the right-hand side will do.
|
|
1983
|
+
const SAFE_EXEC_ALLOWLIST = new Set([
|
|
1984
|
+
"ls",
|
|
1985
|
+
"dir",
|
|
1986
|
+
"pwd",
|
|
1987
|
+
"cd",
|
|
1988
|
+
"echo",
|
|
1989
|
+
"cat",
|
|
1990
|
+
"type",
|
|
1991
|
+
"head",
|
|
1992
|
+
"tail",
|
|
1993
|
+
"wc",
|
|
1994
|
+
"stat",
|
|
1995
|
+
"file",
|
|
1996
|
+
"which",
|
|
1997
|
+
"where",
|
|
1998
|
+
"whoami",
|
|
1999
|
+
"hostname",
|
|
2000
|
+
"date",
|
|
2001
|
+
"uname",
|
|
2002
|
+
"df",
|
|
2003
|
+
"du",
|
|
2004
|
+
"ps",
|
|
2005
|
+
"env",
|
|
2006
|
+
"printenv",
|
|
2007
|
+
"git",
|
|
2008
|
+
"node",
|
|
2009
|
+
"npm",
|
|
2010
|
+
"npx",
|
|
2011
|
+
"deno",
|
|
2012
|
+
"python",
|
|
2013
|
+
"python3",
|
|
2014
|
+
"pip",
|
|
2015
|
+
"pip3"
|
|
2016
|
+
]);
|
|
2017
|
+
// Subcommands considered read-only for tools that take a verb. We only
|
|
2018
|
+
// need to enumerate the dangerous tools here — anything not listed falls
|
|
2019
|
+
// back to "the whole tool is read-only" (e.g. `cat`, `ls`).
|
|
2020
|
+
const SAFE_SUBCOMMANDS = {
|
|
2021
|
+
git: new Set([
|
|
2022
|
+
"status",
|
|
2023
|
+
"log",
|
|
2024
|
+
"diff",
|
|
2025
|
+
"show",
|
|
2026
|
+
"blame",
|
|
2027
|
+
"branch",
|
|
2028
|
+
"tag",
|
|
2029
|
+
"remote",
|
|
2030
|
+
"ls-files",
|
|
2031
|
+
"ls-tree",
|
|
2032
|
+
"config",
|
|
2033
|
+
"rev-parse",
|
|
2034
|
+
"describe",
|
|
2035
|
+
"shortlog",
|
|
2036
|
+
"reflog"
|
|
2037
|
+
]),
|
|
2038
|
+
npm: new Set([
|
|
2039
|
+
"ls",
|
|
2040
|
+
"list",
|
|
2041
|
+
"view",
|
|
2042
|
+
"info",
|
|
2043
|
+
"outdated",
|
|
2044
|
+
"config",
|
|
2045
|
+
"whoami",
|
|
2046
|
+
"ping",
|
|
2047
|
+
"doctor"
|
|
2048
|
+
]),
|
|
2049
|
+
npx: new Set([]),
|
|
2050
|
+
node: new Set([]),
|
|
2051
|
+
python: new Set([]),
|
|
2052
|
+
python3: new Set([]),
|
|
2053
|
+
deno: new Set([
|
|
2054
|
+
"info",
|
|
2055
|
+
"doc"
|
|
2056
|
+
]),
|
|
2057
|
+
pip: new Set([
|
|
2058
|
+
"list",
|
|
2059
|
+
"show",
|
|
2060
|
+
"freeze",
|
|
2061
|
+
"config"
|
|
2062
|
+
]),
|
|
2063
|
+
pip3: new Set([
|
|
2064
|
+
"list",
|
|
2065
|
+
"show",
|
|
2066
|
+
"freeze",
|
|
2067
|
+
"config"
|
|
2068
|
+
])
|
|
2069
|
+
};
|
|
2070
|
+
// Shell metacharacters that compose commands or redirect IO. Their
|
|
2071
|
+
// presence in `safe` mode is grounds for rejection because the
|
|
2072
|
+
// allowlist check only inspects the first token.
|
|
2073
|
+
const COMPOSER_RE = /[|&;`$<>]|\$\(|\|\||&&/;
|
|
2074
|
+
function checkExecAllowed(command, opts) {
|
|
2075
|
+
if (opts.mode === "bypass") return {
|
|
2076
|
+
allowed: true
|
|
2077
|
+
};
|
|
2078
|
+
if (opts.mode === "mostly_safe") {
|
|
2079
|
+
if (opts.blockedByPattern && !opts.allowUnsafe) {
|
|
2080
|
+
return {
|
|
2081
|
+
allowed: false,
|
|
2082
|
+
reason: "Command blocked by safety policy (mode=mostly_safe). Pass allow_unsafe=true only when you fully trust the command."
|
|
2083
|
+
};
|
|
2084
|
+
}
|
|
2085
|
+
return {
|
|
2086
|
+
allowed: true
|
|
2087
|
+
};
|
|
2088
|
+
}
|
|
2089
|
+
// safe mode
|
|
2090
|
+
const trimmed = command.trim();
|
|
2091
|
+
if (!trimmed) return {
|
|
2092
|
+
allowed: false,
|
|
2093
|
+
reason: "command is required"
|
|
2094
|
+
};
|
|
2095
|
+
if (COMPOSER_RE.test(trimmed)) {
|
|
2096
|
+
return {
|
|
2097
|
+
allowed: false,
|
|
2098
|
+
reason: "safe mode rejects pipelines, redirection, command substitution, &&, and ;. " + "Set JARELA_TOOL_SAFETY=mostly_safe (or bypass) to allow composite commands."
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
const tokens = trimmed.split(/\s+/);
|
|
2102
|
+
const head = tokens[0]?.toLowerCase();
|
|
2103
|
+
if (!head || !SAFE_EXEC_ALLOWLIST.has(head)) {
|
|
2104
|
+
return {
|
|
2105
|
+
allowed: false,
|
|
2106
|
+
reason: `safe mode allows only inspection commands (${[
|
|
2107
|
+
...SAFE_EXEC_ALLOWLIST
|
|
2108
|
+
].sort().join(", ")}). ` + "Set JARELA_TOOL_SAFETY=mostly_safe to enable the broader policy."
|
|
2109
|
+
};
|
|
2110
|
+
}
|
|
2111
|
+
const subAllowlist = SAFE_SUBCOMMANDS[head];
|
|
2112
|
+
if (subAllowlist) {
|
|
2113
|
+
const sub = tokens[1]?.toLowerCase().replace(/^--?/, "");
|
|
2114
|
+
// Allow bare invocations that are themselves read-only (e.g. `git`
|
|
2115
|
+
// alone prints help). Reject if the subcommand is missing for tools
|
|
2116
|
+
// that need one to be safe (node/python/npx → arbitrary code).
|
|
2117
|
+
if (subAllowlist.size === 0) {
|
|
2118
|
+
return {
|
|
2119
|
+
allowed: false,
|
|
2120
|
+
reason: `safe mode refuses '${head}' because it can execute arbitrary code. Use mostly_safe or bypass.`
|
|
2121
|
+
};
|
|
2122
|
+
}
|
|
2123
|
+
if (sub && !subAllowlist.has(sub)) {
|
|
2124
|
+
return {
|
|
2125
|
+
allowed: false,
|
|
2126
|
+
reason: `safe mode allows '${head}' only for: ${[
|
|
2127
|
+
...subAllowlist
|
|
2128
|
+
].sort().join(", ")}. ` + "Use mostly_safe or bypass for other subcommands."
|
|
2129
|
+
};
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
return {
|
|
2133
|
+
allowed: true
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
function checkFsAllowed(op, opts) {
|
|
2137
|
+
if (opts.mode === "bypass" || opts.mode === "mostly_safe") return {
|
|
2138
|
+
allowed: true
|
|
2139
|
+
};
|
|
2140
|
+
// safe mode: reads are fine, writes are not.
|
|
2141
|
+
if (op === "read") return {
|
|
2142
|
+
allowed: true
|
|
2143
|
+
};
|
|
2144
|
+
return {
|
|
2145
|
+
allowed: false,
|
|
2146
|
+
reason: "safe mode refuses filesystem mutations (write/edit/move/copy/delete/mkdir). " + "Set JARELA_TOOL_SAFETY=mostly_safe to enable writes outside credential dirs."
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2040
2150
|
;// ./lib/tools/exec.ts
|
|
2041
2151
|
|
|
2042
2152
|
|
|
2043
2153
|
|
|
2044
2154
|
|
|
2045
2155
|
|
|
2156
|
+
|
|
2046
2157
|
const MAX_OUTPUT_BYTES = 8000;
|
|
2047
2158
|
const DEFAULT_TIMEOUT_MS = 10000;
|
|
2048
2159
|
const MAX_TIMEOUT_MS = 60000;
|
|
@@ -2074,10 +2185,17 @@ function runLocalCommand(command, options) {
|
|
|
2074
2185
|
});
|
|
2075
2186
|
}
|
|
2076
2187
|
const timeout = Math.min(options.timeout_ms ?? DEFAULT_TIMEOUT_MS, MAX_TIMEOUT_MS);
|
|
2077
|
-
|
|
2188
|
+
const mode = resolveSafetyMode();
|
|
2189
|
+
const gate = checkExecAllowed(command, {
|
|
2190
|
+
mode,
|
|
2191
|
+
allowUnsafe: options.allow_unsafe,
|
|
2192
|
+
blockedByPattern: isBlockedCommand(command)
|
|
2193
|
+
});
|
|
2194
|
+
if (!gate.allowed) {
|
|
2078
2195
|
return JSON.stringify({
|
|
2079
2196
|
exit_code: 126,
|
|
2080
|
-
stderr:
|
|
2197
|
+
stderr: gate.reason,
|
|
2198
|
+
safety_mode: mode
|
|
2081
2199
|
});
|
|
2082
2200
|
}
|
|
2083
2201
|
const cwd = options.cwd?.trim() ? options.cwd : process.cwd();
|
|
@@ -2169,6 +2287,7 @@ var external_node_os_default = /*#__PURE__*/__webpack_require__.n(external_node_
|
|
|
2169
2287
|
|
|
2170
2288
|
|
|
2171
2289
|
|
|
2290
|
+
|
|
2172
2291
|
// Dedicated file tools. Agents previously had to drive every edit through
|
|
2173
2292
|
// `local_exec` / `shell_exec`, which works for "create a new file with this
|
|
2174
2293
|
// content" (echo / Set-Content) but is hostile to in-place edits: quoting
|
|
@@ -2250,6 +2369,13 @@ function jarelaDataDir() {
|
|
|
2250
2369
|
return process.env.JARELA_DB_DIR ? external_node_path_default().resolve(process.env.JARELA_DB_DIR) : external_node_path_default().join(external_node_os_default().homedir(), ".jarela");
|
|
2251
2370
|
}
|
|
2252
2371
|
function assertSafePath(abs, op) {
|
|
2372
|
+
const mode = resolveSafetyMode();
|
|
2373
|
+
const gate = checkFsAllowed(op, {
|
|
2374
|
+
mode
|
|
2375
|
+
});
|
|
2376
|
+
if (!gate.allowed) throw new Error(gate.reason);
|
|
2377
|
+
// bypass mode disables every guard, including the credential denylist.
|
|
2378
|
+
if (mode === "bypass") return;
|
|
2253
2379
|
if (process.env.JARELA_ALLOW_SENSITIVE_FILES === "1") return;
|
|
2254
2380
|
for (const base of sensitiveBase()){
|
|
2255
2381
|
if (isInside(abs, base)) {
|
|
@@ -5056,6 +5182,94 @@ function initTools() {
|
|
|
5056
5182
|
}
|
|
5057
5183
|
|
|
5058
5184
|
|
|
5185
|
+
/***/ }),
|
|
5186
|
+
|
|
5187
|
+
/***/ 30685:
|
|
5188
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
5189
|
+
|
|
5190
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
5191
|
+
/* harmony export */ V: () => (/* binding */ collectStream)
|
|
5192
|
+
/* harmony export */ });
|
|
5193
|
+
// Shared collector for agent stream consumers.
|
|
5194
|
+
//
|
|
5195
|
+
// Previously three near-identical drain loops lived in:
|
|
5196
|
+
// - app/api/v1/threads/[thread_id]/run/route.ts (HTTP run)
|
|
5197
|
+
// - lib/scheduler/index.ts (cron tasks)
|
|
5198
|
+
// - lib/bridges/dispatcher.ts (WhatsApp / bridges)
|
|
5199
|
+
//
|
|
5200
|
+
// They all read `prepared.stream`, accumulate `text_delta` into a single
|
|
5201
|
+
// assistant string, record `tool_call`/`tool_result` events, stop on
|
|
5202
|
+
// `done`/`error`, and surface the terminal state. This helper unifies that.
|
|
5203
|
+
/** Drain an async stream of `StreamChunk` into a single `CollectedRun`. */ async function collectStream(stream, opts = {}) {
|
|
5204
|
+
const result = {
|
|
5205
|
+
assistantContent: "",
|
|
5206
|
+
usedTools: [],
|
|
5207
|
+
toolEvents: [],
|
|
5208
|
+
terminal: "done"
|
|
5209
|
+
};
|
|
5210
|
+
try {
|
|
5211
|
+
for await (const chunk of stream){
|
|
5212
|
+
opts.onChunk?.(chunk);
|
|
5213
|
+
switch(chunk.type){
|
|
5214
|
+
case "text_delta":
|
|
5215
|
+
{
|
|
5216
|
+
result.assistantContent += chunk.data.delta ?? "";
|
|
5217
|
+
break;
|
|
5218
|
+
}
|
|
5219
|
+
case "tool_call":
|
|
5220
|
+
{
|
|
5221
|
+
const d = chunk.data;
|
|
5222
|
+
if (d.name) result.usedTools.push(d.name);
|
|
5223
|
+
result.toolEvents.push({
|
|
5224
|
+
id: d.id ?? `call-${result.toolEvents.length}`,
|
|
5225
|
+
phase: "call",
|
|
5226
|
+
name: d.name ?? "",
|
|
5227
|
+
payload: d.arguments
|
|
5228
|
+
});
|
|
5229
|
+
break;
|
|
5230
|
+
}
|
|
5231
|
+
case "tool_result":
|
|
5232
|
+
{
|
|
5233
|
+
const d = chunk.data;
|
|
5234
|
+
result.toolEvents.push({
|
|
5235
|
+
id: d.id ?? `result-${result.toolEvents.length}`,
|
|
5236
|
+
phase: "result",
|
|
5237
|
+
name: d.name ?? "",
|
|
5238
|
+
payload: d.result
|
|
5239
|
+
});
|
|
5240
|
+
break;
|
|
5241
|
+
}
|
|
5242
|
+
case "error":
|
|
5243
|
+
{
|
|
5244
|
+
result.terminal = "error";
|
|
5245
|
+
const msg = chunk.data?.message;
|
|
5246
|
+
if (typeof msg === "string") result.errorMessage = msg;
|
|
5247
|
+
return result;
|
|
5248
|
+
}
|
|
5249
|
+
case "done":
|
|
5250
|
+
{
|
|
5251
|
+
const d = chunk.data;
|
|
5252
|
+
if (d?.usage && d.provider && d.model_id && d.usage.source === "provider") {
|
|
5253
|
+
result.usage = {
|
|
5254
|
+
input_tokens: d.usage.input_tokens ?? 0,
|
|
5255
|
+
output_tokens: d.usage.output_tokens ?? 0,
|
|
5256
|
+
provider: d.provider,
|
|
5257
|
+
model_id: d.model_id,
|
|
5258
|
+
model_config_name: d.model_config_name ?? null
|
|
5259
|
+
};
|
|
5260
|
+
}
|
|
5261
|
+
return result;
|
|
5262
|
+
}
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
5265
|
+
} catch (err) {
|
|
5266
|
+
result.terminal = "error";
|
|
5267
|
+
result.errorMessage = err instanceof Error ? err.message : String(err);
|
|
5268
|
+
}
|
|
5269
|
+
return result;
|
|
5270
|
+
}
|
|
5271
|
+
|
|
5272
|
+
|
|
5059
5273
|
/***/ }),
|
|
5060
5274
|
|
|
5061
5275
|
/***/ 38710:
|
|
@@ -5081,8 +5295,8 @@ var dist_messages = __webpack_require__(12016);
|
|
|
5081
5295
|
var providers = __webpack_require__(68866);
|
|
5082
5296
|
// EXTERNAL MODULE: ./lib/stores/model-config.ts
|
|
5083
5297
|
var model_config = __webpack_require__(80937);
|
|
5084
|
-
// EXTERNAL MODULE: ./lib/tools/index.ts +
|
|
5085
|
-
var lib_tools = __webpack_require__(
|
|
5298
|
+
// EXTERNAL MODULE: ./lib/tools/index.ts + 19 modules
|
|
5299
|
+
var lib_tools = __webpack_require__(23696);
|
|
5086
5300
|
// EXTERNAL MODULE: ./node_modules/@langchain/core/dist/language_models/chat_models.js + 1 modules
|
|
5087
5301
|
var chat_models = __webpack_require__(87233);
|
|
5088
5302
|
// EXTERNAL MODULE: ./node_modules/@langchain/core/dist/outputs.js
|
|
@@ -6551,6 +6765,8 @@ var external_node_os_default = /*#__PURE__*/__webpack_require__.n(external_node_
|
|
|
6551
6765
|
var user_profile = __webpack_require__(67308);
|
|
6552
6766
|
// EXTERNAL MODULE: ./lib/stores/integrations.ts
|
|
6553
6767
|
var integrations = __webpack_require__(78228);
|
|
6768
|
+
// EXTERNAL MODULE: ./lib/stores/document-sources.ts
|
|
6769
|
+
var document_sources = __webpack_require__(91441);
|
|
6554
6770
|
// EXTERNAL MODULE: ./lib/agents/adaptive-persona-presets.ts
|
|
6555
6771
|
var adaptive_persona_presets = __webpack_require__(66849);
|
|
6556
6772
|
;// ./lib/agents/adaptive-persona.ts
|
|
@@ -6875,6 +7091,7 @@ var app_config = __webpack_require__(48954);
|
|
|
6875
7091
|
|
|
6876
7092
|
|
|
6877
7093
|
|
|
7094
|
+
|
|
6878
7095
|
const APP_NAME = (0,app_config/* getAppName */.fj)();
|
|
6879
7096
|
function buildSystemPrompt(ctx) {
|
|
6880
7097
|
const { agentCfg, trimmedMessage, budget, recallCtx, warmSummaryCtx, factsCtx, experienceMode, delegateRosterLines } = ctx;
|
|
@@ -6894,6 +7111,7 @@ function buildSystemPrompt(ctx) {
|
|
|
6894
7111
|
adaptivePersonaCtx,
|
|
6895
7112
|
buildUserContext(),
|
|
6896
7113
|
buildIntegrationsContext(),
|
|
7114
|
+
buildDocumentsContext(),
|
|
6897
7115
|
harnessParts.capabilities,
|
|
6898
7116
|
harnessParts.plan_first,
|
|
6899
7117
|
harnessParts.presentation,
|
|
@@ -7001,6 +7219,31 @@ function buildDelegatesContext(lines) {
|
|
|
7001
7219
|
...lines
|
|
7002
7220
|
].join("\n");
|
|
7003
7221
|
}
|
|
7222
|
+
// Surface indexed Documents so the model knows the RAG corpus exists.
|
|
7223
|
+
// Without this nudge agents almost never call `documents_search` — they have
|
|
7224
|
+
// no signal that any local content is searchable. Gated on actually-indexed
|
|
7225
|
+
// chunks (not just configured sources) so an empty/erroring source doesn't
|
|
7226
|
+
// produce false advertising.
|
|
7227
|
+
function buildDocumentsContext() {
|
|
7228
|
+
const sources = (0,document_sources/* listEnabledDocumentSources */.vU)();
|
|
7229
|
+
if (sources.length === 0) return "";
|
|
7230
|
+
let totalChunks = 0;
|
|
7231
|
+
const lines = [];
|
|
7232
|
+
for (const s of sources){
|
|
7233
|
+
const stats = (0,document_sources/* getDocumentSourceStats */.Io)(s.id);
|
|
7234
|
+
if (stats.chunk_count === 0) continue;
|
|
7235
|
+
totalChunks += stats.chunk_count;
|
|
7236
|
+
const label = s.label ?? s.path;
|
|
7237
|
+
lines.push(`- ${label} (${s.kind}, ${stats.chunk_count} chunks)`);
|
|
7238
|
+
}
|
|
7239
|
+
if (totalChunks === 0) return "";
|
|
7240
|
+
return [
|
|
7241
|
+
"--- Indexed documents ---",
|
|
7242
|
+
`The user has ${totalChunks} indexed chunks across ${lines.length} document source(s) available to you:`,
|
|
7243
|
+
...lines,
|
|
7244
|
+
"Call `documents_search` whenever the user asks about local files, notes, project docs, or any content that sounds like it lives in one of these sources. Prefer it over guessing from training data. Use `documents_list_sources` to enumerate, and pass `source_id` to scope a search."
|
|
7245
|
+
].join("\n");
|
|
7246
|
+
}
|
|
7004
7247
|
|
|
7005
7248
|
// EXTERNAL MODULE: ./lib/providers/known-context-windows.ts
|
|
7006
7249
|
var known_context_windows = __webpack_require__(45552);
|