@circuitwall/jarela 0.14.0 → 1.0.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 +1 -1
- 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/agents/[id]/route.js +6 -1
- package/.next/standalone/.next/server/app/api/v1/agents/[id]/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/agents/route.js +6 -1
- package/.next/standalone/.next/server/app/api/v1/agents/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/route.js +9 -1
- package/.next/standalone/.next/server/app/api/v1/bridges/[id]/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/bridges/route.js +9 -1
- package/.next/standalone/.next/server/app/api/v1/bridges/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/builtin-tools/route.js +36 -29
- package/.next/standalone/.next/server/app/api/v1/builtin-tools/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/events/route.js +7 -1
- package/.next/standalone/.next/server/app/api/v1/events/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/extensions/route.js +3 -3
- package/.next/standalone/.next/server/app/api/v1/extensions/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/secrets/route.js +4 -4
- package/.next/standalone/.next/server/app/api/v1/extensions/tools/[name]/secrets/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/health/route.js +7 -1
- package/.next/standalone/.next/server/app/api/v1/health/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/mcp-servers/[name]/route.js +9 -1
- package/.next/standalone/.next/server/app/api/v1/mcp-servers/[name]/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/mcp-servers/route.js +9 -1
- package/.next/standalone/.next/server/app/api/v1/mcp-servers/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/models/route.js +6 -1
- package/.next/standalone/.next/server/app/api/v1/models/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/page-capture/route.js +7 -1
- package/.next/standalone/.next/server/app/api/v1/page-capture/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/pending-actions/[id]/approve/route.js +14 -7
- package/.next/standalone/.next/server/app/api/v1/pending-actions/[id]/approve/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/providers/[provider]/models/route.js +28 -0
- package/.next/standalone/.next/server/app/api/v1/providers/[provider]/models/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/providers/route.js +7 -1
- package/.next/standalone/.next/server/app/api/v1/providers/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/route.js +16 -2
- package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/threads/[thread_id]/run/route.js +8 -1
- 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/threads/route.js +6 -1
- package/.next/standalone/.next/server/app/api/v1/threads/route.js.map +1 -1
- package/.next/standalone/.next/server/app/api/v1/tools/route.js +10 -3
- package/.next/standalone/.next/server/app/api/v1/tools/route.js.map +1 -1
- 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 +56 -0
- 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 +1 -1
- package/.next/standalone/.next/server/chunks/1683.js +2 -2
- package/.next/standalone/.next/server/chunks/2082.js +122 -13
- package/.next/standalone/.next/server/chunks/2082.js.map +1 -1
- package/.next/standalone/.next/server/chunks/210.js +3 -3
- package/.next/standalone/.next/server/chunks/210.js.map +1 -1
- package/.next/standalone/.next/server/chunks/239.js +1902 -1487
- package/.next/standalone/.next/server/chunks/239.js.map +1 -1
- package/.next/standalone/.next/server/chunks/2447.js +9 -1
- package/.next/standalone/.next/server/chunks/2447.js.map +1 -1
- package/.next/standalone/.next/server/chunks/423.js +125 -16
- package/.next/standalone/.next/server/chunks/423.js.map +1 -1
- package/.next/standalone/.next/server/chunks/4631.js +36 -29
- package/.next/standalone/.next/server/chunks/4631.js.map +1 -1
- package/.next/standalone/.next/server/chunks/5937.js +3 -2
- package/.next/standalone/.next/server/chunks/5937.js.map +1 -1
- package/.next/standalone/.next/server/chunks/{947.js → 8866.js} +11321 -10883
- package/.next/standalone/.next/server/chunks/8866.js.map +1 -0
- package/.next/standalone/.next/server/chunks/9032.js +3 -3
- package/.next/standalone/.next/server/chunks/9032.js.map +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +2 -2
- package/.next/standalone/.next/server/middleware.js +122 -13
- 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/proxy.js.map +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/app/{page-473b39ec30c7f569.js → page-a7cae65f235e2942.js} +57 -1
- package/.next/standalone/.next/static/chunks/app/page-a7cae65f235e2942.js.map +1 -0
- package/.next/standalone/.next/static/css/{6f8b1a84bcbcd467.css → e57bdbbbb5a05779.css} +2 -2
- package/.next/standalone/.next/static/css/e57bdbbbb5a05779.css.map +1 -0
- package/.next/standalone/package.json +9 -1
- package/CHANGELOG.md +90 -0
- package/README.md +30 -2
- package/api/types.ts +8 -0
- package/app/api/v1/agents/[id]/route.ts +7 -0
- package/app/api/v1/agents/route.ts +7 -0
- package/app/api/v1/events/route.ts +8 -0
- package/app/api/v1/extensions/route.ts +2 -2
- package/app/api/v1/extensions/tools/[name]/secrets/route.ts +3 -3
- package/app/api/v1/health/route.ts +8 -0
- package/app/api/v1/models/route.ts +7 -0
- package/app/api/v1/page-capture/route.ts +8 -0
- package/app/api/v1/providers/route.ts +8 -0
- package/app/api/v1/threads/[thread_id]/route.ts +8 -0
- package/app/api/v1/threads/[thread_id]/run/route.ts +9 -0
- package/app/api/v1/threads/route.ts +7 -0
- package/app/api/v1/tools/route.ts +9 -0
- package/components/chat/ContextUsageBar.tsx +44 -0
- package/lib/agents/llm.ts +25 -2
- package/lib/agents/run-thread.ts +13 -1
- package/lib/agents/stream-collector.ts +9 -1
- package/lib/api/serializers.test.ts +15 -0
- package/lib/api/serializers.ts +8 -0
- package/lib/db/migrations.ts +15 -0
- package/lib/health/runner.test.ts +24 -2
- package/lib/mcp/registry.ts +14 -6
- package/lib/providers/anthropic.test.ts +95 -0
- package/lib/providers/anthropic.ts +106 -10
- package/lib/providers/jarela-chat-model.ts +9 -1
- package/lib/providers/known-context-windows.ts +21 -0
- package/lib/providers/types.ts +21 -1
- package/lib/stores/message-usage.test.ts +34 -0
- package/lib/stores/message-usage.ts +15 -3
- package/lib/stores/pricing.test.ts +52 -0
- package/lib/stores/pricing.ts +26 -1
- package/lib/tools/builtins.ts +4 -0
- package/lib/tools/extension-surfaces.test.ts +79 -0
- package/lib/tools/extension-surfaces.ts +153 -0
- package/lib/tools/index.ts +27 -8
- package/lib/tools/list-tools.test.ts +76 -0
- package/lib/tools/list-tools.ts +84 -0
- package/lib/tools/mcp-servers-info.test.ts +73 -0
- package/lib/tools/mcp-servers-info.ts +71 -0
- package/lib/tools/providers-info.test.ts +73 -0
- package/lib/tools/providers-info.ts +106 -0
- package/lib/tools/registry.ts +36 -25
- package/lib/tools/types.ts +13 -0
- package/package.json +9 -1
- package/.next/standalone/.next/server/chunks/947.js.map +0 -1
- package/.next/standalone/.next/static/chunks/app/page-473b39ec30c7f569.js.map +0 -1
- package/.next/standalone/.next/static/css/6f8b1a84bcbcd467.css.map +0 -1
- /package/.next/standalone/.next/static/{T0p2VVPsJPj44rwbmjaFb → d_vhp-lJqfdjRFpnLVIqZ}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{T0p2VVPsJPj44rwbmjaFb → d_vhp-lJqfdjRFpnLVIqZ}/_ssgManifest.js +0 -0
|
@@ -1638,8 +1638,8 @@ var dist_messages = __webpack_require__(12016);
|
|
|
1638
1638
|
var providers = __webpack_require__(68866);
|
|
1639
1639
|
// EXTERNAL MODULE: ./lib/stores/model-config.ts
|
|
1640
1640
|
var model_config = __webpack_require__(80937);
|
|
1641
|
-
// EXTERNAL MODULE: ./lib/tools/index.ts +
|
|
1642
|
-
var lib_tools = __webpack_require__(
|
|
1641
|
+
// EXTERNAL MODULE: ./lib/tools/index.ts + 27 modules
|
|
1642
|
+
var lib_tools = __webpack_require__(36141);
|
|
1643
1643
|
// EXTERNAL MODULE: ./node_modules/@langchain/core/dist/language_models/chat_models.js + 1 modules
|
|
1644
1644
|
var chat_models = __webpack_require__(87233);
|
|
1645
1645
|
// EXTERNAL MODULE: ./node_modules/@langchain/core/dist/outputs.js
|
|
@@ -1832,15 +1832,26 @@ class JarelaChatModel extends chat_models/* BaseChatModel */.xV {
|
|
|
1832
1832
|
} else if (event.type === "usage") {
|
|
1833
1833
|
// ADR-0041: surface real provider token counts on the final
|
|
1834
1834
|
// AIMessageChunk via LangChain's standard `usage_metadata` field so
|
|
1835
|
-
// the agent loop can snapshot them into message_usage.
|
|
1835
|
+
// the agent loop can snapshot them into message_usage. PR #181 added
|
|
1836
|
+
// Anthropic prompt caching; carry the cache breakdown through
|
|
1837
|
+
// `input_token_details` (LangChain's standard channel) so cost
|
|
1838
|
+
// attribution downstream can apply the 1.25× / 0.1× rates.
|
|
1836
1839
|
emittedAny = true;
|
|
1840
|
+
const cacheCreation = event.cache_creation_input_tokens ?? 0;
|
|
1841
|
+
const cacheRead = event.cache_read_input_tokens ?? 0;
|
|
1837
1842
|
yield new outputs/* ChatGenerationChunk */.Cf({
|
|
1838
1843
|
message: new dist_messages/* AIMessageChunk */.H({
|
|
1839
1844
|
content: "",
|
|
1840
1845
|
usage_metadata: {
|
|
1841
1846
|
input_tokens: event.input_tokens ?? 0,
|
|
1842
1847
|
output_tokens: event.output_tokens ?? 0,
|
|
1843
|
-
total_tokens: event.total_tokens ?? (event.input_tokens ?? 0) + (event.output_tokens ?? 0)
|
|
1848
|
+
total_tokens: event.total_tokens ?? (event.input_tokens ?? 0) + (event.output_tokens ?? 0),
|
|
1849
|
+
...cacheCreation > 0 || cacheRead > 0 ? {
|
|
1850
|
+
input_token_details: {
|
|
1851
|
+
cache_creation: cacheCreation,
|
|
1852
|
+
cache_read: cacheRead
|
|
1853
|
+
}
|
|
1854
|
+
} : {}
|
|
1844
1855
|
}
|
|
1845
1856
|
}),
|
|
1846
1857
|
text: ""
|
|
@@ -2215,6 +2226,12 @@ async function* streamWithConfig(threadId, messages, options, signal) {
|
|
|
2215
2226
|
// JarelaChatModel; we sum them so the final figure covers the whole turn.
|
|
2216
2227
|
let usageInputTokens = 0;
|
|
2217
2228
|
let usageOutputTokens = 0;
|
|
2229
|
+
// PR #181 + cache-fidelity follow-up: Anthropic prompt-cache reads/writes
|
|
2230
|
+
// arrive as a separate breakdown via `input_token_details`. Sum them
|
|
2231
|
+
// independently so the dashboard can report cost correctly (cache reads
|
|
2232
|
+
// are 10× cheaper, cache writes 1.25× more expensive than fresh input).
|
|
2233
|
+
let usageCacheCreationTokens = 0;
|
|
2234
|
+
let usageCacheReadTokens = 0;
|
|
2218
2235
|
let sawUsage = false;
|
|
2219
2236
|
// Tracks whether the model hit max_tokens mid-stream. JarelaChatModel tags
|
|
2220
2237
|
// the final chunk with additional_kwargs.stop_reason="length" when this
|
|
@@ -2277,6 +2294,11 @@ async function* streamWithConfig(threadId, messages, options, signal) {
|
|
|
2277
2294
|
if (usage && (usage.input_tokens > 0 || usage.output_tokens > 0)) {
|
|
2278
2295
|
usageInputTokens += usage.input_tokens ?? 0;
|
|
2279
2296
|
usageOutputTokens += usage.output_tokens ?? 0;
|
|
2297
|
+
const details = usage.input_token_details;
|
|
2298
|
+
if (details) {
|
|
2299
|
+
usageCacheCreationTokens += details.cache_creation ?? 0;
|
|
2300
|
+
usageCacheReadTokens += details.cache_read ?? 0;
|
|
2301
|
+
}
|
|
2280
2302
|
sawUsage = true;
|
|
2281
2303
|
}
|
|
2282
2304
|
if (typeof chunk.content === "string" && chunk.content) {
|
|
@@ -2376,6 +2398,8 @@ async function* streamWithConfig(threadId, messages, options, signal) {
|
|
|
2376
2398
|
usage: sawUsage ? {
|
|
2377
2399
|
input_tokens: usageInputTokens,
|
|
2378
2400
|
output_tokens: usageOutputTokens,
|
|
2401
|
+
cache_creation_input_tokens: usageCacheCreationTokens,
|
|
2402
|
+
cache_read_input_tokens: usageCacheReadTokens,
|
|
2379
2403
|
source: "provider"
|
|
2380
2404
|
} : {
|
|
2381
2405
|
input_tokens: 0,
|
|
@@ -2472,6 +2496,8 @@ async function* streamWithConfig(threadId, messages, options, signal) {
|
|
|
2472
2496
|
usage: sawUsage ? {
|
|
2473
2497
|
input_tokens: usageInputTokens,
|
|
2474
2498
|
output_tokens: usageOutputTokens,
|
|
2499
|
+
cache_creation_input_tokens: usageCacheCreationTokens,
|
|
2500
|
+
cache_read_input_tokens: usageCacheReadTokens,
|
|
2475
2501
|
source: "provider"
|
|
2476
2502
|
} : {
|
|
2477
2503
|
input_tokens: 0,
|
|
@@ -3909,13 +3935,31 @@ function inferRatesFromSignals(signals) {
|
|
|
3909
3935
|
confidence: tokenRates.length >= 2 ? "medium" : "low"
|
|
3910
3936
|
};
|
|
3911
3937
|
}
|
|
3912
|
-
|
|
3938
|
+
// Anthropic prompt-cache multipliers, applied against the standard input
|
|
3939
|
+
// rate. Cache writes are billed at 1.25× input ("cache create"); cache
|
|
3940
|
+
// reads are billed at 0.1× input ("cache hit"). Source:
|
|
3941
|
+
// https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching#pricing
|
|
3942
|
+
// We apply the same multipliers to other providers that publish a
|
|
3943
|
+
// cache-token breakdown — OpenAI's prompt caching, for example, also
|
|
3944
|
+
// quotes a 0.5× read multiplier, but its API surfaces only `cached_tokens`
|
|
3945
|
+
// (no separate write count) and a future PR can split that out. For now
|
|
3946
|
+
// any provider that emits both fields will be priced as above.
|
|
3947
|
+
const CACHE_CREATION_INPUT_RATE_MULTIPLIER = 1.25;
|
|
3948
|
+
const CACHE_READ_INPUT_RATE_MULTIPLIER = 0.1;
|
|
3949
|
+
function estimateCostUsd(inputTokens, outputTokens, rates, cache) {
|
|
3913
3950
|
const inputRate = rates.inputPer1M;
|
|
3914
3951
|
const outputRate = rates.outputPer1M;
|
|
3915
3952
|
if (inputRate == null && outputRate == null) return 0;
|
|
3916
3953
|
const inCost = inputRate == null ? 0 : inputTokens / 1000000 * inputRate;
|
|
3917
3954
|
const outCost = outputRate == null ? 0 : outputTokens / 1000000 * outputRate;
|
|
3918
|
-
|
|
3955
|
+
let cacheCost = 0;
|
|
3956
|
+
if (cache && inputRate != null) {
|
|
3957
|
+
const create = cache.cache_creation_input_tokens ?? 0;
|
|
3958
|
+
const read = cache.cache_read_input_tokens ?? 0;
|
|
3959
|
+
if (create > 0) cacheCost += create / 1000000 * inputRate * CACHE_CREATION_INPUT_RATE_MULTIPLIER;
|
|
3960
|
+
if (read > 0) cacheCost += read / 1000000 * inputRate * CACHE_READ_INPUT_RATE_MULTIPLIER;
|
|
3961
|
+
}
|
|
3962
|
+
return inCost + outCost + cacheCost;
|
|
3919
3963
|
}
|
|
3920
3964
|
|
|
3921
3965
|
;// ./lib/agents/hallucination-classifier.ts
|
|
@@ -4832,7 +4876,12 @@ function persistAssistantMessage(thread_id, content, usedTools, toolEvents, cate
|
|
|
4832
4876
|
inputPer1M: null,
|
|
4833
4877
|
outputPer1M: null
|
|
4834
4878
|
};
|
|
4835
|
-
const
|
|
4879
|
+
const cacheCreation = hasProviderUsage ? usage.cache_creation_input_tokens ?? 0 : 0;
|
|
4880
|
+
const cacheRead = hasProviderUsage ? usage.cache_read_input_tokens ?? 0 : 0;
|
|
4881
|
+
const cost = hasProviderUsage ? estimateCostUsd(usage.input_tokens, usage.output_tokens, rates, {
|
|
4882
|
+
cache_creation_input_tokens: cacheCreation,
|
|
4883
|
+
cache_read_input_tokens: cacheRead
|
|
4884
|
+
}) : 0;
|
|
4836
4885
|
(0,message_usage/* recordMessageUsage */.up)({
|
|
4837
4886
|
message_id: row.msg_id,
|
|
4838
4887
|
thread_id,
|
|
@@ -4846,6 +4895,8 @@ function persistAssistantMessage(thread_id, content, usedTools, toolEvents, cate
|
|
|
4846
4895
|
input_rate_usd_per_mtok: rates.inputPer1M,
|
|
4847
4896
|
output_rate_usd_per_mtok: rates.outputPer1M,
|
|
4848
4897
|
cost_usd: cost,
|
|
4898
|
+
cache_creation_input_tokens: cacheCreation > 0 ? cacheCreation : null,
|
|
4899
|
+
cache_read_input_tokens: cacheRead > 0 ? cacheRead : null,
|
|
4849
4900
|
tier_usage: contextSnapshot ? {
|
|
4850
4901
|
hot_tokens: contextSnapshot.hot_tokens,
|
|
4851
4902
|
warm_tokens: contextSnapshot.warm_tokens,
|
|
@@ -5564,6 +5615,8 @@ function loadExternalTools(builtinNames) {
|
|
|
5564
5615
|
result.usage = {
|
|
5565
5616
|
input_tokens: d.usage.input_tokens ?? 0,
|
|
5566
5617
|
output_tokens: d.usage.output_tokens ?? 0,
|
|
5618
|
+
cache_creation_input_tokens: d.usage.cache_creation_input_tokens ?? 0,
|
|
5619
|
+
cache_read_input_tokens: d.usage.cache_read_input_tokens ?? 0,
|
|
5567
5620
|
provider: d.provider,
|
|
5568
5621
|
model_id: d.model_id,
|
|
5569
5622
|
model_config_name: d.model_config_name ?? null
|
|
@@ -5583,539 +5636,33 @@ function loadExternalTools(builtinNames) {
|
|
|
5583
5636
|
|
|
5584
5637
|
/***/ }),
|
|
5585
5638
|
|
|
5586
|
-
/***/
|
|
5639
|
+
/***/ 36141:
|
|
5587
5640
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
5588
5641
|
|
|
5589
|
-
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
5590
|
-
/* harmony export */ pN: () => (/* binding */ getKnownMaxOutputTokens),
|
|
5591
|
-
/* harmony export */ zJ: () => (/* binding */ getKnownContextLength)
|
|
5592
|
-
/* harmony export */ });
|
|
5593
|
-
/* unused harmony export getKnownModelLimits */
|
|
5594
|
-
// Web-sourced fallback context-window sizes per (provider, model_id).
|
|
5595
|
-
// Used when the live `/models` endpoint doesn't report `context_length`
|
|
5596
|
-
// (OpenAI's catalog and GitHub Copilot's catalog both omit it) AND the
|
|
5597
|
-
// user hasn't pinned `context_window_tokens` on the model config.
|
|
5598
|
-
//
|
|
5599
|
-
// Resolution order at runtime is:
|
|
5600
|
-
// 1. user-set `params.context_window_tokens` (explicit override)
|
|
5601
|
-
// 2. live API value via `listModels()` / catalog cache (when populated)
|
|
5602
|
-
// 3. this static fallback (this file)
|
|
5603
|
-
// 4. `DEFAULT_CONTEXT_WINDOW_TOKENS` in lib/agents/context-budget.ts
|
|
5604
|
-
//
|
|
5605
|
-
// Verified from each vendor's public docs as of 2026-06. Bump when vendors
|
|
5606
|
-
// publish new families.
|
|
5607
|
-
const ANTHROPIC = {
|
|
5608
|
-
"claude-opus-4-7": {
|
|
5609
|
-
context_length: 1000000,
|
|
5610
|
-
max_output_tokens: 8192
|
|
5611
|
-
},
|
|
5612
|
-
"claude-opus-4": {
|
|
5613
|
-
context_length: 200000,
|
|
5614
|
-
max_output_tokens: 8192
|
|
5615
|
-
},
|
|
5616
|
-
"claude-sonnet-4-6": {
|
|
5617
|
-
context_length: 200000,
|
|
5618
|
-
max_output_tokens: 8192
|
|
5619
|
-
},
|
|
5620
|
-
"claude-sonnet-4": {
|
|
5621
|
-
context_length: 200000,
|
|
5622
|
-
max_output_tokens: 8192
|
|
5623
|
-
},
|
|
5624
|
-
"claude-3.7-sonnet": {
|
|
5625
|
-
context_length: 200000,
|
|
5626
|
-
max_output_tokens: 8192
|
|
5627
|
-
},
|
|
5628
|
-
"claude-3-7-sonnet": {
|
|
5629
|
-
context_length: 200000,
|
|
5630
|
-
max_output_tokens: 8192
|
|
5631
|
-
},
|
|
5632
|
-
"claude-3-5-sonnet": {
|
|
5633
|
-
context_length: 200000,
|
|
5634
|
-
max_output_tokens: 8192
|
|
5635
|
-
},
|
|
5636
|
-
"claude-3-5-haiku": {
|
|
5637
|
-
context_length: 200000,
|
|
5638
|
-
max_output_tokens: 8192
|
|
5639
|
-
},
|
|
5640
|
-
"claude-haiku-4-5": {
|
|
5641
|
-
context_length: 200000,
|
|
5642
|
-
max_output_tokens: 4096
|
|
5643
|
-
},
|
|
5644
|
-
"claude-haiku-4": {
|
|
5645
|
-
context_length: 200000,
|
|
5646
|
-
max_output_tokens: 4096
|
|
5647
|
-
},
|
|
5648
|
-
"claude-3-opus": {
|
|
5649
|
-
context_length: 200000,
|
|
5650
|
-
max_output_tokens: 4096
|
|
5651
|
-
}
|
|
5652
|
-
};
|
|
5653
|
-
const GEMINI = {
|
|
5654
|
-
"gemini-2.5-pro": {
|
|
5655
|
-
context_length: 1048576,
|
|
5656
|
-
max_output_tokens: 65536
|
|
5657
|
-
},
|
|
5658
|
-
"gemini-2.5-flash": {
|
|
5659
|
-
context_length: 1048576,
|
|
5660
|
-
max_output_tokens: 65536
|
|
5661
|
-
},
|
|
5662
|
-
"gemini-2.0-flash-lite": {
|
|
5663
|
-
context_length: 1048576,
|
|
5664
|
-
max_output_tokens: 8192
|
|
5665
|
-
},
|
|
5666
|
-
"gemini-2.0-flash": {
|
|
5667
|
-
context_length: 1048576,
|
|
5668
|
-
max_output_tokens: 8192
|
|
5669
|
-
},
|
|
5670
|
-
"gemini-1.5-pro": {
|
|
5671
|
-
context_length: 2097152,
|
|
5672
|
-
max_output_tokens: 8192
|
|
5673
|
-
},
|
|
5674
|
-
"gemini-1.5-flash": {
|
|
5675
|
-
context_length: 1048576,
|
|
5676
|
-
max_output_tokens: 8192
|
|
5677
|
-
}
|
|
5678
|
-
};
|
|
5679
|
-
const OPENAI = {
|
|
5680
|
-
"gpt-5-mini": {
|
|
5681
|
-
context_length: 400000,
|
|
5682
|
-
max_output_tokens: 128000
|
|
5683
|
-
},
|
|
5684
|
-
"gpt-5": {
|
|
5685
|
-
context_length: 400000,
|
|
5686
|
-
max_output_tokens: 128000
|
|
5687
|
-
},
|
|
5688
|
-
"gpt-4.1-mini": {
|
|
5689
|
-
context_length: 1047576,
|
|
5690
|
-
max_output_tokens: 32768
|
|
5691
|
-
},
|
|
5692
|
-
"gpt-4.1": {
|
|
5693
|
-
context_length: 1047576,
|
|
5694
|
-
max_output_tokens: 32768
|
|
5695
|
-
},
|
|
5696
|
-
"gpt-4o-mini": {
|
|
5697
|
-
context_length: 128000,
|
|
5698
|
-
max_output_tokens: 16384
|
|
5699
|
-
},
|
|
5700
|
-
"gpt-4o": {
|
|
5701
|
-
context_length: 128000,
|
|
5702
|
-
max_output_tokens: 16384
|
|
5703
|
-
},
|
|
5704
|
-
"gpt-4-turbo": {
|
|
5705
|
-
context_length: 128000,
|
|
5706
|
-
max_output_tokens: 4096
|
|
5707
|
-
},
|
|
5708
|
-
"gpt-4": {
|
|
5709
|
-
context_length: 8192,
|
|
5710
|
-
max_output_tokens: 4096
|
|
5711
|
-
},
|
|
5712
|
-
"gpt-3.5-turbo": {
|
|
5713
|
-
context_length: 16385,
|
|
5714
|
-
max_output_tokens: 4096
|
|
5715
|
-
},
|
|
5716
|
-
"chatgpt-4o": {
|
|
5717
|
-
context_length: 128000,
|
|
5718
|
-
max_output_tokens: 16384
|
|
5719
|
-
},
|
|
5720
|
-
"o4-mini": {
|
|
5721
|
-
context_length: 200000,
|
|
5722
|
-
max_output_tokens: 100000
|
|
5723
|
-
},
|
|
5724
|
-
"o3-mini": {
|
|
5725
|
-
context_length: 200000,
|
|
5726
|
-
max_output_tokens: 100000
|
|
5727
|
-
},
|
|
5728
|
-
"o3": {
|
|
5729
|
-
context_length: 200000,
|
|
5730
|
-
max_output_tokens: 100000
|
|
5731
|
-
},
|
|
5732
|
-
"o1-mini": {
|
|
5733
|
-
context_length: 128000,
|
|
5734
|
-
max_output_tokens: 65536
|
|
5735
|
-
},
|
|
5736
|
-
"o1": {
|
|
5737
|
-
context_length: 200000,
|
|
5738
|
-
max_output_tokens: 100000
|
|
5739
|
-
}
|
|
5740
|
-
};
|
|
5741
|
-
const DEEPSEEK = {
|
|
5742
|
-
"deepseek-v4-flash": {
|
|
5743
|
-
context_length: 65536,
|
|
5744
|
-
max_output_tokens: 8192
|
|
5745
|
-
},
|
|
5746
|
-
"deepseek-v4-pro": {
|
|
5747
|
-
context_length: 65536,
|
|
5748
|
-
max_output_tokens: 8192
|
|
5749
|
-
},
|
|
5750
|
-
"deepseek-chat": {
|
|
5751
|
-
context_length: 65536,
|
|
5752
|
-
max_output_tokens: 8192
|
|
5753
|
-
},
|
|
5754
|
-
"deepseek-reasoner": {
|
|
5755
|
-
context_length: 65536,
|
|
5756
|
-
max_output_tokens: 8192
|
|
5757
|
-
}
|
|
5758
|
-
};
|
|
5759
|
-
// GitHub Copilot proxies vendor models — sometimes under a transformed id
|
|
5760
|
-
// (e.g. `Github-Opus4.6`, `copilot-claude-3.5-sonnet`). Strip the proxy
|
|
5761
|
-
// prefix and dispatch to the underlying vendor table.
|
|
5762
|
-
function resolveCopilot(model_id) {
|
|
5763
|
-
const normalized = model_id.replace(/^(?:Github-|copilot-)/i, "").toLowerCase();
|
|
5764
|
-
// Canonicalise a few proxy-specific spellings.
|
|
5765
|
-
const canon = normalized.replace(/^opus4\.6/, "claude-opus-4-7").replace(/^opus4/, "claude-opus-4").replace(/^sonnet4\.6/, "claude-sonnet-4-6").replace(/^sonnet4/, "claude-sonnet-4").replace(/^haiku4\.5/, "claude-haiku-4-5");
|
|
5766
|
-
if (canon.startsWith("claude")) return matchPrefix(ANTHROPIC, canon);
|
|
5767
|
-
if (canon.startsWith("gemini")) return matchPrefix(GEMINI, canon);
|
|
5768
|
-
if (canon.startsWith("gpt") || /^o[134](?:-|$)/.test(canon)) return matchPrefix(OPENAI, canon);
|
|
5769
|
-
return null;
|
|
5770
|
-
}
|
|
5771
|
-
function matchPrefix(table, id) {
|
|
5772
|
-
const lower = id.toLowerCase();
|
|
5773
|
-
const exact = table[lower];
|
|
5774
|
-
if (exact) return exact;
|
|
5775
|
-
// Longest-prefix match so `gpt-4o-2024-08-06` resolves to `gpt-4o` and
|
|
5776
|
-
// not `gpt-4` (which would also prefix-match).
|
|
5777
|
-
let best = null;
|
|
5778
|
-
for (const [k, v] of Object.entries(table)){
|
|
5779
|
-
if (lower.startsWith(k) && (!best || k.length > best.key.length)) {
|
|
5780
|
-
best = {
|
|
5781
|
-
key: k,
|
|
5782
|
-
v
|
|
5783
|
-
};
|
|
5784
|
-
}
|
|
5785
|
-
}
|
|
5786
|
-
return best?.v ?? null;
|
|
5787
|
-
}
|
|
5788
|
-
function getKnownModelLimits(provider, model_id) {
|
|
5789
|
-
if (!provider || !model_id) return null;
|
|
5790
|
-
switch(provider){
|
|
5791
|
-
case "anthropic":
|
|
5792
|
-
return matchPrefix(ANTHROPIC, model_id);
|
|
5793
|
-
case "gemini":
|
|
5794
|
-
return matchPrefix(GEMINI, model_id);
|
|
5795
|
-
case "openai":
|
|
5796
|
-
return matchPrefix(OPENAI, model_id);
|
|
5797
|
-
case "deepseek":
|
|
5798
|
-
return matchPrefix(DEEPSEEK, model_id);
|
|
5799
|
-
case "github-copilot":
|
|
5800
|
-
return resolveCopilot(model_id);
|
|
5801
|
-
default:
|
|
5802
|
-
return null;
|
|
5803
|
-
}
|
|
5804
|
-
}
|
|
5805
|
-
function getKnownContextLength(provider, model_id) {
|
|
5806
|
-
return getKnownModelLimits(provider, model_id)?.context_length ?? null;
|
|
5807
|
-
}
|
|
5808
|
-
function getKnownMaxOutputTokens(provider, model_id) {
|
|
5809
|
-
return getKnownModelLimits(provider, model_id)?.max_output_tokens ?? null;
|
|
5810
|
-
}
|
|
5811
5642
|
|
|
5643
|
+
// EXPORTS
|
|
5644
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
5645
|
+
n0: () => (/* binding */ getAllToolsAsync),
|
|
5646
|
+
sT: () => (/* binding */ getBuiltinToolNames),
|
|
5647
|
+
Dk: () => (/* binding */ getToolCapability),
|
|
5648
|
+
$Z: () => (/* binding */ getToolCategory),
|
|
5649
|
+
y: () => (/* binding */ getToolGroup),
|
|
5650
|
+
s7: () => (/* binding */ getToolSource)
|
|
5651
|
+
});
|
|
5812
5652
|
|
|
5813
|
-
|
|
5653
|
+
// UNUSED EXPORTS: executeTool, getAllTools, getToolsDir, initTools, registerTools, toOpenAITools
|
|
5814
5654
|
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
/* harmony import */ var _lib_db__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(46);
|
|
5827
|
-
|
|
5828
|
-
const now = ()=>new Date().toISOString();
|
|
5829
|
-
const UPSERT_SQL = `
|
|
5830
|
-
INSERT INTO tool_stats
|
|
5831
|
-
(tool_name, call_count, success_count, error_count, used_count, last_called_at, updated_at)
|
|
5832
|
-
VALUES
|
|
5833
|
-
(?, ?, ?, ?, ?, ?, ?)
|
|
5834
|
-
ON CONFLICT(tool_name) DO UPDATE SET
|
|
5835
|
-
call_count = tool_stats.call_count + excluded.call_count,
|
|
5836
|
-
success_count = tool_stats.success_count + excluded.success_count,
|
|
5837
|
-
error_count = tool_stats.error_count + excluded.error_count,
|
|
5838
|
-
used_count = tool_stats.used_count + excluded.used_count,
|
|
5839
|
-
last_called_at = COALESCE(excluded.last_called_at, tool_stats.last_called_at),
|
|
5840
|
-
updated_at = excluded.updated_at
|
|
5841
|
-
`;
|
|
5842
|
-
function recordToolUsage(toolEvents, assistantContent) {
|
|
5843
|
-
const deltas = summarizeToolUsage(toolEvents, assistantContent);
|
|
5844
|
-
if (deltas.length === 0) return;
|
|
5845
|
-
const db = (0,_lib_db__WEBPACK_IMPORTED_MODULE_0__/* .getDb */ .Lf)();
|
|
5846
|
-
const stamp = now();
|
|
5847
|
-
const stmt = db.prepare(UPSERT_SQL);
|
|
5848
|
-
db.exec("BEGIN");
|
|
5849
|
-
try {
|
|
5850
|
-
for (const row of deltas){
|
|
5851
|
-
stmt.run(row.name, row.calls, row.successes, row.errors, row.used, row.calls > 0 ? stamp : null, stamp);
|
|
5852
|
-
}
|
|
5853
|
-
db.exec("COMMIT");
|
|
5854
|
-
} catch (err) {
|
|
5855
|
-
try {
|
|
5856
|
-
db.exec("ROLLBACK");
|
|
5857
|
-
} catch {}
|
|
5858
|
-
throw err;
|
|
5859
|
-
}
|
|
5860
|
-
}
|
|
5861
|
-
function listToolStats() {
|
|
5862
|
-
return (0,_lib_db__WEBPACK_IMPORTED_MODULE_0__/* .getDb */ .Lf)().prepare(`SELECT tool_name, call_count, success_count, error_count, used_count, last_called_at, updated_at
|
|
5863
|
-
FROM tool_stats`).all();
|
|
5864
|
-
}
|
|
5865
|
-
function getToolStatsMap(names) {
|
|
5866
|
-
const rows = names && names.length > 0 ? (0,_lib_db__WEBPACK_IMPORTED_MODULE_0__/* .getDb */ .Lf)().prepare(`SELECT tool_name, call_count, success_count, error_count, used_count, last_called_at, updated_at
|
|
5867
|
-
FROM tool_stats
|
|
5868
|
-
WHERE tool_name IN (${names.map(()=>"?").join(",")})`).all(...names) : listToolStats();
|
|
5869
|
-
const out = new Map();
|
|
5870
|
-
for (const row of rows)out.set(row.tool_name, toStats(row));
|
|
5871
|
-
return out;
|
|
5872
|
-
}
|
|
5873
|
-
function defaultToolStats() {
|
|
5874
|
-
return {
|
|
5875
|
-
call_count: 0,
|
|
5876
|
-
success_count: 0,
|
|
5877
|
-
error_count: 0,
|
|
5878
|
-
used_count: 0,
|
|
5879
|
-
success_rate: 1,
|
|
5880
|
-
usefulness_rate: 1,
|
|
5881
|
-
score: 1,
|
|
5882
|
-
never_used: true,
|
|
5883
|
-
last_called_at: null
|
|
5884
|
-
};
|
|
5885
|
-
}
|
|
5886
|
-
function toStats(row) {
|
|
5887
|
-
const calls = Math.max(0, row.call_count);
|
|
5888
|
-
if (calls === 0) return defaultToolStats();
|
|
5889
|
-
const successRate = clamp01(row.success_count / calls);
|
|
5890
|
-
const usefulnessRate = clamp01(row.used_count / calls);
|
|
5891
|
-
const score = clamp01(successRate * 0.65 + usefulnessRate * 0.35);
|
|
5892
|
-
return {
|
|
5893
|
-
call_count: calls,
|
|
5894
|
-
success_count: row.success_count,
|
|
5895
|
-
error_count: row.error_count,
|
|
5896
|
-
used_count: row.used_count,
|
|
5897
|
-
success_rate: successRate,
|
|
5898
|
-
usefulness_rate: usefulnessRate,
|
|
5899
|
-
score,
|
|
5900
|
-
never_used: false,
|
|
5901
|
-
last_called_at: row.last_called_at
|
|
5902
|
-
};
|
|
5903
|
-
}
|
|
5904
|
-
function summarizeToolUsage(toolEvents, assistantContent) {
|
|
5905
|
-
const byId = new Map();
|
|
5906
|
-
const assistantTerms = normalizeText(assistantContent);
|
|
5907
|
-
for (const ev of toolEvents){
|
|
5908
|
-
if (!ev.name) continue;
|
|
5909
|
-
const key = ev.id || `${ev.phase}:${ev.name}`;
|
|
5910
|
-
const existing = byId.get(key) ?? {
|
|
5911
|
-
name: ev.name,
|
|
5912
|
-
successful: false,
|
|
5913
|
-
used: false
|
|
5914
|
-
};
|
|
5915
|
-
if (ev.phase === "call") {
|
|
5916
|
-
existing.name = ev.name;
|
|
5917
|
-
} else if (ev.phase === "result") {
|
|
5918
|
-
const successful = !isErrorPayload(ev.payload);
|
|
5919
|
-
existing.successful = successful;
|
|
5920
|
-
existing.used = successful && payloadLooksUsed(ev.payload, assistantTerms);
|
|
5921
|
-
}
|
|
5922
|
-
byId.set(key, existing);
|
|
5923
|
-
}
|
|
5924
|
-
const totals = new Map();
|
|
5925
|
-
for (const ev of toolEvents){
|
|
5926
|
-
if (ev.phase !== "call" || !ev.name) continue;
|
|
5927
|
-
const key = ev.id || `${ev.phase}:${ev.name}`;
|
|
5928
|
-
const outcome = byId.get(key);
|
|
5929
|
-
const next = totals.get(ev.name) ?? {
|
|
5930
|
-
name: ev.name,
|
|
5931
|
-
calls: 0,
|
|
5932
|
-
successes: 0,
|
|
5933
|
-
errors: 0,
|
|
5934
|
-
used: 0
|
|
5935
|
-
};
|
|
5936
|
-
next.calls += 1;
|
|
5937
|
-
if (outcome?.successful) next.successes += 1;
|
|
5938
|
-
else next.errors += 1;
|
|
5939
|
-
if (outcome?.used) next.used += 1;
|
|
5940
|
-
totals.set(ev.name, next);
|
|
5941
|
-
}
|
|
5942
|
-
return [
|
|
5943
|
-
...totals.values()
|
|
5944
|
-
];
|
|
5945
|
-
}
|
|
5946
|
-
function payloadLooksUsed(payload, assistantTerms) {
|
|
5947
|
-
if (assistantTerms.size === 0) return false;
|
|
5948
|
-
const candidates = extractPayloadTerms(payload);
|
|
5949
|
-
if (candidates.length === 0) return false;
|
|
5950
|
-
let matched = 0;
|
|
5951
|
-
for (const term of candidates){
|
|
5952
|
-
if (assistantTerms.has(term)) matched += 1;
|
|
5953
|
-
if (matched >= 2) return true;
|
|
5954
|
-
}
|
|
5955
|
-
return false;
|
|
5956
|
-
}
|
|
5957
|
-
function extractPayloadTerms(payload) {
|
|
5958
|
-
const raw = stringifyPayload(payload);
|
|
5959
|
-
if (!raw) return [];
|
|
5960
|
-
const unique = new Set();
|
|
5961
|
-
for (const token of raw.toLowerCase().split(/[^a-z0-9_./:-]+/)){
|
|
5962
|
-
if (token.length < 4) continue;
|
|
5963
|
-
if (/^\d+$/.test(token) && token.length < 6) continue;
|
|
5964
|
-
unique.add(token);
|
|
5965
|
-
if (unique.size >= 24) break;
|
|
5966
|
-
}
|
|
5967
|
-
return [
|
|
5968
|
-
...unique
|
|
5969
|
-
];
|
|
5970
|
-
}
|
|
5971
|
-
function stringifyPayload(payload) {
|
|
5972
|
-
if (typeof payload === "string") return payload;
|
|
5973
|
-
try {
|
|
5974
|
-
return JSON.stringify(payload);
|
|
5975
|
-
} catch {
|
|
5976
|
-
return "";
|
|
5977
|
-
}
|
|
5978
|
-
}
|
|
5979
|
-
function normalizeText(text) {
|
|
5980
|
-
const out = new Set();
|
|
5981
|
-
for (const token of text.toLowerCase().split(/[^a-z0-9_./:-]+/)){
|
|
5982
|
-
if (token.length < 4) continue;
|
|
5983
|
-
out.add(token);
|
|
5984
|
-
}
|
|
5985
|
-
return out;
|
|
5986
|
-
}
|
|
5987
|
-
function isErrorPayload(payload) {
|
|
5988
|
-
if (typeof payload === "string") return /\berror\b|\bfailed\b|\bexception\b/i.test(payload);
|
|
5989
|
-
if (!payload || typeof payload !== "object") return false;
|
|
5990
|
-
if ("error" in payload || "errors" in payload) return true;
|
|
5991
|
-
const status = "status" in payload ? payload.status : undefined;
|
|
5992
|
-
if (typeof status === "string" && /error|failed/i.test(status)) return true;
|
|
5993
|
-
return false;
|
|
5994
|
-
}
|
|
5995
|
-
function clamp01(value) {
|
|
5996
|
-
return Math.max(0, Math.min(1, value));
|
|
5997
|
-
}
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
/***/ }),
|
|
6001
|
-
|
|
6002
|
-
/***/ 52907:
|
|
6003
|
-
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
6004
|
-
|
|
6005
|
-
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
6006
|
-
/* harmony export */ LK: () => (/* binding */ writeBinaryFile),
|
|
6007
|
-
/* harmony export */ Uc: () => (/* binding */ fileAbsPath)
|
|
6008
|
-
/* harmony export */ });
|
|
6009
|
-
/* unused harmony exports FILES_DIR, isSafeFileName */
|
|
6010
|
-
/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(73024);
|
|
6011
|
-
/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_fs__WEBPACK_IMPORTED_MODULE_0__);
|
|
6012
|
-
/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(76760);
|
|
6013
|
-
/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(node_path__WEBPACK_IMPORTED_MODULE_1__);
|
|
6014
|
-
/* harmony import */ var _lib_db_data_dir__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(57477);
|
|
6015
|
-
// Local file store for binary artifacts produced by tools (generated images,
|
|
6016
|
-
// downloads, etc.). Files live under ~/.jarela/files/ and are served by
|
|
6017
|
-
// GET /api/v1/files/[name]. The tool returns a relative URL the chat
|
|
6018
|
-
// renderer can embed as <img src="/api/v1/files/...">.
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
const FILES_DIR = (0,node_path__WEBPACK_IMPORTED_MODULE_1__.join)((0,_lib_db_data_dir__WEBPACK_IMPORTED_MODULE_2__/* .getDataDir */ .o)(), "files");
|
|
6023
|
-
(0,node_fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync)(FILES_DIR, {
|
|
6024
|
-
recursive: true
|
|
6025
|
-
});
|
|
6026
|
-
// Name must be a single path segment with no separators or "..". Callers
|
|
6027
|
-
// generate names from randomUUID() so this is mostly defense-in-depth.
|
|
6028
|
-
const SAFE_NAME = /^[A-Za-z0-9._-]+$/;
|
|
6029
|
-
function isSafeFileName(name) {
|
|
6030
|
-
return SAFE_NAME.test(name) && !name.includes("..");
|
|
6031
|
-
}
|
|
6032
|
-
function fileAbsPath(name) {
|
|
6033
|
-
if (!isSafeFileName(name)) return null;
|
|
6034
|
-
return (0,node_path__WEBPACK_IMPORTED_MODULE_1__.join)(FILES_DIR, name);
|
|
6035
|
-
}
|
|
6036
|
-
function writeBinaryFile(name, data) {
|
|
6037
|
-
if (!isSafeFileName(name)) throw new Error(`unsafe file name: ${name}`);
|
|
6038
|
-
const p = (0,node_path__WEBPACK_IMPORTED_MODULE_1__.join)(FILES_DIR, name);
|
|
6039
|
-
(0,node_fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync)(p, data);
|
|
6040
|
-
return p;
|
|
6041
|
-
}
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
/***/ }),
|
|
6045
|
-
|
|
6046
|
-
/***/ 56718:
|
|
6047
|
-
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
6048
|
-
|
|
6049
|
-
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
6050
|
-
/* harmony export */ HP: () => (/* binding */ disabledCategories),
|
|
6051
|
-
/* harmony export */ MD: () => (/* binding */ setCategoryEnabled)
|
|
6052
|
-
/* harmony export */ });
|
|
6053
|
-
/* unused harmony exports isCategoryEnabled, listCategoryStates */
|
|
6054
|
-
/* harmony import */ var _lib_db__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(46);
|
|
6055
|
-
// Built-in tool category toggles.
|
|
6056
|
-
//
|
|
6057
|
-
// A category is "enabled" unless an explicit row in `builtin_tool_categories`
|
|
6058
|
-
// says otherwise. Default-enabled semantics mean upgrading installs keep
|
|
6059
|
-
// every category working with zero migration work.
|
|
6060
|
-
//
|
|
6061
|
-
// Disabled categories are filtered at three layers:
|
|
6062
|
-
// - GET /api/v1/tools (so the agent editor never offers them as permissions)
|
|
6063
|
-
// - getAllTools / getAllToolsAsync (so the agent runtime can't see them)
|
|
6064
|
-
// - executeTool (defense in depth, blocks stale agent configs)
|
|
6065
|
-
|
|
6066
|
-
const now = ()=>new Date().toISOString();
|
|
6067
|
-
function isCategoryEnabled(category) {
|
|
6068
|
-
const row = getDb().prepare("SELECT enabled FROM builtin_tool_categories WHERE category=?").get(category);
|
|
6069
|
-
return row ? row.enabled === 1 : true;
|
|
6070
|
-
}
|
|
6071
|
-
function disabledCategories() {
|
|
6072
|
-
const rows = (0,_lib_db__WEBPACK_IMPORTED_MODULE_0__/* .getDb */ .Lf)().prepare("SELECT category FROM builtin_tool_categories WHERE enabled=0").all();
|
|
6073
|
-
return new Set(rows.map((r)=>r.category));
|
|
6074
|
-
}
|
|
6075
|
-
function listCategoryStates() {
|
|
6076
|
-
const rows = getDb().prepare("SELECT category, enabled, updated_at FROM builtin_tool_categories").all();
|
|
6077
|
-
return rows.map((r)=>({
|
|
6078
|
-
category: r.category,
|
|
6079
|
-
enabled: r.enabled === 1,
|
|
6080
|
-
updated_at: r.updated_at
|
|
6081
|
-
}));
|
|
6082
|
-
}
|
|
6083
|
-
function setCategoryEnabled(category, enabled) {
|
|
6084
|
-
(0,_lib_db__WEBPACK_IMPORTED_MODULE_0__/* .getDb */ .Lf)().prepare(`INSERT INTO builtin_tool_categories (category, enabled, updated_at)
|
|
6085
|
-
VALUES (?, ?, ?)
|
|
6086
|
-
ON CONFLICT(category) DO UPDATE SET enabled=excluded.enabled, updated_at=excluded.updated_at`).run(category, enabled ? 1 : 0, now());
|
|
6087
|
-
}
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
/***/ }),
|
|
6091
|
-
|
|
6092
|
-
/***/ 64011:
|
|
6093
|
-
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
// EXPORTS
|
|
6097
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
6098
|
-
Wi: () => (/* binding */ BUILTIN_TOOL_NAMES),
|
|
6099
|
-
n0: () => (/* binding */ getAllToolsAsync),
|
|
6100
|
-
Dk: () => (/* binding */ getToolCapability),
|
|
6101
|
-
$Z: () => (/* binding */ getToolCategory),
|
|
6102
|
-
y: () => (/* binding */ getToolGroup),
|
|
6103
|
-
s7: () => (/* binding */ getToolSource)
|
|
6104
|
-
});
|
|
6105
|
-
|
|
6106
|
-
// UNUSED EXPORTS: executeTool, getAllTools, getToolsDir, initTools, registerTools, toOpenAITools
|
|
6107
|
-
|
|
6108
|
-
// EXTERNAL MODULE: ./node_modules/@langchain/core/dist/utils/function_calling.js
|
|
6109
|
-
var function_calling = __webpack_require__(46329);
|
|
6110
|
-
// EXTERNAL MODULE: ./node_modules/@langchain/core/dist/tools/index.js
|
|
6111
|
-
var tools = __webpack_require__(71890);
|
|
6112
|
-
// EXTERNAL MODULE: ./node_modules/zod/v4/classic/schemas.js + 3 modules
|
|
6113
|
-
var schemas = __webpack_require__(49883);
|
|
6114
|
-
// EXTERNAL MODULE: ./lib/stores/memory.ts
|
|
6115
|
-
var memory = __webpack_require__(80956);
|
|
6116
|
-
// EXTERNAL MODULE: ./lib/tools/registry.ts + 1 modules
|
|
6117
|
-
var registry = __webpack_require__(18995);
|
|
6118
|
-
;// ./lib/tools/memory.ts
|
|
5655
|
+
// EXTERNAL MODULE: ./node_modules/@langchain/core/dist/utils/function_calling.js
|
|
5656
|
+
var function_calling = __webpack_require__(46329);
|
|
5657
|
+
// EXTERNAL MODULE: ./node_modules/@langchain/core/dist/tools/index.js
|
|
5658
|
+
var tools = __webpack_require__(71890);
|
|
5659
|
+
// EXTERNAL MODULE: ./node_modules/zod/v4/classic/schemas.js + 3 modules
|
|
5660
|
+
var schemas = __webpack_require__(49883);
|
|
5661
|
+
// EXTERNAL MODULE: ./lib/stores/memory.ts
|
|
5662
|
+
var memory = __webpack_require__(80956);
|
|
5663
|
+
// EXTERNAL MODULE: ./lib/tools/registry.ts + 1 modules
|
|
5664
|
+
var registry = __webpack_require__(18995);
|
|
5665
|
+
;// ./lib/tools/memory.ts
|
|
6119
5666
|
|
|
6120
5667
|
|
|
6121
5668
|
|
|
@@ -9831,371 +9378,672 @@ const proposeConfigChangeTool = (0,tools/* tool */.z6)(async ({ kind, payload, r
|
|
|
9831
9378
|
ts: Date.now()
|
|
9832
9379
|
});
|
|
9833
9380
|
return JSON.stringify({
|
|
9834
|
-
proposal_id: row.id,
|
|
9835
|
-
status: "pending",
|
|
9836
|
-
message: "Proposal queued for the user's approval. Tell the user briefly what you proposed and that " + "they need to approve it in the chat. Do not retry; check status later with check_proposal."
|
|
9381
|
+
proposal_id: row.id,
|
|
9382
|
+
status: "pending",
|
|
9383
|
+
message: "Proposal queued for the user's approval. Tell the user briefly what you proposed and that " + "they need to approve it in the chat. Do not retry; check status later with check_proposal."
|
|
9384
|
+
});
|
|
9385
|
+
}, {
|
|
9386
|
+
name: "propose_config_change",
|
|
9387
|
+
description: "Propose a configuration change that requires user approval. Use this when you'd benefit from " + "installing/toggling an MCP server, or modifying agent settings (tool allowlist, identity, instructions, history window). " + "The proposal is queued and shown to the user; they explicitly approve or deny. " + "Don't propose changes the user didn't ask for — only when the current task clearly needs it.",
|
|
9388
|
+
schema: schemas/* object */.Ik({
|
|
9389
|
+
kind: schemas/* enum */.k5([
|
|
9390
|
+
"install_mcp",
|
|
9391
|
+
"toggle_mcp",
|
|
9392
|
+
"update_agent_tools",
|
|
9393
|
+
"update_agent",
|
|
9394
|
+
"start_oauth",
|
|
9395
|
+
"set_provider_key",
|
|
9396
|
+
"enable_integration",
|
|
9397
|
+
"upsert_harness"
|
|
9398
|
+
]).describe("Type of change being proposed"),
|
|
9399
|
+
payload: schemas/* record */.g1(schemas/* string */.Yj(), schemas/* unknown */.L5()).describe("Parameters for the change. NEVER put secrets, API keys, OAuth tokens, " + "or passwords in this object — those are collected by the approval UI " + "directly. Examples by kind:\n" + "- install_mcp: { registry_id: 'github', variables: { GITHUB_TOKEN: 'asks-user-for-it' } } " + " OR { name, transport, spec }\n" + "- toggle_mcp: { name: 'github', enabled: true }\n" + "- update_agent_tools: { agent_id: '<this-agent>', tools: ['web_search', 'memory_*'] }\n" + "- update_agent: { agent_id, identity?, instructions?, history_limit?, history_window_hours?, harness_id? } " + " — harness_id accepts an existing harness id ('builtin:default' or 'custom:<uuid>'), or null to inherit the global default\n" + "- start_oauth: { integration_id: 'gmail' } — only after enable_integration saved client_id/secret\n" + "- set_provider_key: { name: 'anthropic-default', provider: 'anthropic', model_id: 'claude-opus-4-7', is_default?: true } " + " — the user pastes the API key into the approval modal; do NOT include it here\n" + "- enable_integration: { id: 'gmail' } — the user fills credentials in the approval modal\n" + "- upsert_harness: { id?: 'custom:<uuid>', name, description?, sections: { capabilities?: {enabled,body}, plan_first?: {enabled,body}, presentation?: {enabled,body}, citation?: {enabled,body}, self_config?: {enabled,body} } } " + " — omit `id` to create; pass an existing custom:* id to edit. Built-in harnesses ('builtin:*') are read-only and rejected."),
|
|
9400
|
+
reason: schemas/* string */.Yj().describe("Short human-readable reason shown to the user (≤100 chars)")
|
|
9401
|
+
})
|
|
9402
|
+
});
|
|
9403
|
+
const checkProposalTool = (0,tools/* tool */.z6)(async ({ proposal_id })=>{
|
|
9404
|
+
const row = (0,pending_actions/* getPendingAction */.wv)(proposal_id);
|
|
9405
|
+
if (!row) return JSON.stringify({
|
|
9406
|
+
error: `proposal ${proposal_id} not found`
|
|
9407
|
+
});
|
|
9408
|
+
return JSON.stringify({
|
|
9409
|
+
id: row.id,
|
|
9410
|
+
kind: row.kind,
|
|
9411
|
+
status: row.status,
|
|
9412
|
+
result: row.result ? propose_safeParse(row.result) : null,
|
|
9413
|
+
created_at: row.created_at,
|
|
9414
|
+
decided_at: row.decided_at
|
|
9415
|
+
});
|
|
9416
|
+
}, {
|
|
9417
|
+
name: "check_proposal",
|
|
9418
|
+
description: "Check the status of a previously-submitted config-change proposal by its id.",
|
|
9419
|
+
schema: schemas/* object */.Ik({
|
|
9420
|
+
proposal_id: schemas/* string */.Yj()
|
|
9421
|
+
})
|
|
9422
|
+
});
|
|
9423
|
+
function propose_safeParse(s) {
|
|
9424
|
+
try {
|
|
9425
|
+
return JSON.parse(s);
|
|
9426
|
+
} catch {
|
|
9427
|
+
return s;
|
|
9428
|
+
}
|
|
9429
|
+
}
|
|
9430
|
+
(0,registry/* registerTools */.Fd)("Config", "read", [
|
|
9431
|
+
checkProposalTool
|
|
9432
|
+
]);
|
|
9433
|
+
(0,registry/* registerTools */.Fd)("Config", "write", [
|
|
9434
|
+
proposeConfigChangeTool
|
|
9435
|
+
]);
|
|
9436
|
+
|
|
9437
|
+
// EXTERNAL MODULE: ./lib/integrations/registry.ts + 6 modules
|
|
9438
|
+
var integrations_registry = __webpack_require__(91384);
|
|
9439
|
+
// EXTERNAL MODULE: ./lib/stores/integrations.ts
|
|
9440
|
+
var integrations = __webpack_require__(78228);
|
|
9441
|
+
;// ./lib/tools/integrations.ts
|
|
9442
|
+
// Read-only tools that expose integration manifests to the agent. See
|
|
9443
|
+
// ADR-0010 — these power the "user asks how to connect X → agent narrates
|
|
9444
|
+
// the steps and proposes actions" loop without giving the agent any new
|
|
9445
|
+
// privileges.
|
|
9446
|
+
|
|
9447
|
+
|
|
9448
|
+
|
|
9449
|
+
|
|
9450
|
+
|
|
9451
|
+
function manifestStatus(id) {
|
|
9452
|
+
if (!(0,integrations/* isKnownIntegration */.GV)(id)) return "no_credentials_schema";
|
|
9453
|
+
return (0,integrations/* getIntegrationStatus */.v9)(id)?.configured ? "configured" : "not_configured";
|
|
9454
|
+
}
|
|
9455
|
+
const listIntegrationsTool = (0,tools/* tool */.z6)(async ()=>{
|
|
9456
|
+
const summary = (0,integrations_registry/* listManifests */.po)().map((m)=>({
|
|
9457
|
+
id: m.id,
|
|
9458
|
+
name: m.name,
|
|
9459
|
+
category: m.category,
|
|
9460
|
+
summary: m.summary,
|
|
9461
|
+
status: manifestStatus(m.id)
|
|
9462
|
+
}));
|
|
9463
|
+
return JSON.stringify({
|
|
9464
|
+
integrations: summary
|
|
9465
|
+
});
|
|
9466
|
+
}, {
|
|
9467
|
+
name: "list_integrations",
|
|
9468
|
+
description: "List every integration Jarela knows how to set up, with a one-line summary and " + "current configuration status. Read-only. Use this when the user asks 'what can I connect?' " + "or before proposing enable_integration, so you know what's available and whether it's " + "already configured.",
|
|
9469
|
+
schema: schemas/* object */.Ik({})
|
|
9470
|
+
});
|
|
9471
|
+
const getIntegrationSetupTool = (0,tools/* tool */.z6)(async ({ id })=>{
|
|
9472
|
+
const manifest = (0,integrations_registry/* getManifest */.c2)(id);
|
|
9473
|
+
if (!manifest) {
|
|
9474
|
+
return JSON.stringify({
|
|
9475
|
+
error: `unknown integration "${id}". Call list_integrations to see available ids.`
|
|
9476
|
+
});
|
|
9477
|
+
}
|
|
9478
|
+
return JSON.stringify({
|
|
9479
|
+
id: manifest.id,
|
|
9480
|
+
name: manifest.name,
|
|
9481
|
+
summary: manifest.summary,
|
|
9482
|
+
category: manifest.category,
|
|
9483
|
+
status: manifestStatus(manifest.id),
|
|
9484
|
+
prerequisites: manifest.prerequisites,
|
|
9485
|
+
steps: manifest.steps,
|
|
9486
|
+
troubleshooting: manifest.troubleshooting,
|
|
9487
|
+
notes: [
|
|
9488
|
+
"Walk the user through `prerequisites` first; some require browser actions outside Jarela.",
|
|
9489
|
+
"For each step that has a `proposes` field, call propose_config_change with that kind when ready.",
|
|
9490
|
+
"When a step has a `verify.tool`, call that tool after applying the step to confirm success."
|
|
9491
|
+
]
|
|
9492
|
+
});
|
|
9493
|
+
}, {
|
|
9494
|
+
name: "get_integration_setup",
|
|
9495
|
+
description: "Return the full setup manifest for one integration — prerequisites, ordered steps, and " + "troubleshooting hints. Read-only. Use this before walking the user through a setup, or " + "when a tool fails and you need the integration-specific recovery hint.",
|
|
9496
|
+
schema: schemas/* object */.Ik({
|
|
9497
|
+
id: schemas/* string */.Yj().describe("Integration id from list_integrations (e.g. 'gmail', 'atlassian')")
|
|
9498
|
+
})
|
|
9499
|
+
});
|
|
9500
|
+
(0,registry/* registerTools */.Fd)("Config", "read", [
|
|
9501
|
+
listIntegrationsTool,
|
|
9502
|
+
getIntegrationSetupTool
|
|
9503
|
+
]);
|
|
9504
|
+
|
|
9505
|
+
// EXTERNAL MODULE: ./lib/tools/atlassian.ts
|
|
9506
|
+
var atlassian = __webpack_require__(65856);
|
|
9507
|
+
// EXTERNAL MODULE: ./lib/tools/jira-align.ts
|
|
9508
|
+
var jira_align = __webpack_require__(55738);
|
|
9509
|
+
// EXTERNAL MODULE: ./lib/tools/github.ts
|
|
9510
|
+
var github = __webpack_require__(70729);
|
|
9511
|
+
// EXTERNAL MODULE: ./lib/tools/gmail.ts
|
|
9512
|
+
var gmail = __webpack_require__(77414);
|
|
9513
|
+
// EXTERNAL MODULE: ./lib/integrations/gmail-oauth.ts
|
|
9514
|
+
var gmail_oauth = __webpack_require__(87246);
|
|
9515
|
+
;// ./lib/tools/calendar.ts
|
|
9516
|
+
/**
|
|
9517
|
+
* Native Google Calendar tools — direct REST calls to
|
|
9518
|
+
* calendar.googleapis.com, sharing the Gmail OAuth client (one Google
|
|
9519
|
+
* account, one refresh token, one access-token cache; see
|
|
9520
|
+
* lib/integrations/gmail-oauth.ts).
|
|
9521
|
+
*
|
|
9522
|
+
* Scope-wise this surface is **events on existing calendars**:
|
|
9523
|
+
* - list / get / create / update / delete events
|
|
9524
|
+
* - list the user's calendars (read-only)
|
|
9525
|
+
* There is deliberately no calendar-list create/delete and no ACL
|
|
9526
|
+
* editing. To enable a wider surface, add the broader scope to
|
|
9527
|
+
* GMAIL_SCOPES and (force users to) reconnect.
|
|
9528
|
+
*
|
|
9529
|
+
* v1 design notes:
|
|
9530
|
+
* - calendarId defaults to "primary" everywhere so the agent can
|
|
9531
|
+
* create a quick event without first calling list_calendars.
|
|
9532
|
+
* - All datetimes are RFC3339 strings (e.g. "2026-05-19T16:00:00-07:00").
|
|
9533
|
+
* When the caller omits a timezone offset, Google falls back to the
|
|
9534
|
+
* calendar's default TZ. The tools surface a `time_zone` field that
|
|
9535
|
+
* forwards an IANA name in case the caller wants to be explicit.
|
|
9536
|
+
* - `calendar_create_event` can provision a Google Meet link via the
|
|
9537
|
+
* conferenceData createRequest dance — gated behind `add_meet_link`
|
|
9538
|
+
* so unused calls don't trip Google's quota.
|
|
9539
|
+
*/
|
|
9540
|
+
|
|
9541
|
+
|
|
9542
|
+
|
|
9543
|
+
const CALENDAR_BASE = "https://www.googleapis.com/calendar/v3";
|
|
9544
|
+
const calendarFetch = (auth, path, init)=>(0,gmail_oauth/* googleFetch */.sI)(auth, "Calendar", CALENDAR_BASE, path, init);
|
|
9545
|
+
// Slim down a full event to the fields the agent actually needs in a
|
|
9546
|
+
// thread response. Keeps tool outputs small enough not to blow context.
|
|
9547
|
+
function slimEvent(e) {
|
|
9548
|
+
return {
|
|
9549
|
+
id: e.id,
|
|
9550
|
+
status: e.status,
|
|
9551
|
+
summary: e.summary ?? null,
|
|
9552
|
+
description: e.description ?? null,
|
|
9553
|
+
location: e.location ?? null,
|
|
9554
|
+
start: e.start?.dateTime ?? e.start?.date ?? null,
|
|
9555
|
+
end: e.end?.dateTime ?? e.end?.date ?? null,
|
|
9556
|
+
time_zone: e.start?.timeZone ?? e.end?.timeZone ?? null,
|
|
9557
|
+
attendees: (e.attendees ?? []).map((a)=>({
|
|
9558
|
+
email: a.email,
|
|
9559
|
+
name: a.displayName ?? null,
|
|
9560
|
+
response: a.responseStatus ?? null
|
|
9561
|
+
})),
|
|
9562
|
+
meet_link: e.hangoutLink ?? null,
|
|
9563
|
+
html_link: e.htmlLink ?? null
|
|
9564
|
+
};
|
|
9565
|
+
}
|
|
9566
|
+
// ── Tools ───────────────────────────────────────────────────────────────────
|
|
9567
|
+
const calendarListCalendarsTool = (0,tools/* tool */.z6)(async ()=>{
|
|
9568
|
+
const auth = (0,gmail_oauth/* resolveGoogleAuth */.wq)();
|
|
9569
|
+
if ("error" in auth) return JSON.stringify({
|
|
9570
|
+
error: auth.error
|
|
9571
|
+
});
|
|
9572
|
+
const data = await calendarFetch(auth, "/users/me/calendarList");
|
|
9573
|
+
if ("error" in data && data.error) return JSON.stringify(data);
|
|
9574
|
+
return JSON.stringify({
|
|
9575
|
+
calendars: (data.items ?? []).map((c)=>({
|
|
9576
|
+
id: c.id,
|
|
9577
|
+
summary: c.summary ?? null,
|
|
9578
|
+
primary: c.primary === true,
|
|
9579
|
+
time_zone: c.timeZone ?? null,
|
|
9580
|
+
access_role: c.accessRole ?? null
|
|
9581
|
+
}))
|
|
9582
|
+
});
|
|
9583
|
+
}, {
|
|
9584
|
+
name: "calendar_list_calendars",
|
|
9585
|
+
description: "List the user's Google calendars (primary + any they've subscribed to). " + "Returns id, summary, primary flag, time zone, access role per entry. The " + "`id` is what other calendar_* tools expect as `calendar_id`. Use this when " + "the user mentions a non-primary calendar by name (e.g. 'put it on my Work " + "calendar') — match against `summary` to find the right id.",
|
|
9586
|
+
schema: schemas/* object */.Ik({})
|
|
9587
|
+
});
|
|
9588
|
+
const calendarListEventsTool = (0,tools/* tool */.z6)(async ({ calendar_id, time_min, time_max, query, max_results })=>{
|
|
9589
|
+
const auth = (0,gmail_oauth/* resolveGoogleAuth */.wq)();
|
|
9590
|
+
if ("error" in auth) return JSON.stringify({
|
|
9591
|
+
error: auth.error
|
|
9592
|
+
});
|
|
9593
|
+
const cal = encodeURIComponent(calendar_id ?? "primary");
|
|
9594
|
+
const params = new URLSearchParams({
|
|
9595
|
+
singleEvents: "true",
|
|
9596
|
+
orderBy: "startTime",
|
|
9597
|
+
maxResults: String(Math.min(Math.max(max_results ?? 25, 1), 100))
|
|
9598
|
+
});
|
|
9599
|
+
// Default window: now → +7 days. Keeps "what's on my schedule" cheap.
|
|
9600
|
+
const now = new Date();
|
|
9601
|
+
const inAWeek = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
|
|
9602
|
+
params.set("timeMin", time_min ?? now.toISOString());
|
|
9603
|
+
params.set("timeMax", time_max ?? inAWeek.toISOString());
|
|
9604
|
+
if (query) params.set("q", query);
|
|
9605
|
+
const data = await calendarFetch(auth, `/calendars/${cal}/events?${params.toString()}`);
|
|
9606
|
+
if ("error" in data && data.error) return JSON.stringify(data);
|
|
9607
|
+
return JSON.stringify({
|
|
9608
|
+
events: (data.items ?? []).map(slimEvent)
|
|
9837
9609
|
});
|
|
9838
9610
|
}, {
|
|
9839
|
-
name: "
|
|
9840
|
-
description: "
|
|
9611
|
+
name: "calendar_list_events",
|
|
9612
|
+
description: "List events on a calendar within a time window. Defaults: primary calendar, " + "now → +7 days, ordered by start, recurring events expanded into single " + "instances. **Use this before creating an event** to avoid double-booking, " + "and to look up existing event ids before updating/deleting. " + "Datetimes are RFC3339 (e.g. '2026-05-19T16:00:00-07:00').",
|
|
9841
9613
|
schema: schemas/* object */.Ik({
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
|
|
9846
|
-
|
|
9847
|
-
"start_oauth",
|
|
9848
|
-
"set_provider_key",
|
|
9849
|
-
"enable_integration",
|
|
9850
|
-
"upsert_harness"
|
|
9851
|
-
]).describe("Type of change being proposed"),
|
|
9852
|
-
payload: schemas/* record */.g1(schemas/* string */.Yj(), schemas/* unknown */.L5()).describe("Parameters for the change. NEVER put secrets, API keys, OAuth tokens, " + "or passwords in this object — those are collected by the approval UI " + "directly. Examples by kind:\n" + "- install_mcp: { registry_id: 'github', variables: { GITHUB_TOKEN: 'asks-user-for-it' } } " + " OR { name, transport, spec }\n" + "- toggle_mcp: { name: 'github', enabled: true }\n" + "- update_agent_tools: { agent_id: '<this-agent>', tools: ['web_search', 'memory_*'] }\n" + "- update_agent: { agent_id, identity?, instructions?, history_limit?, history_window_hours?, harness_id? } " + " — harness_id accepts an existing harness id ('builtin:default' or 'custom:<uuid>'), or null to inherit the global default\n" + "- start_oauth: { integration_id: 'gmail' } — only after enable_integration saved client_id/secret\n" + "- set_provider_key: { name: 'anthropic-default', provider: 'anthropic', model_id: 'claude-opus-4-7', is_default?: true } " + " — the user pastes the API key into the approval modal; do NOT include it here\n" + "- enable_integration: { id: 'gmail' } — the user fills credentials in the approval modal\n" + "- upsert_harness: { id?: 'custom:<uuid>', name, description?, sections: { capabilities?: {enabled,body}, plan_first?: {enabled,body}, presentation?: {enabled,body}, citation?: {enabled,body}, self_config?: {enabled,body} } } " + " — omit `id` to create; pass an existing custom:* id to edit. Built-in harnesses ('builtin:*') are read-only and rejected."),
|
|
9853
|
-
reason: schemas/* string */.Yj().describe("Short human-readable reason shown to the user (≤100 chars)")
|
|
9614
|
+
calendar_id: schemas/* string */.Yj().optional().describe("Calendar id (default: 'primary')"),
|
|
9615
|
+
time_min: schemas/* string */.Yj().optional().describe("RFC3339 lower bound (default: now)"),
|
|
9616
|
+
time_max: schemas/* string */.Yj().optional().describe("RFC3339 upper bound (default: now + 7 days)"),
|
|
9617
|
+
query: schemas/* string */.Yj().optional().describe("Free-text search across event fields"),
|
|
9618
|
+
max_results: schemas/* number */.ai().int().optional().describe("Max events (default 25, max 100)")
|
|
9854
9619
|
})
|
|
9855
9620
|
});
|
|
9856
|
-
const
|
|
9857
|
-
const
|
|
9858
|
-
if (
|
|
9859
|
-
error:
|
|
9621
|
+
const calendarGetEventTool = (0,tools/* tool */.z6)(async ({ calendar_id, event_id })=>{
|
|
9622
|
+
const auth = (0,gmail_oauth/* resolveGoogleAuth */.wq)();
|
|
9623
|
+
if ("error" in auth) return JSON.stringify({
|
|
9624
|
+
error: auth.error
|
|
9860
9625
|
});
|
|
9861
|
-
|
|
9862
|
-
|
|
9863
|
-
|
|
9864
|
-
|
|
9865
|
-
|
|
9866
|
-
created_at: row.created_at,
|
|
9867
|
-
decided_at: row.decided_at
|
|
9626
|
+
const cal = encodeURIComponent(calendar_id ?? "primary");
|
|
9627
|
+
const eid = encodeURIComponent(event_id);
|
|
9628
|
+
const data = await calendarFetch(auth, `/calendars/${cal}/events/${eid}`);
|
|
9629
|
+
if (data.error) return JSON.stringify({
|
|
9630
|
+
error: data.error
|
|
9868
9631
|
});
|
|
9632
|
+
return JSON.stringify(slimEvent(data));
|
|
9869
9633
|
}, {
|
|
9870
|
-
name: "
|
|
9871
|
-
description: "
|
|
9634
|
+
name: "calendar_get_event",
|
|
9635
|
+
description: "Fetch one Google Calendar event by id. Returns the same slim shape as " + "calendar_list_events but for a single event.",
|
|
9872
9636
|
schema: schemas/* object */.Ik({
|
|
9873
|
-
|
|
9637
|
+
calendar_id: schemas/* string */.Yj().optional().describe("Calendar id (default: 'primary')"),
|
|
9638
|
+
event_id: schemas/* string */.Yj().describe("Event id (from calendar_list_events results)")
|
|
9874
9639
|
})
|
|
9875
9640
|
});
|
|
9876
|
-
|
|
9877
|
-
|
|
9878
|
-
|
|
9879
|
-
|
|
9880
|
-
|
|
9641
|
+
const calendarCreateEventTool = (0,tools/* tool */.z6)(async ({ calendar_id, summary, subject, start_iso, end_iso, description, location, attendees, time_zone, add_meet_link })=>{
|
|
9642
|
+
const auth = (0,gmail_oauth/* resolveGoogleAuth */.wq)();
|
|
9643
|
+
if ("error" in auth) return JSON.stringify({
|
|
9644
|
+
error: auth.error
|
|
9645
|
+
});
|
|
9646
|
+
const cal = encodeURIComponent(calendar_id ?? "primary");
|
|
9647
|
+
// `subject` is accepted as an alias for `summary` so agents trained on
|
|
9648
|
+
// Outlook vocabulary don't fail the schema on first try.
|
|
9649
|
+
const eventSummary = summary ?? subject;
|
|
9650
|
+
if (!eventSummary) {
|
|
9651
|
+
return JSON.stringify({
|
|
9652
|
+
error: "summary (or subject) is required"
|
|
9653
|
+
});
|
|
9881
9654
|
}
|
|
9882
|
-
|
|
9883
|
-
|
|
9884
|
-
|
|
9885
|
-
|
|
9886
|
-
|
|
9887
|
-
|
|
9888
|
-
|
|
9889
|
-
|
|
9890
|
-
|
|
9891
|
-
|
|
9892
|
-
|
|
9893
|
-
|
|
9894
|
-
|
|
9895
|
-
|
|
9896
|
-
|
|
9897
|
-
|
|
9898
|
-
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
|
|
9902
|
-
|
|
9903
|
-
|
|
9904
|
-
|
|
9905
|
-
|
|
9906
|
-
|
|
9907
|
-
|
|
9908
|
-
|
|
9909
|
-
|
|
9910
|
-
|
|
9911
|
-
|
|
9912
|
-
|
|
9913
|
-
|
|
9914
|
-
|
|
9915
|
-
|
|
9916
|
-
|
|
9917
|
-
|
|
9655
|
+
const body = {
|
|
9656
|
+
summary: eventSummary,
|
|
9657
|
+
start: {
|
|
9658
|
+
dateTime: start_iso,
|
|
9659
|
+
...time_zone ? {
|
|
9660
|
+
timeZone: time_zone
|
|
9661
|
+
} : {}
|
|
9662
|
+
},
|
|
9663
|
+
end: {
|
|
9664
|
+
dateTime: end_iso,
|
|
9665
|
+
...time_zone ? {
|
|
9666
|
+
timeZone: time_zone
|
|
9667
|
+
} : {}
|
|
9668
|
+
}
|
|
9669
|
+
};
|
|
9670
|
+
if (description) body.description = description;
|
|
9671
|
+
if (location) body.location = location;
|
|
9672
|
+
if (attendees && attendees.length > 0) {
|
|
9673
|
+
body.attendees = attendees.map((email)=>({
|
|
9674
|
+
email
|
|
9675
|
+
}));
|
|
9676
|
+
}
|
|
9677
|
+
if (add_meet_link) {
|
|
9678
|
+
body.conferenceData = {
|
|
9679
|
+
createRequest: {
|
|
9680
|
+
// requestId must be unique per createRequest; Google echoes it back.
|
|
9681
|
+
requestId: `jarela-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
9682
|
+
conferenceSolutionKey: {
|
|
9683
|
+
type: "hangoutsMeet"
|
|
9684
|
+
}
|
|
9685
|
+
}
|
|
9686
|
+
};
|
|
9687
|
+
}
|
|
9688
|
+
// conferenceDataVersion=1 is required for Google to honor the
|
|
9689
|
+
// createRequest and provision a Meet URL. Harmless to set without it.
|
|
9690
|
+
const params = add_meet_link ? "?conferenceDataVersion=1" : "";
|
|
9691
|
+
const data = await calendarFetch(auth, `/calendars/${cal}/events${params}`, {
|
|
9692
|
+
method: "POST",
|
|
9693
|
+
body: JSON.stringify(body)
|
|
9694
|
+
});
|
|
9695
|
+
if (data.error) return JSON.stringify({
|
|
9696
|
+
error: data.error
|
|
9918
9697
|
});
|
|
9698
|
+
return JSON.stringify(slimEvent(data));
|
|
9919
9699
|
}, {
|
|
9920
|
-
name: "
|
|
9921
|
-
description: "
|
|
9922
|
-
schema: schemas/* object */.Ik({
|
|
9700
|
+
name: "calendar_create_event",
|
|
9701
|
+
description: "Create a Google Calendar event on a calendar (default: 'primary'). " + "Datetimes are RFC3339 strings — include a timezone offset (e.g. " + "'2026-05-19T16:00:00-07:00') or set `time_zone` to an IANA name (e.g. " + "'America/Los_Angeles') so the user's calendar interprets the time " + "correctly. Attendees are emailed an invite automatically. Set " + "`add_meet_link: true` to provision a Google Meet URL on the event.",
|
|
9702
|
+
schema: schemas/* object */.Ik({
|
|
9703
|
+
calendar_id: schemas/* string */.Yj().optional().describe("Calendar id (default: 'primary')"),
|
|
9704
|
+
summary: schemas/* string */.Yj().min(1).optional().describe("Event title shown on the calendar (alias: subject)"),
|
|
9705
|
+
subject: schemas/* string */.Yj().min(1).optional().describe("Alias for summary (Outlook vocabulary)"),
|
|
9706
|
+
start_iso: schemas/* string */.Yj().describe("Start datetime, RFC3339"),
|
|
9707
|
+
end_iso: schemas/* string */.Yj().describe("End datetime, RFC3339 (must be after start)"),
|
|
9708
|
+
description: schemas/* string */.Yj().optional().describe("Long-form event body (markdown not rendered)"),
|
|
9709
|
+
location: schemas/* string */.Yj().optional().describe("Free-text location string"),
|
|
9710
|
+
attendees: schemas/* array */.YO(schemas/* string */.Yj().email()).optional().describe("Invitee email addresses"),
|
|
9711
|
+
time_zone: schemas/* string */.Yj().optional().describe("IANA timezone, e.g. 'America/Los_Angeles'"),
|
|
9712
|
+
add_meet_link: schemas/* boolean */.zM().optional().describe("Provision a Google Meet URL on this event")
|
|
9713
|
+
})
|
|
9923
9714
|
});
|
|
9924
|
-
const
|
|
9925
|
-
const
|
|
9926
|
-
if (
|
|
9715
|
+
const calendarUpdateEventTool = (0,tools/* tool */.z6)(async ({ calendar_id, event_id, summary, subject, start_iso, end_iso, description, location, attendees, time_zone })=>{
|
|
9716
|
+
const auth = (0,gmail_oauth/* resolveGoogleAuth */.wq)();
|
|
9717
|
+
if ("error" in auth) return JSON.stringify({
|
|
9718
|
+
error: auth.error
|
|
9719
|
+
});
|
|
9720
|
+
const cal = encodeURIComponent(calendar_id ?? "primary");
|
|
9721
|
+
const eid = encodeURIComponent(event_id);
|
|
9722
|
+
const patch = {};
|
|
9723
|
+
const eventSummary = summary ?? subject;
|
|
9724
|
+
if (eventSummary !== undefined) patch.summary = eventSummary;
|
|
9725
|
+
if (description !== undefined) patch.description = description;
|
|
9726
|
+
if (location !== undefined) patch.location = location;
|
|
9727
|
+
if (start_iso !== undefined) {
|
|
9728
|
+
patch.start = {
|
|
9729
|
+
dateTime: start_iso,
|
|
9730
|
+
...time_zone ? {
|
|
9731
|
+
timeZone: time_zone
|
|
9732
|
+
} : {}
|
|
9733
|
+
};
|
|
9734
|
+
}
|
|
9735
|
+
if (end_iso !== undefined) {
|
|
9736
|
+
patch.end = {
|
|
9737
|
+
dateTime: end_iso,
|
|
9738
|
+
...time_zone ? {
|
|
9739
|
+
timeZone: time_zone
|
|
9740
|
+
} : {}
|
|
9741
|
+
};
|
|
9742
|
+
}
|
|
9743
|
+
if (attendees !== undefined) {
|
|
9744
|
+
patch.attendees = attendees.map((email)=>({
|
|
9745
|
+
email
|
|
9746
|
+
}));
|
|
9747
|
+
}
|
|
9748
|
+
if (Object.keys(patch).length === 0) {
|
|
9927
9749
|
return JSON.stringify({
|
|
9928
|
-
error:
|
|
9750
|
+
error: "Provide at least one field to update"
|
|
9929
9751
|
});
|
|
9930
9752
|
}
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
|
|
9937
|
-
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
9941
|
-
|
|
9942
|
-
|
|
9943
|
-
|
|
9944
|
-
|
|
9753
|
+
const data = await calendarFetch(auth, `/calendars/${cal}/events/${eid}`, {
|
|
9754
|
+
method: "PATCH",
|
|
9755
|
+
body: JSON.stringify(patch)
|
|
9756
|
+
});
|
|
9757
|
+
if (data.error) return JSON.stringify({
|
|
9758
|
+
error: data.error
|
|
9759
|
+
});
|
|
9760
|
+
return JSON.stringify(slimEvent(data));
|
|
9761
|
+
}, {
|
|
9762
|
+
name: "calendar_update_event",
|
|
9763
|
+
description: "Patch a Google Calendar event. Only the fields you supply are changed; " + "omit fields to leave them alone. Use this to reschedule (`start_iso`/`end_iso`), " + "rename (`summary`), or adjust the invitee list (`attendees` — note this " + "**replaces** the full list, so include everyone who should remain).",
|
|
9764
|
+
schema: schemas/* object */.Ik({
|
|
9765
|
+
calendar_id: schemas/* string */.Yj().optional().describe("Calendar id (default: 'primary')"),
|
|
9766
|
+
event_id: schemas/* string */.Yj().describe("Event id"),
|
|
9767
|
+
summary: schemas/* string */.Yj().optional().describe("New event title (alias: subject)"),
|
|
9768
|
+
subject: schemas/* string */.Yj().optional().describe("Alias for summary (Outlook vocabulary)"),
|
|
9769
|
+
start_iso: schemas/* string */.Yj().optional().describe("New start datetime, RFC3339"),
|
|
9770
|
+
end_iso: schemas/* string */.Yj().optional().describe("New end datetime, RFC3339"),
|
|
9771
|
+
description: schemas/* string */.Yj().optional().describe("New event body"),
|
|
9772
|
+
location: schemas/* string */.Yj().optional().describe("New location string"),
|
|
9773
|
+
attendees: schemas/* array */.YO(schemas/* string */.Yj().email()).optional().describe("Replacement attendee list"),
|
|
9774
|
+
time_zone: schemas/* string */.Yj().optional().describe("IANA timezone applied to start/end")
|
|
9775
|
+
})
|
|
9776
|
+
});
|
|
9777
|
+
const calendarDeleteEventTool = (0,tools/* tool */.z6)(async ({ calendar_id, event_id })=>{
|
|
9778
|
+
const auth = (0,gmail_oauth/* resolveGoogleAuth */.wq)();
|
|
9779
|
+
if ("error" in auth) return JSON.stringify({
|
|
9780
|
+
error: auth.error
|
|
9781
|
+
});
|
|
9782
|
+
const cal = encodeURIComponent(calendar_id ?? "primary");
|
|
9783
|
+
const eid = encodeURIComponent(event_id);
|
|
9784
|
+
const data = await calendarFetch(auth, `/calendars/${cal}/events/${eid}`, {
|
|
9785
|
+
method: "DELETE"
|
|
9786
|
+
});
|
|
9787
|
+
if (data.error) return JSON.stringify({
|
|
9788
|
+
error: data.error
|
|
9789
|
+
});
|
|
9790
|
+
return JSON.stringify({
|
|
9791
|
+
ok: true,
|
|
9792
|
+
id: event_id
|
|
9945
9793
|
});
|
|
9946
9794
|
}, {
|
|
9947
|
-
name: "
|
|
9948
|
-
description: "
|
|
9795
|
+
name: "calendar_delete_event",
|
|
9796
|
+
description: "Delete a Google Calendar event by id. Attendees are notified by default. " + "Returns `{ ok: true, id }` on success. Use `calendar_list_events` to find " + "the event id first if you only know the title/time.",
|
|
9949
9797
|
schema: schemas/* object */.Ik({
|
|
9950
|
-
|
|
9798
|
+
calendar_id: schemas/* string */.Yj().optional().describe("Calendar id (default: 'primary')"),
|
|
9799
|
+
event_id: schemas/* string */.Yj().describe("Event id to delete")
|
|
9951
9800
|
})
|
|
9952
9801
|
});
|
|
9953
|
-
(0,registry/* registerTools */.Fd)("
|
|
9954
|
-
|
|
9955
|
-
|
|
9802
|
+
(0,registry/* registerTools */.Fd)("Calendar", "read", [
|
|
9803
|
+
calendarListCalendarsTool,
|
|
9804
|
+
calendarListEventsTool,
|
|
9805
|
+
calendarGetEventTool
|
|
9806
|
+
]);
|
|
9807
|
+
(0,registry/* registerTools */.Fd)("Calendar", "execute", [
|
|
9808
|
+
calendarCreateEventTool,
|
|
9809
|
+
calendarUpdateEventTool,
|
|
9810
|
+
calendarDeleteEventTool
|
|
9956
9811
|
]);
|
|
9957
9812
|
|
|
9958
|
-
// EXTERNAL MODULE: ./lib/tools/
|
|
9959
|
-
var
|
|
9960
|
-
// EXTERNAL MODULE: ./lib/
|
|
9961
|
-
var
|
|
9962
|
-
|
|
9963
|
-
var github = __webpack_require__(70729);
|
|
9964
|
-
// EXTERNAL MODULE: ./lib/tools/gmail.ts
|
|
9965
|
-
var gmail = __webpack_require__(77414);
|
|
9966
|
-
// EXTERNAL MODULE: ./lib/integrations/gmail-oauth.ts
|
|
9967
|
-
var gmail_oauth = __webpack_require__(87246);
|
|
9968
|
-
;// ./lib/tools/calendar.ts
|
|
9813
|
+
// EXTERNAL MODULE: ./lib/tools/outlook.ts
|
|
9814
|
+
var outlook = __webpack_require__(77467);
|
|
9815
|
+
// EXTERNAL MODULE: ./lib/integrations/microsoft-oauth.ts
|
|
9816
|
+
var microsoft_oauth = __webpack_require__(89080);
|
|
9817
|
+
;// ./lib/tools/outlook-calendar.ts
|
|
9969
9818
|
/**
|
|
9970
|
-
*
|
|
9971
|
-
*
|
|
9972
|
-
*
|
|
9973
|
-
* lib/integrations/gmail-oauth.ts).
|
|
9974
|
-
*
|
|
9975
|
-
* Scope-wise this surface is **events on existing calendars**:
|
|
9976
|
-
* - list / get / create / update / delete events
|
|
9977
|
-
* - list the user's calendars (read-only)
|
|
9978
|
-
* There is deliberately no calendar-list create/delete and no ACL
|
|
9979
|
-
* editing. To enable a wider surface, add the broader scope to
|
|
9980
|
-
* GMAIL_SCOPES and (force users to) reconnect.
|
|
9819
|
+
* Outlook Calendar tools via Microsoft Graph. Mirrors lib/tools/calendar.ts
|
|
9820
|
+
* (the Google Calendar set) one-for-one so the agent's mental model
|
|
9821
|
+
* carries over between providers.
|
|
9981
9822
|
*
|
|
9982
|
-
*
|
|
9983
|
-
* -
|
|
9984
|
-
*
|
|
9985
|
-
*
|
|
9986
|
-
*
|
|
9987
|
-
*
|
|
9988
|
-
*
|
|
9989
|
-
*
|
|
9990
|
-
*
|
|
9991
|
-
*
|
|
9823
|
+
* Graph differences vs Google Calendar worth knowing:
|
|
9824
|
+
* - Each event's start/end is { dateTime, timeZone } where timeZone is
|
|
9825
|
+
* a Windows-time-zone string by default ("Pacific Standard Time"),
|
|
9826
|
+
* not IANA. We pass an explicit `Prefer: outlook.timezone="UTC"`
|
|
9827
|
+
* header so reads come back in UTC and the agent doesn't have to
|
|
9828
|
+
* navigate two TZ namespaces.
|
|
9829
|
+
* - Listing events in a window uses /calendarView (auto-expands
|
|
9830
|
+
* recurring series), parallel to Google's `singleEvents=true`.
|
|
9831
|
+
* - Online meetings use `isOnlineMeeting:true` +
|
|
9832
|
+
* `onlineMeetingProvider:"teamsForBusiness"`. Provisioning a Teams
|
|
9833
|
+
* link is gated behind `add_teams_link` to keep create_event cheap
|
|
9834
|
+
* when the agent just wants a plain event.
|
|
9992
9835
|
*/
|
|
9993
9836
|
|
|
9994
9837
|
|
|
9995
9838
|
|
|
9996
|
-
|
|
9997
|
-
const calendarFetch = (auth, path, init)=>(0,gmail_oauth/* googleFetch */.sI)(auth, "Calendar", CALENDAR_BASE, path, init);
|
|
9998
|
-
// Slim down a full event to the fields the agent actually needs in a
|
|
9999
|
-
// thread response. Keeps tool outputs small enough not to blow context.
|
|
10000
|
-
function slimEvent(e) {
|
|
9839
|
+
function outlook_calendar_slimEvent(e) {
|
|
10001
9840
|
return {
|
|
10002
9841
|
id: e.id,
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
end: e.end?.dateTime ?? e.end?.date ?? null,
|
|
9842
|
+
subject: e.subject ?? null,
|
|
9843
|
+
description: e.bodyPreview ?? null,
|
|
9844
|
+
location: e.location?.displayName ?? null,
|
|
9845
|
+
start: e.start?.dateTime ?? null,
|
|
9846
|
+
end: e.end?.dateTime ?? null,
|
|
10009
9847
|
time_zone: e.start?.timeZone ?? e.end?.timeZone ?? null,
|
|
10010
9848
|
attendees: (e.attendees ?? []).map((a)=>({
|
|
10011
|
-
email: a.
|
|
10012
|
-
name: a.
|
|
10013
|
-
response: a.
|
|
9849
|
+
email: a.emailAddress?.address ?? null,
|
|
9850
|
+
name: a.emailAddress?.name ?? null,
|
|
9851
|
+
response: a.status?.response ?? null
|
|
10014
9852
|
})),
|
|
10015
|
-
|
|
10016
|
-
|
|
9853
|
+
is_all_day: e.isAllDay === true,
|
|
9854
|
+
is_cancelled: e.isCancelled === true,
|
|
9855
|
+
show_as: e.showAs ?? null,
|
|
9856
|
+
teams_link: e.onlineMeeting?.joinUrl ?? null,
|
|
9857
|
+
web_link: e.webLink ?? null
|
|
10017
9858
|
};
|
|
10018
9859
|
}
|
|
10019
9860
|
// ── Tools ───────────────────────────────────────────────────────────────────
|
|
10020
|
-
const
|
|
10021
|
-
const auth = (0,
|
|
9861
|
+
const outlookCalendarListCalendarsTool = (0,tools/* tool */.z6)(async ()=>{
|
|
9862
|
+
const auth = (0,microsoft_oauth/* resolveMicrosoftAuth */.jG)();
|
|
10022
9863
|
if ("error" in auth) return JSON.stringify({
|
|
10023
9864
|
error: auth.error
|
|
10024
9865
|
});
|
|
10025
|
-
const data = await
|
|
9866
|
+
const data = await (0,microsoft_oauth/* graphFetch */.z$)(auth, "/me/calendars");
|
|
10026
9867
|
if ("error" in data && data.error) return JSON.stringify(data);
|
|
10027
9868
|
return JSON.stringify({
|
|
10028
|
-
calendars: (data.
|
|
9869
|
+
calendars: (data.value ?? []).map((c)=>({
|
|
10029
9870
|
id: c.id,
|
|
10030
|
-
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
9871
|
+
name: c.name ?? null,
|
|
9872
|
+
is_default: c.isDefaultCalendar === true,
|
|
9873
|
+
can_edit: c.canEdit === true,
|
|
9874
|
+
owner: c.owner?.address ?? null
|
|
10034
9875
|
}))
|
|
10035
9876
|
});
|
|
10036
9877
|
}, {
|
|
10037
|
-
name: "
|
|
10038
|
-
description: "List the user's
|
|
9878
|
+
name: "outlook_calendar_list_calendars",
|
|
9879
|
+
description: "List the user's Outlook calendars (primary + shared). Returns id, name, " + "is_default flag, edit permission, owner. The `id` is what other " + "outlook_calendar_* tools expect as `calendar_id`. Omit `calendar_id` " + "in those tools to use the user's default calendar.",
|
|
10039
9880
|
schema: schemas/* object */.Ik({})
|
|
10040
9881
|
});
|
|
10041
|
-
const
|
|
10042
|
-
const auth = (0,
|
|
9882
|
+
const outlookCalendarListEventsTool = (0,tools/* tool */.z6)(async ({ calendar_id, time_min, time_max, max_results })=>{
|
|
9883
|
+
const auth = (0,microsoft_oauth/* resolveMicrosoftAuth */.jG)();
|
|
10043
9884
|
if ("error" in auth) return JSON.stringify({
|
|
10044
9885
|
error: auth.error
|
|
10045
9886
|
});
|
|
10046
|
-
const cal = encodeURIComponent(calendar_id ?? "primary");
|
|
10047
|
-
const params = new URLSearchParams({
|
|
10048
|
-
singleEvents: "true",
|
|
10049
|
-
orderBy: "startTime",
|
|
10050
|
-
maxResults: String(Math.min(Math.max(max_results ?? 25, 1), 100))
|
|
10051
|
-
});
|
|
10052
|
-
// Default window: now → +7 days. Keeps "what's on my schedule" cheap.
|
|
10053
9887
|
const now = new Date();
|
|
10054
9888
|
const inAWeek = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
9889
|
+
const startISO = time_min ?? now.toISOString();
|
|
9890
|
+
const endISO = time_max ?? inAWeek.toISOString();
|
|
9891
|
+
const top = Math.min(Math.max(max_results ?? 25, 1), 100);
|
|
9892
|
+
// /calendarView expands recurring series into individual instances —
|
|
9893
|
+
// the closest parallel to Google's singleEvents=true.
|
|
9894
|
+
const base = calendar_id ? `/me/calendars/${encodeURIComponent(calendar_id)}/calendarView` : "/me/calendarView";
|
|
9895
|
+
const params = new URLSearchParams({
|
|
9896
|
+
startDateTime: startISO,
|
|
9897
|
+
endDateTime: endISO,
|
|
9898
|
+
$top: String(top),
|
|
9899
|
+
$orderby: "start/dateTime"
|
|
9900
|
+
});
|
|
9901
|
+
const data = await (0,microsoft_oauth/* graphFetch */.z$)(auth, `${base}?${params.toString()}`, {
|
|
9902
|
+
// Force UTC in responses so the agent doesn't juggle Windows-TZ names.
|
|
9903
|
+
headers: {
|
|
9904
|
+
Prefer: 'outlook.timezone="UTC"'
|
|
9905
|
+
}
|
|
9906
|
+
});
|
|
10059
9907
|
if ("error" in data && data.error) return JSON.stringify(data);
|
|
10060
9908
|
return JSON.stringify({
|
|
10061
|
-
events: (data.
|
|
9909
|
+
events: (data.value ?? []).map(outlook_calendar_slimEvent)
|
|
10062
9910
|
});
|
|
10063
9911
|
}, {
|
|
10064
|
-
name: "
|
|
10065
|
-
description: "List
|
|
9912
|
+
name: "outlook_calendar_list_events",
|
|
9913
|
+
description: "List Outlook calendar events within a time window. Defaults: default " + "calendar, now → +7 days, ordered by start, recurring series expanded. " + "**Use this before creating an event** to avoid double-booking, and to " + "look up event ids before updating/deleting. All datetimes returned in " + "UTC (RFC3339 'Z'-suffixed).",
|
|
10066
9914
|
schema: schemas/* object */.Ik({
|
|
10067
|
-
calendar_id: schemas/* string */.Yj().optional().describe("Calendar id (default: '
|
|
9915
|
+
calendar_id: schemas/* string */.Yj().optional().describe("Calendar id (default: user's default calendar)"),
|
|
10068
9916
|
time_min: schemas/* string */.Yj().optional().describe("RFC3339 lower bound (default: now)"),
|
|
10069
9917
|
time_max: schemas/* string */.Yj().optional().describe("RFC3339 upper bound (default: now + 7 days)"),
|
|
10070
|
-
query: schemas/* string */.Yj().optional().describe("Free-text search across event fields"),
|
|
10071
9918
|
max_results: schemas/* number */.ai().int().optional().describe("Max events (default 25, max 100)")
|
|
10072
9919
|
})
|
|
10073
9920
|
});
|
|
10074
|
-
const
|
|
10075
|
-
const auth = (0,
|
|
9921
|
+
const outlookCalendarGetEventTool = (0,tools/* tool */.z6)(async ({ event_id })=>{
|
|
9922
|
+
const auth = (0,microsoft_oauth/* resolveMicrosoftAuth */.jG)();
|
|
10076
9923
|
if ("error" in auth) return JSON.stringify({
|
|
10077
9924
|
error: auth.error
|
|
10078
9925
|
});
|
|
10079
|
-
const
|
|
10080
|
-
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
error: data.error
|
|
9926
|
+
const e = await (0,microsoft_oauth/* graphFetch */.z$)(auth, `/me/events/${encodeURIComponent(event_id)}`, {
|
|
9927
|
+
headers: {
|
|
9928
|
+
Prefer: 'outlook.timezone="UTC"'
|
|
9929
|
+
}
|
|
10084
9930
|
});
|
|
10085
|
-
return JSON.stringify(
|
|
9931
|
+
if (e.error) return JSON.stringify({
|
|
9932
|
+
error: e.error
|
|
9933
|
+
});
|
|
9934
|
+
return JSON.stringify(outlook_calendar_slimEvent(e));
|
|
10086
9935
|
}, {
|
|
10087
|
-
name: "
|
|
10088
|
-
description: "Fetch one
|
|
9936
|
+
name: "outlook_calendar_get_event",
|
|
9937
|
+
description: "Fetch one Outlook calendar event by id. Returns the same slim shape as " + "outlook_calendar_list_events but for a single event.",
|
|
10089
9938
|
schema: schemas/* object */.Ik({
|
|
10090
|
-
|
|
10091
|
-
event_id: schemas/* string */.Yj().describe("Event id (from calendar_list_events results)")
|
|
9939
|
+
event_id: schemas/* string */.Yj().describe("Event id (from outlook_calendar_list_events)")
|
|
10092
9940
|
})
|
|
10093
9941
|
});
|
|
10094
|
-
const
|
|
10095
|
-
const auth = (0,
|
|
9942
|
+
const outlookCalendarCreateEventTool = (0,tools/* tool */.z6)(async ({ calendar_id, subject, summary, start_iso, end_iso, description, location, attendees, time_zone, add_teams_link })=>{
|
|
9943
|
+
const auth = (0,microsoft_oauth/* resolveMicrosoftAuth */.jG)();
|
|
10096
9944
|
if ("error" in auth) return JSON.stringify({
|
|
10097
9945
|
error: auth.error
|
|
10098
9946
|
});
|
|
10099
|
-
|
|
10100
|
-
//
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
if (!eventSummary) {
|
|
9947
|
+
// `summary` is accepted as an alias for `subject` so agents trained on
|
|
9948
|
+
// Google Calendar's vocabulary don't fail the schema on first try.
|
|
9949
|
+
const eventSubject = subject ?? summary;
|
|
9950
|
+
if (!eventSubject) {
|
|
10104
9951
|
return JSON.stringify({
|
|
10105
|
-
error: "
|
|
9952
|
+
error: "subject (or summary) is required"
|
|
10106
9953
|
});
|
|
10107
9954
|
}
|
|
9955
|
+
// Graph uses Windows TZ names by default but also accepts IANA names
|
|
9956
|
+
// when the body specifies them per-field. Default to UTC if the
|
|
9957
|
+
// caller omits time_zone (matches the list endpoint's behavior).
|
|
9958
|
+
const tz = time_zone ?? "UTC";
|
|
10108
9959
|
const body = {
|
|
10109
|
-
|
|
9960
|
+
subject: eventSubject,
|
|
10110
9961
|
start: {
|
|
10111
9962
|
dateTime: start_iso,
|
|
10112
|
-
|
|
10113
|
-
timeZone: time_zone
|
|
10114
|
-
} : {}
|
|
9963
|
+
timeZone: tz
|
|
10115
9964
|
},
|
|
10116
9965
|
end: {
|
|
10117
9966
|
dateTime: end_iso,
|
|
10118
|
-
|
|
10119
|
-
timeZone: time_zone
|
|
10120
|
-
} : {}
|
|
9967
|
+
timeZone: tz
|
|
10121
9968
|
}
|
|
10122
9969
|
};
|
|
10123
|
-
if (description) body.
|
|
10124
|
-
|
|
9970
|
+
if (description) body.body = {
|
|
9971
|
+
contentType: "text",
|
|
9972
|
+
content: description
|
|
9973
|
+
};
|
|
9974
|
+
if (location) body.location = {
|
|
9975
|
+
displayName: location
|
|
9976
|
+
};
|
|
10125
9977
|
if (attendees && attendees.length > 0) {
|
|
10126
|
-
body.attendees = attendees.map((
|
|
10127
|
-
|
|
9978
|
+
body.attendees = attendees.map((address)=>({
|
|
9979
|
+
emailAddress: {
|
|
9980
|
+
address
|
|
9981
|
+
},
|
|
9982
|
+
type: "required"
|
|
10128
9983
|
}));
|
|
10129
9984
|
}
|
|
10130
|
-
if (
|
|
10131
|
-
body.
|
|
10132
|
-
|
|
10133
|
-
// requestId must be unique per createRequest; Google echoes it back.
|
|
10134
|
-
requestId: `jarela-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
10135
|
-
conferenceSolutionKey: {
|
|
10136
|
-
type: "hangoutsMeet"
|
|
10137
|
-
}
|
|
10138
|
-
}
|
|
10139
|
-
};
|
|
9985
|
+
if (add_teams_link) {
|
|
9986
|
+
body.isOnlineMeeting = true;
|
|
9987
|
+
body.onlineMeetingProvider = "teamsForBusiness";
|
|
10140
9988
|
}
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
const params = add_meet_link ? "?conferenceDataVersion=1" : "";
|
|
10144
|
-
const data = await calendarFetch(auth, `/calendars/${cal}/events${params}`, {
|
|
9989
|
+
const path = calendar_id ? `/me/calendars/${encodeURIComponent(calendar_id)}/events` : "/me/events";
|
|
9990
|
+
const r = await (0,microsoft_oauth/* graphFetch */.z$)(auth, path, {
|
|
10145
9991
|
method: "POST",
|
|
10146
|
-
body: JSON.stringify(body)
|
|
9992
|
+
body: JSON.stringify(body),
|
|
9993
|
+
headers: {
|
|
9994
|
+
Prefer: 'outlook.timezone="UTC"'
|
|
9995
|
+
}
|
|
10147
9996
|
});
|
|
10148
|
-
if (
|
|
10149
|
-
error:
|
|
9997
|
+
if (r.error) return JSON.stringify({
|
|
9998
|
+
error: r.error
|
|
10150
9999
|
});
|
|
10151
|
-
return JSON.stringify(
|
|
10000
|
+
return JSON.stringify(outlook_calendar_slimEvent(r));
|
|
10152
10001
|
}, {
|
|
10153
|
-
name: "
|
|
10154
|
-
description: "Create
|
|
10002
|
+
name: "outlook_calendar_create_event",
|
|
10003
|
+
description: "Create an Outlook calendar event. Datetimes are RFC3339 strings; pair " + "with `time_zone` (IANA like 'America/Los_Angeles' or Windows TZ like " + "'Pacific Standard Time') so Outlook interprets them correctly. Defaults " + "to UTC if omitted. Attendees are automatically sent invites. Set " + "`add_teams_link: true` to provision a Teams meeting URL (requires a " + "work/school M365 account; personal Microsoft accounts cannot create " + "Teams meetings via Graph).",
|
|
10155
10004
|
schema: schemas/* object */.Ik({
|
|
10156
|
-
calendar_id: schemas/* string */.Yj().optional().describe("Calendar id (default: '
|
|
10157
|
-
|
|
10158
|
-
|
|
10005
|
+
calendar_id: schemas/* string */.Yj().optional().describe("Calendar id (default: user's default calendar)"),
|
|
10006
|
+
subject: schemas/* string */.Yj().min(1).optional().describe("Event title shown on the calendar (alias: summary)"),
|
|
10007
|
+
summary: schemas/* string */.Yj().min(1).optional().describe("Alias for subject (Google Calendar vocabulary)"),
|
|
10159
10008
|
start_iso: schemas/* string */.Yj().describe("Start datetime, RFC3339"),
|
|
10160
10009
|
end_iso: schemas/* string */.Yj().describe("End datetime, RFC3339 (must be after start)"),
|
|
10161
|
-
description: schemas/* string */.Yj().optional().describe("Long-form event body (
|
|
10010
|
+
description: schemas/* string */.Yj().optional().describe("Long-form event body (plain text)"),
|
|
10162
10011
|
location: schemas/* string */.Yj().optional().describe("Free-text location string"),
|
|
10163
10012
|
attendees: schemas/* array */.YO(schemas/* string */.Yj().email()).optional().describe("Invitee email addresses"),
|
|
10164
|
-
time_zone: schemas/* string */.Yj().optional().describe("IANA timezone
|
|
10165
|
-
|
|
10013
|
+
time_zone: schemas/* string */.Yj().optional().describe("IANA or Windows timezone (default 'UTC')"),
|
|
10014
|
+
add_teams_link: schemas/* boolean */.zM().optional().describe("Provision a Teams meeting URL on this event")
|
|
10166
10015
|
})
|
|
10167
10016
|
});
|
|
10168
|
-
const
|
|
10169
|
-
const auth = (0,
|
|
10017
|
+
const outlookCalendarUpdateEventTool = (0,tools/* tool */.z6)(async ({ event_id, subject, summary, start_iso, end_iso, description, location, attendees, time_zone })=>{
|
|
10018
|
+
const auth = (0,microsoft_oauth/* resolveMicrosoftAuth */.jG)();
|
|
10170
10019
|
if ("error" in auth) return JSON.stringify({
|
|
10171
10020
|
error: auth.error
|
|
10172
10021
|
});
|
|
10173
|
-
const
|
|
10174
|
-
const eid = encodeURIComponent(event_id);
|
|
10022
|
+
const tz = time_zone ?? "UTC";
|
|
10175
10023
|
const patch = {};
|
|
10176
|
-
const
|
|
10177
|
-
if (
|
|
10178
|
-
if (description !== undefined) patch.
|
|
10179
|
-
|
|
10180
|
-
|
|
10181
|
-
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
|
|
10185
|
-
|
|
10186
|
-
|
|
10187
|
-
|
|
10188
|
-
|
|
10189
|
-
|
|
10190
|
-
|
|
10191
|
-
|
|
10192
|
-
|
|
10193
|
-
} : {}
|
|
10194
|
-
};
|
|
10195
|
-
}
|
|
10024
|
+
const eventSubject = subject ?? summary;
|
|
10025
|
+
if (eventSubject !== undefined) patch.subject = eventSubject;
|
|
10026
|
+
if (description !== undefined) patch.body = {
|
|
10027
|
+
contentType: "text",
|
|
10028
|
+
content: description
|
|
10029
|
+
};
|
|
10030
|
+
if (location !== undefined) patch.location = {
|
|
10031
|
+
displayName: location
|
|
10032
|
+
};
|
|
10033
|
+
if (start_iso !== undefined) patch.start = {
|
|
10034
|
+
dateTime: start_iso,
|
|
10035
|
+
timeZone: tz
|
|
10036
|
+
};
|
|
10037
|
+
if (end_iso !== undefined) patch.end = {
|
|
10038
|
+
dateTime: end_iso,
|
|
10039
|
+
timeZone: tz
|
|
10040
|
+
};
|
|
10196
10041
|
if (attendees !== undefined) {
|
|
10197
|
-
patch.attendees = attendees.map((
|
|
10198
|
-
|
|
10042
|
+
patch.attendees = attendees.map((address)=>({
|
|
10043
|
+
emailAddress: {
|
|
10044
|
+
address
|
|
10045
|
+
},
|
|
10046
|
+
type: "required"
|
|
10199
10047
|
}));
|
|
10200
10048
|
}
|
|
10201
10049
|
if (Object.keys(patch).length === 0) {
|
|
@@ -10203,373 +10051,678 @@ const calendarUpdateEventTool = (0,tools/* tool */.z6)(async ({ calendar_id, eve
|
|
|
10203
10051
|
error: "Provide at least one field to update"
|
|
10204
10052
|
});
|
|
10205
10053
|
}
|
|
10206
|
-
const
|
|
10054
|
+
const r = await (0,microsoft_oauth/* graphFetch */.z$)(auth, `/me/events/${encodeURIComponent(event_id)}`, {
|
|
10207
10055
|
method: "PATCH",
|
|
10208
|
-
body: JSON.stringify(patch)
|
|
10056
|
+
body: JSON.stringify(patch),
|
|
10057
|
+
headers: {
|
|
10058
|
+
Prefer: 'outlook.timezone="UTC"'
|
|
10059
|
+
}
|
|
10209
10060
|
});
|
|
10210
|
-
if (
|
|
10211
|
-
error:
|
|
10061
|
+
if (r.error) return JSON.stringify({
|
|
10062
|
+
error: r.error
|
|
10212
10063
|
});
|
|
10213
|
-
return JSON.stringify(
|
|
10064
|
+
return JSON.stringify(outlook_calendar_slimEvent(r));
|
|
10214
10065
|
}, {
|
|
10215
|
-
name: "
|
|
10216
|
-
description: "Patch
|
|
10066
|
+
name: "outlook_calendar_update_event",
|
|
10067
|
+
description: "Patch an Outlook calendar event. Only supplied fields are changed; omit " + "fields to leave them alone. Note `attendees` REPLACES the full invitee " + "list, so include everyone who should remain.",
|
|
10217
10068
|
schema: schemas/* object */.Ik({
|
|
10218
|
-
calendar_id: schemas/* string */.Yj().optional().describe("Calendar id (default: 'primary')"),
|
|
10219
10069
|
event_id: schemas/* string */.Yj().describe("Event id"),
|
|
10220
|
-
|
|
10221
|
-
|
|
10070
|
+
subject: schemas/* string */.Yj().optional().describe("New event title (alias: summary)"),
|
|
10071
|
+
summary: schemas/* string */.Yj().optional().describe("Alias for subject (Google Calendar vocabulary)"),
|
|
10222
10072
|
start_iso: schemas/* string */.Yj().optional().describe("New start datetime, RFC3339"),
|
|
10223
10073
|
end_iso: schemas/* string */.Yj().optional().describe("New end datetime, RFC3339"),
|
|
10224
|
-
description: schemas/* string */.Yj().optional().describe("New event body"),
|
|
10074
|
+
description: schemas/* string */.Yj().optional().describe("New event body (plain text)"),
|
|
10225
10075
|
location: schemas/* string */.Yj().optional().describe("New location string"),
|
|
10226
10076
|
attendees: schemas/* array */.YO(schemas/* string */.Yj().email()).optional().describe("Replacement attendee list"),
|
|
10227
|
-
time_zone: schemas/* string */.Yj().optional().describe("IANA
|
|
10077
|
+
time_zone: schemas/* string */.Yj().optional().describe("IANA or Windows TZ applied to start/end (default 'UTC')")
|
|
10228
10078
|
})
|
|
10229
10079
|
});
|
|
10230
|
-
const
|
|
10231
|
-
const auth = (0,
|
|
10080
|
+
const outlookCalendarDeleteEventTool = (0,tools/* tool */.z6)(async ({ event_id })=>{
|
|
10081
|
+
const auth = (0,microsoft_oauth/* resolveMicrosoftAuth */.jG)();
|
|
10232
10082
|
if ("error" in auth) return JSON.stringify({
|
|
10233
10083
|
error: auth.error
|
|
10234
10084
|
});
|
|
10235
|
-
const
|
|
10236
|
-
const eid = encodeURIComponent(event_id);
|
|
10237
|
-
const data = await calendarFetch(auth, `/calendars/${cal}/events/${eid}`, {
|
|
10085
|
+
const r = await (0,microsoft_oauth/* graphFetch */.z$)(auth, `/me/events/${encodeURIComponent(event_id)}`, {
|
|
10238
10086
|
method: "DELETE"
|
|
10239
10087
|
});
|
|
10240
|
-
if (
|
|
10241
|
-
error:
|
|
10088
|
+
if (r.error) return JSON.stringify({
|
|
10089
|
+
error: r.error
|
|
10242
10090
|
});
|
|
10243
10091
|
return JSON.stringify({
|
|
10244
10092
|
ok: true,
|
|
10245
10093
|
id: event_id
|
|
10246
10094
|
});
|
|
10247
10095
|
}, {
|
|
10248
|
-
name: "
|
|
10249
|
-
description: "Delete
|
|
10096
|
+
name: "outlook_calendar_delete_event",
|
|
10097
|
+
description: "Delete an Outlook calendar event by id. Attendees are notified. Returns " + "`{ ok: true, id }` on success. Use outlook_calendar_list_events to find " + "the event id first if you only know the title/time.",
|
|
10098
|
+
schema: schemas/* object */.Ik({
|
|
10099
|
+
event_id: schemas/* string */.Yj().describe("Event id to delete")
|
|
10100
|
+
})
|
|
10101
|
+
});
|
|
10102
|
+
(0,registry/* registerTools */.Fd)("Calendar", "read", [
|
|
10103
|
+
outlookCalendarListCalendarsTool,
|
|
10104
|
+
outlookCalendarListEventsTool,
|
|
10105
|
+
outlookCalendarGetEventTool
|
|
10106
|
+
]);
|
|
10107
|
+
(0,registry/* registerTools */.Fd)("Calendar", "execute", [
|
|
10108
|
+
outlookCalendarCreateEventTool,
|
|
10109
|
+
outlookCalendarUpdateEventTool,
|
|
10110
|
+
outlookCalendarDeleteEventTool
|
|
10111
|
+
]);
|
|
10112
|
+
|
|
10113
|
+
// EXTERNAL MODULE: ./lib/agents/run-thread.ts + 17 modules
|
|
10114
|
+
var run_thread = __webpack_require__(8459);
|
|
10115
|
+
// EXTERNAL MODULE: ./lib/agents/stream-collector.ts
|
|
10116
|
+
var stream_collector = __webpack_require__(30685);
|
|
10117
|
+
// EXTERNAL MODULE: ./lib/agents/run-queue.ts
|
|
10118
|
+
var run_queue = __webpack_require__(3944);
|
|
10119
|
+
;// ./lib/tools/delegate.ts
|
|
10120
|
+
|
|
10121
|
+
|
|
10122
|
+
|
|
10123
|
+
|
|
10124
|
+
|
|
10125
|
+
|
|
10126
|
+
|
|
10127
|
+
|
|
10128
|
+
function readDelegateContext(config) {
|
|
10129
|
+
const threadId = config?.configurable?.thread_id;
|
|
10130
|
+
if (!threadId) return null;
|
|
10131
|
+
const thread = (0,threads/* getThread */.fG)(threadId);
|
|
10132
|
+
if (!thread) return null;
|
|
10133
|
+
const depth = config?.configurable?.delegation_depth ?? 0;
|
|
10134
|
+
const ancestorsRaw = config?.configurable?.delegation_ancestors;
|
|
10135
|
+
const ancestors = Array.isArray(ancestorsRaw) ? ancestorsRaw : [];
|
|
10136
|
+
return {
|
|
10137
|
+
parentAgentId: thread.agent_id,
|
|
10138
|
+
depth,
|
|
10139
|
+
ancestors
|
|
10140
|
+
};
|
|
10141
|
+
}
|
|
10142
|
+
function fail(code, message, extra = {}) {
|
|
10143
|
+
return JSON.stringify({
|
|
10144
|
+
ok: false,
|
|
10145
|
+
error_code: code,
|
|
10146
|
+
message,
|
|
10147
|
+
...extra
|
|
10148
|
+
});
|
|
10149
|
+
}
|
|
10150
|
+
const delegateToAgentTool = (0,tools/* tool */.z6)(async ({ agent_id, task }, config)=>{
|
|
10151
|
+
const ctx = readDelegateContext(config);
|
|
10152
|
+
if (!ctx) return fail("no_context", "No agent context (missing thread_id)");
|
|
10153
|
+
const parent = (0,agent_configs/* getAgentConfig */.mJ)(ctx.parentAgentId);
|
|
10154
|
+
if (!parent) return fail("agent_not_found", `Parent agent "${ctx.parentAgentId}" not found`);
|
|
10155
|
+
if (agent_id === ctx.parentAgentId) {
|
|
10156
|
+
return fail("cycle_detected", "Cannot delegate to self");
|
|
10157
|
+
}
|
|
10158
|
+
if (ctx.ancestors.includes(agent_id)) {
|
|
10159
|
+
return fail("cycle_detected", `Delegation cycle: ${agent_id} is already in the chain [${ctx.ancestors.join(" -> ")}]`);
|
|
10160
|
+
}
|
|
10161
|
+
if (ctx.depth >= run_thread/* MAX_DELEGATION_DEPTH */.Ye) {
|
|
10162
|
+
return fail("depth_exceeded", `Maximum delegation depth (${run_thread/* MAX_DELEGATION_DEPTH */.Ye}) reached. Chain: [${[
|
|
10163
|
+
...ctx.ancestors,
|
|
10164
|
+
ctx.parentAgentId
|
|
10165
|
+
].join(" -> ")}]`);
|
|
10166
|
+
}
|
|
10167
|
+
const roster = (0,agent_configs/* parseDelegateTargets */.bg)(parent.delegate_targets);
|
|
10168
|
+
if (!roster.includes(agent_id)) {
|
|
10169
|
+
return fail("not_in_roster", `Agent "${agent_id}" is not in the delegate roster for "${parent.id}". Available: [${roster.join(", ") || "none"}]`);
|
|
10170
|
+
}
|
|
10171
|
+
const child = (0,agent_configs/* getAgentConfig */.mJ)(agent_id);
|
|
10172
|
+
if (!child) return fail("agent_not_found", `Delegate agent "${agent_id}" not found`);
|
|
10173
|
+
const childThread = (0,threads/* getOrCreateAgentThread */.xH)(agent_id);
|
|
10174
|
+
const startedAt = Date.now();
|
|
10175
|
+
try {
|
|
10176
|
+
// Serialise on the child thread_id with every other entry point
|
|
10177
|
+
// (HTTP POST, scheduler, watcher, bridge, sibling delegations) —
|
|
10178
|
+
// see lib/agents/run-queue.ts. A delegate fired while the child is
|
|
10179
|
+
// already running waits in the child's queue instead of racing the
|
|
10180
|
+
// checkpoint store.
|
|
10181
|
+
const queued = await (0,run_queue/* enqueueThreadRun */.M6)(childThread.thread_id, "delegate", async ()=>{
|
|
10182
|
+
const prepared = await (0,run_thread/* prepareThreadRun */.fn)({
|
|
10183
|
+
thread_id: childThread.thread_id,
|
|
10184
|
+
message: task,
|
|
10185
|
+
user_category: "delegation",
|
|
10186
|
+
_delegation_depth: ctx.depth + 1,
|
|
10187
|
+
_delegation_ancestors: [
|
|
10188
|
+
...ctx.ancestors,
|
|
10189
|
+
ctx.parentAgentId
|
|
10190
|
+
]
|
|
10191
|
+
});
|
|
10192
|
+
const collected = await (0,stream_collector/* collectStream */.V)(prepared.stream);
|
|
10193
|
+
if (collected.terminal !== "error") {
|
|
10194
|
+
(0,run_thread/* persistAssistantMessage */._w)(childThread.thread_id, collected.assistantContent, collected.usedTools, collected.toolEvents, "delegation", collected.usage ?? null, prepared.context_snapshot ?? null, prepared.source_manifest ?? null);
|
|
10195
|
+
}
|
|
10196
|
+
return collected;
|
|
10197
|
+
}).result;
|
|
10198
|
+
const elapsed_ms = Date.now() - startedAt;
|
|
10199
|
+
if (queued.terminal === "error") {
|
|
10200
|
+
return fail("child_error", queued.errorMessage ?? "Child agent run failed", {
|
|
10201
|
+
agent_id,
|
|
10202
|
+
agent_name: child.name,
|
|
10203
|
+
thread_id: childThread.thread_id
|
|
10204
|
+
});
|
|
10205
|
+
}
|
|
10206
|
+
return JSON.stringify({
|
|
10207
|
+
ok: true,
|
|
10208
|
+
agent_id: child.id,
|
|
10209
|
+
agent_name: child.name,
|
|
10210
|
+
thread_id: childThread.thread_id,
|
|
10211
|
+
depth: ctx.depth + 1,
|
|
10212
|
+
result: queued.assistantContent.trim(),
|
|
10213
|
+
used_tools: Array.from(new Set(queued.usedTools)),
|
|
10214
|
+
elapsed_ms
|
|
10215
|
+
});
|
|
10216
|
+
} catch (err) {
|
|
10217
|
+
return fail("child_error", err instanceof Error ? err.message : String(err), {
|
|
10218
|
+
agent_id,
|
|
10219
|
+
agent_name: child.name,
|
|
10220
|
+
thread_id: childThread.thread_id
|
|
10221
|
+
});
|
|
10222
|
+
}
|
|
10223
|
+
}, {
|
|
10224
|
+
name: "delegate_to_agent",
|
|
10225
|
+
description: "Hand a subtask to another agent that has specialized knowledge or tools you lack. " + "The delegate runs in its own thread; the user sees a tool card with the delegate's name, " + "the task you sent, and the delegate's final answer (plus a link to open the delegate's thread). " + "Only delegate when the target agent is genuinely better-suited — do NOT delegate trivial subtasks " + "you can handle yourself. Before calling this tool, tell the user in one sentence which agent you " + "are handing to and why. Available delegate ids are listed in the 'Available delegates' system " + "section; calling with an id outside that list will be refused.",
|
|
10250
10226
|
schema: schemas/* object */.Ik({
|
|
10251
|
-
|
|
10252
|
-
|
|
10227
|
+
agent_id: schemas/* string */.Yj().describe("The id of the delegate agent. Must appear in the 'Available delegates' list in your system prompt."),
|
|
10228
|
+
task: schemas/* string */.Yj().min(1).describe("A self-contained task description for the delegate. Include all context the delegate needs — " + "the delegate does NOT see your conversation history with the user, only this task string.")
|
|
10253
10229
|
})
|
|
10254
10230
|
});
|
|
10255
|
-
(0,registry/* registerTools */.Fd)("
|
|
10256
|
-
|
|
10257
|
-
calendarListEventsTool,
|
|
10258
|
-
calendarGetEventTool
|
|
10259
|
-
]);
|
|
10260
|
-
(0,registry/* registerTools */.Fd)("Calendar", "execute", [
|
|
10261
|
-
calendarCreateEventTool,
|
|
10262
|
-
calendarUpdateEventTool,
|
|
10263
|
-
calendarDeleteEventTool
|
|
10231
|
+
(0,registry/* registerTools */.Fd)("Agent", "execute", [
|
|
10232
|
+
delegateToAgentTool
|
|
10264
10233
|
]);
|
|
10265
10234
|
|
|
10266
|
-
// EXTERNAL MODULE: ./lib/
|
|
10267
|
-
var
|
|
10268
|
-
// EXTERNAL MODULE: ./lib/
|
|
10269
|
-
var
|
|
10270
|
-
;// ./lib/tools/
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10274
|
-
|
|
10275
|
-
|
|
10276
|
-
|
|
10277
|
-
|
|
10278
|
-
|
|
10279
|
-
|
|
10280
|
-
|
|
10281
|
-
|
|
10282
|
-
|
|
10283
|
-
|
|
10284
|
-
|
|
10285
|
-
|
|
10286
|
-
* link is gated behind `add_teams_link` to keep create_event cheap
|
|
10287
|
-
* when the agent just wants a plain event.
|
|
10288
|
-
*/
|
|
10235
|
+
// EXTERNAL MODULE: ./lib/env/schema.ts
|
|
10236
|
+
var schema = __webpack_require__(69353);
|
|
10237
|
+
// EXTERNAL MODULE: ./lib/env/overrides.ts
|
|
10238
|
+
var overrides = __webpack_require__(86037);
|
|
10239
|
+
;// ./lib/tools/system_config.ts
|
|
10240
|
+
// Agent-callable knobs for the JARELA_* override store.
|
|
10241
|
+
//
|
|
10242
|
+
// Both tools are gated by the per-var schema flag `agentWritable` —
|
|
10243
|
+
// agents cannot write to anything not flagged true (defaults to false).
|
|
10244
|
+
// `restart_server` is only wired here; agents still need the tool to be
|
|
10245
|
+
// in their selected toolset to call it (default agents do not include
|
|
10246
|
+
// these).
|
|
10247
|
+
//
|
|
10248
|
+
// Use cases the user explicitly asked to support:
|
|
10249
|
+
// - "agent, lower the run idle timeout to 30s and restart"
|
|
10250
|
+
// - "agent, switch the log level to debug for the next hour"
|
|
10251
|
+
//
|
|
10252
|
+
// We surface the schema's tier/restart flags in the response so the
|
|
10253
|
+
// agent's reply can tell the user what changed and whether a restart
|
|
10254
|
+
// fired (or is needed but skipped).
|
|
10289
10255
|
|
|
10290
10256
|
|
|
10291
10257
|
|
|
10292
|
-
|
|
10293
|
-
|
|
10294
|
-
|
|
10295
|
-
|
|
10296
|
-
|
|
10297
|
-
|
|
10298
|
-
|
|
10299
|
-
end: e.end?.dateTime ?? null,
|
|
10300
|
-
time_zone: e.start?.timeZone ?? e.end?.timeZone ?? null,
|
|
10301
|
-
attendees: (e.attendees ?? []).map((a)=>({
|
|
10302
|
-
email: a.emailAddress?.address ?? null,
|
|
10303
|
-
name: a.emailAddress?.name ?? null,
|
|
10304
|
-
response: a.status?.response ?? null
|
|
10305
|
-
})),
|
|
10306
|
-
is_all_day: e.isAllDay === true,
|
|
10307
|
-
is_cancelled: e.isCancelled === true,
|
|
10308
|
-
show_as: e.showAs ?? null,
|
|
10309
|
-
teams_link: e.onlineMeeting?.joinUrl ?? null,
|
|
10310
|
-
web_link: e.webLink ?? null
|
|
10311
|
-
};
|
|
10312
|
-
}
|
|
10313
|
-
// ── Tools ───────────────────────────────────────────────────────────────────
|
|
10314
|
-
const outlookCalendarListCalendarsTool = (0,tools/* tool */.z6)(async ()=>{
|
|
10315
|
-
const auth = (0,microsoft_oauth/* resolveMicrosoftAuth */.jG)();
|
|
10316
|
-
if ("error" in auth) return JSON.stringify({
|
|
10317
|
-
error: auth.error
|
|
10318
|
-
});
|
|
10319
|
-
const data = await (0,microsoft_oauth/* graphFetch */.z$)(auth, "/me/calendars");
|
|
10320
|
-
if ("error" in data && data.error) return JSON.stringify(data);
|
|
10321
|
-
return JSON.stringify({
|
|
10322
|
-
calendars: (data.value ?? []).map((c)=>({
|
|
10323
|
-
id: c.id,
|
|
10324
|
-
name: c.name ?? null,
|
|
10325
|
-
is_default: c.isDefaultCalendar === true,
|
|
10326
|
-
can_edit: c.canEdit === true,
|
|
10327
|
-
owner: c.owner?.address ?? null
|
|
10328
|
-
}))
|
|
10329
|
-
});
|
|
10330
|
-
}, {
|
|
10331
|
-
name: "outlook_calendar_list_calendars",
|
|
10332
|
-
description: "List the user's Outlook calendars (primary + shared). Returns id, name, " + "is_default flag, edit permission, owner. The `id` is what other " + "outlook_calendar_* tools expect as `calendar_id`. Omit `calendar_id` " + "in those tools to use the user's default calendar.",
|
|
10333
|
-
schema: schemas/* object */.Ik({})
|
|
10258
|
+
|
|
10259
|
+
|
|
10260
|
+
|
|
10261
|
+
const setEnvSchema = schemas/* object */.Ik({
|
|
10262
|
+
name: schemas/* string */.Yj().describe("Env var name. Must be a JARELA_* knob the schema flags as agent-writable; otherwise the call returns code=forbidden."),
|
|
10263
|
+
value: schemas/* string */.Yj().nullable().describe("New value as a string (numbers/bools come as their string form: '5000' / 'true'). Pass null to clear the override and revert to the default."),
|
|
10264
|
+
reason: schemas/* string */.Yj().optional().describe("Short note explaining the change — logged for postmortems.")
|
|
10334
10265
|
});
|
|
10335
|
-
const
|
|
10336
|
-
const
|
|
10337
|
-
if (
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
|
|
10341
|
-
|
|
10342
|
-
|
|
10343
|
-
|
|
10344
|
-
|
|
10345
|
-
|
|
10346
|
-
|
|
10347
|
-
|
|
10348
|
-
|
|
10349
|
-
|
|
10350
|
-
|
|
10351
|
-
|
|
10352
|
-
|
|
10353
|
-
|
|
10354
|
-
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
|
|
10266
|
+
const setEnvVar = (0,tools/* tool */.z6)(async ({ name, value, reason })=>{
|
|
10267
|
+
const def = (0,schema/* envSchemaByName */.Db)().get(name);
|
|
10268
|
+
if (!def) {
|
|
10269
|
+
return JSON.stringify({
|
|
10270
|
+
ok: false,
|
|
10271
|
+
code: "unknown_var",
|
|
10272
|
+
error: `unknown env var: ${name}`,
|
|
10273
|
+
hint: "List the schema with /api/v1/env (GET) before guessing names. Only JARELA_* keys defined in lib/env/schema.ts are accepted."
|
|
10274
|
+
});
|
|
10275
|
+
}
|
|
10276
|
+
if (!def.agentWritable) {
|
|
10277
|
+
return JSON.stringify({
|
|
10278
|
+
ok: false,
|
|
10279
|
+
code: "forbidden",
|
|
10280
|
+
error: `${name} is not flagged agentWritable in the schema`,
|
|
10281
|
+
hint: "Agents cannot edit infra knobs (port, hostname, dataDir, …). Tell the user to change this from the Environment panel themselves."
|
|
10282
|
+
});
|
|
10283
|
+
}
|
|
10284
|
+
if (value !== null) {
|
|
10285
|
+
const verr = (0,overrides/* validateForSchema */.xg)(def, value);
|
|
10286
|
+
if (verr) {
|
|
10287
|
+
return JSON.stringify({
|
|
10288
|
+
ok: false,
|
|
10289
|
+
code: "invalid_value",
|
|
10290
|
+
error: `${name}: ${verr}`,
|
|
10291
|
+
hint: "Re-issue the call with a value that matches the schema's type/min/max/enum."
|
|
10292
|
+
});
|
|
10358
10293
|
}
|
|
10359
|
-
}
|
|
10360
|
-
|
|
10294
|
+
}
|
|
10295
|
+
await (0,overrides/* patchOverride */.PJ)(name, value);
|
|
10296
|
+
if (value === null) delete process.env[name];
|
|
10297
|
+
else process.env[name] = value;
|
|
10298
|
+
(0,config/* resetConfigCache */.y)();
|
|
10361
10299
|
return JSON.stringify({
|
|
10362
|
-
|
|
10300
|
+
ok: true,
|
|
10301
|
+
name,
|
|
10302
|
+
value,
|
|
10303
|
+
requiresRestart: def.requiresRestart,
|
|
10304
|
+
reason: reason ?? null,
|
|
10305
|
+
hint: def.requiresRestart ? "Override persisted. The change requires a server restart — call restart_server to apply, OR tell the user to click Restart in the Environment panel." : "Override persisted and is in effect immediately. No restart needed."
|
|
10363
10306
|
});
|
|
10364
10307
|
}, {
|
|
10365
|
-
name: "
|
|
10366
|
-
description: "
|
|
10367
|
-
schema:
|
|
10368
|
-
calendar_id: schemas/* string */.Yj().optional().describe("Calendar id (default: user's default calendar)"),
|
|
10369
|
-
time_min: schemas/* string */.Yj().optional().describe("RFC3339 lower bound (default: now)"),
|
|
10370
|
-
time_max: schemas/* string */.Yj().optional().describe("RFC3339 upper bound (default: now + 7 days)"),
|
|
10371
|
-
max_results: schemas/* number */.ai().int().optional().describe("Max events (default 25, max 100)")
|
|
10372
|
-
})
|
|
10308
|
+
name: "set_env_var",
|
|
10309
|
+
description: "Set or unset a JARELA_* runtime override. Only schema-flagged agent-writable knobs are accepted; everything else returns code=forbidden. Use this when the user explicitly asks to change a runtime setting (e.g. log level, retry budget). Pair with restart_server when the result reports requiresRestart=true.",
|
|
10310
|
+
schema: setEnvSchema
|
|
10373
10311
|
});
|
|
10374
|
-
const
|
|
10375
|
-
|
|
10376
|
-
if ("error" in auth) return JSON.stringify({
|
|
10377
|
-
error: auth.error
|
|
10378
|
-
});
|
|
10379
|
-
const e = await (0,microsoft_oauth/* graphFetch */.z$)(auth, `/me/events/${encodeURIComponent(event_id)}`, {
|
|
10380
|
-
headers: {
|
|
10381
|
-
Prefer: 'outlook.timezone="UTC"'
|
|
10382
|
-
}
|
|
10383
|
-
});
|
|
10384
|
-
if (e.error) return JSON.stringify({
|
|
10385
|
-
error: e.error
|
|
10386
|
-
});
|
|
10387
|
-
return JSON.stringify(outlook_calendar_slimEvent(e));
|
|
10388
|
-
}, {
|
|
10389
|
-
name: "outlook_calendar_get_event",
|
|
10390
|
-
description: "Fetch one Outlook calendar event by id. Returns the same slim shape as " + "outlook_calendar_list_events but for a single event.",
|
|
10391
|
-
schema: schemas/* object */.Ik({
|
|
10392
|
-
event_id: schemas/* string */.Yj().describe("Event id (from outlook_calendar_list_events)")
|
|
10393
|
-
})
|
|
10312
|
+
const restartSchema = schemas/* object */.Ik({
|
|
10313
|
+
reason: schemas/* string */.Yj().min(1).describe("Why the restart is needed (logged + included in /api/v1/system/restart payload). Required.")
|
|
10394
10314
|
});
|
|
10395
|
-
const
|
|
10396
|
-
|
|
10397
|
-
|
|
10398
|
-
|
|
10399
|
-
|
|
10400
|
-
|
|
10401
|
-
|
|
10402
|
-
|
|
10403
|
-
|
|
10315
|
+
const restartServer = (0,tools/* tool */.z6)(async ({ reason })=>{
|
|
10316
|
+
// Use the same endpoint the UI hits. Doing it via fetch instead of
|
|
10317
|
+
// calling process.exit() directly here means the request response
|
|
10318
|
+
// flushes back to the agent (and through it, the user) before the
|
|
10319
|
+
// process tears down.
|
|
10320
|
+
try {
|
|
10321
|
+
const port = Number(process.env.JARELA_PORT ?? process.env.PORT ?? 4312);
|
|
10322
|
+
const host = process.env.JARELA_HOSTNAME ?? process.env.HOSTNAME ?? "127.0.0.1";
|
|
10323
|
+
const r = await fetch(`http://${host}:${port}/api/v1/system/restart`, {
|
|
10324
|
+
method: "POST",
|
|
10325
|
+
headers: {
|
|
10326
|
+
"Content-Type": "application/json"
|
|
10327
|
+
},
|
|
10328
|
+
body: JSON.stringify({
|
|
10329
|
+
reason: `[agent] ${reason}`
|
|
10330
|
+
})
|
|
10331
|
+
});
|
|
10332
|
+
const body = await r.json().catch(()=>({}));
|
|
10404
10333
|
return JSON.stringify({
|
|
10405
|
-
|
|
10334
|
+
ok: r.ok,
|
|
10335
|
+
status: r.status,
|
|
10336
|
+
reason,
|
|
10337
|
+
hint: body.hint ?? "Restart request sent. The supervisor will relaunch the process; the user's UI will reconnect automatically."
|
|
10338
|
+
});
|
|
10339
|
+
} catch (e) {
|
|
10340
|
+
return JSON.stringify({
|
|
10341
|
+
ok: false,
|
|
10342
|
+
code: "restart_failed",
|
|
10343
|
+
error: e.message,
|
|
10344
|
+
hint: "Could not reach /api/v1/system/restart from inside the same process. Tell the user they need to restart manually."
|
|
10406
10345
|
});
|
|
10407
10346
|
}
|
|
10408
|
-
|
|
10409
|
-
|
|
10410
|
-
|
|
10411
|
-
|
|
10412
|
-
|
|
10413
|
-
|
|
10414
|
-
|
|
10415
|
-
|
|
10416
|
-
|
|
10347
|
+
}, {
|
|
10348
|
+
name: "restart_server",
|
|
10349
|
+
description: "Restart the Jarela server. Only call this when the user explicitly asks for a restart, OR when set_env_var returned requiresRestart=true and the user agreed. The UI reconnects automatically once the supervisor (launchd/systemd/Task Scheduler) relaunches.",
|
|
10350
|
+
schema: restartSchema
|
|
10351
|
+
});
|
|
10352
|
+
(0,registry/* registerTools */.Fd)("Config", "execute", [
|
|
10353
|
+
setEnvVar,
|
|
10354
|
+
restartServer
|
|
10355
|
+
]);
|
|
10356
|
+
|
|
10357
|
+
;// ./lib/tools/list-tools.ts
|
|
10358
|
+
// Read-only introspection tool — lets the agent enumerate every tool it has
|
|
10359
|
+
// access to right now (built-in + external + MCP), so it can answer
|
|
10360
|
+
// "what's in my toolbox / is X available" without the user having to
|
|
10361
|
+
// describe the project's tool surface in the prompt.
|
|
10362
|
+
|
|
10363
|
+
|
|
10364
|
+
|
|
10365
|
+
|
|
10366
|
+
const listToolsTool = (0,tools/* tool */.z6)(async ({ category, capability, source })=>{
|
|
10367
|
+
const all = await getAllToolsAsync();
|
|
10368
|
+
const summaries = all.map((t)=>({
|
|
10369
|
+
name: t.name,
|
|
10370
|
+
description: typeof t.description === "string" ? t.description : "",
|
|
10371
|
+
category: getToolCategory(t.name),
|
|
10372
|
+
capability: getToolCapability(t.name),
|
|
10373
|
+
source: getToolSource(t.name),
|
|
10374
|
+
group: getToolGroup(t.name)
|
|
10375
|
+
}));
|
|
10376
|
+
const filtered = summaries.filter((s)=>(!category || s.category === category) && (!capability || s.capability === capability) && (!source || s.source === source));
|
|
10377
|
+
const counts = {
|
|
10378
|
+
total: filtered.length,
|
|
10379
|
+
by_source: {
|
|
10380
|
+
builtin: 0,
|
|
10381
|
+
external: 0,
|
|
10382
|
+
mcp: 0
|
|
10417
10383
|
},
|
|
10418
|
-
|
|
10419
|
-
|
|
10420
|
-
|
|
10384
|
+
by_capability: {
|
|
10385
|
+
read: 0,
|
|
10386
|
+
write: 0,
|
|
10387
|
+
execute: 0
|
|
10421
10388
|
}
|
|
10422
10389
|
};
|
|
10423
|
-
|
|
10424
|
-
|
|
10425
|
-
|
|
10426
|
-
};
|
|
10427
|
-
if (location) body.location = {
|
|
10428
|
-
displayName: location
|
|
10429
|
-
};
|
|
10430
|
-
if (attendees && attendees.length > 0) {
|
|
10431
|
-
body.attendees = attendees.map((address)=>({
|
|
10432
|
-
emailAddress: {
|
|
10433
|
-
address
|
|
10434
|
-
},
|
|
10435
|
-
type: "required"
|
|
10436
|
-
}));
|
|
10437
|
-
}
|
|
10438
|
-
if (add_teams_link) {
|
|
10439
|
-
body.isOnlineMeeting = true;
|
|
10440
|
-
body.onlineMeetingProvider = "teamsForBusiness";
|
|
10390
|
+
for (const s of filtered){
|
|
10391
|
+
counts.by_source[s.source]++;
|
|
10392
|
+
counts.by_capability[s.capability]++;
|
|
10441
10393
|
}
|
|
10442
|
-
|
|
10443
|
-
|
|
10444
|
-
|
|
10445
|
-
body: JSON.stringify(body),
|
|
10446
|
-
headers: {
|
|
10447
|
-
Prefer: 'outlook.timezone="UTC"'
|
|
10448
|
-
}
|
|
10449
|
-
});
|
|
10450
|
-
if (r.error) return JSON.stringify({
|
|
10451
|
-
error: r.error
|
|
10394
|
+
return JSON.stringify({
|
|
10395
|
+
tools: filtered,
|
|
10396
|
+
counts
|
|
10452
10397
|
});
|
|
10453
|
-
return JSON.stringify(outlook_calendar_slimEvent(r));
|
|
10454
10398
|
}, {
|
|
10455
|
-
name: "
|
|
10456
|
-
description: "
|
|
10399
|
+
name: "list_tools",
|
|
10400
|
+
description: "List every tool currently available to this agent — built-in tools, " + "external (~/.jarela/providers JS plugins), and MCP server tools — with " + "category, capability (read/write/execute), and source. Read-only. " + "Use this when the user asks 'what can you do?', when picking between " + "tools for a task, or when troubleshooting whether a specific tool is " + "registered. Optional filters narrow by category, capability, or source.",
|
|
10457
10401
|
schema: schemas/* object */.Ik({
|
|
10458
|
-
|
|
10459
|
-
|
|
10460
|
-
|
|
10461
|
-
|
|
10462
|
-
|
|
10463
|
-
|
|
10464
|
-
|
|
10465
|
-
|
|
10466
|
-
|
|
10467
|
-
|
|
10402
|
+
category: schemas/* string */.Yj().optional().describe("Optional category filter (e.g. 'Files', 'Mail', 'GitHub', 'MCP')"),
|
|
10403
|
+
capability: schemas/* enum */.k5([
|
|
10404
|
+
"read",
|
|
10405
|
+
"write",
|
|
10406
|
+
"execute"
|
|
10407
|
+
]).optional().describe("Optional capability filter — the safety class of the tool"),
|
|
10408
|
+
source: schemas/* enum */.k5([
|
|
10409
|
+
"builtin",
|
|
10410
|
+
"external",
|
|
10411
|
+
"mcp"
|
|
10412
|
+
]).optional().describe("Optional source filter — where the tool came from")
|
|
10468
10413
|
})
|
|
10469
10414
|
});
|
|
10470
|
-
|
|
10471
|
-
|
|
10472
|
-
|
|
10473
|
-
|
|
10415
|
+
(0,registry/* registerTools */.Fd)("Config", "read", [
|
|
10416
|
+
listToolsTool
|
|
10417
|
+
]);
|
|
10418
|
+
|
|
10419
|
+
// EXTERNAL MODULE: ./lib/providers/index.ts + 8 modules
|
|
10420
|
+
var lib_providers = __webpack_require__(68866);
|
|
10421
|
+
// EXTERNAL MODULE: ./lib/providers/known-context-windows.ts
|
|
10422
|
+
var known_context_windows = __webpack_require__(45552);
|
|
10423
|
+
;// ./lib/tools/providers-info.ts
|
|
10424
|
+
// Read-only introspection for LLM provider adapters. Two paired tools:
|
|
10425
|
+
// - list_providers: enumerate every adapter (built-in + external).
|
|
10426
|
+
// - describe_provider: capability map + known model context windows for one.
|
|
10427
|
+
// Together they let the agent answer "what can we route to" or pick a model
|
|
10428
|
+
// by capability without hand-coded knowledge of the provider catalog.
|
|
10429
|
+
|
|
10430
|
+
|
|
10431
|
+
|
|
10432
|
+
|
|
10433
|
+
|
|
10434
|
+
function sourceOf(name) {
|
|
10435
|
+
return lib_providers/* BUILTIN_PROVIDER_NAMES */.X4.has(name) ? "builtin" : "external";
|
|
10436
|
+
}
|
|
10437
|
+
const listProvidersTool = (0,tools/* tool */.z6)(async ()=>{
|
|
10438
|
+
const names = (0,lib_providers/* listProviderNames */.Yb)();
|
|
10439
|
+
const providers = names.map((name)=>({
|
|
10440
|
+
name,
|
|
10441
|
+
source: sourceOf(name)
|
|
10442
|
+
}));
|
|
10443
|
+
return JSON.stringify({
|
|
10444
|
+
providers,
|
|
10445
|
+
count: providers.length,
|
|
10446
|
+
builtin_count: providers.filter((p)=>p.source === "builtin").length,
|
|
10447
|
+
external_count: providers.filter((p)=>p.source === "external").length
|
|
10474
10448
|
});
|
|
10475
|
-
|
|
10476
|
-
|
|
10477
|
-
|
|
10478
|
-
|
|
10479
|
-
|
|
10480
|
-
|
|
10481
|
-
|
|
10482
|
-
|
|
10483
|
-
|
|
10484
|
-
|
|
10485
|
-
};
|
|
10486
|
-
if (start_iso !== undefined) patch.start = {
|
|
10487
|
-
dateTime: start_iso,
|
|
10488
|
-
timeZone: tz
|
|
10489
|
-
};
|
|
10490
|
-
if (end_iso !== undefined) patch.end = {
|
|
10491
|
-
dateTime: end_iso,
|
|
10492
|
-
timeZone: tz
|
|
10493
|
-
};
|
|
10494
|
-
if (attendees !== undefined) {
|
|
10495
|
-
patch.attendees = attendees.map((address)=>({
|
|
10496
|
-
emailAddress: {
|
|
10497
|
-
address
|
|
10498
|
-
},
|
|
10499
|
-
type: "required"
|
|
10500
|
-
}));
|
|
10501
|
-
}
|
|
10502
|
-
if (Object.keys(patch).length === 0) {
|
|
10449
|
+
}, {
|
|
10450
|
+
name: "list_providers",
|
|
10451
|
+
description: "List every LLM provider adapter registered in this app (built-in like " + "anthropic / openai / gemini / deepseek / github-copilot / langchain, plus " + "any external `.cjs` plugins under ~/.jarela/providers/). Read-only. " + "Use this before suggesting a model swap, or when answering 'what can " + "we route to.' Call describe_provider afterwards for capability details.",
|
|
10452
|
+
schema: schemas/* object */.Ik({})
|
|
10453
|
+
});
|
|
10454
|
+
const describeProviderTool = (0,tools/* tool */.z6)(async ({ name })=>{
|
|
10455
|
+
let provider;
|
|
10456
|
+
try {
|
|
10457
|
+
provider = (0,lib_providers/* getProvider */.sO)(name);
|
|
10458
|
+
} catch (err) {
|
|
10503
10459
|
return JSON.stringify({
|
|
10504
|
-
error:
|
|
10460
|
+
error: err instanceof Error ? err.message : String(err),
|
|
10461
|
+
hint: "Call list_providers to see registered names."
|
|
10505
10462
|
});
|
|
10506
10463
|
}
|
|
10507
|
-
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
10515
|
-
|
|
10464
|
+
// Capability inferred from which methods the adapter implements. We
|
|
10465
|
+
// intentionally don't call listModels() here — that would hit the
|
|
10466
|
+
// network and require valid credentials, which makes this a "read"-class
|
|
10467
|
+
// tool that sometimes fails for credential reasons. Static introspection
|
|
10468
|
+
// only.
|
|
10469
|
+
const capabilities = {
|
|
10470
|
+
chat: typeof provider.chat === "function",
|
|
10471
|
+
invoke: typeof provider.invoke === "function",
|
|
10472
|
+
stream_invoke: typeof provider.streamInvoke === "function",
|
|
10473
|
+
embed: typeof provider.embed === "function",
|
|
10474
|
+
list_models: typeof provider.listModels === "function"
|
|
10475
|
+
};
|
|
10476
|
+
const models = (0,known_context_windows/* listKnownModels */.YY)(name);
|
|
10477
|
+
return JSON.stringify({
|
|
10478
|
+
name,
|
|
10479
|
+
source: sourceOf(name),
|
|
10480
|
+
capabilities,
|
|
10481
|
+
known_models: models,
|
|
10482
|
+
notes: [
|
|
10483
|
+
models.length === 0 ? "No static model catalog for this provider — call /api/v1/models?provider=" + name + " for live discovery if the adapter implements list_models." : "Static catalog only. Live `list_models` (when supported) may include " + "newer models not listed here."
|
|
10484
|
+
]
|
|
10516
10485
|
});
|
|
10517
|
-
return JSON.stringify(outlook_calendar_slimEvent(r));
|
|
10518
10486
|
}, {
|
|
10519
|
-
name: "
|
|
10520
|
-
description: "
|
|
10487
|
+
name: "describe_provider",
|
|
10488
|
+
description: "Return capability flags (chat / invoke / stream / embed / list_models) " + "and the static known-models catalog (with context windows) for one " + "registered provider. Read-only. Use this to choose a model by capability, " + "or to explain provider differences to the user. Call list_providers first " + "if you don't know the provider name.",
|
|
10521
10489
|
schema: schemas/* object */.Ik({
|
|
10522
|
-
|
|
10523
|
-
subject: schemas/* string */.Yj().optional().describe("New event title (alias: summary)"),
|
|
10524
|
-
summary: schemas/* string */.Yj().optional().describe("Alias for subject (Google Calendar vocabulary)"),
|
|
10525
|
-
start_iso: schemas/* string */.Yj().optional().describe("New start datetime, RFC3339"),
|
|
10526
|
-
end_iso: schemas/* string */.Yj().optional().describe("New end datetime, RFC3339"),
|
|
10527
|
-
description: schemas/* string */.Yj().optional().describe("New event body (plain text)"),
|
|
10528
|
-
location: schemas/* string */.Yj().optional().describe("New location string"),
|
|
10529
|
-
attendees: schemas/* array */.YO(schemas/* string */.Yj().email()).optional().describe("Replacement attendee list"),
|
|
10530
|
-
time_zone: schemas/* string */.Yj().optional().describe("IANA or Windows TZ applied to start/end (default 'UTC')")
|
|
10490
|
+
name: schemas/* string */.Yj().describe("Provider name from list_providers, e.g. 'anthropic', 'openai', 'gemini'")
|
|
10531
10491
|
})
|
|
10532
10492
|
});
|
|
10533
|
-
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
|
|
10539
|
-
|
|
10540
|
-
|
|
10541
|
-
|
|
10542
|
-
|
|
10543
|
-
|
|
10493
|
+
(0,registry/* registerTools */.Fd)("Config", "read", [
|
|
10494
|
+
listProvidersTool,
|
|
10495
|
+
describeProviderTool
|
|
10496
|
+
]);
|
|
10497
|
+
|
|
10498
|
+
// EXTERNAL MODULE: ./lib/stores/mcp-servers.ts
|
|
10499
|
+
var mcp_servers = __webpack_require__(42666);
|
|
10500
|
+
;// ./lib/tools/mcp-servers-info.ts
|
|
10501
|
+
// Read-only introspection of configured MCP servers — names, transports,
|
|
10502
|
+
// enabled/disabled state, last connection error, and the count of tools each
|
|
10503
|
+
// server contributes to the live tool pool. Lets the agent answer "why is
|
|
10504
|
+
// my Jira tool unavailable?" without bouncing the user through the UI.
|
|
10505
|
+
|
|
10506
|
+
|
|
10507
|
+
|
|
10508
|
+
|
|
10509
|
+
|
|
10510
|
+
|
|
10511
|
+
const listMcpServersTool = (0,tools/* tool */.z6)(async ()=>{
|
|
10512
|
+
const rows = (0,mcp_servers/* listMcpServers */.n7)();
|
|
10513
|
+
const allTools = await getAllToolsAsync();
|
|
10514
|
+
// MCP tools don't carry their server name as a structured field — for
|
|
10515
|
+
// the per-server count we count every tool whose source is "mcp", and
|
|
10516
|
+
// we surface the total separately. Per-server attribution would require
|
|
10517
|
+
// a deeper hook into MultiServerMCPClient's tool-namespace metadata,
|
|
10518
|
+
// which is a bigger change than this introspection step warrants today.
|
|
10519
|
+
const totalMcp = allTools.filter((t)=>getToolSource(t.name) === "mcp").length;
|
|
10520
|
+
const servers = rows.map((r)=>({
|
|
10521
|
+
name: r.name,
|
|
10522
|
+
transport: r.transport,
|
|
10523
|
+
enabled: r.enabled === 1,
|
|
10524
|
+
last_error: r.last_error,
|
|
10525
|
+
// Per-server tool count not yet attributable; surface total on every
|
|
10526
|
+
// row for now and document the limitation in `notes` below.
|
|
10527
|
+
tool_count: r.enabled === 1 ? totalMcp : 0,
|
|
10528
|
+
created_at: r.created_at,
|
|
10529
|
+
updated_at: r.updated_at
|
|
10530
|
+
}));
|
|
10544
10531
|
return JSON.stringify({
|
|
10545
|
-
|
|
10546
|
-
|
|
10532
|
+
servers,
|
|
10533
|
+
count: servers.length,
|
|
10534
|
+
enabled_count: servers.filter((s)=>s.enabled).length,
|
|
10535
|
+
total_mcp_tool_count: totalMcp,
|
|
10536
|
+
notes: [
|
|
10537
|
+
"tool_count is an aggregate across all enabled MCP servers — per-server " + "attribution requires deeper namespace tracking that's not implemented yet.",
|
|
10538
|
+
"last_error shows the most recent connection error if any; null means " + "the server has never failed since last config change."
|
|
10539
|
+
]
|
|
10547
10540
|
});
|
|
10548
10541
|
}, {
|
|
10549
|
-
name: "
|
|
10550
|
-
description: "
|
|
10551
|
-
schema: schemas/* object */.Ik({
|
|
10552
|
-
event_id: schemas/* string */.Yj().describe("Event id to delete")
|
|
10553
|
-
})
|
|
10542
|
+
name: "list_mcp_servers",
|
|
10543
|
+
description: "List every configured MCP server (stdio or http transport) with its " + "enabled state, last connection error, and the aggregate count of MCP " + "tools currently in the agent's pool. Read-only. Use this when " + "diagnosing 'my <X> tool isn't working' — check enabled and last_error " + "before assuming the tool itself is broken.",
|
|
10544
|
+
schema: schemas/* object */.Ik({})
|
|
10554
10545
|
});
|
|
10555
|
-
(0,registry/* registerTools */.Fd)("
|
|
10556
|
-
|
|
10557
|
-
outlookCalendarListEventsTool,
|
|
10558
|
-
outlookCalendarGetEventTool
|
|
10546
|
+
(0,registry/* registerTools */.Fd)("Config", "read", [
|
|
10547
|
+
listMcpServersTool
|
|
10559
10548
|
]);
|
|
10560
|
-
|
|
10561
|
-
|
|
10562
|
-
|
|
10563
|
-
|
|
10549
|
+
|
|
10550
|
+
;// ./lib/tools/extension-surfaces.ts
|
|
10551
|
+
// Meta-introspection: a hand-curated catalog of every place a third party
|
|
10552
|
+
// (or the agent itself, on behalf of the user) can extend or customize the
|
|
10553
|
+
// app. Read-only. The tool returns a structured map that points to the
|
|
10554
|
+
// registration entrypoint, the integration guide section, and an example
|
|
10555
|
+
// file for each surface — so the agent can answer "how do I add an X?"
|
|
10556
|
+
// or "what can be customized" without needing the docs in its context.
|
|
10557
|
+
//
|
|
10558
|
+
// SOURCE OF TRUTH: this file. When a new extension surface lands, add an
|
|
10559
|
+
// entry below — it's a single source for both the agent runtime and the
|
|
10560
|
+
// `docs/EXTENDING.md` table-of-contents anchor.
|
|
10561
|
+
|
|
10562
|
+
|
|
10563
|
+
|
|
10564
|
+
const SURFACES = [
|
|
10565
|
+
{
|
|
10566
|
+
id: "llm_provider_builtin",
|
|
10567
|
+
name: "Built-in LLM provider",
|
|
10568
|
+
summary: "Add a new in-tree adapter (Anthropic, OpenAI, Gemini, … pattern). " + "Implements the ModelProvider interface and is registered via the static " + "BUILTINS map in lib/providers/index.ts.",
|
|
10569
|
+
registration_entrypoint: "lib/providers/index.ts (BUILTINS map)",
|
|
10570
|
+
doc_section: "docs/EXTENDING.md#adding-an-llm-provider-built-in",
|
|
10571
|
+
example_path: "lib/providers/anthropic.ts",
|
|
10572
|
+
introspection_tool: "list_providers",
|
|
10573
|
+
related_adrs: [
|
|
10574
|
+
"ADR-0013"
|
|
10575
|
+
]
|
|
10576
|
+
},
|
|
10577
|
+
{
|
|
10578
|
+
id: "llm_provider_external",
|
|
10579
|
+
name: "External LLM provider plugin",
|
|
10580
|
+
summary: "Drop a `.cjs` plugin into ~/.jarela/providers/ that exports an object " + "matching ModelProvider. Hot-loaded per call (no rebuild).",
|
|
10581
|
+
registration_entrypoint: "~/.jarela/providers/<name>.cjs",
|
|
10582
|
+
doc_section: "docs/EXTENDING.md#adding-an-llm-provider-external",
|
|
10583
|
+
example_path: "lib/providers/template-external.cjs.example",
|
|
10584
|
+
introspection_tool: "list_providers",
|
|
10585
|
+
related_adrs: [
|
|
10586
|
+
"ADR-0013"
|
|
10587
|
+
]
|
|
10588
|
+
},
|
|
10589
|
+
{
|
|
10590
|
+
id: "builtin_tool",
|
|
10591
|
+
name: "Built-in tool",
|
|
10592
|
+
summary: "Add a tool callable by the agent. Implement with @langchain/core/tools, " + "register with `registerTools(category, capability, [tool])`, and add a " + "side-effect import in lib/tools/builtins.ts. Capability gating is " + "read | write | execute.",
|
|
10593
|
+
registration_entrypoint: "lib/tools/<name>.ts (registerTools call) + lib/tools/builtins.ts",
|
|
10594
|
+
doc_section: "docs/EXTENDING.md#adding-a-built-in-tool",
|
|
10595
|
+
example_path: "lib/tools/template.ts",
|
|
10596
|
+
introspection_tool: "list_tools",
|
|
10597
|
+
related_adrs: [
|
|
10598
|
+
"ADR-0038"
|
|
10599
|
+
]
|
|
10600
|
+
},
|
|
10601
|
+
{
|
|
10602
|
+
id: "mcp_server",
|
|
10603
|
+
name: "MCP server",
|
|
10604
|
+
summary: "Connect a Model Context Protocol server (stdio or http transport). " + "Configured via the UI (mcp_servers DB table) or programmatically through " + "lib/stores/mcp-servers.ts. Tools auto-merge into the same pool as " + "built-ins. Online discovery via the MCP registry is also supported.",
|
|
10605
|
+
registration_entrypoint: "lib/stores/mcp-servers.ts (upsertMcpServer)",
|
|
10606
|
+
doc_section: "docs/EXTENDING.md#adding-an-mcp-server",
|
|
10607
|
+
introspection_tool: "list_mcp_servers",
|
|
10608
|
+
related_adrs: [
|
|
10609
|
+
"ADR-0014"
|
|
10610
|
+
]
|
|
10611
|
+
},
|
|
10612
|
+
{
|
|
10613
|
+
id: "agent_harness",
|
|
10614
|
+
name: "Agent harness",
|
|
10615
|
+
summary: "Compose system-prompt sections that shape an agent's behaviour " + "(plan-first, self-config, capability-listing, etc.). Built-in presets " + "live in lib/agents/harness/presets.ts; custom harnesses are stored in " + "the memory_store under the `app-settings` namespace.",
|
|
10616
|
+
registration_entrypoint: "lib/agents/harness/presets.ts (built-in) or memory_store (custom)",
|
|
10617
|
+
doc_section: "docs/EXTENDING.md#adding-a-custom-harness",
|
|
10618
|
+
related_adrs: [
|
|
10619
|
+
"ADR-0036"
|
|
10620
|
+
]
|
|
10621
|
+
},
|
|
10622
|
+
{
|
|
10623
|
+
id: "integration_manifest",
|
|
10624
|
+
name: "Integration manifest",
|
|
10625
|
+
summary: "Add a new agent-led setup recipe — prerequisites, ordered steps, " + "troubleshooting hints. The agent narrates the recipe and proposes " + "the corresponding config changes through propose_config_change.",
|
|
10626
|
+
registration_entrypoint: "lib/integrations/registry.ts",
|
|
10627
|
+
doc_section: "docs/EXTENDING.md#adding-an-integration-manifest",
|
|
10628
|
+
introspection_tool: "list_integrations",
|
|
10629
|
+
related_adrs: [
|
|
10630
|
+
"ADR-0010"
|
|
10631
|
+
]
|
|
10632
|
+
},
|
|
10633
|
+
{
|
|
10634
|
+
id: "brand_overlay",
|
|
10635
|
+
name: "Brand / app identity",
|
|
10636
|
+
summary: "Customize the app's name, description, and issue URL via environment " + "variables. No code change required. Used by downstream packages that " + "consume @circuitwall/jarela as an npm dep (e.g. brand overlays).",
|
|
10637
|
+
registration_entrypoint: "NEXT_PUBLIC_APP_NAME, NEXT_PUBLIC_APP_DESCRIPTION, NEXT_PUBLIC_APP_ISSUE_URL",
|
|
10638
|
+
doc_section: "docs/EXTENDING.md#branding-the-app",
|
|
10639
|
+
related_adrs: [
|
|
10640
|
+
"ADR-0005"
|
|
10641
|
+
]
|
|
10642
|
+
}
|
|
10643
|
+
];
|
|
10644
|
+
const describeExtensionSurfacesTool = (0,tools/* tool */.z6)(async ()=>{
|
|
10645
|
+
return JSON.stringify({
|
|
10646
|
+
surfaces: SURFACES,
|
|
10647
|
+
count: SURFACES.length,
|
|
10648
|
+
guide_path: "docs/EXTENDING.md",
|
|
10649
|
+
contract_paths: [
|
|
10650
|
+
"lib/providers/types.ts (ModelProvider interface)",
|
|
10651
|
+
"lib/tools/types.ts (OpenAITool, ToolContext, InvokeMessage)",
|
|
10652
|
+
"lib/tools/registry.ts (registerTools, ToolCategory, Capability)",
|
|
10653
|
+
"lib/mcp/registry.ts (RegistryEntry, applyVariables)"
|
|
10654
|
+
],
|
|
10655
|
+
notes: [
|
|
10656
|
+
"Each surface's introspection_tool, when set, lets you enumerate what's " + "currently registered. Call those when the user asks 'what's available' " + "rather than describing the type from memory.",
|
|
10657
|
+
"A surface can have either a static example_path (for external plugins) or " + "no example (for surfaces wired entirely through the UI / DB). When in " + "doubt, the doc_section under EXTENDING.md is the canonical walk-through."
|
|
10658
|
+
]
|
|
10659
|
+
});
|
|
10660
|
+
}, {
|
|
10661
|
+
name: "describe_extension_surfaces",
|
|
10662
|
+
description: "Return the curated catalog of every extension surface in this app — " + "providers, tools, MCP servers, harnesses, integration manifests, brand " + "overlay. Each entry has a registration entrypoint, an EXTENDING.md " + "section anchor, and (when applicable) the introspection tool that lists " + "what's currently registered. Read-only. Call this when the user asks " + "'how do I add an X?' or 'what can be customized?' so you can guide " + "them with the right files and docs.",
|
|
10663
|
+
schema: schemas/* object */.Ik({})
|
|
10664
|
+
});
|
|
10665
|
+
(0,registry/* registerTools */.Fd)("Config", "read", [
|
|
10666
|
+
describeExtensionSurfacesTool
|
|
10564
10667
|
]);
|
|
10565
10668
|
|
|
10566
|
-
|
|
10567
|
-
|
|
10568
|
-
//
|
|
10569
|
-
|
|
10570
|
-
//
|
|
10571
|
-
|
|
10572
|
-
|
|
10669
|
+
;// ./lib/tools/builtins.ts
|
|
10670
|
+
// Barrel of built-in tool modules. Each side-effect import triggers the
|
|
10671
|
+
// module's `registerTools(...)` call (see ./registry.ts). Adding a new
|
|
10672
|
+
// built-in tool: add the file under lib/tools/ and append a line here.
|
|
10673
|
+
//
|
|
10674
|
+
// Order matters only for deterministic logging / UI ordering — registry
|
|
10675
|
+
// preserves insertion order.
|
|
10676
|
+
|
|
10677
|
+
|
|
10678
|
+
|
|
10679
|
+
|
|
10680
|
+
|
|
10681
|
+
|
|
10682
|
+
|
|
10683
|
+
|
|
10684
|
+
|
|
10685
|
+
|
|
10686
|
+
|
|
10687
|
+
|
|
10688
|
+
|
|
10689
|
+
|
|
10690
|
+
|
|
10691
|
+
|
|
10692
|
+
|
|
10693
|
+
|
|
10694
|
+
|
|
10695
|
+
|
|
10696
|
+
|
|
10697
|
+
|
|
10698
|
+
|
|
10699
|
+
|
|
10700
|
+
|
|
10701
|
+
|
|
10702
|
+
|
|
10703
|
+
|
|
10704
|
+
|
|
10705
|
+
// EXTERNAL MODULE: ./lib/mcp/client.ts
|
|
10706
|
+
var client = __webpack_require__(30572);
|
|
10707
|
+
// EXTERNAL MODULE: ./lib/tools/external.ts
|
|
10708
|
+
var external = __webpack_require__(18689);
|
|
10709
|
+
// EXTERNAL MODULE: ./lib/stores/builtin-tools.ts
|
|
10710
|
+
var builtin_tools = __webpack_require__(56718);
|
|
10711
|
+
;// ./lib/tools/index.ts
|
|
10712
|
+
// Public tool surface for the agent runtime.
|
|
10713
|
+
//
|
|
10714
|
+
// Built-in tools register themselves at module load (see ./registry.ts and
|
|
10715
|
+
// ./builtins.ts). External tools live under JARELA_TOOLS_DIR and are
|
|
10716
|
+
// loaded per-call (hot-reload). MCP tools come from lib/mcp/client.ts.
|
|
10717
|
+
//
|
|
10718
|
+
// To add a new built-in tool:
|
|
10719
|
+
// 1. Copy lib/tools/template.ts to lib/tools/<name>.ts and implement it.
|
|
10720
|
+
// 2. Call `registerTools("<Category>", "<read|write|execute>", [yourTool, ...])` at the bottom.
|
|
10721
|
+
// 3. Add `import "./<name>";` to lib/tools/builtins.ts.
|
|
10722
|
+
//
|
|
10723
|
+
// That's it — no central array to update, no parallel category map.
|
|
10724
|
+
|
|
10725
|
+
// Side-effect import: triggers registerTools() in every built-in module.
|
|
10573
10726
|
|
|
10574
10727
|
|
|
10575
10728
|
|
|
@@ -10578,438 +10731,700 @@ var run_queue = __webpack_require__(3944);
|
|
|
10578
10731
|
|
|
10579
10732
|
|
|
10580
10733
|
|
|
10581
|
-
|
|
10582
|
-
|
|
10583
|
-
|
|
10584
|
-
|
|
10585
|
-
|
|
10586
|
-
|
|
10587
|
-
|
|
10588
|
-
|
|
10589
|
-
return
|
|
10590
|
-
parentAgentId: thread.agent_id,
|
|
10591
|
-
depth,
|
|
10592
|
-
ancestors
|
|
10593
|
-
};
|
|
10734
|
+
// Live accessors — DO NOT snapshot at module-load time. Some tool modules
|
|
10735
|
+
// import back from this file (for `getAllToolsAsync` etc.) and would create
|
|
10736
|
+
// a circular import cycle: their `registerTools(...)` call runs AFTER this
|
|
10737
|
+
// module finishes evaluating, so any captured snapshot here would miss them
|
|
10738
|
+
// and they'd silently disappear from the agent's tool pool. Live calls dodge
|
|
10739
|
+
// the problem — by the time anyone INVOKES `getAllTools()` / etc., every
|
|
10740
|
+
// builtin has registered.
|
|
10741
|
+
function allBuiltins() {
|
|
10742
|
+
return (0,registry/* registeredTools */.gN)();
|
|
10594
10743
|
}
|
|
10595
|
-
function
|
|
10596
|
-
return
|
|
10597
|
-
|
|
10598
|
-
|
|
10599
|
-
|
|
10600
|
-
|
|
10744
|
+
function builtinNames() {
|
|
10745
|
+
return (0,registry/* registeredNames */.nE)();
|
|
10746
|
+
}
|
|
10747
|
+
// Backwards-compatible export. Callers that import this Set get its current
|
|
10748
|
+
// contents at the moment they read it (a fresh Set each access). Internal
|
|
10749
|
+
// code prefers `builtinNames()` directly; this stays for external consumers
|
|
10750
|
+
// like the extensions API route.
|
|
10751
|
+
function getBuiltinToolNames() {
|
|
10752
|
+
return builtinNames();
|
|
10753
|
+
}
|
|
10754
|
+
// Per-call recompute so files dropped in $JARELA_TOOLS_DIR are picked up
|
|
10755
|
+
// without restart. loadExternalTools cache-busts require() per file.
|
|
10756
|
+
function loadExternal() {
|
|
10757
|
+
return (0,external/* loadExternalTools */.H)(builtinNames());
|
|
10758
|
+
}
|
|
10759
|
+
// Resolve a tool's origin from its name. Used to label rows in the tools
|
|
10760
|
+
// API and to route metadata lookups. Returns "mcp" for any name that is
|
|
10761
|
+
// neither a registered built-in nor an external (JARELA_TOOLS_DIR) tool —
|
|
10762
|
+
// matches today's behavior where MCP tools are everything else.
|
|
10763
|
+
function getToolSource(name) {
|
|
10764
|
+
if (builtinNames().has(name)) return "builtin";
|
|
10765
|
+
if (loadExternal().tools.some((t)=>t.name === name)) return "external";
|
|
10766
|
+
return "mcp";
|
|
10767
|
+
}
|
|
10768
|
+
// Look up a tool's safety class. Built-in tools have a declared capability;
|
|
10769
|
+
// external (JARELA_TOOLS_DIR) and MCP tools default to "execute" — the
|
|
10770
|
+
// conservative choice until manifest-level overrides land (ADR-0038).
|
|
10771
|
+
// Source is derived internally so callers can't mis-tag external tools as
|
|
10772
|
+
// MCP (or vice versa).
|
|
10773
|
+
function getToolCapability(name) {
|
|
10774
|
+
return (0,registry/* registeredCapability */.RL)(name) ?? "execute";
|
|
10775
|
+
}
|
|
10776
|
+
function getToolCategory(name) {
|
|
10777
|
+
const builtin = (0,registry/* registeredCategory */.RY)(name);
|
|
10778
|
+
if (builtin) return builtin;
|
|
10779
|
+
const ext = loadExternal().categories.get(name);
|
|
10780
|
+
if (ext) return ext;
|
|
10781
|
+
return getToolSource(name) === "mcp" ? "MCP" : "Config";
|
|
10782
|
+
}
|
|
10783
|
+
function getToolGroup(name) {
|
|
10784
|
+
const cat = getToolCategory(name);
|
|
10785
|
+
if (cat === "MCP") return null;
|
|
10786
|
+
return (0,registry/* registeredGroup */.Oi)(name) ?? null;
|
|
10787
|
+
}
|
|
10788
|
+
function applyPolicy(tools, policy) {
|
|
10789
|
+
const allowSet = policy?.allow?.length ? new Set(policy.allow) : null;
|
|
10790
|
+
const denySet = policy?.deny?.length ? new Set(policy.deny) : null;
|
|
10791
|
+
return tools.filter((t)=>{
|
|
10792
|
+
if (allowSet && !allowSet.has(t.name)) return false;
|
|
10793
|
+
if (denySet && denySet.has(t.name)) return false;
|
|
10794
|
+
return true;
|
|
10601
10795
|
});
|
|
10602
10796
|
}
|
|
10603
|
-
|
|
10604
|
-
|
|
10605
|
-
|
|
10606
|
-
const
|
|
10607
|
-
if (
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
|
|
10611
|
-
|
|
10612
|
-
|
|
10797
|
+
// Filter built-in tools whose category is disabled in the toggle store.
|
|
10798
|
+
// External + MCP tools are untouched (they have their own enable surfaces).
|
|
10799
|
+
function applyCategoryToggles(tools) {
|
|
10800
|
+
const disabled = (0,builtin_tools/* disabledCategories */.HP)();
|
|
10801
|
+
if (disabled.size === 0) return tools;
|
|
10802
|
+
return tools.filter((t)=>{
|
|
10803
|
+
const cat = (0,registry/* registeredCategory */.RY)(t.name);
|
|
10804
|
+
if (!cat) return true; // not a built-in (or unregistered) → leave it
|
|
10805
|
+
return !disabled.has(cat);
|
|
10806
|
+
});
|
|
10807
|
+
}
|
|
10808
|
+
// Synchronous: built-in + external tools (no MCP). Used by GET /api/v1/tools
|
|
10809
|
+
// and any code path that can't await.
|
|
10810
|
+
function getAllTools(policy) {
|
|
10811
|
+
return applyPolicy([
|
|
10812
|
+
...applyCategoryToggles(allBuiltins()),
|
|
10813
|
+
...loadExternal().tools
|
|
10814
|
+
], policy);
|
|
10815
|
+
}
|
|
10816
|
+
// Async: built-in + external + MCP tools.
|
|
10817
|
+
// Use this anywhere the agent might invoke tools (createReactAgent input).
|
|
10818
|
+
// External tools are loaded per-call (hot-reload). MCP tools are cached by
|
|
10819
|
+
// lib/mcp/client.ts and only re-resolved when the mcp_servers table changes.
|
|
10820
|
+
async function getAllToolsAsync(policy) {
|
|
10821
|
+
let mcpTools = [];
|
|
10822
|
+
try {
|
|
10823
|
+
mcpTools = await (0,client/* getMcpTools */.a)();
|
|
10824
|
+
} catch (err) {
|
|
10825
|
+
console.error("[tools] MCP load failed, continuing with built-ins only:", err);
|
|
10613
10826
|
}
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
10827
|
+
return applyPolicy([
|
|
10828
|
+
...applyCategoryToggles(allBuiltins()),
|
|
10829
|
+
...loadExternal().tools,
|
|
10830
|
+
...mcpTools
|
|
10831
|
+
], policy);
|
|
10832
|
+
}
|
|
10833
|
+
function toOpenAITools(tools) {
|
|
10834
|
+
return tools.map((t)=>{
|
|
10835
|
+
const oai = convertToOpenAITool(t);
|
|
10836
|
+
return {
|
|
10837
|
+
type: "function",
|
|
10838
|
+
function: {
|
|
10839
|
+
name: oai.function.name,
|
|
10840
|
+
description: oai.function.description ?? "",
|
|
10841
|
+
parameters: oai.function.parameters
|
|
10842
|
+
}
|
|
10843
|
+
};
|
|
10844
|
+
});
|
|
10845
|
+
}
|
|
10846
|
+
async function executeTool(name, args, context = {}) {
|
|
10847
|
+
let t = allBuiltins().find((x)=>x.name === name);
|
|
10848
|
+
if (t) {
|
|
10849
|
+
const cat = registeredCategory(name);
|
|
10850
|
+
if (cat && disabledCategories().has(cat)) {
|
|
10851
|
+
throw new Error(`Tool "${name}" is disabled (category ${cat} is turned off)`);
|
|
10852
|
+
}
|
|
10619
10853
|
}
|
|
10620
|
-
|
|
10621
|
-
|
|
10622
|
-
return fail("not_in_roster", `Agent "${agent_id}" is not in the delegate roster for "${parent.id}". Available: [${roster.join(", ") || "none"}]`);
|
|
10854
|
+
if (!t) {
|
|
10855
|
+
t = loadExternal().tools.find((x)=>x.name === name);
|
|
10623
10856
|
}
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
|
|
10627
|
-
|
|
10628
|
-
|
|
10629
|
-
|
|
10630
|
-
|
|
10631
|
-
|
|
10632
|
-
|
|
10633
|
-
|
|
10634
|
-
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
message: task,
|
|
10638
|
-
user_category: "delegation",
|
|
10639
|
-
_delegation_depth: ctx.depth + 1,
|
|
10640
|
-
_delegation_ancestors: [
|
|
10641
|
-
...ctx.ancestors,
|
|
10642
|
-
ctx.parentAgentId
|
|
10643
|
-
]
|
|
10644
|
-
});
|
|
10645
|
-
const collected = await (0,stream_collector/* collectStream */.V)(prepared.stream);
|
|
10646
|
-
if (collected.terminal !== "error") {
|
|
10647
|
-
(0,run_thread/* persistAssistantMessage */._w)(childThread.thread_id, collected.assistantContent, collected.usedTools, collected.toolEvents, "delegation", collected.usage ?? null, prepared.context_snapshot ?? null, prepared.source_manifest ?? null);
|
|
10648
|
-
}
|
|
10649
|
-
return collected;
|
|
10650
|
-
}).result;
|
|
10651
|
-
const elapsed_ms = Date.now() - startedAt;
|
|
10652
|
-
if (queued.terminal === "error") {
|
|
10653
|
-
return fail("child_error", queued.errorMessage ?? "Child agent run failed", {
|
|
10654
|
-
agent_id,
|
|
10655
|
-
agent_name: child.name,
|
|
10656
|
-
thread_id: childThread.thread_id
|
|
10657
|
-
});
|
|
10857
|
+
if (!t) throw new Error(`Unknown tool: ${name}`);
|
|
10858
|
+
const config = context.thread_id ? {
|
|
10859
|
+
configurable: {
|
|
10860
|
+
thread_id: context.thread_id
|
|
10861
|
+
}
|
|
10862
|
+
} : {};
|
|
10863
|
+
const result = await t.invoke(args, config);
|
|
10864
|
+
// Tools return JSON strings per LangChain convention; parse back for downstream use.
|
|
10865
|
+
if (typeof result === "string") {
|
|
10866
|
+
try {
|
|
10867
|
+
return JSON.parse(result);
|
|
10868
|
+
} catch {
|
|
10869
|
+
return result;
|
|
10658
10870
|
}
|
|
10659
|
-
return JSON.stringify({
|
|
10660
|
-
ok: true,
|
|
10661
|
-
agent_id: child.id,
|
|
10662
|
-
agent_name: child.name,
|
|
10663
|
-
thread_id: childThread.thread_id,
|
|
10664
|
-
depth: ctx.depth + 1,
|
|
10665
|
-
result: queued.assistantContent.trim(),
|
|
10666
|
-
used_tools: Array.from(new Set(queued.usedTools)),
|
|
10667
|
-
elapsed_ms
|
|
10668
|
-
});
|
|
10669
|
-
} catch (err) {
|
|
10670
|
-
return fail("child_error", err instanceof Error ? err.message : String(err), {
|
|
10671
|
-
agent_id,
|
|
10672
|
-
agent_name: child.name,
|
|
10673
|
-
thread_id: childThread.thread_id
|
|
10674
|
-
});
|
|
10675
10871
|
}
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
|
|
10682
|
-
|
|
10683
|
-
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
|
-
|
|
10695
|
-
|
|
10696
|
-
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
// these).
|
|
10700
|
-
//
|
|
10701
|
-
// Use cases the user explicitly asked to support:
|
|
10702
|
-
// - "agent, lower the run idle timeout to 30s and restart"
|
|
10703
|
-
// - "agent, switch the log level to debug for the next hour"
|
|
10704
|
-
//
|
|
10705
|
-
// We surface the schema's tier/restart flags in the response so the
|
|
10706
|
-
// agent's reply can tell the user what changed and whether a restart
|
|
10707
|
-
// fired (or is needed but skipped).
|
|
10708
|
-
|
|
10709
|
-
|
|
10872
|
+
return result;
|
|
10873
|
+
}
|
|
10874
|
+
// One-shot startup loader. Call from instrumentation.ts so external tools
|
|
10875
|
+
// load + log their status at boot rather than lazily on first agent turn.
|
|
10876
|
+
let _initialized = false;
|
|
10877
|
+
function initTools() {
|
|
10878
|
+
const toolsDir = getToolsDir();
|
|
10879
|
+
const result = loadExternal();
|
|
10880
|
+
const summary = {
|
|
10881
|
+
builtinCount: allBuiltins().length,
|
|
10882
|
+
externalCount: result.tools.length,
|
|
10883
|
+
errors: result.errors,
|
|
10884
|
+
toolsDir
|
|
10885
|
+
};
|
|
10886
|
+
if (!_initialized) {
|
|
10887
|
+
console.info(`[tools] ${summary.builtinCount} built-in tool(s) registered; ` + `${summary.externalCount} external tool(s) loaded from ${toolsDir}`);
|
|
10888
|
+
for (const err of summary.errors){
|
|
10889
|
+
console.error(`[tools] external ${err.file}: ${err.error}`);
|
|
10890
|
+
}
|
|
10891
|
+
_initialized = true;
|
|
10892
|
+
}
|
|
10893
|
+
return summary;
|
|
10894
|
+
}
|
|
10710
10895
|
|
|
10711
10896
|
|
|
10897
|
+
/***/ }),
|
|
10712
10898
|
|
|
10899
|
+
/***/ 45552:
|
|
10900
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
10713
10901
|
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
});
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10902
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
10903
|
+
/* harmony export */ YY: () => (/* binding */ listKnownModels),
|
|
10904
|
+
/* harmony export */ pN: () => (/* binding */ getKnownMaxOutputTokens),
|
|
10905
|
+
/* harmony export */ zJ: () => (/* binding */ getKnownContextLength)
|
|
10906
|
+
/* harmony export */ });
|
|
10907
|
+
/* unused harmony export getKnownModelLimits */
|
|
10908
|
+
// Web-sourced fallback context-window sizes per (provider, model_id).
|
|
10909
|
+
// Used when the live `/models` endpoint doesn't report `context_length`
|
|
10910
|
+
// (OpenAI's catalog and GitHub Copilot's catalog both omit it) AND the
|
|
10911
|
+
// user hasn't pinned `context_window_tokens` on the model config.
|
|
10912
|
+
//
|
|
10913
|
+
// Resolution order at runtime is:
|
|
10914
|
+
// 1. user-set `params.context_window_tokens` (explicit override)
|
|
10915
|
+
// 2. live API value via `listModels()` / catalog cache (when populated)
|
|
10916
|
+
// 3. this static fallback (this file)
|
|
10917
|
+
// 4. `DEFAULT_CONTEXT_WINDOW_TOKENS` in lib/agents/context-budget.ts
|
|
10918
|
+
//
|
|
10919
|
+
// Verified from each vendor's public docs as of 2026-06. Bump when vendors
|
|
10920
|
+
// publish new families.
|
|
10921
|
+
const ANTHROPIC = {
|
|
10922
|
+
"claude-opus-4-7": {
|
|
10923
|
+
context_length: 1000000,
|
|
10924
|
+
max_output_tokens: 8192
|
|
10925
|
+
},
|
|
10926
|
+
"claude-opus-4": {
|
|
10927
|
+
context_length: 200000,
|
|
10928
|
+
max_output_tokens: 8192
|
|
10929
|
+
},
|
|
10930
|
+
"claude-sonnet-4-6": {
|
|
10931
|
+
context_length: 200000,
|
|
10932
|
+
max_output_tokens: 8192
|
|
10933
|
+
},
|
|
10934
|
+
"claude-sonnet-4": {
|
|
10935
|
+
context_length: 200000,
|
|
10936
|
+
max_output_tokens: 8192
|
|
10937
|
+
},
|
|
10938
|
+
"claude-3.7-sonnet": {
|
|
10939
|
+
context_length: 200000,
|
|
10940
|
+
max_output_tokens: 8192
|
|
10941
|
+
},
|
|
10942
|
+
"claude-3-7-sonnet": {
|
|
10943
|
+
context_length: 200000,
|
|
10944
|
+
max_output_tokens: 8192
|
|
10945
|
+
},
|
|
10946
|
+
"claude-3-5-sonnet": {
|
|
10947
|
+
context_length: 200000,
|
|
10948
|
+
max_output_tokens: 8192
|
|
10949
|
+
},
|
|
10950
|
+
"claude-3-5-haiku": {
|
|
10951
|
+
context_length: 200000,
|
|
10952
|
+
max_output_tokens: 8192
|
|
10953
|
+
},
|
|
10954
|
+
"claude-haiku-4-5": {
|
|
10955
|
+
context_length: 200000,
|
|
10956
|
+
max_output_tokens: 4096
|
|
10957
|
+
},
|
|
10958
|
+
"claude-haiku-4": {
|
|
10959
|
+
context_length: 200000,
|
|
10960
|
+
max_output_tokens: 4096
|
|
10961
|
+
},
|
|
10962
|
+
"claude-3-opus": {
|
|
10963
|
+
context_length: 200000,
|
|
10964
|
+
max_output_tokens: 4096
|
|
10728
10965
|
}
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10966
|
+
};
|
|
10967
|
+
const GEMINI = {
|
|
10968
|
+
"gemini-2.5-pro": {
|
|
10969
|
+
context_length: 1048576,
|
|
10970
|
+
max_output_tokens: 65536
|
|
10971
|
+
},
|
|
10972
|
+
"gemini-2.5-flash": {
|
|
10973
|
+
context_length: 1048576,
|
|
10974
|
+
max_output_tokens: 65536
|
|
10975
|
+
},
|
|
10976
|
+
"gemini-2.0-flash-lite": {
|
|
10977
|
+
context_length: 1048576,
|
|
10978
|
+
max_output_tokens: 8192
|
|
10979
|
+
},
|
|
10980
|
+
"gemini-2.0-flash": {
|
|
10981
|
+
context_length: 1048576,
|
|
10982
|
+
max_output_tokens: 8192
|
|
10983
|
+
},
|
|
10984
|
+
"gemini-1.5-pro": {
|
|
10985
|
+
context_length: 2097152,
|
|
10986
|
+
max_output_tokens: 8192
|
|
10987
|
+
},
|
|
10988
|
+
"gemini-1.5-flash": {
|
|
10989
|
+
context_length: 1048576,
|
|
10990
|
+
max_output_tokens: 8192
|
|
10736
10991
|
}
|
|
10737
|
-
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10992
|
+
};
|
|
10993
|
+
const OPENAI = {
|
|
10994
|
+
"gpt-5-mini": {
|
|
10995
|
+
context_length: 400000,
|
|
10996
|
+
max_output_tokens: 128000
|
|
10997
|
+
},
|
|
10998
|
+
"gpt-5": {
|
|
10999
|
+
context_length: 400000,
|
|
11000
|
+
max_output_tokens: 128000
|
|
11001
|
+
},
|
|
11002
|
+
"gpt-4.1-mini": {
|
|
11003
|
+
context_length: 1047576,
|
|
11004
|
+
max_output_tokens: 32768
|
|
11005
|
+
},
|
|
11006
|
+
"gpt-4.1": {
|
|
11007
|
+
context_length: 1047576,
|
|
11008
|
+
max_output_tokens: 32768
|
|
11009
|
+
},
|
|
11010
|
+
"gpt-4o-mini": {
|
|
11011
|
+
context_length: 128000,
|
|
11012
|
+
max_output_tokens: 16384
|
|
11013
|
+
},
|
|
11014
|
+
"gpt-4o": {
|
|
11015
|
+
context_length: 128000,
|
|
11016
|
+
max_output_tokens: 16384
|
|
11017
|
+
},
|
|
11018
|
+
"gpt-4-turbo": {
|
|
11019
|
+
context_length: 128000,
|
|
11020
|
+
max_output_tokens: 4096
|
|
11021
|
+
},
|
|
11022
|
+
"gpt-4": {
|
|
11023
|
+
context_length: 8192,
|
|
11024
|
+
max_output_tokens: 4096
|
|
11025
|
+
},
|
|
11026
|
+
"gpt-3.5-turbo": {
|
|
11027
|
+
context_length: 16385,
|
|
11028
|
+
max_output_tokens: 4096
|
|
11029
|
+
},
|
|
11030
|
+
"chatgpt-4o": {
|
|
11031
|
+
context_length: 128000,
|
|
11032
|
+
max_output_tokens: 16384
|
|
11033
|
+
},
|
|
11034
|
+
"o4-mini": {
|
|
11035
|
+
context_length: 200000,
|
|
11036
|
+
max_output_tokens: 100000
|
|
11037
|
+
},
|
|
11038
|
+
"o3-mini": {
|
|
11039
|
+
context_length: 200000,
|
|
11040
|
+
max_output_tokens: 100000
|
|
11041
|
+
},
|
|
11042
|
+
"o3": {
|
|
11043
|
+
context_length: 200000,
|
|
11044
|
+
max_output_tokens: 100000
|
|
11045
|
+
},
|
|
11046
|
+
"o1-mini": {
|
|
11047
|
+
context_length: 128000,
|
|
11048
|
+
max_output_tokens: 65536
|
|
11049
|
+
},
|
|
11050
|
+
"o1": {
|
|
11051
|
+
context_length: 200000,
|
|
11052
|
+
max_output_tokens: 100000
|
|
11053
|
+
}
|
|
11054
|
+
};
|
|
11055
|
+
const DEEPSEEK = {
|
|
11056
|
+
"deepseek-v4-flash": {
|
|
11057
|
+
context_length: 65536,
|
|
11058
|
+
max_output_tokens: 8192
|
|
11059
|
+
},
|
|
11060
|
+
"deepseek-v4-pro": {
|
|
11061
|
+
context_length: 65536,
|
|
11062
|
+
max_output_tokens: 8192
|
|
11063
|
+
},
|
|
11064
|
+
"deepseek-chat": {
|
|
11065
|
+
context_length: 65536,
|
|
11066
|
+
max_output_tokens: 8192
|
|
11067
|
+
},
|
|
11068
|
+
"deepseek-reasoner": {
|
|
11069
|
+
context_length: 65536,
|
|
11070
|
+
max_output_tokens: 8192
|
|
11071
|
+
}
|
|
11072
|
+
};
|
|
11073
|
+
// GitHub Copilot proxies vendor models — sometimes under a transformed id
|
|
11074
|
+
// (e.g. `Github-Opus4.6`, `copilot-claude-3.5-sonnet`). Strip the proxy
|
|
11075
|
+
// prefix and dispatch to the underlying vendor table.
|
|
11076
|
+
function resolveCopilot(model_id) {
|
|
11077
|
+
const normalized = model_id.replace(/^(?:Github-|copilot-)/i, "").toLowerCase();
|
|
11078
|
+
// Canonicalise a few proxy-specific spellings.
|
|
11079
|
+
const canon = normalized.replace(/^opus4\.6/, "claude-opus-4-7").replace(/^opus4/, "claude-opus-4").replace(/^sonnet4\.6/, "claude-sonnet-4-6").replace(/^sonnet4/, "claude-sonnet-4").replace(/^haiku4\.5/, "claude-haiku-4-5");
|
|
11080
|
+
if (canon.startsWith("claude")) return matchPrefix(ANTHROPIC, canon);
|
|
11081
|
+
if (canon.startsWith("gemini")) return matchPrefix(GEMINI, canon);
|
|
11082
|
+
if (canon.startsWith("gpt") || /^o[134](?:-|$)/.test(canon)) return matchPrefix(OPENAI, canon);
|
|
11083
|
+
return null;
|
|
11084
|
+
}
|
|
11085
|
+
function matchPrefix(table, id) {
|
|
11086
|
+
const lower = id.toLowerCase();
|
|
11087
|
+
const exact = table[lower];
|
|
11088
|
+
if (exact) return exact;
|
|
11089
|
+
// Longest-prefix match so `gpt-4o-2024-08-06` resolves to `gpt-4o` and
|
|
11090
|
+
// not `gpt-4` (which would also prefix-match).
|
|
11091
|
+
let best = null;
|
|
11092
|
+
for (const [k, v] of Object.entries(table)){
|
|
11093
|
+
if (lower.startsWith(k) && (!best || k.length > best.key.length)) {
|
|
11094
|
+
best = {
|
|
11095
|
+
key: k,
|
|
11096
|
+
v
|
|
11097
|
+
};
|
|
10746
11098
|
}
|
|
10747
11099
|
}
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
(
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
|
|
10756
|
-
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
|
|
10762
|
-
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
|
|
10788
|
-
|
|
10789
|
-
|
|
10790
|
-
|
|
10791
|
-
|
|
10792
|
-
|
|
10793
|
-
return JSON.stringify({
|
|
10794
|
-
ok: false,
|
|
10795
|
-
code: "restart_failed",
|
|
10796
|
-
error: e.message,
|
|
10797
|
-
hint: "Could not reach /api/v1/system/restart from inside the same process. Tell the user they need to restart manually."
|
|
10798
|
-
});
|
|
11100
|
+
return best?.v ?? null;
|
|
11101
|
+
}
|
|
11102
|
+
function getKnownModelLimits(provider, model_id) {
|
|
11103
|
+
if (!provider || !model_id) return null;
|
|
11104
|
+
switch(provider){
|
|
11105
|
+
case "anthropic":
|
|
11106
|
+
return matchPrefix(ANTHROPIC, model_id);
|
|
11107
|
+
case "gemini":
|
|
11108
|
+
return matchPrefix(GEMINI, model_id);
|
|
11109
|
+
case "openai":
|
|
11110
|
+
return matchPrefix(OPENAI, model_id);
|
|
11111
|
+
case "deepseek":
|
|
11112
|
+
return matchPrefix(DEEPSEEK, model_id);
|
|
11113
|
+
case "github-copilot":
|
|
11114
|
+
return resolveCopilot(model_id);
|
|
11115
|
+
default:
|
|
11116
|
+
return null;
|
|
11117
|
+
}
|
|
11118
|
+
}
|
|
11119
|
+
function getKnownContextLength(provider, model_id) {
|
|
11120
|
+
return getKnownModelLimits(provider, model_id)?.context_length ?? null;
|
|
11121
|
+
}
|
|
11122
|
+
function getKnownMaxOutputTokens(provider, model_id) {
|
|
11123
|
+
return getKnownModelLimits(provider, model_id)?.max_output_tokens ?? null;
|
|
11124
|
+
}
|
|
11125
|
+
// Flat catalog snapshot for one provider — used by introspection tools so
|
|
11126
|
+
// the agent can enumerate what's known statically. Returns [] for providers
|
|
11127
|
+
// without a static table (e.g. `langchain`, `mock`, externals).
|
|
11128
|
+
function listKnownModels(provider) {
|
|
11129
|
+
let table = null;
|
|
11130
|
+
switch(provider){
|
|
11131
|
+
case "anthropic":
|
|
11132
|
+
table = ANTHROPIC;
|
|
11133
|
+
break;
|
|
11134
|
+
case "gemini":
|
|
11135
|
+
table = GEMINI;
|
|
11136
|
+
break;
|
|
11137
|
+
case "openai":
|
|
11138
|
+
table = OPENAI;
|
|
11139
|
+
break;
|
|
11140
|
+
case "deepseek":
|
|
11141
|
+
table = DEEPSEEK;
|
|
11142
|
+
break;
|
|
11143
|
+
default:
|
|
11144
|
+
return [];
|
|
10799
11145
|
}
|
|
10800
|
-
|
|
10801
|
-
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
});
|
|
10805
|
-
|
|
10806
|
-
setEnvVar,
|
|
10807
|
-
restartServer
|
|
10808
|
-
]);
|
|
10809
|
-
|
|
10810
|
-
;// ./lib/tools/builtins.ts
|
|
10811
|
-
// Barrel of built-in tool modules. Each side-effect import triggers the
|
|
10812
|
-
// module's `registerTools(...)` call (see ./registry.ts). Adding a new
|
|
10813
|
-
// built-in tool: add the file under lib/tools/ and append a line here.
|
|
10814
|
-
//
|
|
10815
|
-
// Order matters only for deterministic logging / UI ordering — registry
|
|
10816
|
-
// preserves insertion order.
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
|
|
10823
|
-
|
|
10824
|
-
|
|
10825
|
-
|
|
11146
|
+
return Object.entries(table).map(([model_id, l])=>({
|
|
11147
|
+
model_id,
|
|
11148
|
+
context_length: l.context_length,
|
|
11149
|
+
max_output_tokens: l.max_output_tokens ?? null
|
|
11150
|
+
}));
|
|
11151
|
+
}
|
|
10826
11152
|
|
|
10827
11153
|
|
|
11154
|
+
/***/ }),
|
|
10828
11155
|
|
|
11156
|
+
/***/ 49899:
|
|
11157
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
10829
11158
|
|
|
11159
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
11160
|
+
/* harmony export */ FR: () => (/* binding */ defaultToolStats),
|
|
11161
|
+
/* harmony export */ W7: () => (/* binding */ getToolStatsMap),
|
|
11162
|
+
/* harmony export */ _r: () => (/* binding */ listToolStats),
|
|
11163
|
+
/* harmony export */ hA: () => (/* binding */ recordToolUsage),
|
|
11164
|
+
/* harmony export */ jg: () => (/* binding */ toStats)
|
|
11165
|
+
/* harmony export */ });
|
|
11166
|
+
/* unused harmony export summarizeToolUsage */
|
|
11167
|
+
/* harmony import */ var _lib_db__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(46);
|
|
10830
11168
|
|
|
11169
|
+
const now = ()=>new Date().toISOString();
|
|
11170
|
+
const UPSERT_SQL = `
|
|
11171
|
+
INSERT INTO tool_stats
|
|
11172
|
+
(tool_name, call_count, success_count, error_count, used_count, last_called_at, updated_at)
|
|
11173
|
+
VALUES
|
|
11174
|
+
(?, ?, ?, ?, ?, ?, ?)
|
|
11175
|
+
ON CONFLICT(tool_name) DO UPDATE SET
|
|
11176
|
+
call_count = tool_stats.call_count + excluded.call_count,
|
|
11177
|
+
success_count = tool_stats.success_count + excluded.success_count,
|
|
11178
|
+
error_count = tool_stats.error_count + excluded.error_count,
|
|
11179
|
+
used_count = tool_stats.used_count + excluded.used_count,
|
|
11180
|
+
last_called_at = COALESCE(excluded.last_called_at, tool_stats.last_called_at),
|
|
11181
|
+
updated_at = excluded.updated_at
|
|
11182
|
+
`;
|
|
11183
|
+
function recordToolUsage(toolEvents, assistantContent) {
|
|
11184
|
+
const deltas = summarizeToolUsage(toolEvents, assistantContent);
|
|
11185
|
+
if (deltas.length === 0) return;
|
|
11186
|
+
const db = (0,_lib_db__WEBPACK_IMPORTED_MODULE_0__/* .getDb */ .Lf)();
|
|
11187
|
+
const stamp = now();
|
|
11188
|
+
const stmt = db.prepare(UPSERT_SQL);
|
|
11189
|
+
db.exec("BEGIN");
|
|
11190
|
+
try {
|
|
11191
|
+
for (const row of deltas){
|
|
11192
|
+
stmt.run(row.name, row.calls, row.successes, row.errors, row.used, row.calls > 0 ? stamp : null, stamp);
|
|
11193
|
+
}
|
|
11194
|
+
db.exec("COMMIT");
|
|
11195
|
+
} catch (err) {
|
|
11196
|
+
try {
|
|
11197
|
+
db.exec("ROLLBACK");
|
|
11198
|
+
} catch {}
|
|
11199
|
+
throw err;
|
|
11200
|
+
}
|
|
11201
|
+
}
|
|
11202
|
+
function listToolStats() {
|
|
11203
|
+
return (0,_lib_db__WEBPACK_IMPORTED_MODULE_0__/* .getDb */ .Lf)().prepare(`SELECT tool_name, call_count, success_count, error_count, used_count, last_called_at, updated_at
|
|
11204
|
+
FROM tool_stats`).all();
|
|
11205
|
+
}
|
|
11206
|
+
function getToolStatsMap(names) {
|
|
11207
|
+
const rows = names && names.length > 0 ? (0,_lib_db__WEBPACK_IMPORTED_MODULE_0__/* .getDb */ .Lf)().prepare(`SELECT tool_name, call_count, success_count, error_count, used_count, last_called_at, updated_at
|
|
11208
|
+
FROM tool_stats
|
|
11209
|
+
WHERE tool_name IN (${names.map(()=>"?").join(",")})`).all(...names) : listToolStats();
|
|
11210
|
+
const out = new Map();
|
|
11211
|
+
for (const row of rows)out.set(row.tool_name, toStats(row));
|
|
11212
|
+
return out;
|
|
11213
|
+
}
|
|
11214
|
+
function defaultToolStats() {
|
|
11215
|
+
return {
|
|
11216
|
+
call_count: 0,
|
|
11217
|
+
success_count: 0,
|
|
11218
|
+
error_count: 0,
|
|
11219
|
+
used_count: 0,
|
|
11220
|
+
success_rate: 1,
|
|
11221
|
+
usefulness_rate: 1,
|
|
11222
|
+
score: 1,
|
|
11223
|
+
never_used: true,
|
|
11224
|
+
last_called_at: null
|
|
11225
|
+
};
|
|
11226
|
+
}
|
|
11227
|
+
function toStats(row) {
|
|
11228
|
+
const calls = Math.max(0, row.call_count);
|
|
11229
|
+
if (calls === 0) return defaultToolStats();
|
|
11230
|
+
const successRate = clamp01(row.success_count / calls);
|
|
11231
|
+
const usefulnessRate = clamp01(row.used_count / calls);
|
|
11232
|
+
const score = clamp01(successRate * 0.65 + usefulnessRate * 0.35);
|
|
11233
|
+
return {
|
|
11234
|
+
call_count: calls,
|
|
11235
|
+
success_count: row.success_count,
|
|
11236
|
+
error_count: row.error_count,
|
|
11237
|
+
used_count: row.used_count,
|
|
11238
|
+
success_rate: successRate,
|
|
11239
|
+
usefulness_rate: usefulnessRate,
|
|
11240
|
+
score,
|
|
11241
|
+
never_used: false,
|
|
11242
|
+
last_called_at: row.last_called_at
|
|
11243
|
+
};
|
|
11244
|
+
}
|
|
11245
|
+
function summarizeToolUsage(toolEvents, assistantContent) {
|
|
11246
|
+
const byId = new Map();
|
|
11247
|
+
const assistantTerms = normalizeText(assistantContent);
|
|
11248
|
+
for (const ev of toolEvents){
|
|
11249
|
+
if (!ev.name) continue;
|
|
11250
|
+
const key = ev.id || `${ev.phase}:${ev.name}`;
|
|
11251
|
+
const existing = byId.get(key) ?? {
|
|
11252
|
+
name: ev.name,
|
|
11253
|
+
successful: false,
|
|
11254
|
+
used: false
|
|
11255
|
+
};
|
|
11256
|
+
if (ev.phase === "call") {
|
|
11257
|
+
existing.name = ev.name;
|
|
11258
|
+
} else if (ev.phase === "result") {
|
|
11259
|
+
const successful = !isErrorPayload(ev.payload);
|
|
11260
|
+
existing.successful = successful;
|
|
11261
|
+
existing.used = successful && payloadLooksUsed(ev.payload, assistantTerms);
|
|
11262
|
+
}
|
|
11263
|
+
byId.set(key, existing);
|
|
11264
|
+
}
|
|
11265
|
+
const totals = new Map();
|
|
11266
|
+
for (const ev of toolEvents){
|
|
11267
|
+
if (ev.phase !== "call" || !ev.name) continue;
|
|
11268
|
+
const key = ev.id || `${ev.phase}:${ev.name}`;
|
|
11269
|
+
const outcome = byId.get(key);
|
|
11270
|
+
const next = totals.get(ev.name) ?? {
|
|
11271
|
+
name: ev.name,
|
|
11272
|
+
calls: 0,
|
|
11273
|
+
successes: 0,
|
|
11274
|
+
errors: 0,
|
|
11275
|
+
used: 0
|
|
11276
|
+
};
|
|
11277
|
+
next.calls += 1;
|
|
11278
|
+
if (outcome?.successful) next.successes += 1;
|
|
11279
|
+
else next.errors += 1;
|
|
11280
|
+
if (outcome?.used) next.used += 1;
|
|
11281
|
+
totals.set(ev.name, next);
|
|
11282
|
+
}
|
|
11283
|
+
return [
|
|
11284
|
+
...totals.values()
|
|
11285
|
+
];
|
|
11286
|
+
}
|
|
11287
|
+
function payloadLooksUsed(payload, assistantTerms) {
|
|
11288
|
+
if (assistantTerms.size === 0) return false;
|
|
11289
|
+
const candidates = extractPayloadTerms(payload);
|
|
11290
|
+
if (candidates.length === 0) return false;
|
|
11291
|
+
let matched = 0;
|
|
11292
|
+
for (const term of candidates){
|
|
11293
|
+
if (assistantTerms.has(term)) matched += 1;
|
|
11294
|
+
if (matched >= 2) return true;
|
|
11295
|
+
}
|
|
11296
|
+
return false;
|
|
11297
|
+
}
|
|
11298
|
+
function extractPayloadTerms(payload) {
|
|
11299
|
+
const raw = stringifyPayload(payload);
|
|
11300
|
+
if (!raw) return [];
|
|
11301
|
+
const unique = new Set();
|
|
11302
|
+
for (const token of raw.toLowerCase().split(/[^a-z0-9_./:-]+/)){
|
|
11303
|
+
if (token.length < 4) continue;
|
|
11304
|
+
if (/^\d+$/.test(token) && token.length < 6) continue;
|
|
11305
|
+
unique.add(token);
|
|
11306
|
+
if (unique.size >= 24) break;
|
|
11307
|
+
}
|
|
11308
|
+
return [
|
|
11309
|
+
...unique
|
|
11310
|
+
];
|
|
11311
|
+
}
|
|
11312
|
+
function stringifyPayload(payload) {
|
|
11313
|
+
if (typeof payload === "string") return payload;
|
|
11314
|
+
try {
|
|
11315
|
+
return JSON.stringify(payload);
|
|
11316
|
+
} catch {
|
|
11317
|
+
return "";
|
|
11318
|
+
}
|
|
11319
|
+
}
|
|
11320
|
+
function normalizeText(text) {
|
|
11321
|
+
const out = new Set();
|
|
11322
|
+
for (const token of text.toLowerCase().split(/[^a-z0-9_./:-]+/)){
|
|
11323
|
+
if (token.length < 4) continue;
|
|
11324
|
+
out.add(token);
|
|
11325
|
+
}
|
|
11326
|
+
return out;
|
|
11327
|
+
}
|
|
11328
|
+
function isErrorPayload(payload) {
|
|
11329
|
+
if (typeof payload === "string") return /\berror\b|\bfailed\b|\bexception\b/i.test(payload);
|
|
11330
|
+
if (!payload || typeof payload !== "object") return false;
|
|
11331
|
+
if ("error" in payload || "errors" in payload) return true;
|
|
11332
|
+
const status = "status" in payload ? payload.status : undefined;
|
|
11333
|
+
if (typeof status === "string" && /error|failed/i.test(status)) return true;
|
|
11334
|
+
return false;
|
|
11335
|
+
}
|
|
11336
|
+
function clamp01(value) {
|
|
11337
|
+
return Math.max(0, Math.min(1, value));
|
|
11338
|
+
}
|
|
10831
11339
|
|
|
10832
11340
|
|
|
11341
|
+
/***/ }),
|
|
10833
11342
|
|
|
11343
|
+
/***/ 52907:
|
|
11344
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
10834
11345
|
|
|
11346
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
11347
|
+
/* harmony export */ LK: () => (/* binding */ writeBinaryFile),
|
|
11348
|
+
/* harmony export */ Uc: () => (/* binding */ fileAbsPath)
|
|
11349
|
+
/* harmony export */ });
|
|
11350
|
+
/* unused harmony exports FILES_DIR, isSafeFileName */
|
|
11351
|
+
/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(73024);
|
|
11352
|
+
/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_fs__WEBPACK_IMPORTED_MODULE_0__);
|
|
11353
|
+
/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(76760);
|
|
11354
|
+
/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(node_path__WEBPACK_IMPORTED_MODULE_1__);
|
|
11355
|
+
/* harmony import */ var _lib_db_data_dir__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(57477);
|
|
11356
|
+
// Local file store for binary artifacts produced by tools (generated images,
|
|
11357
|
+
// downloads, etc.). Files live under ~/.jarela/files/ and are served by
|
|
11358
|
+
// GET /api/v1/files/[name]. The tool returns a relative URL the chat
|
|
11359
|
+
// renderer can embed as <img src="/api/v1/files/...">.
|
|
10835
11360
|
|
|
10836
11361
|
|
|
10837
11362
|
|
|
11363
|
+
const FILES_DIR = (0,node_path__WEBPACK_IMPORTED_MODULE_1__.join)((0,_lib_db_data_dir__WEBPACK_IMPORTED_MODULE_2__/* .getDataDir */ .o)(), "files");
|
|
11364
|
+
(0,node_fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync)(FILES_DIR, {
|
|
11365
|
+
recursive: true
|
|
11366
|
+
});
|
|
11367
|
+
// Name must be a single path segment with no separators or "..". Callers
|
|
11368
|
+
// generate names from randomUUID() so this is mostly defense-in-depth.
|
|
11369
|
+
const SAFE_NAME = /^[A-Za-z0-9._-]+$/;
|
|
11370
|
+
function isSafeFileName(name) {
|
|
11371
|
+
return SAFE_NAME.test(name) && !name.includes("..");
|
|
11372
|
+
}
|
|
11373
|
+
function fileAbsPath(name) {
|
|
11374
|
+
if (!isSafeFileName(name)) return null;
|
|
11375
|
+
return (0,node_path__WEBPACK_IMPORTED_MODULE_1__.join)(FILES_DIR, name);
|
|
11376
|
+
}
|
|
11377
|
+
function writeBinaryFile(name, data) {
|
|
11378
|
+
if (!isSafeFileName(name)) throw new Error(`unsafe file name: ${name}`);
|
|
11379
|
+
const p = (0,node_path__WEBPACK_IMPORTED_MODULE_1__.join)(FILES_DIR, name);
|
|
11380
|
+
(0,node_fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync)(p, data);
|
|
11381
|
+
return p;
|
|
11382
|
+
}
|
|
10838
11383
|
|
|
10839
11384
|
|
|
11385
|
+
/***/ }),
|
|
10840
11386
|
|
|
11387
|
+
/***/ 56718:
|
|
11388
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
10841
11389
|
|
|
10842
|
-
|
|
10843
|
-
|
|
10844
|
-
|
|
10845
|
-
|
|
10846
|
-
|
|
10847
|
-
var
|
|
10848
|
-
|
|
10849
|
-
// Public tool surface for the agent runtime.
|
|
10850
|
-
//
|
|
10851
|
-
// Built-in tools register themselves at module load (see ./registry.ts and
|
|
10852
|
-
// ./builtins.ts). External tools live under JARELA_TOOLS_DIR and are
|
|
10853
|
-
// loaded per-call (hot-reload). MCP tools come from lib/mcp/client.ts.
|
|
11390
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
11391
|
+
/* harmony export */ HP: () => (/* binding */ disabledCategories),
|
|
11392
|
+
/* harmony export */ MD: () => (/* binding */ setCategoryEnabled)
|
|
11393
|
+
/* harmony export */ });
|
|
11394
|
+
/* unused harmony exports isCategoryEnabled, listCategoryStates */
|
|
11395
|
+
/* harmony import */ var _lib_db__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(46);
|
|
11396
|
+
// Built-in tool category toggles.
|
|
10854
11397
|
//
|
|
10855
|
-
//
|
|
10856
|
-
//
|
|
10857
|
-
//
|
|
10858
|
-
// 3. Add `import "./<name>";` to lib/tools/builtins.ts.
|
|
11398
|
+
// A category is "enabled" unless an explicit row in `builtin_tool_categories`
|
|
11399
|
+
// says otherwise. Default-enabled semantics mean upgrading installs keep
|
|
11400
|
+
// every category working with zero migration work.
|
|
10859
11401
|
//
|
|
10860
|
-
//
|
|
10861
|
-
|
|
10862
|
-
//
|
|
10863
|
-
|
|
10864
|
-
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
11402
|
+
// Disabled categories are filtered at three layers:
|
|
11403
|
+
// - GET /api/v1/tools (so the agent editor never offers them as permissions)
|
|
11404
|
+
// - getAllTools / getAllToolsAsync (so the agent runtime can't see them)
|
|
11405
|
+
// - executeTool (defense in depth, blocks stale agent configs)
|
|
10870
11406
|
|
|
10871
|
-
const
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
function loadExternal() {
|
|
10876
|
-
return (0,external/* loadExternalTools */.H)(BUILTIN_TOOL_NAMES);
|
|
10877
|
-
}
|
|
10878
|
-
// Resolve a tool's origin from its name. Used to label rows in the tools
|
|
10879
|
-
// API and to route metadata lookups. Returns "mcp" for any name that is
|
|
10880
|
-
// neither a registered built-in nor an external (JARELA_TOOLS_DIR) tool —
|
|
10881
|
-
// matches today's behavior where MCP tools are everything else.
|
|
10882
|
-
function getToolSource(name) {
|
|
10883
|
-
if (BUILTIN_TOOL_NAMES.has(name)) return "builtin";
|
|
10884
|
-
if (loadExternal().tools.some((t)=>t.name === name)) return "external";
|
|
10885
|
-
return "mcp";
|
|
10886
|
-
}
|
|
10887
|
-
// Look up a tool's safety class. Built-in tools have a declared capability;
|
|
10888
|
-
// external (JARELA_TOOLS_DIR) and MCP tools default to "execute" — the
|
|
10889
|
-
// conservative choice until manifest-level overrides land (ADR-0038).
|
|
10890
|
-
// Source is derived internally so callers can't mis-tag external tools as
|
|
10891
|
-
// MCP (or vice versa).
|
|
10892
|
-
function getToolCapability(name) {
|
|
10893
|
-
return (0,registry/* registeredCapability */.RL)(name) ?? "execute";
|
|
10894
|
-
}
|
|
10895
|
-
function getToolCategory(name) {
|
|
10896
|
-
const builtin = (0,registry/* registeredCategory */.RY)(name);
|
|
10897
|
-
if (builtin) return builtin;
|
|
10898
|
-
const ext = loadExternal().categories.get(name);
|
|
10899
|
-
if (ext) return ext;
|
|
10900
|
-
return getToolSource(name) === "mcp" ? "MCP" : "Config";
|
|
10901
|
-
}
|
|
10902
|
-
function getToolGroup(name) {
|
|
10903
|
-
const cat = getToolCategory(name);
|
|
10904
|
-
if (cat === "MCP") return null;
|
|
10905
|
-
return (0,registry/* registeredGroup */.Oi)(name) ?? null;
|
|
10906
|
-
}
|
|
10907
|
-
function applyPolicy(tools, policy) {
|
|
10908
|
-
const allowSet = policy?.allow?.length ? new Set(policy.allow) : null;
|
|
10909
|
-
const denySet = policy?.deny?.length ? new Set(policy.deny) : null;
|
|
10910
|
-
return tools.filter((t)=>{
|
|
10911
|
-
if (allowSet && !allowSet.has(t.name)) return false;
|
|
10912
|
-
if (denySet && denySet.has(t.name)) return false;
|
|
10913
|
-
return true;
|
|
10914
|
-
});
|
|
10915
|
-
}
|
|
10916
|
-
// Filter built-in tools whose category is disabled in the toggle store.
|
|
10917
|
-
// External + MCP tools are untouched (they have their own enable surfaces).
|
|
10918
|
-
function applyCategoryToggles(tools) {
|
|
10919
|
-
const disabled = (0,builtin_tools/* disabledCategories */.HP)();
|
|
10920
|
-
if (disabled.size === 0) return tools;
|
|
10921
|
-
return tools.filter((t)=>{
|
|
10922
|
-
const cat = (0,registry/* registeredCategory */.RY)(t.name);
|
|
10923
|
-
if (!cat) return true; // not a built-in (or unregistered) → leave it
|
|
10924
|
-
return !disabled.has(cat);
|
|
10925
|
-
});
|
|
10926
|
-
}
|
|
10927
|
-
// Synchronous: built-in + external tools (no MCP). Used by GET /api/v1/tools
|
|
10928
|
-
// and any code path that can't await.
|
|
10929
|
-
function getAllTools(policy) {
|
|
10930
|
-
return applyPolicy([
|
|
10931
|
-
...applyCategoryToggles(ALL_BUILTINS),
|
|
10932
|
-
...loadExternal().tools
|
|
10933
|
-
], policy);
|
|
10934
|
-
}
|
|
10935
|
-
// Async: built-in + external + MCP tools.
|
|
10936
|
-
// Use this anywhere the agent might invoke tools (createReactAgent input).
|
|
10937
|
-
// External tools are loaded per-call (hot-reload). MCP tools are cached by
|
|
10938
|
-
// lib/mcp/client.ts and only re-resolved when the mcp_servers table changes.
|
|
10939
|
-
async function getAllToolsAsync(policy) {
|
|
10940
|
-
let mcpTools = [];
|
|
10941
|
-
try {
|
|
10942
|
-
mcpTools = await (0,client/* getMcpTools */.a)();
|
|
10943
|
-
} catch (err) {
|
|
10944
|
-
console.error("[tools] MCP load failed, continuing with built-ins only:", err);
|
|
10945
|
-
}
|
|
10946
|
-
return applyPolicy([
|
|
10947
|
-
...applyCategoryToggles(ALL_BUILTINS),
|
|
10948
|
-
...loadExternal().tools,
|
|
10949
|
-
...mcpTools
|
|
10950
|
-
], policy);
|
|
11407
|
+
const now = ()=>new Date().toISOString();
|
|
11408
|
+
function isCategoryEnabled(category) {
|
|
11409
|
+
const row = getDb().prepare("SELECT enabled FROM builtin_tool_categories WHERE category=?").get(category);
|
|
11410
|
+
return row ? row.enabled === 1 : true;
|
|
10951
11411
|
}
|
|
10952
|
-
function
|
|
10953
|
-
|
|
10954
|
-
|
|
10955
|
-
return {
|
|
10956
|
-
type: "function",
|
|
10957
|
-
function: {
|
|
10958
|
-
name: oai.function.name,
|
|
10959
|
-
description: oai.function.description ?? "",
|
|
10960
|
-
parameters: oai.function.parameters
|
|
10961
|
-
}
|
|
10962
|
-
};
|
|
10963
|
-
});
|
|
11412
|
+
function disabledCategories() {
|
|
11413
|
+
const rows = (0,_lib_db__WEBPACK_IMPORTED_MODULE_0__/* .getDb */ .Lf)().prepare("SELECT category FROM builtin_tool_categories WHERE enabled=0").all();
|
|
11414
|
+
return new Set(rows.map((r)=>r.category));
|
|
10964
11415
|
}
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
}
|
|
10972
|
-
}
|
|
10973
|
-
if (!t) {
|
|
10974
|
-
t = loadExternal().tools.find((x)=>x.name === name);
|
|
10975
|
-
}
|
|
10976
|
-
if (!t) throw new Error(`Unknown tool: ${name}`);
|
|
10977
|
-
const config = context.thread_id ? {
|
|
10978
|
-
configurable: {
|
|
10979
|
-
thread_id: context.thread_id
|
|
10980
|
-
}
|
|
10981
|
-
} : {};
|
|
10982
|
-
const result = await t.invoke(args, config);
|
|
10983
|
-
// Tools return JSON strings per LangChain convention; parse back for downstream use.
|
|
10984
|
-
if (typeof result === "string") {
|
|
10985
|
-
try {
|
|
10986
|
-
return JSON.parse(result);
|
|
10987
|
-
} catch {
|
|
10988
|
-
return result;
|
|
10989
|
-
}
|
|
10990
|
-
}
|
|
10991
|
-
return result;
|
|
11416
|
+
function listCategoryStates() {
|
|
11417
|
+
const rows = getDb().prepare("SELECT category, enabled, updated_at FROM builtin_tool_categories").all();
|
|
11418
|
+
return rows.map((r)=>({
|
|
11419
|
+
category: r.category,
|
|
11420
|
+
enabled: r.enabled === 1,
|
|
11421
|
+
updated_at: r.updated_at
|
|
11422
|
+
}));
|
|
10992
11423
|
}
|
|
10993
|
-
|
|
10994
|
-
|
|
10995
|
-
|
|
10996
|
-
|
|
10997
|
-
const toolsDir = getToolsDir();
|
|
10998
|
-
const result = loadExternal();
|
|
10999
|
-
const summary = {
|
|
11000
|
-
builtinCount: ALL_BUILTINS.length,
|
|
11001
|
-
externalCount: result.tools.length,
|
|
11002
|
-
errors: result.errors,
|
|
11003
|
-
toolsDir
|
|
11004
|
-
};
|
|
11005
|
-
if (!_initialized) {
|
|
11006
|
-
console.info(`[tools] ${summary.builtinCount} built-in tool(s) registered; ` + `${summary.externalCount} external tool(s) loaded from ${toolsDir}`);
|
|
11007
|
-
for (const err of summary.errors){
|
|
11008
|
-
console.error(`[tools] external ${err.file}: ${err.error}`);
|
|
11009
|
-
}
|
|
11010
|
-
_initialized = true;
|
|
11011
|
-
}
|
|
11012
|
-
return summary;
|
|
11424
|
+
function setCategoryEnabled(category, enabled) {
|
|
11425
|
+
(0,_lib_db__WEBPACK_IMPORTED_MODULE_0__/* .getDb */ .Lf)().prepare(`INSERT INTO builtin_tool_categories (category, enabled, updated_at)
|
|
11426
|
+
VALUES (?, ?, ?)
|
|
11427
|
+
ON CONFLICT(category) DO UPDATE SET enabled=excluded.enabled, updated_at=excluded.updated_at`).run(category, enabled ? 1 : 0, now());
|
|
11013
11428
|
}
|
|
11014
11429
|
|
|
11015
11430
|
|