@markus-global/cli 0.6.7 → 0.6.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/start.js +39 -13
- package/dist/commands/start.js.map +1 -1
- package/dist/markus.mjs +1451 -225
- package/dist/tray.js +34 -4
- package/dist/tray.js.map +1 -1
- package/dist/tray.mjs +32 -3
- package/dist/utils/browser.d.ts +5 -0
- package/dist/utils/browser.d.ts.map +1 -1
- package/dist/utils/browser.js +27 -0
- package/dist/utils/browser.js.map +1 -1
- package/dist/web-ui/assets/index-B8jf_U2f.js +385 -0
- package/dist/web-ui/assets/index-bD7A_PcE.css +1 -0
- package/dist/web-ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/web-ui/assets/index-80hhDueA.css +0 -1
- package/dist/web-ui/assets/index-BO3gU7n4.js +0 -351
package/dist/markus.mjs
CHANGED
|
@@ -4216,7 +4216,7 @@ function withJitter(baseMs, factor = 0.2) {
|
|
|
4216
4216
|
const jitter = baseMs * factor * (2 * Math.random() - 1);
|
|
4217
4217
|
return Math.max(0, Math.round(baseMs + jitter));
|
|
4218
4218
|
}
|
|
4219
|
-
var TASK_GET_NOTES_DEFAULT, TASK_GET_DELIVERABLES_DEFAULT, TASK_GET_STATUS_HISTORY_DEFAULT, REQUIREMENT_LIST_DEFAULT, ENTITY_COMMENTS_DEFAULT, PROMPT_TASK_NOTES_MAX, PROMPT_TASK_NOTE_CHARS, PROMPT_DEP_NOTES_MAX, PROMPT_DEP_NOTE_CHARS, PROMPT_DEP_DESC_CHARS, PROMPT_EXECUTION_ROUNDS_MAX, PROMPT_LOG_ENTRY_CHARS, PROMPT_RECENT_ERRORS_MAX, PROMPT_HUMAN_COMMENTS_MAX, REVIEWER_NOTES_MAX, SYSTEM_MY_TASKS_MAX, SYSTEM_TEAM_TASKS_MAX, SYSTEM_TASK_DESC_CHARS, PROMPT_PROJECT_DESC_CHARS, PROMPT_REQUIREMENT_DESC_CHARS, REVIEWER_FILE_LIST_MAX, DELIVERABLE_TITLE_CHARS, REVISION_REASON_CHARS, TASK_MAX_RETRIES, MAILBOX_ITEM_MAX_RETRIES, COMPLETION_MARKER, COMPLETION_MARKER_INSTRUCTION, TASK_MAX_NO_SUBMIT_RETRIES, TASK_RETRY_DELAYS_MS, PREEMPT_REQUEUE_DELAY_MS, SYSTEM_KNOWLEDGE_CHARS, SYSTEM_SOPS_CHARS, SYSTEM_LONGTERM_MEMORY_CHARS, MEMORY_MD_SECTION_MAX_CHARS, MEMORY_MD_TOTAL_MAX_CHARS, SYSTEM_LESSON_ENTRIES_MAX, SYSTEM_BEST_PRACTICE_ENTRIES_MAX, SYSTEM_DELIVERABLES_CHARS, SYSTEM_DAILY_LOG_CHARS, SYSTEM_DAILY_LOG_DAYS, SYSTEM_USER_PROFILE_CHARS, SYSTEM_CHAT_SESSIONS_MAX, HEARTBEAT_DAILY_LOG_CHARS, SYSTEM_PROJECT_DESC_CHARS, SYSTEM_DELIVERABLE_PREVIEW_CHARS, SYSTEM_MAILBOX_MERGED_CHARS, SYSTEM_MAILBOX_ITEM_PREVIEW_CHARS, TASK_LIST_PAGE_SIZE, TASK_LIST_PAGE_MAX, ARCHIVE_COMPLETED_AFTER_DAYS, ARCHIVE_TERMINAL_AFTER_DAYS, ARCHIVE_REQUIREMENT_AFTER_DAYS, ARCHIVE_SCAN_INTERVAL_MS, MAILBOX_QUEUED_TTL_MS, MAILBOX_PROCESSING_TIMEOUT_MS, WATCHDOG_INTERVAL_MS, WATCHDOG_DRIFT_THRESHOLD_MS, TRIAGE_PROMPT_MAX_ITEMS, TRIAGE_MAX_TOKENS, TRIAGE_TEMPERATURE, TRIAGE_CONTEXT_MESSAGES_MAX, TRIAGE_CONTEXT_MSG_CHARS, TRIAGE_ITEM_CONTENT_CHARS, TRIAGE_STALE_INFO_TTL_MS, TRIAGE_STALE_DROP_TYPES, TRIAGE_MAX_TOOL_ITERATIONS, TRIAGE_ALLOWED_TOOLS, SUBAGENT_TASK_PREVIEW_CHARS, SUBAGENT_THINKING_PREVIEW_CHARS, SUBAGENT_RESULT_PREVIEW_CHARS, SUBAGENT_LOG_ENTRY_CHARS, SUBAGENT_ERROR_PREVIEW_CHARS, SUBAGENT_MAX_PARALLEL, SUBAGENT_MAX_LLM_RETRIES, SUBAGENT_RETRY_BASE_MS, SHELL_TIMEOUT_DEFAULT_MS, SHELL_TIMEOUT_MAX_MS, APPROVAL_WAIT_TIMEOUT_MS, HEARTBEAT_MIN_INITIAL_DELAY_MS, HEARTBEAT_STARTUP_JITTER_MS, LLM_CIRCUIT_RESET_RATE_LIMIT_MS, LLM_MAX_CONCURRENT_PER_PROVIDER, LLM_CONCURRENCY_JITTER_BASE_MS;
|
|
4219
|
+
var TASK_GET_NOTES_DEFAULT, TASK_GET_DELIVERABLES_DEFAULT, TASK_GET_STATUS_HISTORY_DEFAULT, REQUIREMENT_LIST_DEFAULT, ENTITY_COMMENTS_DEFAULT, PROMPT_TASK_NOTES_MAX, PROMPT_TASK_NOTE_CHARS, PROMPT_DEP_NOTES_MAX, PROMPT_DEP_NOTE_CHARS, PROMPT_DEP_DESC_CHARS, PROMPT_EXECUTION_ROUNDS_MAX, PROMPT_LOG_ENTRY_CHARS, PROMPT_RECENT_ERRORS_MAX, PROMPT_HUMAN_COMMENTS_MAX, REVIEWER_NOTES_MAX, SYSTEM_MY_TASKS_MAX, SYSTEM_TEAM_TASKS_MAX, SYSTEM_TASK_DESC_CHARS, PROMPT_PROJECT_DESC_CHARS, PROMPT_REQUIREMENT_DESC_CHARS, REVIEWER_FILE_LIST_MAX, DELIVERABLE_TITLE_CHARS, REVISION_REASON_CHARS, TASK_MAX_RETRIES, MAILBOX_ITEM_MAX_RETRIES, COMPLETION_MARKER, COMPLETION_MARKER_INSTRUCTION, TASK_MAX_NO_SUBMIT_RETRIES, TASK_RETRY_DELAYS_MS, PREEMPT_REQUEUE_DELAY_MS, SYSTEM_KNOWLEDGE_CHARS, SYSTEM_SOPS_CHARS, SYSTEM_LONGTERM_MEMORY_CHARS, MEMORY_MD_SECTION_MAX_CHARS, MEMORY_MD_TOTAL_MAX_CHARS, SYSTEM_LESSON_ENTRIES_MAX, SYSTEM_BEST_PRACTICE_ENTRIES_MAX, SYSTEM_DELIVERABLES_CHARS, SYSTEM_DAILY_LOG_CHARS, SYSTEM_DAILY_LOG_DAYS, SYSTEM_USER_PROFILE_CHARS, SYSTEM_CHAT_SESSIONS_MAX, HEARTBEAT_DAILY_LOG_CHARS, SYSTEM_PROJECT_DESC_CHARS, SYSTEM_DELIVERABLE_PREVIEW_CHARS, SYSTEM_MAILBOX_MERGED_CHARS, SYSTEM_MAILBOX_ITEM_PREVIEW_CHARS, TASK_LIST_PAGE_SIZE, TASK_LIST_PAGE_MAX, ARCHIVE_COMPLETED_AFTER_DAYS, ARCHIVE_TERMINAL_AFTER_DAYS, ARCHIVE_REQUIREMENT_AFTER_DAYS, ARCHIVE_SCAN_INTERVAL_MS, MAILBOX_QUEUED_TTL_MS, MAILBOX_PROCESSING_TIMEOUT_MS, WATCHDOG_INTERVAL_MS, WATCHDOG_DRIFT_THRESHOLD_MS, TRIAGE_PROMPT_MAX_ITEMS, TRIAGE_MAX_TOKENS, TRIAGE_TEMPERATURE, TRIAGE_CONTEXT_MESSAGES_MAX, TRIAGE_CONTEXT_MSG_CHARS, TRIAGE_ITEM_CONTENT_CHARS, TRIAGE_STALE_INFO_TTL_MS, TRIAGE_STALE_DROP_TYPES, TRIAGE_MAX_TOOL_ITERATIONS, TRIAGE_ALLOWED_TOOLS, DELIBERATION_MAX_TOOL_ITERATIONS, DELIBERATION_ALLOWED_TOOLS, SUBAGENT_TASK_PREVIEW_CHARS, SUBAGENT_THINKING_PREVIEW_CHARS, SUBAGENT_RESULT_PREVIEW_CHARS, SUBAGENT_LOG_ENTRY_CHARS, SUBAGENT_ERROR_PREVIEW_CHARS, SUBAGENT_MAX_PARALLEL, SUBAGENT_MAX_LLM_RETRIES, SUBAGENT_RETRY_BASE_MS, SHELL_TIMEOUT_DEFAULT_MS, SHELL_TIMEOUT_MAX_MS, SHELL_MAX_SESSIONS_PER_AGENT, SHELL_SESSION_IDLE_TIMEOUT_MS, SHELL_SESSION_MAX_OUTPUT_BYTES, APPROVAL_WAIT_TIMEOUT_MS, HEARTBEAT_MIN_INITIAL_DELAY_MS, HEARTBEAT_STARTUP_JITTER_MS, LLM_CIRCUIT_RESET_RATE_LIMIT_MS, LLM_MAX_CONCURRENT_PER_PROVIDER, LLM_CONCURRENCY_JITTER_BASE_MS;
|
|
4220
4220
|
var init_limits = __esm({
|
|
4221
4221
|
"../shared/dist/limits.js"() {
|
|
4222
4222
|
"use strict";
|
|
@@ -4292,14 +4292,41 @@ var init_limits = __esm({
|
|
|
4292
4292
|
"memory_consolidation",
|
|
4293
4293
|
"daily_report"
|
|
4294
4294
|
];
|
|
4295
|
-
TRIAGE_MAX_TOOL_ITERATIONS =
|
|
4295
|
+
TRIAGE_MAX_TOOL_ITERATIONS = 6;
|
|
4296
4296
|
TRIAGE_ALLOWED_TOOLS = [
|
|
4297
4297
|
"task_list",
|
|
4298
4298
|
"task_get",
|
|
4299
4299
|
"requirement_list",
|
|
4300
4300
|
"requirement_get",
|
|
4301
4301
|
"list_projects",
|
|
4302
|
-
"team_list"
|
|
4302
|
+
"team_list",
|
|
4303
|
+
"recall_activity",
|
|
4304
|
+
"memory_search",
|
|
4305
|
+
"memory_search_longterm"
|
|
4306
|
+
];
|
|
4307
|
+
DELIBERATION_MAX_TOOL_ITERATIONS = 10;
|
|
4308
|
+
DELIBERATION_ALLOWED_TOOLS = [
|
|
4309
|
+
// Context gathering (read-only)
|
|
4310
|
+
"task_list",
|
|
4311
|
+
"task_get",
|
|
4312
|
+
"requirement_list",
|
|
4313
|
+
"requirement_get",
|
|
4314
|
+
"list_projects",
|
|
4315
|
+
"team_list",
|
|
4316
|
+
"team_status",
|
|
4317
|
+
"recall_activity",
|
|
4318
|
+
"memory_search",
|
|
4319
|
+
"memory_search_longterm",
|
|
4320
|
+
// Inline action (lightweight communication)
|
|
4321
|
+
"notify_user",
|
|
4322
|
+
"task_comment",
|
|
4323
|
+
"requirement_comment",
|
|
4324
|
+
"agent_send_message",
|
|
4325
|
+
"agent_send_group_message",
|
|
4326
|
+
"agent_create_group_chat",
|
|
4327
|
+
"agent_list_group_chats",
|
|
4328
|
+
// Decision output
|
|
4329
|
+
"complete_deliberation"
|
|
4303
4330
|
];
|
|
4304
4331
|
SUBAGENT_TASK_PREVIEW_CHARS = 500;
|
|
4305
4332
|
SUBAGENT_THINKING_PREVIEW_CHARS = 1e3;
|
|
@@ -4311,6 +4338,9 @@ var init_limits = __esm({
|
|
|
4311
4338
|
SUBAGENT_RETRY_BASE_MS = 2e3;
|
|
4312
4339
|
SHELL_TIMEOUT_DEFAULT_MS = 6e4;
|
|
4313
4340
|
SHELL_TIMEOUT_MAX_MS = 3e5;
|
|
4341
|
+
SHELL_MAX_SESSIONS_PER_AGENT = 3;
|
|
4342
|
+
SHELL_SESSION_IDLE_TIMEOUT_MS = 10 * 6e4;
|
|
4343
|
+
SHELL_SESSION_MAX_OUTPUT_BYTES = 2 * 1024 * 1024;
|
|
4314
4344
|
APPROVAL_WAIT_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
|
|
4315
4345
|
HEARTBEAT_MIN_INITIAL_DELAY_MS = 5e3;
|
|
4316
4346
|
HEARTBEAT_STARTUP_JITTER_MS = 1e4;
|
|
@@ -4320,6 +4350,40 @@ var init_limits = __esm({
|
|
|
4320
4350
|
}
|
|
4321
4351
|
});
|
|
4322
4352
|
|
|
4353
|
+
// ../shared/dist/sanitize.js
|
|
4354
|
+
function sanitizeForLLM(text) {
|
|
4355
|
+
return text.replace(ANSI_CSI, "").replace(ANSI_OSC, "").replace(ANSI_OTHER, "").replace(C0_CONTROL, "").replace(C1_CONTROL, "").replace(LONE_HIGH_SURROGATE, "\uFFFD").replace(LONE_LOW_SURROGATE, "\uFFFD");
|
|
4356
|
+
}
|
|
4357
|
+
function safeSlice(text, start, end) {
|
|
4358
|
+
let result = text.slice(start, end);
|
|
4359
|
+
if (result.length === 0)
|
|
4360
|
+
return result;
|
|
4361
|
+
const first = result.charCodeAt(0);
|
|
4362
|
+
if (first >= 56320 && first <= 57343) {
|
|
4363
|
+
result = result.slice(1);
|
|
4364
|
+
}
|
|
4365
|
+
if (result.length === 0)
|
|
4366
|
+
return result;
|
|
4367
|
+
const last = result.charCodeAt(result.length - 1);
|
|
4368
|
+
if (last >= 55296 && last <= 56319) {
|
|
4369
|
+
result = result.slice(0, -1);
|
|
4370
|
+
}
|
|
4371
|
+
return result;
|
|
4372
|
+
}
|
|
4373
|
+
var ANSI_CSI, ANSI_OSC, ANSI_OTHER, C0_CONTROL, C1_CONTROL, LONE_HIGH_SURROGATE, LONE_LOW_SURROGATE;
|
|
4374
|
+
var init_sanitize = __esm({
|
|
4375
|
+
"../shared/dist/sanitize.js"() {
|
|
4376
|
+
"use strict";
|
|
4377
|
+
ANSI_CSI = /\x1b\[[0-9;]*[a-zA-Z]/g;
|
|
4378
|
+
ANSI_OSC = /\x1b\][^\x07]*(?:\x07|\x1b\\)/g;
|
|
4379
|
+
ANSI_OTHER = /\x1b[^[\]].?/g;
|
|
4380
|
+
C0_CONTROL = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
4381
|
+
C1_CONTROL = /[\x80-\x9f]/g;
|
|
4382
|
+
LONE_HIGH_SURROGATE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])/g;
|
|
4383
|
+
LONE_LOW_SURROGATE = /(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
|
|
4384
|
+
}
|
|
4385
|
+
});
|
|
4386
|
+
|
|
4323
4387
|
// ../shared/dist/index.js
|
|
4324
4388
|
var dist_exports = {};
|
|
4325
4389
|
__export(dist_exports, {
|
|
@@ -4332,6 +4396,8 @@ __export(dist_exports, {
|
|
|
4332
4396
|
COMPLETION_MARKER: () => COMPLETION_MARKER,
|
|
4333
4397
|
COMPLETION_MARKER_INSTRUCTION: () => COMPLETION_MARKER_INSTRUCTION,
|
|
4334
4398
|
CognitiveDepth: () => CognitiveDepth,
|
|
4399
|
+
DELIBERATION_ALLOWED_TOOLS: () => DELIBERATION_ALLOWED_TOOLS,
|
|
4400
|
+
DELIBERATION_MAX_TOOL_ITERATIONS: () => DELIBERATION_MAX_TOOL_ITERATIONS,
|
|
4335
4401
|
DELIVERABLE_TITLE_CHARS: () => DELIVERABLE_TITLE_CHARS,
|
|
4336
4402
|
ENTITY_COMMENTS_DEFAULT: () => ENTITY_COMMENTS_DEFAULT,
|
|
4337
4403
|
HEARTBEAT_DAILY_LOG_CHARS: () => HEARTBEAT_DAILY_LOG_CHARS,
|
|
@@ -4368,6 +4434,9 @@ __export(dist_exports, {
|
|
|
4368
4434
|
REVIEWER_FILE_LIST_MAX: () => REVIEWER_FILE_LIST_MAX,
|
|
4369
4435
|
REVIEWER_NOTES_MAX: () => REVIEWER_NOTES_MAX,
|
|
4370
4436
|
REVISION_REASON_CHARS: () => REVISION_REASON_CHARS,
|
|
4437
|
+
SHELL_MAX_SESSIONS_PER_AGENT: () => SHELL_MAX_SESSIONS_PER_AGENT,
|
|
4438
|
+
SHELL_SESSION_IDLE_TIMEOUT_MS: () => SHELL_SESSION_IDLE_TIMEOUT_MS,
|
|
4439
|
+
SHELL_SESSION_MAX_OUTPUT_BYTES: () => SHELL_SESSION_MAX_OUTPUT_BYTES,
|
|
4371
4440
|
SHELL_TIMEOUT_DEFAULT_MS: () => SHELL_TIMEOUT_DEFAULT_MS,
|
|
4372
4441
|
SHELL_TIMEOUT_MAX_MS: () => SHELL_TIMEOUT_MAX_MS,
|
|
4373
4442
|
SUBAGENT_ERROR_PREVIEW_CHARS: () => SUBAGENT_ERROR_PREVIEW_CHARS,
|
|
@@ -4437,6 +4506,8 @@ __export(dist_exports, {
|
|
|
4437
4506
|
orgId: () => orgId,
|
|
4438
4507
|
readManifest: () => readManifest,
|
|
4439
4508
|
requirementId: () => requirementId,
|
|
4509
|
+
safeSlice: () => safeSlice,
|
|
4510
|
+
sanitizeForLLM: () => sanitizeForLLM,
|
|
4440
4511
|
saveConfig: () => saveConfig,
|
|
4441
4512
|
stripInternalBlocks: () => stripInternalBlocks,
|
|
4442
4513
|
taskId: () => taskId,
|
|
@@ -4468,6 +4539,7 @@ var init_dist = __esm({
|
|
|
4468
4539
|
init_version();
|
|
4469
4540
|
init_update_checker();
|
|
4470
4541
|
init_limits();
|
|
4542
|
+
init_sanitize();
|
|
4471
4543
|
}
|
|
4472
4544
|
});
|
|
4473
4545
|
|
|
@@ -5464,6 +5536,10 @@ import { join as join6 } from "node:path";
|
|
|
5464
5536
|
function freshCounters() {
|
|
5465
5537
|
return {
|
|
5466
5538
|
totalTokens: 0,
|
|
5539
|
+
promptTokens: 0,
|
|
5540
|
+
completionTokens: 0,
|
|
5541
|
+
estimatedCost: 0,
|
|
5542
|
+
costToday: 0,
|
|
5467
5543
|
requestCount: 0,
|
|
5468
5544
|
toolCalls: 0,
|
|
5469
5545
|
errorCount: 0,
|
|
@@ -5507,6 +5583,7 @@ var init_agent_metrics = __esm({
|
|
|
5507
5583
|
c.tokensToday = 0;
|
|
5508
5584
|
c.requestsToday = 0;
|
|
5509
5585
|
c.toolCallsToday = 0;
|
|
5586
|
+
c.costToday = 0;
|
|
5510
5587
|
c.todayCutoffDate = today;
|
|
5511
5588
|
}
|
|
5512
5589
|
c.totalEvents++;
|
|
@@ -5517,6 +5594,12 @@ var init_agent_metrics = __esm({
|
|
|
5517
5594
|
if (event.type === "llm_request") {
|
|
5518
5595
|
const tokens = event.tokensUsed ?? 0;
|
|
5519
5596
|
c.totalTokens += tokens;
|
|
5597
|
+
c.promptTokens += event.inputTokens ?? 0;
|
|
5598
|
+
c.completionTokens += event.outputTokens ?? 0;
|
|
5599
|
+
if (event.cost) {
|
|
5600
|
+
c.estimatedCost += event.cost;
|
|
5601
|
+
c.costToday += event.cost;
|
|
5602
|
+
}
|
|
5520
5603
|
c.requestCount++;
|
|
5521
5604
|
c.tokensToday += tokens;
|
|
5522
5605
|
c.requestsToday++;
|
|
@@ -5575,19 +5658,29 @@ var init_agent_metrics = __esm({
|
|
|
5575
5658
|
*/
|
|
5576
5659
|
getUsageStats() {
|
|
5577
5660
|
const c = this.counters;
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5661
|
+
let cost = c.estimatedCost;
|
|
5662
|
+
let costToday = c.costToday;
|
|
5663
|
+
if (cost === 0 && c.totalTokens > 0) {
|
|
5664
|
+
const input = Math.round(c.totalTokens * 0.7);
|
|
5665
|
+
const output = c.totalTokens - input;
|
|
5666
|
+
cost = input / 1e6 * 3 + output / 1e6 * 15;
|
|
5667
|
+
}
|
|
5668
|
+
if (costToday === 0 && c.tokensToday > 0) {
|
|
5669
|
+
const input = Math.round(c.tokensToday * 0.7);
|
|
5670
|
+
const output = c.tokensToday - input;
|
|
5671
|
+
costToday = input / 1e6 * 3 + output / 1e6 * 15;
|
|
5672
|
+
}
|
|
5581
5673
|
return {
|
|
5582
5674
|
totalTokens: c.totalTokens,
|
|
5583
|
-
promptTokens:
|
|
5584
|
-
completionTokens:
|
|
5675
|
+
promptTokens: c.promptTokens || Math.round(c.totalTokens * 0.7),
|
|
5676
|
+
completionTokens: c.completionTokens || c.totalTokens - Math.round(c.totalTokens * 0.7),
|
|
5585
5677
|
requestCount: c.requestCount,
|
|
5586
5678
|
toolCalls: c.toolCalls,
|
|
5587
5679
|
tokensToday: c.tokensToday,
|
|
5588
5680
|
requestsToday: c.requestsToday,
|
|
5589
5681
|
toolCallsToday: c.toolCallsToday,
|
|
5590
|
-
estimatedCost: Math.round(
|
|
5682
|
+
estimatedCost: Math.round(cost * 1e4) / 1e4,
|
|
5683
|
+
costToday: Math.round(costToday * 1e4) / 1e4
|
|
5591
5684
|
};
|
|
5592
5685
|
}
|
|
5593
5686
|
/**
|
|
@@ -5609,9 +5702,12 @@ var init_agent_metrics = __esm({
|
|
|
5609
5702
|
return Math.round(Math.min(100, heartbeatComponent + taskComponent + errorComponent + recencyComponent));
|
|
5610
5703
|
}
|
|
5611
5704
|
computeTokenUsageFromCounters(c) {
|
|
5612
|
-
const input = Math.round(c.totalTokens * 0.7);
|
|
5613
|
-
const output = c.totalTokens - input;
|
|
5614
|
-
|
|
5705
|
+
const input = c.promptTokens || Math.round(c.totalTokens * 0.7);
|
|
5706
|
+
const output = c.completionTokens || c.totalTokens - input;
|
|
5707
|
+
let cost = c.estimatedCost;
|
|
5708
|
+
if (cost === 0 && c.totalTokens > 0) {
|
|
5709
|
+
cost = input / 1e6 * 3 + output / 1e6 * 15;
|
|
5710
|
+
}
|
|
5615
5711
|
return { input, output, cost: Math.round(cost * 1e4) / 1e4 };
|
|
5616
5712
|
}
|
|
5617
5713
|
computeTaskMetrics(tasks) {
|
|
@@ -6403,6 +6499,13 @@ var init_context_engine = __esm({
|
|
|
6403
6499
|
stable.push("**Built-in tools over CLI**: ALWAYS prefer built-in tools (`task_create`, `task_assign`, `package_install`, `agent_send_message`, `memory_save`, etc.) over running `markus` CLI commands via `shell_execute`. The CLI is for human operators \u2014 agents must use their native tool interface. Only fall back to CLI if no built-in tool exists for the operation.");
|
|
6404
6500
|
stable.push('**No auto-install/deploy**: NEVER automatically install or deploy agents, teams, or skills via `package_install` or `hub_install` unless explicitly requested by a human team member (e.g., "install", "deploy", "hire", "start"). Creating an artifact (writing files to `builder-artifacts/`) is separate from deploying it into the live organization.');
|
|
6405
6501
|
stable.push("");
|
|
6502
|
+
stable.push("\n## Deliverable & Report Output Format");
|
|
6503
|
+
stable.push("When creating deliverable files (reports, analysis, documentation, etc.), choose the most appropriate format:");
|
|
6504
|
+
stable.push("- **Markdown (.md)**: Use for simple, short, or text-heavy content \u2014 READMEs, notes, status summaries, concise reports. Preferred when content is linear and doesn't need interactive elements.");
|
|
6505
|
+
stable.push("- **HTML (.html)**: Use for complex, data-rich, or interactive content \u2014 dashboards, multi-section reports with charts/tables, comparative analyses, visual summaries, or any content where layout, color-coding, or collapsible sections would help the reader absorb information faster. Include inline CSS for styling. You may embed lightweight JavaScript for interactivity (collapsible sections, sortable tables, tab switching, chart rendering via CDN libraries like Chart.js or ECharts).");
|
|
6506
|
+
stable.push("- **Other formats**: Use the format that best fits the content (e.g., JSON for structured data, CSV for tabular exports, SVG for diagrams).");
|
|
6507
|
+
stable.push("Default to markdown for brevity; escalate to HTML when richness helps comprehension. Always use the correct file extension so the platform can detect and render it properly.");
|
|
6508
|
+
stable.push("");
|
|
6406
6509
|
stable.push("\n## Task & Requirement Workflow");
|
|
6407
6510
|
stable.push("");
|
|
6408
6511
|
stable.push("**Requirements** (governance gate):");
|
|
@@ -6747,6 +6850,8 @@ ${ctx.mergedContent.slice(0, SYSTEM_MAILBOX_MERGED_CHARS)}`);
|
|
|
6747
6850
|
lines.push("**After creating tasks, STOP.** Do NOT execute the task work yourself. The task runs in its own isolated context after user approval. Reply with a summary of created tasks, assignees, and dependency structure. Tell the requester to review and approve.");
|
|
6748
6851
|
lines.push("");
|
|
6749
6852
|
lines.push("Keep responses concise and human-friendly. The user should not see raw tool outputs or complex operations.");
|
|
6853
|
+
lines.push("");
|
|
6854
|
+
lines.push("**Notification context**: Previous messages in this session may contain `<!-- notify_context: ... -->` metadata comments from your earlier `notify_user` calls. These embed `task_id`, `requirement_id`, and `priority` references. When the human replies to such a message, use these references to retrieve full context (e.g. via `recall_activity`, `search_tasks`) before responding.");
|
|
6750
6855
|
break;
|
|
6751
6856
|
case "task_execution":
|
|
6752
6857
|
lines.push("You are in **task execution mode** \u2014 an isolated session for focused, thorough work.");
|
|
@@ -6875,6 +6980,40 @@ ${ctx.mergedContent.slice(0, SYSTEM_MAILBOX_MERGED_CHARS)}`);
|
|
|
6875
6980
|
lines.push("Do NOT call any tools. Do NOT take any actions. Do NOT discuss tasks or projects.");
|
|
6876
6981
|
lines.push("Respond with ONLY the JSON object as specified in the user message.");
|
|
6877
6982
|
break;
|
|
6983
|
+
case "deliberation":
|
|
6984
|
+
lines.push("You are in **deliberation mode** \u2014 reviewing your mailbox before committing to work.");
|
|
6985
|
+
lines.push("");
|
|
6986
|
+
lines.push("**Purpose**: You have multiple pending items. Take a moment to understand the full picture before deciding what to focus on.");
|
|
6987
|
+
lines.push("");
|
|
6988
|
+
lines.push("**What you can do**:");
|
|
6989
|
+
lines.push("1. **Gather context**: Call tools like recall_activity, task_get, memory_search to understand history and commitments.");
|
|
6990
|
+
lines.push("2. **Handle simple items inline**: For trivial acknowledgments or quick notifications, use notify_user, task_comment, or agent_send_message now. Mark them as inline_completed in your final decision.");
|
|
6991
|
+
lines.push("3. **Choose your focus**: Decide which complex item deserves your full attention next.");
|
|
6992
|
+
lines.push("4. **Defer or drop**: Explicitly defer items for later or drop stale/redundant ones.");
|
|
6993
|
+
lines.push("");
|
|
6994
|
+
lines.push("**Rules**:");
|
|
6995
|
+
lines.push("- Human messages and comments are ALWAYS highest priority.");
|
|
6996
|
+
lines.push("- Consider your active tasks, pending commitments, and recent conversation context.");
|
|
6997
|
+
lines.push("- Stale informational items (old heartbeats, status updates) should be dropped aggressively.");
|
|
6998
|
+
lines.push("- When done, you MUST call the `complete_deliberation` tool with your decision.");
|
|
6999
|
+
lines.push("");
|
|
7000
|
+
lines.push("**Communication channel**: Your text output is NOT visible to anyone. Only tool calls have effect. To reach humans, use `notify_user`. To reach agents, use `agent_send_message`.");
|
|
7001
|
+
break;
|
|
7002
|
+
case "requirement_action":
|
|
7003
|
+
lines.push("You are processing a **requirement update that requires action** (e.g., all tasks completed and requirement needs review, or a human approved/rejected your proposed requirement).");
|
|
7004
|
+
lines.push("");
|
|
7005
|
+
lines.push("**Communication channel**: Your text output is **NOT visible** to any human or agent. You MUST use tools to take action and communicate. Simply writing text and ending your turn accomplishes nothing.");
|
|
7006
|
+
lines.push("");
|
|
7007
|
+
lines.push("**Required actions** \u2014 you MUST do at least one of the following:");
|
|
7008
|
+
lines.push("1. **Update requirement status**: `requirement_update_status` to mark the requirement as completed, or keep it active if more work is needed.");
|
|
7009
|
+
lines.push("2. **Create follow-up tasks**: `task_create` with the `requirement_id` if additional work is needed to fulfill the requirement.");
|
|
7010
|
+
lines.push("3. **Post a comment**: `requirement_comment` to leave notes or reasoning visible in the requirement thread.");
|
|
7011
|
+
lines.push("4. **Notify a human**: `notify_user` if the requirement outcome needs human attention or decision.");
|
|
7012
|
+
lines.push("");
|
|
7013
|
+
lines.push("**MANDATORY**: Before deciding, call `requirement_get` to understand the full current state of the requirement, including linked tasks, status, and comments.");
|
|
7014
|
+
lines.push("");
|
|
7015
|
+
lines.push("**CRITICAL**: You MUST call at least one action tool before finishing. Do NOT just output text \u2014 it will be lost.");
|
|
7016
|
+
break;
|
|
6878
7017
|
}
|
|
6879
7018
|
return lines.join("\n");
|
|
6880
7019
|
}
|
|
@@ -7273,12 +7412,12 @@ ${heuristicSummary}
|
|
|
7273
7412
|
return m;
|
|
7274
7413
|
const headSize = Math.min(Math.floor(effectiveCap * 0.65), isResearch ? 4e3 : 1500);
|
|
7275
7414
|
const tailSize = Math.min(Math.floor(effectiveCap * 0.25), isResearch ? 1500 : 800);
|
|
7276
|
-
const head = text
|
|
7277
|
-
const tail = text.
|
|
7278
|
-
const omitted = text.length -
|
|
7415
|
+
const head = safeSlice(text, 0, headSize);
|
|
7416
|
+
const tail = safeSlice(text, text.length - tailSize);
|
|
7417
|
+
const omitted = text.length - head.length - tail.length;
|
|
7279
7418
|
return {
|
|
7280
7419
|
...m,
|
|
7281
|
-
content: `[Tool result compacted: showing ${
|
|
7420
|
+
content: `[Tool result compacted: showing ${head.length} head + ${tail.length} tail of ${text.length} chars.]
|
|
7282
7421
|
${head}
|
|
7283
7422
|
[... ${omitted} chars omitted ...]
|
|
7284
7423
|
${tail}`
|
|
@@ -7288,7 +7427,7 @@ ${tail}`
|
|
|
7288
7427
|
return m;
|
|
7289
7428
|
return {
|
|
7290
7429
|
...m,
|
|
7291
|
-
content: text
|
|
7430
|
+
content: safeSlice(text, 0, maxChars) + `
|
|
7292
7431
|
|
|
7293
7432
|
[... content trimmed from ${text.length} chars]`
|
|
7294
7433
|
};
|
|
@@ -7748,6 +7887,7 @@ var init_cognitive2 = __esm({
|
|
|
7748
7887
|
a2a: CognitiveDepth.D1_Reactive,
|
|
7749
7888
|
comment_response: CognitiveDepth.D1_Reactive,
|
|
7750
7889
|
review: CognitiveDepth.D1_Reactive,
|
|
7890
|
+
requirement_action: CognitiveDepth.D1_Reactive,
|
|
7751
7891
|
task_execution: CognitiveDepth.D2_Deliberative
|
|
7752
7892
|
};
|
|
7753
7893
|
CognitivePreparation = class {
|
|
@@ -8432,7 +8572,8 @@ var init_tool_selector = __esm({
|
|
|
8432
8572
|
title: { type: "string", description: "Short headline (1 line)" },
|
|
8433
8573
|
body: { type: "string", description: "Full message content. Be thorough \u2014 this is what the recipient reads in chat." },
|
|
8434
8574
|
priority: { type: "string", enum: ["low", "normal", "high", "urgent"], description: "Default: normal" },
|
|
8435
|
-
related_task_id: { type: "string", description: "If related to a task, include the task ID for deep-linking" }
|
|
8575
|
+
related_task_id: { type: "string", description: "If related to a task, include the task ID for deep-linking" },
|
|
8576
|
+
target_user_id: { type: "string", description: "User ID to send the message to. If omitted, sends to the user you are currently interacting with (or the team owner)." }
|
|
8436
8577
|
},
|
|
8437
8578
|
required: ["title", "body"]
|
|
8438
8579
|
}
|
|
@@ -8480,6 +8621,22 @@ var init_tool_selector = __esm({
|
|
|
8480
8621
|
required: ["operation"]
|
|
8481
8622
|
}
|
|
8482
8623
|
});
|
|
8624
|
+
pushUnique({
|
|
8625
|
+
name: "complete_deliberation",
|
|
8626
|
+
description: "Finalize your mailbox deliberation. Declare which item to process next, which to defer/drop, and which you handled inline. Only available in deliberation mode.",
|
|
8627
|
+
inputSchema: {
|
|
8628
|
+
type: "object",
|
|
8629
|
+
properties: {
|
|
8630
|
+
process_item_id: { type: "string", description: "ID of the mailbox item to process in full next" },
|
|
8631
|
+
defer_item_ids: { type: "array", items: { type: "string" }, description: "IDs of items to defer for later" },
|
|
8632
|
+
drop_item_ids: { type: "array", items: { type: "string" }, description: "IDs of stale/redundant items to drop" },
|
|
8633
|
+
inline_completed_ids: { type: "array", items: { type: "string" }, description: "IDs of items you already handled inline during this deliberation (e.g., sent a notification, posted a comment)" },
|
|
8634
|
+
reasoning: { type: "string", description: "1-2 sentence explanation of your decision" },
|
|
8635
|
+
situational_awareness: { type: "string", description: "Your current understanding of the situation \u2014 injected into future prompts for continuity" }
|
|
8636
|
+
},
|
|
8637
|
+
required: ["process_item_id", "reasoning"]
|
|
8638
|
+
}
|
|
8639
|
+
});
|
|
8483
8640
|
log10.debug("Tool selection complete", {
|
|
8484
8641
|
total: opts.allTools.size,
|
|
8485
8642
|
selected: result.length,
|
|
@@ -8644,8 +8801,310 @@ var init_security = __esm({
|
|
|
8644
8801
|
}
|
|
8645
8802
|
});
|
|
8646
8803
|
|
|
8647
|
-
// ../core/dist/tools/shell.js
|
|
8804
|
+
// ../core/dist/tools/shell-session.js
|
|
8648
8805
|
import { spawn } from "node:child_process";
|
|
8806
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
8807
|
+
function makeSentinel() {
|
|
8808
|
+
return SENTINEL_PREFIX + randomBytes2(8).toString("hex");
|
|
8809
|
+
}
|
|
8810
|
+
function getShellSessionManager() {
|
|
8811
|
+
if (!_defaultManager) {
|
|
8812
|
+
_defaultManager = new ShellSessionManager();
|
|
8813
|
+
}
|
|
8814
|
+
return _defaultManager;
|
|
8815
|
+
}
|
|
8816
|
+
var SENTINEL_PREFIX, ManagedSession, ShellSessionManager, _defaultManager;
|
|
8817
|
+
var init_shell_session = __esm({
|
|
8818
|
+
"../core/dist/tools/shell-session.js"() {
|
|
8819
|
+
"use strict";
|
|
8820
|
+
init_dist();
|
|
8821
|
+
SENTINEL_PREFIX = "__MARKUS_DONE_";
|
|
8822
|
+
ManagedSession = class {
|
|
8823
|
+
id;
|
|
8824
|
+
agentId;
|
|
8825
|
+
process;
|
|
8826
|
+
createdAt = Date.now();
|
|
8827
|
+
lastUsedAt = Date.now();
|
|
8828
|
+
alive = true;
|
|
8829
|
+
pending = null;
|
|
8830
|
+
dataBuffer = "";
|
|
8831
|
+
idleTimer = null;
|
|
8832
|
+
constructor(id, agentId2, proc) {
|
|
8833
|
+
this.id = id;
|
|
8834
|
+
this.agentId = agentId2;
|
|
8835
|
+
this.process = proc;
|
|
8836
|
+
proc.stdout?.on("data", (chunk) => this.onData(chunk.toString()));
|
|
8837
|
+
proc.stderr?.on("data", (chunk) => this.onData(chunk.toString()));
|
|
8838
|
+
proc.on("exit", () => {
|
|
8839
|
+
this.alive = false;
|
|
8840
|
+
this.rejectPending("Shell session exited unexpectedly");
|
|
8841
|
+
});
|
|
8842
|
+
proc.on("error", () => {
|
|
8843
|
+
this.alive = false;
|
|
8844
|
+
this.rejectPending("Shell session error");
|
|
8845
|
+
});
|
|
8846
|
+
this.resetIdleTimer();
|
|
8847
|
+
}
|
|
8848
|
+
onData(data) {
|
|
8849
|
+
if (!this.pending)
|
|
8850
|
+
return;
|
|
8851
|
+
this.pending.output += data;
|
|
8852
|
+
if (this.pending.output.length > SHELL_SESSION_MAX_OUTPUT_BYTES) {
|
|
8853
|
+
const keep = SHELL_SESSION_MAX_OUTPUT_BYTES - 1e3;
|
|
8854
|
+
this.pending.output = "[... truncated ...]\n" + this.pending.output.slice(-keep);
|
|
8855
|
+
}
|
|
8856
|
+
const sentinelRe = new RegExp(`${this.pending.sentinel}_(\\d+)_
|
|
8857
|
+
?$`);
|
|
8858
|
+
const match2 = this.pending.output.match(sentinelRe);
|
|
8859
|
+
if (match2) {
|
|
8860
|
+
const exitCode = parseInt(match2[1], 10);
|
|
8861
|
+
const output = this.pending.output.slice(0, match2.index).replace(/^\n/, "");
|
|
8862
|
+
clearTimeout(this.pending.timer);
|
|
8863
|
+
const p = this.pending;
|
|
8864
|
+
this.pending = null;
|
|
8865
|
+
this.resetIdleTimer();
|
|
8866
|
+
p.resolve({ stdout: output, exitCode });
|
|
8867
|
+
}
|
|
8868
|
+
}
|
|
8869
|
+
rejectPending(reason) {
|
|
8870
|
+
if (this.pending) {
|
|
8871
|
+
clearTimeout(this.pending.timer);
|
|
8872
|
+
const p = this.pending;
|
|
8873
|
+
this.pending = null;
|
|
8874
|
+
p.resolve({ stdout: p.output + `
|
|
8875
|
+
[${reason}]`, exitCode: -1 });
|
|
8876
|
+
}
|
|
8877
|
+
}
|
|
8878
|
+
resetIdleTimer() {
|
|
8879
|
+
if (this.idleTimer)
|
|
8880
|
+
clearTimeout(this.idleTimer);
|
|
8881
|
+
this.idleTimer = setTimeout(() => this.kill(), SHELL_SESSION_IDLE_TIMEOUT_MS);
|
|
8882
|
+
}
|
|
8883
|
+
/**
|
|
8884
|
+
* Execute a command in this session. Returns when the sentinel is detected
|
|
8885
|
+
* or the timeout fires.
|
|
8886
|
+
*/
|
|
8887
|
+
execute(command, timeoutMs, onOutput) {
|
|
8888
|
+
if (!this.alive) {
|
|
8889
|
+
return Promise.resolve({
|
|
8890
|
+
stdout: "[Session is no longer alive]",
|
|
8891
|
+
exitCode: -1
|
|
8892
|
+
});
|
|
8893
|
+
}
|
|
8894
|
+
if (this.pending) {
|
|
8895
|
+
return Promise.resolve({
|
|
8896
|
+
stdout: "[Session is busy with another command]",
|
|
8897
|
+
exitCode: -1
|
|
8898
|
+
});
|
|
8899
|
+
}
|
|
8900
|
+
this.lastUsedAt = Date.now();
|
|
8901
|
+
if (this.idleTimer)
|
|
8902
|
+
clearTimeout(this.idleTimer);
|
|
8903
|
+
const sentinel = makeSentinel();
|
|
8904
|
+
return new Promise((resolve20) => {
|
|
8905
|
+
const timer = setTimeout(() => {
|
|
8906
|
+
const partial = this.pending?.output ?? "";
|
|
8907
|
+
this.pending = null;
|
|
8908
|
+
this.resetIdleTimer();
|
|
8909
|
+
resolve20({
|
|
8910
|
+
stdout: partial + `
|
|
8911
|
+
[Command timed out after ${timeoutMs}ms]`,
|
|
8912
|
+
exitCode: -1
|
|
8913
|
+
});
|
|
8914
|
+
}, timeoutMs);
|
|
8915
|
+
this.pending = { sentinel, output: "", resolve: resolve20, timer };
|
|
8916
|
+
if (onOutput) {
|
|
8917
|
+
const origOnData = this.onData.bind(this);
|
|
8918
|
+
const origPendingRef = this.pending;
|
|
8919
|
+
let lastLen = 0;
|
|
8920
|
+
const outputPoll = setInterval(() => {
|
|
8921
|
+
if (this.pending !== origPendingRef) {
|
|
8922
|
+
clearInterval(outputPoll);
|
|
8923
|
+
return;
|
|
8924
|
+
}
|
|
8925
|
+
const newContent = this.pending.output.slice(lastLen);
|
|
8926
|
+
if (newContent) {
|
|
8927
|
+
const cleaned = newContent.replace(new RegExp(`echo ${sentinel}_\\$\\?_`), "");
|
|
8928
|
+
if (cleaned)
|
|
8929
|
+
onOutput(cleaned);
|
|
8930
|
+
lastLen = this.pending.output.length;
|
|
8931
|
+
}
|
|
8932
|
+
}, 200);
|
|
8933
|
+
const origResolve = this.pending.resolve;
|
|
8934
|
+
this.pending.resolve = (result) => {
|
|
8935
|
+
clearInterval(outputPoll);
|
|
8936
|
+
origResolve(result);
|
|
8937
|
+
};
|
|
8938
|
+
}
|
|
8939
|
+
const script = `${command}
|
|
8940
|
+
echo ${sentinel}_$?_
|
|
8941
|
+
`;
|
|
8942
|
+
this.process.stdin?.write(script);
|
|
8943
|
+
});
|
|
8944
|
+
}
|
|
8945
|
+
kill() {
|
|
8946
|
+
if (this.idleTimer)
|
|
8947
|
+
clearTimeout(this.idleTimer);
|
|
8948
|
+
this.alive = false;
|
|
8949
|
+
this.rejectPending("Session killed");
|
|
8950
|
+
try {
|
|
8951
|
+
this.process.kill("SIGTERM");
|
|
8952
|
+
setTimeout(() => {
|
|
8953
|
+
try {
|
|
8954
|
+
this.process.kill("SIGKILL");
|
|
8955
|
+
} catch {
|
|
8956
|
+
}
|
|
8957
|
+
}, 1e3);
|
|
8958
|
+
} catch {
|
|
8959
|
+
}
|
|
8960
|
+
}
|
|
8961
|
+
toInfo() {
|
|
8962
|
+
return {
|
|
8963
|
+
id: this.id,
|
|
8964
|
+
agentId: this.agentId,
|
|
8965
|
+
process: this.process,
|
|
8966
|
+
cwd: "",
|
|
8967
|
+
createdAt: this.createdAt,
|
|
8968
|
+
lastUsedAt: this.lastUsedAt,
|
|
8969
|
+
alive: this.alive
|
|
8970
|
+
};
|
|
8971
|
+
}
|
|
8972
|
+
};
|
|
8973
|
+
ShellSessionManager = class {
|
|
8974
|
+
sessions = /* @__PURE__ */ new Map();
|
|
8975
|
+
agentSessions = /* @__PURE__ */ new Map();
|
|
8976
|
+
/**
|
|
8977
|
+
* Get or create the default session for an agent.
|
|
8978
|
+
* If no session exists, one is lazily created.
|
|
8979
|
+
*/
|
|
8980
|
+
getOrCreateDefault(agentId2, cwd) {
|
|
8981
|
+
const defaultId = `${agentId2}:default`;
|
|
8982
|
+
const existing = this.sessions.get(defaultId);
|
|
8983
|
+
if (existing?.alive)
|
|
8984
|
+
return existing;
|
|
8985
|
+
if (existing && !existing.alive) {
|
|
8986
|
+
this.removeSession(defaultId);
|
|
8987
|
+
}
|
|
8988
|
+
return this.createSession(defaultId, agentId2, cwd);
|
|
8989
|
+
}
|
|
8990
|
+
/**
|
|
8991
|
+
* Create a named session for an agent.
|
|
8992
|
+
*/
|
|
8993
|
+
create(agentId2, sessionName, cwd) {
|
|
8994
|
+
const sessionId = `${agentId2}:${sessionName}`;
|
|
8995
|
+
if (this.sessions.has(sessionId)) {
|
|
8996
|
+
const s2 = this.sessions.get(sessionId);
|
|
8997
|
+
if (s2.alive)
|
|
8998
|
+
return s2;
|
|
8999
|
+
this.removeSession(sessionId);
|
|
9000
|
+
}
|
|
9001
|
+
const agentSet = this.agentSessions.get(agentId2) ?? /* @__PURE__ */ new Set();
|
|
9002
|
+
if (agentSet.size >= SHELL_MAX_SESSIONS_PER_AGENT) {
|
|
9003
|
+
return null;
|
|
9004
|
+
}
|
|
9005
|
+
return this.createSession(sessionId, agentId2, cwd);
|
|
9006
|
+
}
|
|
9007
|
+
get(sessionId) {
|
|
9008
|
+
const s2 = this.sessions.get(sessionId);
|
|
9009
|
+
if (s2 && !s2.alive) {
|
|
9010
|
+
this.removeSession(sessionId);
|
|
9011
|
+
return void 0;
|
|
9012
|
+
}
|
|
9013
|
+
return s2;
|
|
9014
|
+
}
|
|
9015
|
+
/**
|
|
9016
|
+
* Execute a command in the given session (or agent default).
|
|
9017
|
+
*/
|
|
9018
|
+
async execute(agentId2, command, options) {
|
|
9019
|
+
const timeoutMs = Math.min(options?.timeoutMs ?? SHELL_TIMEOUT_DEFAULT_MS, SHELL_TIMEOUT_MAX_MS);
|
|
9020
|
+
let session;
|
|
9021
|
+
if (options?.sessionId) {
|
|
9022
|
+
session = this.get(options.sessionId);
|
|
9023
|
+
if (!session) {
|
|
9024
|
+
return { stdout: `[Session ${options.sessionId} not found]`, exitCode: -1 };
|
|
9025
|
+
}
|
|
9026
|
+
} else {
|
|
9027
|
+
session = this.getOrCreateDefault(agentId2, options?.cwd);
|
|
9028
|
+
}
|
|
9029
|
+
if (options?.cwd) {
|
|
9030
|
+
const cdResult = await session.execute(`cd ${JSON.stringify(options.cwd)} 2>/dev/null`, 5e3);
|
|
9031
|
+
if (cdResult.exitCode !== 0) {
|
|
9032
|
+
return { stdout: `[Failed to cd to ${options.cwd}]`, exitCode: -1 };
|
|
9033
|
+
}
|
|
9034
|
+
}
|
|
9035
|
+
return session.execute(command, timeoutMs, options?.onOutput);
|
|
9036
|
+
}
|
|
9037
|
+
listForAgent(agentId2) {
|
|
9038
|
+
const ids = this.agentSessions.get(agentId2);
|
|
9039
|
+
if (!ids)
|
|
9040
|
+
return [];
|
|
9041
|
+
const result = [];
|
|
9042
|
+
for (const id of ids) {
|
|
9043
|
+
const s2 = this.sessions.get(id);
|
|
9044
|
+
if (s2?.alive)
|
|
9045
|
+
result.push(s2.toInfo());
|
|
9046
|
+
}
|
|
9047
|
+
return result;
|
|
9048
|
+
}
|
|
9049
|
+
killSession(sessionId) {
|
|
9050
|
+
const s2 = this.sessions.get(sessionId);
|
|
9051
|
+
if (!s2)
|
|
9052
|
+
return false;
|
|
9053
|
+
s2.kill();
|
|
9054
|
+
this.removeSession(sessionId);
|
|
9055
|
+
return true;
|
|
9056
|
+
}
|
|
9057
|
+
killAllForAgent(agentId2) {
|
|
9058
|
+
const ids = this.agentSessions.get(agentId2);
|
|
9059
|
+
if (!ids)
|
|
9060
|
+
return;
|
|
9061
|
+
for (const id of [...ids]) {
|
|
9062
|
+
this.killSession(id);
|
|
9063
|
+
}
|
|
9064
|
+
}
|
|
9065
|
+
destroyAll() {
|
|
9066
|
+
for (const [id, s2] of this.sessions) {
|
|
9067
|
+
s2.kill();
|
|
9068
|
+
}
|
|
9069
|
+
this.sessions.clear();
|
|
9070
|
+
this.agentSessions.clear();
|
|
9071
|
+
}
|
|
9072
|
+
createSession(sessionId, agentId2, cwd) {
|
|
9073
|
+
const shell = process.env["SHELL"] || "/bin/sh";
|
|
9074
|
+
const child = spawn(shell, ["--norc", "--noprofile", "-i"], {
|
|
9075
|
+
cwd: cwd ?? process.cwd(),
|
|
9076
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
9077
|
+
env: {
|
|
9078
|
+
...process.env,
|
|
9079
|
+
PS1: "",
|
|
9080
|
+
PS2: "",
|
|
9081
|
+
PROMPT_COMMAND: "",
|
|
9082
|
+
TERM: "dumb"
|
|
9083
|
+
}
|
|
9084
|
+
});
|
|
9085
|
+
const session = new ManagedSession(sessionId, agentId2, child);
|
|
9086
|
+
this.sessions.set(sessionId, session);
|
|
9087
|
+
const agentSet = this.agentSessions.get(agentId2) ?? /* @__PURE__ */ new Set();
|
|
9088
|
+
agentSet.add(sessionId);
|
|
9089
|
+
this.agentSessions.set(agentId2, agentSet);
|
|
9090
|
+
return session;
|
|
9091
|
+
}
|
|
9092
|
+
removeSession(sessionId) {
|
|
9093
|
+
const s2 = this.sessions.get(sessionId);
|
|
9094
|
+
if (s2) {
|
|
9095
|
+
const agentSet = this.agentSessions.get(s2.agentId);
|
|
9096
|
+
agentSet?.delete(sessionId);
|
|
9097
|
+
if (agentSet?.size === 0)
|
|
9098
|
+
this.agentSessions.delete(s2.agentId);
|
|
9099
|
+
}
|
|
9100
|
+
this.sessions.delete(sessionId);
|
|
9101
|
+
}
|
|
9102
|
+
};
|
|
9103
|
+
}
|
|
9104
|
+
});
|
|
9105
|
+
|
|
9106
|
+
// ../core/dist/tools/shell.js
|
|
9107
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
8649
9108
|
import { resolve as resolve4, normalize, sep } from "node:path";
|
|
8650
9109
|
function injectGitCommitMeta(command, meta) {
|
|
8651
9110
|
if (!meta)
|
|
@@ -8718,6 +9177,10 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8718
9177
|
timeout_ms: {
|
|
8719
9178
|
type: "number",
|
|
8720
9179
|
description: `Timeout in milliseconds (default: ${SHELL_TIMEOUT_DEFAULT_MS}, max: ${SHELL_TIMEOUT_MAX_MS})`
|
|
9180
|
+
},
|
|
9181
|
+
session_id: {
|
|
9182
|
+
type: "string",
|
|
9183
|
+
description: "Reuse a persistent shell session by name. State (cwd, env vars, shell variables) persists across calls with the same session_id. Omit to use the default session."
|
|
8721
9184
|
}
|
|
8722
9185
|
},
|
|
8723
9186
|
required: ["command"]
|
|
@@ -8774,22 +9237,71 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8774
9237
|
}
|
|
8775
9238
|
}
|
|
8776
9239
|
const finalCommand = injectGitCommitMeta(command, agentMeta);
|
|
9240
|
+
const sessionId = args["session_id"];
|
|
9241
|
+
if (agentMeta?.agentId) {
|
|
9242
|
+
try {
|
|
9243
|
+
const mgr = getShellSessionManager();
|
|
9244
|
+
const result = await mgr.execute(agentMeta.agentId, finalCommand, {
|
|
9245
|
+
sessionId: sessionId ? `${agentMeta.agentId}:${sessionId}` : void 0,
|
|
9246
|
+
cwd: effectiveCwd ?? void 0,
|
|
9247
|
+
timeoutMs,
|
|
9248
|
+
onOutput: onOutput ? (chunk) => onOutput(sanitizeForLLM(chunk)) : void 0
|
|
9249
|
+
});
|
|
9250
|
+
const stdout = sanitizeForLLM(result.stdout);
|
|
9251
|
+
if (result.exitCode !== 0) {
|
|
9252
|
+
return JSON.stringify({
|
|
9253
|
+
status: "error",
|
|
9254
|
+
error: `Process exited with code ${result.exitCode}`,
|
|
9255
|
+
exitCode: result.exitCode,
|
|
9256
|
+
stdout: stdout.slice(0, 4e3)
|
|
9257
|
+
});
|
|
9258
|
+
}
|
|
9259
|
+
return JSON.stringify({
|
|
9260
|
+
status: "success",
|
|
9261
|
+
stdout: stdout.trim() || void 0
|
|
9262
|
+
});
|
|
9263
|
+
} catch {
|
|
9264
|
+
}
|
|
9265
|
+
}
|
|
8777
9266
|
return new Promise((resolve20) => {
|
|
8778
|
-
|
|
9267
|
+
let settled = false;
|
|
9268
|
+
const settle = (result) => {
|
|
9269
|
+
if (settled)
|
|
9270
|
+
return;
|
|
9271
|
+
settled = true;
|
|
9272
|
+
resolve20(result);
|
|
9273
|
+
};
|
|
9274
|
+
const child = spawn2("sh", ["-c", finalCommand], {
|
|
8779
9275
|
cwd: effectiveCwd ?? void 0,
|
|
8780
9276
|
stdio: ["ignore", "pipe", "pipe"],
|
|
9277
|
+
detached: true,
|
|
8781
9278
|
env: { ...process.env }
|
|
8782
9279
|
});
|
|
9280
|
+
child.unref();
|
|
8783
9281
|
let stdout = "";
|
|
8784
9282
|
let stderr = "";
|
|
8785
9283
|
let killed = false;
|
|
8786
9284
|
const maxBuffer = 10 * 1024 * 1024;
|
|
8787
9285
|
const timeout = setTimeout(() => {
|
|
8788
9286
|
killed = true;
|
|
8789
|
-
|
|
9287
|
+
try {
|
|
9288
|
+
process.kill(-child.pid, "SIGTERM");
|
|
9289
|
+
} catch {
|
|
9290
|
+
}
|
|
8790
9291
|
setTimeout(() => {
|
|
8791
|
-
|
|
8792
|
-
|
|
9292
|
+
try {
|
|
9293
|
+
process.kill(-child.pid, "SIGKILL");
|
|
9294
|
+
} catch {
|
|
9295
|
+
}
|
|
9296
|
+
child.stdout?.destroy();
|
|
9297
|
+
child.stderr?.destroy();
|
|
9298
|
+
settle(JSON.stringify({
|
|
9299
|
+
status: "error",
|
|
9300
|
+
error: `Command timed out after ${timeoutMs}ms`,
|
|
9301
|
+
exitCode: null,
|
|
9302
|
+
stdout: sanitizeForLLM(stdout).slice(0, 4e3),
|
|
9303
|
+
stderr: sanitizeForLLM(stderr).slice(0, 4e3)
|
|
9304
|
+
}));
|
|
8793
9305
|
}, 2e3);
|
|
8794
9306
|
}, timeoutMs);
|
|
8795
9307
|
let outputBuffer = "";
|
|
@@ -8828,27 +9340,29 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8828
9340
|
clearTimeout(flushTimer);
|
|
8829
9341
|
flushOutput();
|
|
8830
9342
|
}
|
|
9343
|
+
const cleanOut = sanitizeForLLM(stdout);
|
|
9344
|
+
const cleanErr = sanitizeForLLM(stderr);
|
|
8831
9345
|
if (killed) {
|
|
8832
|
-
|
|
9346
|
+
settle(JSON.stringify({
|
|
8833
9347
|
status: "error",
|
|
8834
9348
|
error: `Command timed out after ${timeoutMs}ms`,
|
|
8835
9349
|
exitCode: code,
|
|
8836
|
-
stdout:
|
|
8837
|
-
stderr:
|
|
9350
|
+
stdout: cleanOut.slice(0, 4e3),
|
|
9351
|
+
stderr: cleanErr.slice(0, 4e3)
|
|
8838
9352
|
}));
|
|
8839
9353
|
} else if (code !== 0) {
|
|
8840
|
-
|
|
9354
|
+
settle(JSON.stringify({
|
|
8841
9355
|
status: "error",
|
|
8842
|
-
error:
|
|
9356
|
+
error: cleanErr.trim() || `Process exited with code ${code}`,
|
|
8843
9357
|
exitCode: code,
|
|
8844
|
-
stdout:
|
|
8845
|
-
stderr:
|
|
9358
|
+
stdout: cleanOut.slice(0, 4e3),
|
|
9359
|
+
stderr: cleanErr.slice(0, 4e3)
|
|
8846
9360
|
}));
|
|
8847
9361
|
} else {
|
|
8848
|
-
|
|
9362
|
+
settle(JSON.stringify({
|
|
8849
9363
|
status: "success",
|
|
8850
|
-
stdout:
|
|
8851
|
-
stderr:
|
|
9364
|
+
stdout: cleanOut.trim() || void 0,
|
|
9365
|
+
stderr: cleanErr.trim() || void 0
|
|
8852
9366
|
}));
|
|
8853
9367
|
}
|
|
8854
9368
|
});
|
|
@@ -8858,11 +9372,11 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8858
9372
|
clearTimeout(flushTimer);
|
|
8859
9373
|
flushOutput();
|
|
8860
9374
|
}
|
|
8861
|
-
|
|
9375
|
+
settle(JSON.stringify({
|
|
8862
9376
|
status: "error",
|
|
8863
9377
|
error: err.message,
|
|
8864
|
-
stdout: stdout.slice(0, 4e3),
|
|
8865
|
-
stderr: stderr.slice(0, 4e3)
|
|
9378
|
+
stdout: sanitizeForLLM(stdout).slice(0, 4e3),
|
|
9379
|
+
stderr: sanitizeForLLM(stderr).slice(0, 4e3)
|
|
8866
9380
|
}));
|
|
8867
9381
|
});
|
|
8868
9382
|
});
|
|
@@ -8875,6 +9389,7 @@ var init_shell = __esm({
|
|
|
8875
9389
|
"use strict";
|
|
8876
9390
|
init_dist();
|
|
8877
9391
|
init_security();
|
|
9392
|
+
init_shell_session();
|
|
8878
9393
|
GIT_ALWAYS_DENY = [];
|
|
8879
9394
|
GIT_NEEDS_APPROVAL = [
|
|
8880
9395
|
{ pattern: /\bgit\s+push\s+--force/, label: "force push (--force)" },
|
|
@@ -41343,44 +41858,32 @@ async function searchBrave(query2, maxResults) {
|
|
|
41343
41858
|
date: r.page_age
|
|
41344
41859
|
}));
|
|
41345
41860
|
}
|
|
41346
|
-
async function
|
|
41347
|
-
const
|
|
41861
|
+
async function searchBocha(query2, maxResults) {
|
|
41862
|
+
const apiKey = process.env["BOCHA_API_KEY"];
|
|
41863
|
+
if (!apiKey)
|
|
41864
|
+
throw new Error("BOCHA_API_KEY not configured");
|
|
41348
41865
|
let res;
|
|
41349
41866
|
try {
|
|
41350
|
-
res = await proxyFetch(
|
|
41351
|
-
|
|
41867
|
+
res = await proxyFetch("https://api.bochaai.com/v1/web-search", {
|
|
41868
|
+
method: "POST",
|
|
41869
|
+
headers: {
|
|
41870
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
41871
|
+
"Content-Type": "application/json"
|
|
41872
|
+
},
|
|
41873
|
+
body: JSON.stringify({ query: query2, count: maxResults, summary: true })
|
|
41352
41874
|
});
|
|
41353
41875
|
} catch (err) {
|
|
41354
41876
|
throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
41355
41877
|
}
|
|
41356
41878
|
if (!res.ok)
|
|
41357
41879
|
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
41358
|
-
const
|
|
41359
|
-
|
|
41360
|
-
|
|
41361
|
-
|
|
41362
|
-
|
|
41363
|
-
|
|
41364
|
-
|
|
41365
|
-
const results = [];
|
|
41366
|
-
const algoRegex = /<li[^>]*class="b_algo"[^>]*>([\s\S]*?)<\/li>/g;
|
|
41367
|
-
let match2;
|
|
41368
|
-
while ((match2 = algoRegex.exec(html)) !== null) {
|
|
41369
|
-
if (results.length >= max)
|
|
41370
|
-
break;
|
|
41371
|
-
const item = match2[1];
|
|
41372
|
-
const linkMatch = item.match(/<a[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/i);
|
|
41373
|
-
if (!linkMatch)
|
|
41374
|
-
continue;
|
|
41375
|
-
const url = linkMatch[1];
|
|
41376
|
-
const title = stripHtml(linkMatch[2]);
|
|
41377
|
-
if (!url || !title)
|
|
41378
|
-
continue;
|
|
41379
|
-
const snippetMatch = item.match(/<p[^>]*>([\s\S]*?)<\/p>/i);
|
|
41380
|
-
const snippet = snippetMatch ? stripHtml(snippetMatch[1]) : "";
|
|
41381
|
-
results.push({ title, url, snippet });
|
|
41382
|
-
}
|
|
41383
|
-
return results;
|
|
41880
|
+
const data = await res.json();
|
|
41881
|
+
return (data.webPages?.value ?? []).slice(0, maxResults).map((r) => ({
|
|
41882
|
+
title: r.name,
|
|
41883
|
+
url: r.url,
|
|
41884
|
+
snippet: r.summary || r.snippet,
|
|
41885
|
+
date: r.datePublished
|
|
41886
|
+
}));
|
|
41384
41887
|
}
|
|
41385
41888
|
async function searchDuckDuckGo(query2, maxResults) {
|
|
41386
41889
|
const encoded = encodeURIComponent(query2);
|
|
@@ -41470,7 +41973,7 @@ function parseDDGHtml(html, maxResults) {
|
|
|
41470
41973
|
function stripHtml(html) {
|
|
41471
41974
|
return html.replace(/<[^>]*>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'").replace(/ /g, " ").replace(/\s+/g, " ").trim();
|
|
41472
41975
|
}
|
|
41473
|
-
var SEARCH_TIMEOUT_MS, _dispatcher, WebSearchTool,
|
|
41976
|
+
var SEARCH_TIMEOUT_MS, _dispatcher, WebSearchTool, DDG_UA, DDG_ENDPOINTS;
|
|
41474
41977
|
var init_web_search = __esm({
|
|
41475
41978
|
"../core/dist/tools/web-search.js"() {
|
|
41476
41979
|
"use strict";
|
|
@@ -41499,7 +42002,7 @@ var init_web_search = __esm({
|
|
|
41499
42002
|
const backends = [
|
|
41500
42003
|
{ name: "Serper", fn: searchSerper },
|
|
41501
42004
|
{ name: "Brave", fn: searchBrave },
|
|
41502
|
-
{ name: "
|
|
42005
|
+
{ name: "Bocha", fn: searchBocha },
|
|
41503
42006
|
{ name: "DuckDuckGo", fn: searchDuckDuckGo }
|
|
41504
42007
|
];
|
|
41505
42008
|
const errors = [];
|
|
@@ -41531,7 +42034,6 @@ var init_web_search = __esm({
|
|
|
41531
42034
|
});
|
|
41532
42035
|
}
|
|
41533
42036
|
};
|
|
41534
|
-
BING_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
|
|
41535
42037
|
DDG_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36";
|
|
41536
42038
|
DDG_ENDPOINTS = [
|
|
41537
42039
|
"https://lite.duckduckgo.com/lite/",
|
|
@@ -42106,7 +42608,7 @@ var init_patch = __esm({
|
|
|
42106
42608
|
});
|
|
42107
42609
|
|
|
42108
42610
|
// ../core/dist/tools/process-manager.js
|
|
42109
|
-
import { spawn as
|
|
42611
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
42110
42612
|
import { resolve as resolve7 } from "node:path";
|
|
42111
42613
|
function onBackgroundCompletion(cb) {
|
|
42112
42614
|
completionListeners.push(cb);
|
|
@@ -42174,7 +42676,7 @@ function createBackgroundExecTool(workspacePath) {
|
|
|
42174
42676
|
return JSON.stringify({ status: "denied", error: "Working directory must be within workspace" });
|
|
42175
42677
|
}
|
|
42176
42678
|
const id = `bg_${++sessionCounter}_${Date.now()}`;
|
|
42177
|
-
const child =
|
|
42679
|
+
const child = spawn3("sh", ["-c", command], {
|
|
42178
42680
|
cwd: effectiveCwd,
|
|
42179
42681
|
stdio: ["ignore", "pipe", "pipe"]
|
|
42180
42682
|
});
|
|
@@ -43392,6 +43894,8 @@ var init_attention = __esm({
|
|
|
43392
43894
|
triageToolHandlers;
|
|
43393
43895
|
triageChatFn;
|
|
43394
43896
|
lastTriageResult;
|
|
43897
|
+
/** True while a full-session deliberation is in progress (suppresses yield points). */
|
|
43898
|
+
isDeliberating = false;
|
|
43395
43899
|
/** Tracks whether the last yield-point decision was 'cancel' vs 'preempt'. */
|
|
43396
43900
|
lastYieldDecision;
|
|
43397
43901
|
unsubscribeNewItem;
|
|
@@ -43534,50 +44038,22 @@ var init_attention = __esm({
|
|
|
43534
44038
|
}
|
|
43535
44039
|
}
|
|
43536
44040
|
let triaged = false;
|
|
43537
|
-
if (this.mailbox.depth > 0 && this.
|
|
43538
|
-
|
|
43539
|
-
|
|
43540
|
-
|
|
43541
|
-
|
|
43542
|
-
|
|
43543
|
-
|
|
43544
|
-
|
|
43545
|
-
|
|
43546
|
-
} else {
|
|
43547
|
-
const redequeued = this.mailbox.dequeueById(item.id);
|
|
43548
|
-
if (redequeued)
|
|
43549
|
-
item = redequeued;
|
|
43550
|
-
}
|
|
44041
|
+
if (this.mailbox.depth > 0 && this.needsLLMTriage(item) && (this.delegate?.performDeliberation || this.triageJudge)) {
|
|
44042
|
+
if (this.delegate?.performDeliberation) {
|
|
44043
|
+
const allItems = [item, ...this.mailbox.getQueuedItems()];
|
|
44044
|
+
this.isDeliberating = true;
|
|
44045
|
+
const deliberationResult = await this.delegate.performDeliberation(item, allItems);
|
|
44046
|
+
this.isDeliberating = false;
|
|
44047
|
+
if (deliberationResult) {
|
|
44048
|
+
triaged = true;
|
|
44049
|
+
item = this.applyDeliberationResult(item, deliberationResult);
|
|
43551
44050
|
}
|
|
43552
|
-
|
|
43553
|
-
const
|
|
43554
|
-
|
|
43555
|
-
|
|
43556
|
-
|
|
43557
|
-
if (it.sourceType === "human_chat")
|
|
43558
|
-
return true;
|
|
43559
|
-
if (it.payload.extra?.triggerExecution)
|
|
43560
|
-
return true;
|
|
43561
|
-
return false;
|
|
43562
|
-
};
|
|
43563
|
-
for (const deferId of triageResult.deferItemIds) {
|
|
43564
|
-
if (isProtected(deferId))
|
|
43565
|
-
continue;
|
|
43566
|
-
this.mailbox.defer(deferId);
|
|
43567
|
-
}
|
|
43568
|
-
for (const dropId of triageResult.dropItemIds) {
|
|
43569
|
-
if (isProtected(dropId))
|
|
43570
|
-
continue;
|
|
43571
|
-
this.mailbox.drop(dropId);
|
|
44051
|
+
} else {
|
|
44052
|
+
const triageResult = await this.performTriage(item);
|
|
44053
|
+
if (triageResult) {
|
|
44054
|
+
triaged = true;
|
|
44055
|
+
item = this.applyTriageResult(item, triageResult);
|
|
43572
44056
|
}
|
|
43573
|
-
this.lastTriageResult = { ...triageResult, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
43574
|
-
this.delegate?.onTriageCompleted?.(triageResult);
|
|
43575
|
-
this.eventBus.emit("attention:triage", {
|
|
43576
|
-
agentId: this.agentId,
|
|
43577
|
-
triage: this.lastTriageResult
|
|
43578
|
-
});
|
|
43579
|
-
const triageDecision = this.recordDecision("triage", item, triageResult.reasoning);
|
|
43580
|
-
this.delegate?.onDecisionMade(triageDecision);
|
|
43581
44057
|
}
|
|
43582
44058
|
}
|
|
43583
44059
|
if (!triaged) {
|
|
@@ -43744,6 +44220,9 @@ var init_attention = __esm({
|
|
|
43744
44220
|
* - 'merge' → item was absorbed into current work (caller may inject into session)
|
|
43745
44221
|
*/
|
|
43746
44222
|
async checkYieldPoint() {
|
|
44223
|
+
if (this.isDeliberating) {
|
|
44224
|
+
return { decision: "continue" };
|
|
44225
|
+
}
|
|
43747
44226
|
if (!this.interruptSignal || !this.currentFocus) {
|
|
43748
44227
|
return { decision: "continue" };
|
|
43749
44228
|
}
|
|
@@ -43959,8 +44438,10 @@ var init_attention = __esm({
|
|
|
43959
44438
|
description: t.description,
|
|
43960
44439
|
inputSchema: t.inputSchema
|
|
43961
44440
|
}));
|
|
44441
|
+
const triageAgentName = ctx?.agentName ?? "Agent";
|
|
44442
|
+
const triageRoleHint = ctx?.agentRole ? ` Your role: ${ctx.agentRole}.` : "";
|
|
43962
44443
|
const messages = [
|
|
43963
|
-
{ role: "system", content:
|
|
44444
|
+
{ role: "system", content: `You are ${triageAgentName}, deliberating over your mailbox.${triageRoleHint} You may call tools to gather context before making your decision. When ready, output ONLY a single JSON object \u2014 no explanation, no markdown fences, no <think> tags. Start your response with {` },
|
|
43964
44445
|
{ role: "user", content: prompt }
|
|
43965
44446
|
];
|
|
43966
44447
|
let iterations = 0;
|
|
@@ -44028,6 +44509,120 @@ var init_attention = __esm({
|
|
|
44028
44509
|
return null;
|
|
44029
44510
|
}
|
|
44030
44511
|
}
|
|
44512
|
+
/**
|
|
44513
|
+
* Apply a TriageResult to the mailbox: reorder, defer, drop items.
|
|
44514
|
+
* Returns the item to process next.
|
|
44515
|
+
*/
|
|
44516
|
+
applyTriageResult(currentItem, triageResult) {
|
|
44517
|
+
let item = currentItem;
|
|
44518
|
+
if (triageResult.processItemId !== item.id) {
|
|
44519
|
+
this.mailbox.putBack(item);
|
|
44520
|
+
const chosen = this.mailbox.dequeueById(triageResult.processItemId);
|
|
44521
|
+
if (chosen) {
|
|
44522
|
+
item = chosen;
|
|
44523
|
+
} else {
|
|
44524
|
+
const redequeued = this.mailbox.dequeueById(currentItem.id);
|
|
44525
|
+
if (redequeued)
|
|
44526
|
+
item = redequeued;
|
|
44527
|
+
}
|
|
44528
|
+
}
|
|
44529
|
+
const queueSnapshot = this.mailbox.getQueuedItems();
|
|
44530
|
+
const isProtected = (id) => {
|
|
44531
|
+
const it = queueSnapshot.find((i) => i.id === id);
|
|
44532
|
+
if (!it)
|
|
44533
|
+
return false;
|
|
44534
|
+
if (it.sourceType === "human_chat")
|
|
44535
|
+
return true;
|
|
44536
|
+
if (it.payload.extra?.triggerExecution)
|
|
44537
|
+
return true;
|
|
44538
|
+
return false;
|
|
44539
|
+
};
|
|
44540
|
+
for (const deferId of triageResult.deferItemIds) {
|
|
44541
|
+
if (isProtected(deferId))
|
|
44542
|
+
continue;
|
|
44543
|
+
this.mailbox.defer(deferId);
|
|
44544
|
+
}
|
|
44545
|
+
for (const dropId of triageResult.dropItemIds) {
|
|
44546
|
+
if (isProtected(dropId))
|
|
44547
|
+
continue;
|
|
44548
|
+
this.mailbox.drop(dropId);
|
|
44549
|
+
}
|
|
44550
|
+
this.lastTriageResult = { ...triageResult, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
44551
|
+
this.delegate?.onTriageCompleted?.(triageResult);
|
|
44552
|
+
this.eventBus.emit("attention:triage", {
|
|
44553
|
+
agentId: this.agentId,
|
|
44554
|
+
triage: this.lastTriageResult
|
|
44555
|
+
});
|
|
44556
|
+
const triageDecision = this.recordDecision("triage", item, triageResult.reasoning);
|
|
44557
|
+
this.delegate?.onDecisionMade(triageDecision);
|
|
44558
|
+
return item;
|
|
44559
|
+
}
|
|
44560
|
+
/**
|
|
44561
|
+
* Apply a DeliberationResult to the mailbox: handle inline completions, reorder, defer, drop.
|
|
44562
|
+
* Returns the item to process next.
|
|
44563
|
+
*/
|
|
44564
|
+
applyDeliberationResult(currentItem, result) {
|
|
44565
|
+
let item = currentItem;
|
|
44566
|
+
const queueSnapshot = this.mailbox.getQueuedItems();
|
|
44567
|
+
const isProtected = (id) => {
|
|
44568
|
+
const it = queueSnapshot.find((i) => i.id === id);
|
|
44569
|
+
if (!it)
|
|
44570
|
+
return false;
|
|
44571
|
+
if (it.sourceType === "human_chat")
|
|
44572
|
+
return true;
|
|
44573
|
+
if (it.payload.extra?.triggerExecution)
|
|
44574
|
+
return true;
|
|
44575
|
+
return false;
|
|
44576
|
+
};
|
|
44577
|
+
for (const completedId of result.inlineCompletedIds) {
|
|
44578
|
+
if (isProtected(completedId))
|
|
44579
|
+
continue;
|
|
44580
|
+
if (completedId === currentItem.id)
|
|
44581
|
+
continue;
|
|
44582
|
+
const completedItem = queueSnapshot.find((i) => i.id === completedId);
|
|
44583
|
+
this.mailbox.complete(completedId);
|
|
44584
|
+
if (completedItem) {
|
|
44585
|
+
this.recordDecision("complete", completedItem, "Handled inline during deliberation");
|
|
44586
|
+
}
|
|
44587
|
+
}
|
|
44588
|
+
if (result.processItemId !== item.id) {
|
|
44589
|
+
this.mailbox.putBack(item);
|
|
44590
|
+
const chosen = this.mailbox.dequeueById(result.processItemId);
|
|
44591
|
+
if (chosen) {
|
|
44592
|
+
item = chosen;
|
|
44593
|
+
} else {
|
|
44594
|
+
const redequeued = this.mailbox.dequeueById(currentItem.id);
|
|
44595
|
+
if (redequeued)
|
|
44596
|
+
item = redequeued;
|
|
44597
|
+
}
|
|
44598
|
+
}
|
|
44599
|
+
for (const deferId of result.deferItemIds) {
|
|
44600
|
+
if (isProtected(deferId))
|
|
44601
|
+
continue;
|
|
44602
|
+
this.mailbox.defer(deferId);
|
|
44603
|
+
}
|
|
44604
|
+
for (const dropId of result.dropItemIds) {
|
|
44605
|
+
if (isProtected(dropId))
|
|
44606
|
+
continue;
|
|
44607
|
+
this.mailbox.drop(dropId);
|
|
44608
|
+
}
|
|
44609
|
+
const triageEquivalent = {
|
|
44610
|
+
processItemId: result.processItemId,
|
|
44611
|
+
deferItemIds: result.deferItemIds,
|
|
44612
|
+
dropItemIds: result.dropItemIds,
|
|
44613
|
+
inlineCompletedIds: result.inlineCompletedIds,
|
|
44614
|
+
reasoning: result.reasoning
|
|
44615
|
+
};
|
|
44616
|
+
this.lastTriageResult = { ...triageEquivalent, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
44617
|
+
this.delegate?.onDeliberationCompleted?.(result);
|
|
44618
|
+
this.eventBus.emit("attention:triage", {
|
|
44619
|
+
agentId: this.agentId,
|
|
44620
|
+
triage: this.lastTriageResult
|
|
44621
|
+
});
|
|
44622
|
+
const triageDecision = this.recordDecision("triage", item, `[deliberation] ${result.reasoning}`);
|
|
44623
|
+
this.delegate?.onDecisionMade(triageDecision);
|
|
44624
|
+
return item;
|
|
44625
|
+
}
|
|
44031
44626
|
buildTriagePrompt(headItem, ctx) {
|
|
44032
44627
|
const agentName = ctx?.agentName ?? "Agent";
|
|
44033
44628
|
const queuedItems = this.mailbox.getQueuedItems();
|
|
@@ -44149,6 +44744,7 @@ var init_attention = __esm({
|
|
|
44149
44744
|
processedItemId: this.lastTriageResult.processItemId,
|
|
44150
44745
|
deferredItemIds: this.lastTriageResult.deferItemIds,
|
|
44151
44746
|
droppedItemIds: this.lastTriageResult.dropItemIds,
|
|
44747
|
+
inlineCompletedIds: this.lastTriageResult.inlineCompletedIds ?? [],
|
|
44152
44748
|
timestamp: this.lastTriageResult.timestamp
|
|
44153
44749
|
} : void 0
|
|
44154
44750
|
};
|
|
@@ -44952,7 +45548,8 @@ var init_tool_loop_detector = __esm({
|
|
|
44952
45548
|
detectors: {
|
|
44953
45549
|
genericRepeat: true,
|
|
44954
45550
|
pingPong: true,
|
|
44955
|
-
noProgress: true
|
|
45551
|
+
noProgress: true,
|
|
45552
|
+
sameToolBurst: true
|
|
44956
45553
|
}
|
|
44957
45554
|
};
|
|
44958
45555
|
ToolLoopDetector = class {
|
|
@@ -44991,6 +45588,11 @@ var init_tool_loop_detector = __esm({
|
|
|
44991
45588
|
if (result.detected)
|
|
44992
45589
|
return result;
|
|
44993
45590
|
}
|
|
45591
|
+
if (this.config.detectors.sameToolBurst) {
|
|
45592
|
+
const result = this.detectSameToolBurst();
|
|
45593
|
+
if (result.detected)
|
|
45594
|
+
return result;
|
|
45595
|
+
}
|
|
44994
45596
|
return { detected: false, severity: "none", pattern: "", message: "" };
|
|
44995
45597
|
}
|
|
44996
45598
|
/**
|
|
@@ -45085,6 +45687,38 @@ var init_tool_loop_detector = __esm({
|
|
|
45085
45687
|
}
|
|
45086
45688
|
return noDetection();
|
|
45087
45689
|
}
|
|
45690
|
+
/**
|
|
45691
|
+
* Detects: a single tool called many times consecutively, even with different
|
|
45692
|
+
* args/results each time. Catches "semantic loops" where the agent retries
|
|
45693
|
+
* variations of the same approach (e.g., different shell commands to debug
|
|
45694
|
+
* the same failing server) without switching strategy.
|
|
45695
|
+
*/
|
|
45696
|
+
detectSameToolBurst() {
|
|
45697
|
+
if (this.history.length < this.config.warningThreshold)
|
|
45698
|
+
return noDetection();
|
|
45699
|
+
const last = this.history[this.history.length - 1];
|
|
45700
|
+
let streak = 1;
|
|
45701
|
+
for (let i = this.history.length - 2; i >= 0; i--) {
|
|
45702
|
+
if (this.history[i].name === last.name) {
|
|
45703
|
+
streak++;
|
|
45704
|
+
} else {
|
|
45705
|
+
break;
|
|
45706
|
+
}
|
|
45707
|
+
}
|
|
45708
|
+
const burstCritical = this.config.criticalThreshold + 2;
|
|
45709
|
+
const burstWarning = this.config.warningThreshold + 2;
|
|
45710
|
+
if (streak >= burstCritical) {
|
|
45711
|
+
const msg = `Critical: "${last.name}" called ${streak} times consecutively (with varying arguments) \u2014 likely stuck in a retry loop`;
|
|
45712
|
+
log15.warn(msg);
|
|
45713
|
+
return { detected: true, severity: "critical", pattern: "sameToolBurst", message: msg };
|
|
45714
|
+
}
|
|
45715
|
+
if (streak >= burstWarning) {
|
|
45716
|
+
const msg = `Warning: "${last.name}" called ${streak} times consecutively \u2014 consider a different approach`;
|
|
45717
|
+
log15.warn(msg);
|
|
45718
|
+
return { detected: true, severity: "warning", pattern: "sameToolBurst", message: msg };
|
|
45719
|
+
}
|
|
45720
|
+
return noDetection();
|
|
45721
|
+
}
|
|
45088
45722
|
reset() {
|
|
45089
45723
|
this.history = [];
|
|
45090
45724
|
}
|
|
@@ -45314,6 +45948,7 @@ var init_agent2 = __esm({
|
|
|
45314
45948
|
semanticSearch;
|
|
45315
45949
|
currentSessionId;
|
|
45316
45950
|
currentInteractingUserId;
|
|
45951
|
+
pendingDeliberationResult;
|
|
45317
45952
|
dbSessionMap = /* @__PURE__ */ new Map();
|
|
45318
45953
|
orgContext;
|
|
45319
45954
|
contextMdPath;
|
|
@@ -45722,6 +46357,12 @@ ${notification.stdoutTail}`);
|
|
|
45722
46357
|
getAttentionController() {
|
|
45723
46358
|
return this.attentionController;
|
|
45724
46359
|
}
|
|
46360
|
+
/** Retrieve and clear the pending deliberation result (set by complete_deliberation tool). */
|
|
46361
|
+
consumeDeliberationResult() {
|
|
46362
|
+
const result = this.pendingDeliberationResult;
|
|
46363
|
+
this.pendingDeliberationResult = void 0;
|
|
46364
|
+
return result;
|
|
46365
|
+
}
|
|
45725
46366
|
/**
|
|
45726
46367
|
* Check yield point during task execution — called between LLM turns.
|
|
45727
46368
|
* Returns decision info so the tool loop can act on preemption or merges.
|
|
@@ -45770,12 +46411,20 @@ ${notification.stdoutTail}`);
|
|
|
45770
46411
|
const messages = this.currentSessionId ? this.memory.getRecentMessages(this.currentSessionId, TRIAGE_CONTEXT_MESSAGES_MAX * 2).filter((m) => m.role === "user" || m.role === "assistant").slice(-TRIAGE_CONTEXT_MESSAGES_MAX).map((m) => ({ role: m.role, content: typeof m.content === "string" ? m.content.slice(0, TRIAGE_CONTEXT_MSG_CHARS) : String(m.content).slice(0, TRIAGE_CONTEXT_MSG_CHARS) })) : [];
|
|
45771
46412
|
const activities = this.recentActivitySummaries();
|
|
45772
46413
|
const activeTaskIds = Array.from(this.activeTasks);
|
|
45773
|
-
return { agentName: this.config.name, recentMainSessionMessages: messages, recentActivitySummaries: activities, activeTaskIds };
|
|
46414
|
+
return { agentName: this.config.name, agentRole: this.role.name, recentMainSessionMessages: messages, recentActivitySummaries: activities, activeTaskIds };
|
|
45774
46415
|
},
|
|
45775
46416
|
onTriageCompleted: (result) => {
|
|
45776
46417
|
if (!result)
|
|
45777
46418
|
return;
|
|
45778
46419
|
this.updateCognition(result);
|
|
46420
|
+
},
|
|
46421
|
+
performDeliberation: async (headItem, allItems) => {
|
|
46422
|
+
return this.performDeliberation(headItem, allItems);
|
|
46423
|
+
},
|
|
46424
|
+
onDeliberationCompleted: (result) => {
|
|
46425
|
+
if (!result)
|
|
46426
|
+
return;
|
|
46427
|
+
this.updateCognitionFromDeliberation(result);
|
|
45779
46428
|
}
|
|
45780
46429
|
};
|
|
45781
46430
|
}
|
|
@@ -45874,7 +46523,7 @@ ${notification.stdoutTail}`);
|
|
|
45874
46523
|
case "requirement_update": {
|
|
45875
46524
|
if (extra.actionRequired) {
|
|
45876
46525
|
const reqId = item.payload.requirementId ?? "unknown";
|
|
45877
|
-
const reply = await this.handleMessage(item.payload.content +
|
|
46526
|
+
const reply = await this.handleMessage(item.payload.content + COMPLETION_MARKER_INSTRUCTION, item.metadata?.senderId, senderInfo, buildHandleOpts({ sessionId: `requirement_${reqId}_${ts}`, scenario: "requirement_action" }));
|
|
45878
46527
|
resolveResponse(reply);
|
|
45879
46528
|
return reply;
|
|
45880
46529
|
}
|
|
@@ -45887,7 +46536,7 @@ ${notification.stdoutTail}`);
|
|
|
45887
46536
|
}
|
|
45888
46537
|
case "requirement_comment": {
|
|
45889
46538
|
const reqId = item.payload.requirementId ?? "unknown";
|
|
45890
|
-
const reply = await this.handleMessage(item.payload.content +
|
|
46539
|
+
const reply = await this.handleMessage(item.payload.content + COMPLETION_MARKER_INSTRUCTION, item.metadata?.senderId, senderInfo, buildHandleOpts({ sessionId: `comment_${reqId}_${ts}`, scenario: "comment_response" }));
|
|
45891
46540
|
resolveResponse(reply);
|
|
45892
46541
|
return reply;
|
|
45893
46542
|
}
|
|
@@ -45899,7 +46548,7 @@ ${notification.stdoutTail}`);
|
|
|
45899
46548
|
this.injectUserMessage(sessionId, item.payload.content);
|
|
45900
46549
|
} else {
|
|
45901
46550
|
const commentTaskId = taskId2 ?? "unknown";
|
|
45902
|
-
await this.handleMessage(item.payload.content +
|
|
46551
|
+
await this.handleMessage(item.payload.content + COMPLETION_MARKER_INSTRUCTION, item.metadata?.senderId, senderInfo, buildHandleOpts({ sessionId: `comment_${commentTaskId}_${ts}`, scenario: "comment_response" }));
|
|
45903
46552
|
}
|
|
45904
46553
|
resolveResponse("");
|
|
45905
46554
|
return;
|
|
@@ -46407,7 +47056,7 @@ ${conversationText}`
|
|
|
46407
47056
|
const filename = `${toolName}_${++this.toolResultCounter}_${Date.now()}.txt`;
|
|
46408
47057
|
const filepath = join9(offloadDir, filename);
|
|
46409
47058
|
writeFileSync8(filepath, result);
|
|
46410
|
-
const preview = result
|
|
47059
|
+
const preview = safeSlice(result, 0, previewSize);
|
|
46411
47060
|
const lineCount = result.split("\n").length;
|
|
46412
47061
|
return [
|
|
46413
47062
|
`[FULL output (${result.length} chars, ${lineCount} lines) saved to: ${filepath}]`,
|
|
@@ -46416,11 +47065,11 @@ ${conversationText}`
|
|
|
46416
47065
|
``,
|
|
46417
47066
|
preview,
|
|
46418
47067
|
``,
|
|
46419
|
-
`[... remaining ${result.length -
|
|
47068
|
+
`[... remaining ${result.length - preview.length} chars in file ...]`
|
|
46420
47069
|
].join("\n");
|
|
46421
47070
|
} catch {
|
|
46422
47071
|
const fallbackSize = isBrowserTool ? 3e4 : 8e3;
|
|
46423
|
-
return result
|
|
47072
|
+
return safeSlice(result, 0, fallbackSize) + `
|
|
46424
47073
|
|
|
46425
47074
|
[... output truncated at ${fallbackSize} of ${result.length} total chars due to file-save failure ...]`;
|
|
46426
47075
|
}
|
|
@@ -46635,6 +47284,109 @@ ${conversationText}`
|
|
|
46635
47284
|
lines.push(`Reasoning: ${result.reasoning}`);
|
|
46636
47285
|
this.currentCognition = lines.join("\n");
|
|
46637
47286
|
}
|
|
47287
|
+
updateCognitionFromDeliberation(result) {
|
|
47288
|
+
if (result.situationalAwareness) {
|
|
47289
|
+
this.currentCognition = `## Current Situational Awareness (deliberation)
|
|
47290
|
+
${result.situationalAwareness}`;
|
|
47291
|
+
} else {
|
|
47292
|
+
const lines = [];
|
|
47293
|
+
lines.push("## Current Situational Awareness (deliberation)");
|
|
47294
|
+
lines.push(`Decision: Processing item [${result.processItemId}]`);
|
|
47295
|
+
if (result.inlineCompletedIds.length > 0) {
|
|
47296
|
+
lines.push(`Handled ${result.inlineCompletedIds.length} item(s) inline`);
|
|
47297
|
+
}
|
|
47298
|
+
if (result.deferItemIds.length > 0) {
|
|
47299
|
+
lines.push(`Deferred ${result.deferItemIds.length} item(s)`);
|
|
47300
|
+
}
|
|
47301
|
+
if (result.dropItemIds.length > 0) {
|
|
47302
|
+
lines.push(`Dropped ${result.dropItemIds.length} item(s)`);
|
|
47303
|
+
}
|
|
47304
|
+
lines.push(`Reasoning: ${result.reasoning}`);
|
|
47305
|
+
this.currentCognition = lines.join("\n");
|
|
47306
|
+
}
|
|
47307
|
+
}
|
|
47308
|
+
/**
|
|
47309
|
+
* Full-session deliberation: the agent deliberates over all queued items as itself,
|
|
47310
|
+
* with access to its full tool set (filtered to deliberation-safe tools).
|
|
47311
|
+
*/
|
|
47312
|
+
async performDeliberation(headItem, allItems) {
|
|
47313
|
+
const formatAge = (ms) => {
|
|
47314
|
+
if (ms < 6e4)
|
|
47315
|
+
return `${Math.round(ms / 1e3)}s`;
|
|
47316
|
+
if (ms < 36e5)
|
|
47317
|
+
return `${Math.round(ms / 6e4)}min`;
|
|
47318
|
+
return `${(ms / 36e5).toFixed(1)}h`;
|
|
47319
|
+
};
|
|
47320
|
+
const formatItem = (item, idx) => {
|
|
47321
|
+
const pri = PRIORITY_LABELS?.[item.priority] ?? `p${item.priority}`;
|
|
47322
|
+
const ageMs = Date.now() - new Date(item.queuedAt).getTime();
|
|
47323
|
+
const contentPreview = item.payload.content ? `
|
|
47324
|
+
content: "${item.payload.content.slice(0, TRIAGE_ITEM_CONTENT_CHARS)}"` : "";
|
|
47325
|
+
return [
|
|
47326
|
+
`[${idx + 1}] id="${item.id}"`,
|
|
47327
|
+
` type=${item.sourceType} priority=${pri} age=${formatAge(ageMs)}`,
|
|
47328
|
+
` summary: "${item.payload.summary}"`,
|
|
47329
|
+
item.payload.taskId ? ` taskId: ${item.payload.taskId}` : null,
|
|
47330
|
+
item.metadata?.senderName ? ` from: ${item.metadata.senderName} (${item.metadata?.senderRole ?? "unknown"})` : null,
|
|
47331
|
+
contentPreview || null
|
|
47332
|
+
].filter(Boolean).join("\n");
|
|
47333
|
+
};
|
|
47334
|
+
const itemsSection = allItems.map(formatItem).join("\n\n");
|
|
47335
|
+
const deliberationPrompt = [
|
|
47336
|
+
"[DELIBERATION MODE]",
|
|
47337
|
+
"",
|
|
47338
|
+
`You have ${allItems.length} items in your mailbox that need attention. Before diving into work, take a moment to deliberate.`,
|
|
47339
|
+
"",
|
|
47340
|
+
"## Your Mailbox",
|
|
47341
|
+
itemsSection,
|
|
47342
|
+
"",
|
|
47343
|
+
"## What You Can Do",
|
|
47344
|
+
"1. **Gather context**: Use recall_activity, task_get, memory_search to understand the full picture.",
|
|
47345
|
+
"2. **Handle simple items inline**: For trivial acknowledgments, quick replies, or status notifications, handle them now using notify_user, task_comment, or agent_send_message. Mark them as inline_completed in your final decision.",
|
|
47346
|
+
"3. **Choose your focus**: Decide which complex item deserves your full attention next.",
|
|
47347
|
+
"4. **Defer or drop**: Explicitly defer items for later or drop stale/redundant ones.",
|
|
47348
|
+
"",
|
|
47349
|
+
"When ready, call `complete_deliberation` with your decision."
|
|
47350
|
+
].join("\n");
|
|
47351
|
+
this.pendingDeliberationResult = void 0;
|
|
47352
|
+
const prevMailboxItemId = this.processingMailboxItemId;
|
|
47353
|
+
this.processingMailboxItemId = headItem.id;
|
|
47354
|
+
try {
|
|
47355
|
+
const allowedTools = new Set(DELIBERATION_ALLOWED_TOOLS);
|
|
47356
|
+
await this.handleMessage(deliberationPrompt, void 0, void 0, {
|
|
47357
|
+
sessionId: `deliberation_${this.id}_${Date.now()}`,
|
|
47358
|
+
scenario: "deliberation",
|
|
47359
|
+
maxToolIterations: DELIBERATION_MAX_TOOL_ITERATIONS,
|
|
47360
|
+
allowedTools
|
|
47361
|
+
});
|
|
47362
|
+
const result = this.consumeDeliberationResult();
|
|
47363
|
+
if (result) {
|
|
47364
|
+
log17.info("Deliberation completed", {
|
|
47365
|
+
agentId: this.id,
|
|
47366
|
+
processItemId: result.processItemId,
|
|
47367
|
+
inlineCompleted: result.inlineCompletedIds.length,
|
|
47368
|
+
deferred: result.deferItemIds.length,
|
|
47369
|
+
dropped: result.dropItemIds.length
|
|
47370
|
+
});
|
|
47371
|
+
for (const completedId of result.inlineCompletedIds) {
|
|
47372
|
+
const completedItem = allItems.find((i) => i.id === completedId);
|
|
47373
|
+
if (!completedItem)
|
|
47374
|
+
continue;
|
|
47375
|
+
const inlineActId = this.startActivity("inline_deliberation", `Handled inline: ${completedItem.payload.summary.slice(0, 80)}`, { mailboxItemId: completedId });
|
|
47376
|
+
this.emitActivityLog(inlineActId, "text", `This item was handled inline during deliberation. Reasoning: ${result.reasoning}`);
|
|
47377
|
+
this.endActivity(inlineActId);
|
|
47378
|
+
}
|
|
47379
|
+
return result;
|
|
47380
|
+
}
|
|
47381
|
+
log17.warn("Deliberation session ended without complete_deliberation call", { agentId: this.id });
|
|
47382
|
+
return null;
|
|
47383
|
+
} catch (err) {
|
|
47384
|
+
log17.warn("Deliberation failed", { agentId: this.id, error: String(err) });
|
|
47385
|
+
return null;
|
|
47386
|
+
} finally {
|
|
47387
|
+
this.processingMailboxItemId = prevMailboxItemId;
|
|
47388
|
+
}
|
|
47389
|
+
}
|
|
46638
47390
|
getDynamicContext() {
|
|
46639
47391
|
const parts = [...this.dynamicContextProviders.values()].map((p) => p()).filter(Boolean);
|
|
46640
47392
|
for (const [name, instructions] of this.activatedSkillInstructions) {
|
|
@@ -46718,6 +47470,12 @@ ${instructions}
|
|
|
46718
47470
|
getUsageStats() {
|
|
46719
47471
|
return this.metricsCollector.getUsageStats();
|
|
46720
47472
|
}
|
|
47473
|
+
computeCallCost(inputTokens, outputTokens) {
|
|
47474
|
+
const modelCost = this.llmRouter.getModelCost(this.getEffectiveProvider());
|
|
47475
|
+
if (!modelCost)
|
|
47476
|
+
return 0;
|
|
47477
|
+
return inputTokens / 1e6 * modelCost.input + outputTokens / 1e6 * modelCost.output;
|
|
47478
|
+
}
|
|
46721
47479
|
emitAudit(event) {
|
|
46722
47480
|
this.metricsCollector.recordAudit(event);
|
|
46723
47481
|
this.auditCallback?.(event);
|
|
@@ -47136,12 +47894,16 @@ ${block}
|
|
|
47136
47894
|
type: "llm_request",
|
|
47137
47895
|
action: "chat",
|
|
47138
47896
|
tokensUsed: tokensThisCall,
|
|
47897
|
+
inputTokens: response.usage.inputTokens,
|
|
47898
|
+
outputTokens: response.usage.outputTokens,
|
|
47899
|
+
cost: this.computeCallCost(response.usage.inputTokens, response.usage.outputTokens),
|
|
47139
47900
|
durationMs: Date.now() - llmStart,
|
|
47140
47901
|
success: true
|
|
47141
47902
|
});
|
|
47142
47903
|
let toolIterations = 0;
|
|
47143
47904
|
const effectiveMaxIter = options?.maxToolIterations ?? this._maxToolIterations;
|
|
47144
47905
|
const commentToolUsed = /* @__PURE__ */ new Set();
|
|
47906
|
+
const requirementActionToolUsed = /* @__PURE__ */ new Set();
|
|
47145
47907
|
while (response.finishReason === "tool_use" && response.toolCalls?.length || response.finishReason === "max_tokens") {
|
|
47146
47908
|
if (++toolIterations > effectiveMaxIter) {
|
|
47147
47909
|
log17.warn("Tool loop hit max iterations", {
|
|
@@ -47242,6 +48004,10 @@ ${block}
|
|
|
47242
48004
|
if (tc.name === "task_comment" || tc.name === "requirement_comment") {
|
|
47243
48005
|
commentToolUsed.add(tc.name);
|
|
47244
48006
|
}
|
|
48007
|
+
const REQ_ACTION_TOOLS = ["requirement_update_status", "requirement_comment", "task_create", "notify_user", "request_user_approval"];
|
|
48008
|
+
if (REQ_ACTION_TOOLS.includes(tc.name)) {
|
|
48009
|
+
requirementActionToolUsed.add(tc.name);
|
|
48010
|
+
}
|
|
47245
48011
|
}
|
|
47246
48012
|
const loopCheck = this.loopDetector.check();
|
|
47247
48013
|
if (loopCheck.detected) {
|
|
@@ -47310,6 +48076,9 @@ ${chatYield.item.payload.content}`;
|
|
|
47310
48076
|
type: "llm_request",
|
|
47311
48077
|
action: "chat",
|
|
47312
48078
|
tokensUsed: tokens2,
|
|
48079
|
+
inputTokens: response.usage.inputTokens,
|
|
48080
|
+
outputTokens: response.usage.outputTokens,
|
|
48081
|
+
cost: this.computeCallCost(response.usage.inputTokens, response.usage.outputTokens),
|
|
47313
48082
|
durationMs: Date.now() - llmStart2,
|
|
47314
48083
|
success: true
|
|
47315
48084
|
});
|
|
@@ -47401,6 +48170,92 @@ ${chatYield.item.payload.content}`;
|
|
|
47401
48170
|
}, this.getEffectiveProvider()), "Chat LLM comment-reminder-final");
|
|
47402
48171
|
}
|
|
47403
48172
|
}
|
|
48173
|
+
if (scenario === "requirement_action" && requirementActionToolUsed.size === 0 && toolIterations < effectiveMaxIter) {
|
|
48174
|
+
this.memory.appendMessage(sessionId, {
|
|
48175
|
+
role: "assistant",
|
|
48176
|
+
content: response.content,
|
|
48177
|
+
toolCalls: response.toolCalls,
|
|
48178
|
+
reasoningContent: response.reasoningContent
|
|
48179
|
+
});
|
|
48180
|
+
this.memory.appendMessage(sessionId, {
|
|
48181
|
+
role: "user",
|
|
48182
|
+
content: "[SYSTEM] You are about to end your turn WITHOUT taking any action. In requirement_action mode your text output is NOT visible to anyone. You MUST call at least one action tool: requirement_update_status, requirement_comment, task_create, or notify_user. Call requirement_get first if you need context, then take action."
|
|
48183
|
+
});
|
|
48184
|
+
const reminderMessages = this.memory.getRecentMessages(sessionId, maxHistory);
|
|
48185
|
+
const preparedReminder = await this.contextEngine.prepareMessages({
|
|
48186
|
+
systemPrompt,
|
|
48187
|
+
sessionMessages: reminderMessages,
|
|
48188
|
+
memory: this.memory,
|
|
48189
|
+
sessionId,
|
|
48190
|
+
agentId: this.id,
|
|
48191
|
+
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
48192
|
+
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
48193
|
+
toolDefinitions: llmTools,
|
|
48194
|
+
systemCacheSegments
|
|
48195
|
+
});
|
|
48196
|
+
response = await this.withNetworkRetry(() => this.llmRouter.chat({
|
|
48197
|
+
messages: preparedReminder.messages,
|
|
48198
|
+
tools: llmTools.length > 0 ? llmTools : void 0,
|
|
48199
|
+
metadata: this.getLLMMetadata(sessionId),
|
|
48200
|
+
compaction: useCompaction,
|
|
48201
|
+
systemCacheSegments
|
|
48202
|
+
}, this.getEffectiveProvider()), "Chat LLM requirement-action-reminder");
|
|
48203
|
+
if (response.finishReason === "tool_use" && response.toolCalls?.length) {
|
|
48204
|
+
const currentActId = this.state.currentActivity?.id;
|
|
48205
|
+
this.memory.appendMessage(sessionId, {
|
|
48206
|
+
role: "assistant",
|
|
48207
|
+
content: response.content,
|
|
48208
|
+
toolCalls: response.toolCalls,
|
|
48209
|
+
reasoningContent: response.reasoningContent
|
|
48210
|
+
});
|
|
48211
|
+
const toolResults = await Promise.all(response.toolCalls.map(async (tc) => {
|
|
48212
|
+
const toolStart = Date.now();
|
|
48213
|
+
if (currentActId) {
|
|
48214
|
+
this.emitActivityLog(currentActId, "tool_start", tc.name, { arguments: tc.arguments });
|
|
48215
|
+
}
|
|
48216
|
+
try {
|
|
48217
|
+
let result = await this.executeTool(tc, void 0, sessionId);
|
|
48218
|
+
result = this.offloadLargeResult(tc.name, result);
|
|
48219
|
+
if (currentActId) {
|
|
48220
|
+
this.emitActivityLog(currentActId, "tool_end", tc.name, {
|
|
48221
|
+
durationMs: Date.now() - toolStart,
|
|
48222
|
+
success: !isErrorResult2(result),
|
|
48223
|
+
arguments: tc.arguments,
|
|
48224
|
+
result
|
|
48225
|
+
});
|
|
48226
|
+
}
|
|
48227
|
+
return { toolCallId: tc.id, content: result, error: false };
|
|
48228
|
+
} catch (toolErr) {
|
|
48229
|
+
if (currentActId) {
|
|
48230
|
+
this.emitActivityLog(currentActId, "error", `Tool ${tc.name} failed: ${String(toolErr)}`);
|
|
48231
|
+
}
|
|
48232
|
+
return { toolCallId: tc.id, content: `Error: ${String(toolErr)}`, error: true };
|
|
48233
|
+
}
|
|
48234
|
+
}));
|
|
48235
|
+
for (const tr of toolResults) {
|
|
48236
|
+
this.memory.appendMessage(sessionId, { role: "tool", content: tr.content, toolCallId: tr.toolCallId });
|
|
48237
|
+
}
|
|
48238
|
+
const finalMessages = this.memory.getRecentMessages(sessionId, maxHistory);
|
|
48239
|
+
const preparedFinal = await this.contextEngine.prepareMessages({
|
|
48240
|
+
systemPrompt,
|
|
48241
|
+
sessionMessages: finalMessages,
|
|
48242
|
+
memory: this.memory,
|
|
48243
|
+
sessionId,
|
|
48244
|
+
agentId: this.id,
|
|
48245
|
+
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
48246
|
+
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
48247
|
+
toolDefinitions: llmTools,
|
|
48248
|
+
systemCacheSegments
|
|
48249
|
+
});
|
|
48250
|
+
response = await this.withNetworkRetry(() => this.llmRouter.chat({
|
|
48251
|
+
messages: preparedFinal.messages,
|
|
48252
|
+
tools: llmTools.length > 0 ? llmTools : void 0,
|
|
48253
|
+
metadata: this.getLLMMetadata(sessionId),
|
|
48254
|
+
compaction: useCompaction,
|
|
48255
|
+
systemCacheSegments
|
|
48256
|
+
}, this.getEffectiveProvider()), "Chat LLM requirement-action-reminder-final");
|
|
48257
|
+
}
|
|
48258
|
+
}
|
|
47404
48259
|
const rawReply = sanitizeLLMReply(response.content);
|
|
47405
48260
|
const displayReply = stripCompletionMarker(rawReply);
|
|
47406
48261
|
const outputCheck = await this.guardrails.checkOutput(displayReply, { agentId: this.id });
|
|
@@ -47569,6 +48424,9 @@ ${chatYield.item.payload.content}`;
|
|
|
47569
48424
|
type: "llm_request",
|
|
47570
48425
|
action: "chat_stream",
|
|
47571
48426
|
tokensUsed: tokensThisCall,
|
|
48427
|
+
inputTokens: response.usage.inputTokens,
|
|
48428
|
+
outputTokens: response.usage.outputTokens,
|
|
48429
|
+
cost: this.computeCallCost(response.usage.inputTokens, response.usage.outputTokens),
|
|
47572
48430
|
durationMs: Date.now() - llmStart,
|
|
47573
48431
|
success: true
|
|
47574
48432
|
});
|
|
@@ -47747,6 +48605,9 @@ ${streamYield.item.payload.content}`;
|
|
|
47747
48605
|
type: "llm_request",
|
|
47748
48606
|
action: "chat_stream",
|
|
47749
48607
|
tokensUsed: tokens2,
|
|
48608
|
+
inputTokens: response.usage.inputTokens,
|
|
48609
|
+
outputTokens: response.usage.outputTokens,
|
|
48610
|
+
cost: this.computeCallCost(response.usage.inputTokens, response.usage.outputTokens),
|
|
47750
48611
|
durationMs: Date.now() - llmStart2,
|
|
47751
48612
|
success: true
|
|
47752
48613
|
});
|
|
@@ -48052,7 +48913,7 @@ ${streamYield.item.payload.content}`;
|
|
|
48052
48913
|
let taskLlmTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
48053
48914
|
this.updateTokensUsed(taskLlmTokens);
|
|
48054
48915
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
48055
|
-
this.emitAudit({ type: "llm_request", action: "task_execution", tokensUsed: taskLlmTokens, durationMs: Date.now() - taskLlmStart, success: true });
|
|
48916
|
+
this.emitAudit({ type: "llm_request", action: "task_execution", tokensUsed: taskLlmTokens, inputTokens: response.usage.inputTokens, outputTokens: response.usage.outputTokens, cost: this.computeCallCost(response.usage.inputTokens, response.usage.outputTokens), durationMs: Date.now() - taskLlmStart, success: true });
|
|
48056
48917
|
while (response.finishReason === "tool_use" && response.toolCalls?.length || response.finishReason === "max_tokens") {
|
|
48057
48918
|
taskToolIterations++;
|
|
48058
48919
|
if (cancelToken?.cancelled) {
|
|
@@ -48244,7 +49105,7 @@ ${yieldResult.item.payload.content}`
|
|
|
48244
49105
|
taskLlmTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
48245
49106
|
this.updateTokensUsed(taskLlmTokens);
|
|
48246
49107
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
48247
|
-
this.emitAudit({ type: "llm_request", action: "task_execution", tokensUsed: taskLlmTokens, durationMs: Date.now() - taskLlmStart, success: true });
|
|
49108
|
+
this.emitAudit({ type: "llm_request", action: "task_execution", tokensUsed: taskLlmTokens, inputTokens: response.usage.inputTokens, outputTokens: response.usage.outputTokens, cost: this.computeCallCost(response.usage.inputTokens, response.usage.outputTokens), durationMs: Date.now() - taskLlmStart, success: true });
|
|
48248
49109
|
}
|
|
48249
49110
|
if (cancelToken?.cancelled) {
|
|
48250
49111
|
flushText();
|
|
@@ -48484,7 +49345,7 @@ ${yieldResult.item.payload.content}`
|
|
|
48484
49345
|
let risTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
48485
49346
|
this.updateTokensUsed(risTokens);
|
|
48486
49347
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
48487
|
-
this.emitAudit({ type: "llm_request", action: "respond_in_session", tokensUsed: risTokens, durationMs: Date.now() - risLlmStart, success: true });
|
|
49348
|
+
this.emitAudit({ type: "llm_request", action: "respond_in_session", tokensUsed: risTokens, inputTokens: response.usage.inputTokens, outputTokens: response.usage.outputTokens, cost: this.computeCallCost(response.usage.inputTokens, response.usage.outputTokens), durationMs: Date.now() - risLlmStart, success: true });
|
|
48488
49349
|
let toolIter = 0;
|
|
48489
49350
|
while (response.finishReason === "tool_use" && response.toolCalls?.length || response.finishReason === "max_tokens") {
|
|
48490
49351
|
if (++toolIter > 200)
|
|
@@ -48513,6 +49374,7 @@ ${yieldResult.item.payload.content}`
|
|
|
48513
49374
|
continue;
|
|
48514
49375
|
}
|
|
48515
49376
|
emit("tool_start", tc.name, { arguments: tc.arguments });
|
|
49377
|
+
this.emitActivityLog(actId, "tool_start", tc.name, { arguments: tc.arguments });
|
|
48516
49378
|
const toolStart = Date.now();
|
|
48517
49379
|
try {
|
|
48518
49380
|
let result = await this.executeTool(tc, void 0, sessionId);
|
|
@@ -48520,11 +49382,13 @@ ${yieldResult.item.payload.content}`
|
|
|
48520
49382
|
const isErr = isErrorResult2(result);
|
|
48521
49383
|
const durationMs = Date.now() - toolStart;
|
|
48522
49384
|
emit("tool_end", tc.name, { success: !isErr, durationMs, arguments: tc.arguments, result });
|
|
49385
|
+
this.emitActivityLog(actId, "tool_end", tc.name, { durationMs, success: !isErr, arguments: tc.arguments, result });
|
|
48523
49386
|
this.emitAudit({ type: "tool_call", action: tc.name, durationMs, success: !isErr });
|
|
48524
49387
|
this.memory.appendMessage(sessionId, { role: "tool", content: result, toolCallId: tc.id });
|
|
48525
49388
|
} catch (toolErr) {
|
|
48526
49389
|
const durationMs = Date.now() - toolStart;
|
|
48527
49390
|
emit("tool_end", tc.name, { success: false, durationMs, arguments: tc.arguments, error: String(toolErr) });
|
|
49391
|
+
this.emitActivityLog(actId, "tool_end", tc.name, { durationMs, success: false, arguments: tc.arguments, error: String(toolErr) });
|
|
48528
49392
|
this.emitAudit({ type: "tool_call", action: tc.name, durationMs, success: false });
|
|
48529
49393
|
this.memory.appendMessage(sessionId, { role: "tool", content: `Error: ${String(toolErr)}`, toolCallId: tc.id });
|
|
48530
49394
|
}
|
|
@@ -48546,11 +49410,14 @@ ${yieldResult.item.payload.content}`
|
|
|
48546
49410
|
risTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
48547
49411
|
this.updateTokensUsed(risTokens);
|
|
48548
49412
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
48549
|
-
this.emitAudit({ type: "llm_request", action: "respond_in_session", tokensUsed: risTokens, durationMs: Date.now() - risLlmStart, success: true });
|
|
49413
|
+
this.emitAudit({ type: "llm_request", action: "respond_in_session", tokensUsed: risTokens, inputTokens: response.usage.inputTokens, outputTokens: response.usage.outputTokens, cost: this.computeCallCost(response.usage.inputTokens, response.usage.outputTokens), durationMs: Date.now() - risLlmStart, success: true });
|
|
48550
49414
|
}
|
|
48551
49415
|
flushText();
|
|
48552
49416
|
const rawReply = sanitizeLLMReply(response.content);
|
|
48553
49417
|
const displayReply = stripCompletionMarker(rawReply);
|
|
49418
|
+
if (displayReply.trim()) {
|
|
49419
|
+
this.emitActivityLog(actId, "text", displayReply);
|
|
49420
|
+
}
|
|
48554
49421
|
this.memory.appendMessage(sessionId, { role: "assistant", content: displayReply, reasoningContent: response.reasoningContent });
|
|
48555
49422
|
return rawReply;
|
|
48556
49423
|
} catch (error) {
|
|
@@ -48834,9 +49701,20 @@ ${d.text}
|
|
|
48834
49701
|
const explicitTaskId = toolCall.arguments.related_task_id;
|
|
48835
49702
|
const taskId2 = explicitTaskId ?? this.getCurrentTaskId();
|
|
48836
49703
|
const requirementId2 = this.getCurrentRequirementId();
|
|
49704
|
+
const explicitTargetUser = toolCall.arguments.target_user_id;
|
|
49705
|
+
const contextParts = [];
|
|
49706
|
+
if (taskId2)
|
|
49707
|
+
contextParts.push(`task_id=${taskId2}`);
|
|
49708
|
+
if (requirementId2)
|
|
49709
|
+
contextParts.push(`requirement_id=${requirementId2}`);
|
|
49710
|
+
if (priority && priority !== "normal")
|
|
49711
|
+
contextParts.push(`priority=${priority}`);
|
|
49712
|
+
const contextSuffix = contextParts.length > 0 ? `
|
|
49713
|
+
|
|
49714
|
+
<!-- notify_context: ${contextParts.join(", ")} -->` : "";
|
|
48837
49715
|
const formattedMsg = `**${title}**
|
|
48838
49716
|
|
|
48839
|
-
${body}`;
|
|
49717
|
+
${body}${contextSuffix}`;
|
|
48840
49718
|
if (this.currentSessionId) {
|
|
48841
49719
|
this.memory.appendMessage(this.currentSessionId, {
|
|
48842
49720
|
role: "assistant",
|
|
@@ -48850,7 +49728,7 @@ ${body}`;
|
|
|
48850
49728
|
this.eventBus.emit("agent:notify-user", {
|
|
48851
49729
|
agentId: this.id,
|
|
48852
49730
|
sessionId: this.currentSessionId,
|
|
48853
|
-
targetUserId: this.currentInteractingUserId,
|
|
49731
|
+
targetUserId: explicitTargetUser ?? this.currentInteractingUserId,
|
|
48854
49732
|
title,
|
|
48855
49733
|
body,
|
|
48856
49734
|
priority,
|
|
@@ -48903,6 +49781,21 @@ ${body}`;
|
|
|
48903
49781
|
return JSON.stringify({ status: "error", message: `Failed to get user approval: ${String(err)}` });
|
|
48904
49782
|
}
|
|
48905
49783
|
}
|
|
49784
|
+
if (toolCall.name === "complete_deliberation") {
|
|
49785
|
+
const processItemId = toolCall.arguments.process_item_id;
|
|
49786
|
+
if (!processItemId) {
|
|
49787
|
+
return JSON.stringify({ status: "error", message: "process_item_id is required" });
|
|
49788
|
+
}
|
|
49789
|
+
this.pendingDeliberationResult = {
|
|
49790
|
+
processItemId,
|
|
49791
|
+
deferItemIds: toolCall.arguments.defer_item_ids ?? [],
|
|
49792
|
+
dropItemIds: toolCall.arguments.drop_item_ids ?? [],
|
|
49793
|
+
inlineCompletedIds: toolCall.arguments.inline_completed_ids ?? [],
|
|
49794
|
+
reasoning: toolCall.arguments.reasoning ?? "",
|
|
49795
|
+
situationalAwareness: toolCall.arguments.situational_awareness
|
|
49796
|
+
};
|
|
49797
|
+
return JSON.stringify({ status: "ok", message: "Deliberation decision recorded. Proceeding to focused processing." });
|
|
49798
|
+
}
|
|
48906
49799
|
const profile = this.config.profile;
|
|
48907
49800
|
if (profile) {
|
|
48908
49801
|
if (profile.toolWhitelist && !profile.toolWhitelist.includes(toolCall.name)) {
|
|
@@ -49174,6 +50067,9 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
49174
50067
|
"**Report format** \u2014 create a deliverable via `deliverable_create`:",
|
|
49175
50068
|
`- **title**: "Daily Report \u2014 ${todayDate}"`,
|
|
49176
50069
|
'- **type**: "file"',
|
|
50070
|
+
"- **format**: Choose based on content complexity:",
|
|
50071
|
+
' - Use **"markdown"** (file extension `.md`) for simple, text-heavy reports with few metrics',
|
|
50072
|
+
' - Use **"html"** (file extension `.html`) when the report includes dashboards, tables with many columns, charts, color-coded status indicators, or interactive elements that help readers quickly grasp team status',
|
|
49177
50073
|
"- **Content must be concise, clear, and accurate**:",
|
|
49178
50074
|
" 1. **My work today**: What you personally accomplished (tasks reviewed, approved/rejected, decisions made)",
|
|
49179
50075
|
" 2. **My team progress**: What each member of YOUR team accomplished today (use `team_status` to check). Focus on your own team only.",
|
|
@@ -49880,21 +50776,52 @@ ${sharedContent}` : roleContent;
|
|
|
49880
50776
|
});
|
|
49881
50777
|
|
|
49882
50778
|
// ../core/dist/tools/mcp-client.js
|
|
49883
|
-
import { spawn as
|
|
49884
|
-
var log18, MCPClientManager;
|
|
50779
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
50780
|
+
var log18, DEFAULT_IDLE_TIMEOUT_MS, MCPClientManager;
|
|
49885
50781
|
var init_mcp_client = __esm({
|
|
49886
50782
|
"../core/dist/tools/mcp-client.js"() {
|
|
49887
50783
|
"use strict";
|
|
49888
50784
|
init_dist();
|
|
49889
50785
|
log18 = createLogger("mcp-client");
|
|
50786
|
+
DEFAULT_IDLE_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
49890
50787
|
MCPClientManager = class _MCPClientManager {
|
|
49891
50788
|
servers = /* @__PURE__ */ new Map();
|
|
50789
|
+
serverConfigs = /* @__PURE__ */ new Map();
|
|
49892
50790
|
requestId = 0;
|
|
49893
50791
|
pendingRequests = /* @__PURE__ */ new Map();
|
|
49894
50792
|
stdoutBuffers = /* @__PURE__ */ new Map();
|
|
50793
|
+
idleTimers = /* @__PURE__ */ new Map();
|
|
50794
|
+
idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_MS;
|
|
49895
50795
|
static scopedKey(name, scopeId) {
|
|
49896
50796
|
return `${name}::${scopeId}`;
|
|
49897
50797
|
}
|
|
50798
|
+
setIdleTimeout(ms) {
|
|
50799
|
+
this.idleTimeoutMs = ms;
|
|
50800
|
+
}
|
|
50801
|
+
resetIdleTimer(key2) {
|
|
50802
|
+
const existing = this.idleTimers.get(key2);
|
|
50803
|
+
if (existing)
|
|
50804
|
+
clearTimeout(existing);
|
|
50805
|
+
if (this.idleTimeoutMs <= 0)
|
|
50806
|
+
return;
|
|
50807
|
+
const timer = setTimeout(() => {
|
|
50808
|
+
this.idleTimers.delete(key2);
|
|
50809
|
+
if (this.servers.has(key2)) {
|
|
50810
|
+
log18.info(`MCP server idle timeout reached, disconnecting: ${key2}`);
|
|
50811
|
+
this.disconnectServer(key2).catch(() => {
|
|
50812
|
+
});
|
|
50813
|
+
}
|
|
50814
|
+
}, this.idleTimeoutMs);
|
|
50815
|
+
timer.unref();
|
|
50816
|
+
this.idleTimers.set(key2, timer);
|
|
50817
|
+
}
|
|
50818
|
+
clearIdleTimer(key2) {
|
|
50819
|
+
const timer = this.idleTimers.get(key2);
|
|
50820
|
+
if (timer) {
|
|
50821
|
+
clearTimeout(timer);
|
|
50822
|
+
this.idleTimers.delete(key2);
|
|
50823
|
+
}
|
|
50824
|
+
}
|
|
49898
50825
|
/**
|
|
49899
50826
|
* Spawn an MCP server process, run JSON-RPC init handshake, list tools,
|
|
49900
50827
|
* and store under the given internal key. Shared by connect and connectScoped.
|
|
@@ -49905,8 +50832,9 @@ var init_mcp_client = __esm({
|
|
|
49905
50832
|
log18.info(`MCP server ${displayName} already connected, reusing (${existing.tools.length} tools)`);
|
|
49906
50833
|
return existing.tools;
|
|
49907
50834
|
}
|
|
50835
|
+
this.serverConfigs.set(key2, { displayName, config });
|
|
49908
50836
|
log18.info(`Connecting to MCP server: ${displayName}`, { command: config.command, key: key2 });
|
|
49909
|
-
const proc =
|
|
50837
|
+
const proc = spawn4(config.command, config.args ?? [], {
|
|
49910
50838
|
stdio: ["pipe", "pipe", "pipe"],
|
|
49911
50839
|
env: { ...process.env, ...config.env },
|
|
49912
50840
|
shell: process.platform === "win32"
|
|
@@ -49931,6 +50859,7 @@ var init_mcp_client = __esm({
|
|
|
49931
50859
|
}
|
|
49932
50860
|
this.servers.delete(key2);
|
|
49933
50861
|
this.stdoutBuffers.delete(proc);
|
|
50862
|
+
this.clearIdleTimer(key2);
|
|
49934
50863
|
for (const [id, req] of this.pendingRequests) {
|
|
49935
50864
|
if (req.proc !== proc)
|
|
49936
50865
|
continue;
|
|
@@ -49951,6 +50880,7 @@ var init_mcp_client = __esm({
|
|
|
49951
50880
|
const toolsResult = await this.sendRequest(proc, "tools/list", {});
|
|
49952
50881
|
const tools = toolsResult?.tools ?? [];
|
|
49953
50882
|
this.servers.set(key2, { process: proc, tools });
|
|
50883
|
+
this.resetIdleTimer(key2);
|
|
49954
50884
|
log18.info(`MCP server ${displayName} connected with ${tools.length} tools`);
|
|
49955
50885
|
return tools;
|
|
49956
50886
|
} catch (err) {
|
|
@@ -49970,19 +50900,27 @@ var init_mcp_client = __esm({
|
|
|
49970
50900
|
const key2 = _MCPClientManager.scopedKey(name, scopeId);
|
|
49971
50901
|
return this.connectByKey(key2, `${name}[${scopeId}]`, config);
|
|
49972
50902
|
}
|
|
49973
|
-
callToolByKey(key2, toolName, args) {
|
|
49974
|
-
|
|
49975
|
-
if (!server)
|
|
49976
|
-
|
|
49977
|
-
|
|
50903
|
+
async callToolByKey(key2, toolName, args) {
|
|
50904
|
+
let server = this.servers.get(key2);
|
|
50905
|
+
if (!server) {
|
|
50906
|
+
const saved = this.serverConfigs.get(key2);
|
|
50907
|
+
if (saved) {
|
|
50908
|
+
log18.info(`MCP server ${key2} not running, auto-reconnecting...`);
|
|
50909
|
+
await this.connectByKey(key2, saved.displayName, saved.config);
|
|
50910
|
+
server = this.servers.get(key2);
|
|
50911
|
+
}
|
|
50912
|
+
if (!server)
|
|
50913
|
+
throw new Error(`MCP server not found: ${key2}`);
|
|
50914
|
+
}
|
|
50915
|
+
this.resetIdleTimer(key2);
|
|
50916
|
+
const result = await this.sendRequest(server.process, "tools/call", {
|
|
49978
50917
|
name: toolName,
|
|
49979
50918
|
arguments: args
|
|
49980
|
-
}).then((result) => {
|
|
49981
|
-
const content = result?.content;
|
|
49982
|
-
if (content?.[0]?.text)
|
|
49983
|
-
return content[0].text;
|
|
49984
|
-
return JSON.stringify(result);
|
|
49985
50919
|
});
|
|
50920
|
+
const content = result?.content;
|
|
50921
|
+
if (content?.[0]?.text)
|
|
50922
|
+
return content[0].text;
|
|
50923
|
+
return JSON.stringify(result);
|
|
49986
50924
|
}
|
|
49987
50925
|
async callTool(serverName, toolName, args) {
|
|
49988
50926
|
return this.callToolByKey(serverName, toolName, args);
|
|
@@ -50023,6 +50961,7 @@ var init_mcp_client = __esm({
|
|
|
50023
50961
|
async disconnectServer(name) {
|
|
50024
50962
|
const server = this.servers.get(name);
|
|
50025
50963
|
if (server) {
|
|
50964
|
+
this.clearIdleTimer(name);
|
|
50026
50965
|
server.process.kill();
|
|
50027
50966
|
this.servers.delete(name);
|
|
50028
50967
|
this.stdoutBuffers.delete(server.process);
|
|
@@ -50036,6 +50975,7 @@ var init_mcp_client = __esm({
|
|
|
50036
50975
|
/**
|
|
50037
50976
|
* Disconnect all scoped server instances belonging to a given scope (e.g. agent).
|
|
50038
50977
|
* Shared (non-scoped) servers are not affected.
|
|
50978
|
+
* The server configs are retained so the server can auto-reconnect on next tool call.
|
|
50039
50979
|
*/
|
|
50040
50980
|
async disconnectAllForScope(scopeId) {
|
|
50041
50981
|
const suffix = `::${scopeId}`;
|
|
@@ -50045,10 +50985,28 @@ var init_mcp_client = __esm({
|
|
|
50045
50985
|
}
|
|
50046
50986
|
}
|
|
50047
50987
|
}
|
|
50988
|
+
/**
|
|
50989
|
+
* Permanently disconnect and forget all scoped servers for a scope.
|
|
50990
|
+
* Used when an agent is removed and will never reconnect.
|
|
50991
|
+
*/
|
|
50992
|
+
async removeAllForScope(scopeId) {
|
|
50993
|
+
const suffix = `::${scopeId}`;
|
|
50994
|
+
for (const key2 of [...this.servers.keys()]) {
|
|
50995
|
+
if (key2.endsWith(suffix)) {
|
|
50996
|
+
await this.disconnectServer(key2);
|
|
50997
|
+
}
|
|
50998
|
+
}
|
|
50999
|
+
for (const key2 of [...this.serverConfigs.keys()]) {
|
|
51000
|
+
if (key2.endsWith(suffix)) {
|
|
51001
|
+
this.serverConfigs.delete(key2);
|
|
51002
|
+
}
|
|
51003
|
+
}
|
|
51004
|
+
}
|
|
50048
51005
|
async disconnectAll() {
|
|
50049
51006
|
for (const name of [...this.servers.keys()]) {
|
|
50050
51007
|
await this.disconnectServer(name);
|
|
50051
51008
|
}
|
|
51009
|
+
this.serverConfigs.clear();
|
|
50052
51010
|
}
|
|
50053
51011
|
/**
|
|
50054
51012
|
* Accumulates stdout data into a line buffer and dispatches
|
|
@@ -52664,6 +53622,10 @@ function createProjectTools(ctx) {
|
|
|
52664
53622
|
type: "string",
|
|
52665
53623
|
description: "Path to the file or directory that contains the actual content (must already exist)"
|
|
52666
53624
|
},
|
|
53625
|
+
format: {
|
|
53626
|
+
type: "string",
|
|
53627
|
+
description: "Content format of the deliverable file: markdown, html, text, json, csv, etc. Auto-detected from file extension if omitted."
|
|
53628
|
+
},
|
|
52667
53629
|
tags: { type: "string", description: "Comma-separated tags for discoverability" }
|
|
52668
53630
|
},
|
|
52669
53631
|
required: ["type", "title", "summary"]
|
|
@@ -52675,6 +53637,7 @@ function createProjectTools(ctx) {
|
|
|
52675
53637
|
title: args["title"],
|
|
52676
53638
|
summary: args["summary"],
|
|
52677
53639
|
reference: args["reference"],
|
|
53640
|
+
format: args["format"],
|
|
52678
53641
|
tags: args["tags"]
|
|
52679
53642
|
});
|
|
52680
53643
|
const resp = {
|
|
@@ -53961,6 +54924,9 @@ var init_agent_manager = __esm({
|
|
|
53961
54924
|
escalationHandler;
|
|
53962
54925
|
approvalHandler;
|
|
53963
54926
|
stateChangeHandler;
|
|
54927
|
+
/** Grace timers for releasing scoped MCP processes after agent goes idle */
|
|
54928
|
+
mcpReleaseTimers = /* @__PURE__ */ new Map();
|
|
54929
|
+
static MCP_IDLE_GRACE_MS = 3e4;
|
|
53964
54930
|
activityCallbacks;
|
|
53965
54931
|
recallCallbacks;
|
|
53966
54932
|
delegationManager;
|
|
@@ -54027,6 +54993,7 @@ var init_agent_manager = __esm({
|
|
|
54027
54993
|
title: opts.title,
|
|
54028
54994
|
summary: opts.summary,
|
|
54029
54995
|
reference: opts.reference,
|
|
54996
|
+
format: opts.format,
|
|
54030
54997
|
tags,
|
|
54031
54998
|
agentId: agentId2,
|
|
54032
54999
|
projectId
|
|
@@ -54823,9 +55790,7 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
54823
55790
|
const ah = this.approvalHandler;
|
|
54824
55791
|
agent.setApprovalCallback(async (req) => ah(id, req));
|
|
54825
55792
|
}
|
|
54826
|
-
|
|
54827
|
-
agent.setStateChangeCallback(this.stateChangeHandler);
|
|
54828
|
-
}
|
|
55793
|
+
agent.setStateChangeCallback(this.buildStateChangeCallback());
|
|
54829
55794
|
if (this.activityCallbacks) {
|
|
54830
55795
|
agent.setActivityCallbacks(this.activityCallbacks);
|
|
54831
55796
|
}
|
|
@@ -55374,9 +56339,7 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55374
56339
|
const ah = this.approvalHandler;
|
|
55375
56340
|
agent.setApprovalCallback(async (req) => ah(id, req));
|
|
55376
56341
|
}
|
|
55377
|
-
|
|
55378
|
-
agent.setStateChangeCallback(this.stateChangeHandler);
|
|
55379
|
-
}
|
|
56342
|
+
agent.setStateChangeCallback(this.buildStateChangeCallback());
|
|
55380
56343
|
if (this.activityCallbacks) {
|
|
55381
56344
|
agent.setActivityCallbacks(this.activityCallbacks);
|
|
55382
56345
|
}
|
|
@@ -55440,6 +56403,9 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55440
56403
|
async stopAgent(agentId2) {
|
|
55441
56404
|
const agent = this.getAgent(agentId2);
|
|
55442
56405
|
await agent.stop();
|
|
56406
|
+
this.cancelMcpRelease(agentId2);
|
|
56407
|
+
this.browserSessionManager.cleanupAgent(agentId2);
|
|
56408
|
+
await this.mcpManager.removeAllForScope(agentId2);
|
|
55443
56409
|
}
|
|
55444
56410
|
async removeAgent(agentId2, opts) {
|
|
55445
56411
|
const agent = this.agents.get(agentId2);
|
|
@@ -55448,8 +56414,9 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55448
56414
|
await agent.stop();
|
|
55449
56415
|
} catch {
|
|
55450
56416
|
}
|
|
56417
|
+
this.cancelMcpRelease(agentId2);
|
|
55451
56418
|
this.browserSessionManager.cleanupAgent(agentId2);
|
|
55452
|
-
await this.mcpManager.
|
|
56419
|
+
await this.mcpManager.removeAllForScope(agentId2);
|
|
55453
56420
|
this.delegationManager.unregisterAgentCard(agentId2);
|
|
55454
56421
|
this.agents.delete(agentId2);
|
|
55455
56422
|
this.eventBus.emit("agent:removed", { agentId: agentId2 });
|
|
@@ -55517,13 +56484,49 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55517
56484
|
agent.setApprovalCallback(async (req) => handler4(id, req));
|
|
55518
56485
|
}
|
|
55519
56486
|
}
|
|
55520
|
-
|
|
55521
|
-
|
|
55522
|
-
|
|
56487
|
+
/**
|
|
56488
|
+
* Build the combined state-change callback for an agent. Handles:
|
|
56489
|
+
* 1. MCP scoped-process lifecycle (release on idle, cancel release on working)
|
|
56490
|
+
* 2. DelegationManager status sync
|
|
56491
|
+
* 3. External handler forwarding (DB persistence, WS broadcast, etc.)
|
|
56492
|
+
*/
|
|
56493
|
+
buildStateChangeCallback() {
|
|
56494
|
+
return (agentId2, state) => {
|
|
56495
|
+
if (state.status === "idle" && state.activeTaskIds.length === 0) {
|
|
56496
|
+
this.scheduleMcpRelease(agentId2);
|
|
56497
|
+
} else if (state.status === "working") {
|
|
56498
|
+
this.cancelMcpRelease(agentId2);
|
|
56499
|
+
}
|
|
55523
56500
|
this.delegationManager.updateAgentStatus(agentId2, state.status);
|
|
56501
|
+
if (this.stateChangeHandler) {
|
|
56502
|
+
this.stateChangeHandler(agentId2, state);
|
|
56503
|
+
}
|
|
55524
56504
|
};
|
|
56505
|
+
}
|
|
56506
|
+
scheduleMcpRelease(agentId2) {
|
|
56507
|
+
if (this.mcpReleaseTimers.has(agentId2))
|
|
56508
|
+
return;
|
|
56509
|
+
const timer = setTimeout(() => {
|
|
56510
|
+
this.mcpReleaseTimers.delete(agentId2);
|
|
56511
|
+
this.browserSessionManager.cleanupAgent(agentId2);
|
|
56512
|
+
this.mcpManager.disconnectAllForScope(agentId2).catch(() => {
|
|
56513
|
+
});
|
|
56514
|
+
log32.info(`Released scoped MCP processes for idle agent: ${agentId2}`);
|
|
56515
|
+
}, _AgentManager.MCP_IDLE_GRACE_MS);
|
|
56516
|
+
timer.unref();
|
|
56517
|
+
this.mcpReleaseTimers.set(agentId2, timer);
|
|
56518
|
+
}
|
|
56519
|
+
cancelMcpRelease(agentId2) {
|
|
56520
|
+
const timer = this.mcpReleaseTimers.get(agentId2);
|
|
56521
|
+
if (timer) {
|
|
56522
|
+
clearTimeout(timer);
|
|
56523
|
+
this.mcpReleaseTimers.delete(agentId2);
|
|
56524
|
+
}
|
|
56525
|
+
}
|
|
56526
|
+
setStateChangeHandler(handler4) {
|
|
56527
|
+
this.stateChangeHandler = handler4;
|
|
55525
56528
|
for (const [, agent] of this.agents) {
|
|
55526
|
-
agent.setStateChangeCallback(this.
|
|
56529
|
+
agent.setStateChangeCallback(this.buildStateChangeCallback());
|
|
55527
56530
|
}
|
|
55528
56531
|
}
|
|
55529
56532
|
/**
|
|
@@ -55544,6 +56547,10 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55544
56547
|
"agent:resumed",
|
|
55545
56548
|
"agent:focus-changed",
|
|
55546
56549
|
"agent:message",
|
|
56550
|
+
"agent:notify-user",
|
|
56551
|
+
"agent:escalation",
|
|
56552
|
+
"agent:activity-log",
|
|
56553
|
+
"agent:activity_log",
|
|
55547
56554
|
"task:completed",
|
|
55548
56555
|
"task:failed",
|
|
55549
56556
|
"mailbox:new-item",
|
|
@@ -55781,6 +56788,7 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55781
56788
|
} catch {
|
|
55782
56789
|
}
|
|
55783
56790
|
}
|
|
56791
|
+
await this.mcpManager.disconnectAll();
|
|
55784
56792
|
log32.info("AgentManager shutdown complete \u2014 all metrics flushed");
|
|
55785
56793
|
}
|
|
55786
56794
|
// ─── Role Template Versioning & Sync ──────────────────────────────────────
|
|
@@ -56198,7 +57206,7 @@ var init_anthropic = __esm({
|
|
|
56198
57206
|
{
|
|
56199
57207
|
type: "tool_result",
|
|
56200
57208
|
tool_use_id: m.toolCallId ?? "",
|
|
56201
|
-
content: getTextContent(m.content)
|
|
57209
|
+
content: sanitizeForLLM(getTextContent(m.content))
|
|
56202
57210
|
}
|
|
56203
57211
|
]
|
|
56204
57212
|
};
|
|
@@ -56391,7 +57399,7 @@ var init_openai = __esm({
|
|
|
56391
57399
|
if (m.role === "tool") {
|
|
56392
57400
|
return {
|
|
56393
57401
|
role: "tool",
|
|
56394
|
-
content: getTextContent(m.content),
|
|
57402
|
+
content: sanitizeForLLM(getTextContent(m.content)),
|
|
56395
57403
|
tool_call_id: m.toolCallId ?? ""
|
|
56396
57404
|
};
|
|
56397
57405
|
}
|
|
@@ -56795,7 +57803,7 @@ var init_google = __esm({
|
|
|
56795
57803
|
parts: [{
|
|
56796
57804
|
functionResponse: {
|
|
56797
57805
|
name: msg.toolCallId ?? "unknown",
|
|
56798
|
-
response: { result: getTextContent(msg.content) }
|
|
57806
|
+
response: { result: sanitizeForLLM(getTextContent(msg.content)) }
|
|
56799
57807
|
}
|
|
56800
57808
|
}]
|
|
56801
57809
|
});
|
|
@@ -57017,7 +58025,7 @@ var init_ollama = __esm({
|
|
|
57017
58025
|
convertMessages(messages) {
|
|
57018
58026
|
return messages.map((m) => {
|
|
57019
58027
|
if (m.role === "tool") {
|
|
57020
|
-
return { role: "tool", content: getTextContent(m.content) };
|
|
58028
|
+
return { role: "tool", content: sanitizeForLLM(getTextContent(m.content)) };
|
|
57021
58029
|
}
|
|
57022
58030
|
if (m.toolCalls?.length) {
|
|
57023
58031
|
return {
|
|
@@ -57253,9 +58261,9 @@ var init_auth_profiles = __esm({
|
|
|
57253
58261
|
|
|
57254
58262
|
// ../core/dist/llm/oauth-manager.js
|
|
57255
58263
|
import { createServer } from "node:http";
|
|
57256
|
-
import { randomBytes as
|
|
58264
|
+
import { randomBytes as randomBytes3, createHash } from "node:crypto";
|
|
57257
58265
|
function generatePKCE() {
|
|
57258
|
-
const verifier =
|
|
58266
|
+
const verifier = randomBytes3(32).toString("base64url");
|
|
57259
58267
|
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
|
57260
58268
|
return { verifier, challenge };
|
|
57261
58269
|
}
|
|
@@ -57336,7 +58344,7 @@ var init_oauth_manager = __esm({
|
|
|
57336
58344
|
throw new Error(`Unknown OAuth provider: ${provider}`);
|
|
57337
58345
|
this.cancelPendingLogin(provider);
|
|
57338
58346
|
const { verifier, challenge } = generatePKCE();
|
|
57339
|
-
const state =
|
|
58347
|
+
const state = randomBytes3(16).toString("hex");
|
|
57340
58348
|
const port = config.callbackPort ?? 1455;
|
|
57341
58349
|
const redirectUri = `http://localhost:${port}/auth/callback`;
|
|
57342
58350
|
const promise = new Promise((resolve20, reject) => {
|
|
@@ -57625,6 +58633,7 @@ var init_router = __esm({
|
|
|
57625
58633
|
autoSelect = false;
|
|
57626
58634
|
providerTiers = [];
|
|
57627
58635
|
fallbackOrder = [];
|
|
58636
|
+
_autoFallback = true;
|
|
57628
58637
|
/** Health tracked per model: key = "providerName:modelId" */
|
|
57629
58638
|
modelHealth = /* @__PURE__ */ new Map();
|
|
57630
58639
|
/** Provider-level degradation for non-retryable (auth/billing) errors */
|
|
@@ -57913,6 +58922,12 @@ var init_router = __esm({
|
|
|
57913
58922
|
setFallbackOrder(order) {
|
|
57914
58923
|
this.fallbackOrder = order.filter((n2) => this.providers.has(n2));
|
|
57915
58924
|
}
|
|
58925
|
+
get autoFallback() {
|
|
58926
|
+
return this._autoFallback;
|
|
58927
|
+
}
|
|
58928
|
+
setAutoFallback(enabled) {
|
|
58929
|
+
this._autoFallback = enabled;
|
|
58930
|
+
}
|
|
57916
58931
|
static assessComplexity(request) {
|
|
57917
58932
|
const totalChars = request.messages.reduce((s2, m) => s2 + getTextContent(m.content).length, 0);
|
|
57918
58933
|
const toolCount = request.tools?.length ?? 0;
|
|
@@ -57964,6 +58979,8 @@ var init_router = __esm({
|
|
|
57964
58979
|
return this.defaultProvider;
|
|
57965
58980
|
}
|
|
57966
58981
|
getFallbacks(primary) {
|
|
58982
|
+
if (!this._autoFallback)
|
|
58983
|
+
return [];
|
|
57967
58984
|
const order = this.fallbackOrder.length > 0 ? this.fallbackOrder : [...this.providers.keys()];
|
|
57968
58985
|
return order.filter((n2) => n2 !== primary && this.isAvailable(n2));
|
|
57969
58986
|
}
|
|
@@ -58082,7 +59099,7 @@ var init_router = __esm({
|
|
|
58082
59099
|
} catch (error) {
|
|
58083
59100
|
lastError = error;
|
|
58084
59101
|
log35.error(`LLM request failed for ${primary}:${provider.model}`, { error: String(error) });
|
|
58085
|
-
if (!_LLMRouter.isNonRetryableError(error)) {
|
|
59102
|
+
if (this._autoFallback && !_LLMRouter.isNonRetryableError(error)) {
|
|
58086
59103
|
const altModel = this.findHealthyModel(primary);
|
|
58087
59104
|
if (altModel && altModel !== provider.model) {
|
|
58088
59105
|
log35.info(`Trying alternate model ${altModel} on ${primary}`);
|
|
@@ -58173,7 +59190,7 @@ var init_router = __esm({
|
|
|
58173
59190
|
throw lastError;
|
|
58174
59191
|
}
|
|
58175
59192
|
log35.error(`LLM stream request failed for ${primary}:${provider.model}`, { error: String(error) });
|
|
58176
|
-
if (!_LLMRouter.isNonRetryableError(error)) {
|
|
59193
|
+
if (this._autoFallback && !_LLMRouter.isNonRetryableError(error)) {
|
|
58177
59194
|
const altModel = this.findHealthyModel(primary);
|
|
58178
59195
|
if (altModel && altModel !== provider.model) {
|
|
58179
59196
|
log35.info(`Stream: trying alternate model ${altModel} on ${primary}`);
|
|
@@ -58304,7 +59321,7 @@ var init_router = __esm({
|
|
|
58304
59321
|
};
|
|
58305
59322
|
}
|
|
58306
59323
|
}
|
|
58307
|
-
return { defaultProvider: this.defaultProvider, providers };
|
|
59324
|
+
return { defaultProvider: this.defaultProvider, autoFallback: this._autoFallback, providers };
|
|
58308
59325
|
}
|
|
58309
59326
|
updateProviderModelConfig(providerName, config) {
|
|
58310
59327
|
this.customModelConfigs.set(providerName, {
|
|
@@ -58401,6 +59418,17 @@ var init_router = __esm({
|
|
|
58401
59418
|
const provider = this.providers.get(name);
|
|
58402
59419
|
return provider?.model ?? "";
|
|
58403
59420
|
}
|
|
59421
|
+
getModelCost(providerName) {
|
|
59422
|
+
const name = providerName ?? this.defaultProvider;
|
|
59423
|
+
const provider = this.providers.get(name);
|
|
59424
|
+
if (!provider)
|
|
59425
|
+
return void 0;
|
|
59426
|
+
const custom = this.customModelConfigs.get(name);
|
|
59427
|
+
if (custom?.cost)
|
|
59428
|
+
return custom.cost;
|
|
59429
|
+
const catalogEntry = BUILTIN_MODEL_CATALOG.find((m) => m.id === provider.model && m.provider === name) ?? BUILTIN_MODEL_CATALOG.find((m) => m.id === provider.model) ?? this.customModelCatalog.get(name)?.find((m) => m.id === provider.model);
|
|
59430
|
+
return catalogEntry?.cost;
|
|
59431
|
+
}
|
|
58404
59432
|
getModelInputTypes(providerName) {
|
|
58405
59433
|
const name = providerName ?? this.defaultProvider;
|
|
58406
59434
|
const provider = this.providers.get(name);
|
|
@@ -58559,7 +59587,7 @@ var init_enhanced_role_loader = __esm({
|
|
|
58559
59587
|
});
|
|
58560
59588
|
|
|
58561
59589
|
// ../core/dist/external-gateway.js
|
|
58562
|
-
import { createHmac, randomBytes as
|
|
59590
|
+
import { createHmac, randomBytes as randomBytes4, timingSafeEqual } from "node:crypto";
|
|
58563
59591
|
var log37, ExternalAgentGateway, GatewayError;
|
|
58564
59592
|
var init_external_gateway = __esm({
|
|
58565
59593
|
"../core/dist/external-gateway.js"() {
|
|
@@ -58738,7 +59766,7 @@ var init_external_gateway = __esm({
|
|
|
58738
59766
|
return payload;
|
|
58739
59767
|
}
|
|
58740
59768
|
async routeMessage(token, message) {
|
|
58741
|
-
const messageId = `gwmsg_${Date.now()}_${
|
|
59769
|
+
const messageId = `gwmsg_${Date.now()}_${randomBytes4(4).toString("hex")}`;
|
|
58742
59770
|
const key2 = this.registrationKey(token.externalAgentId, token.orgId);
|
|
58743
59771
|
const registration = this.registrations.get(key2);
|
|
58744
59772
|
if (registration) {
|
|
@@ -61352,39 +62380,28 @@ var init_org_service = __esm({
|
|
|
61352
62380
|
return p;
|
|
61353
62381
|
}
|
|
61354
62382
|
/**
|
|
61355
|
-
* Seed a
|
|
61356
|
-
*
|
|
61357
|
-
*
|
|
62383
|
+
* Seed a Secretary agent for a fresh organization.
|
|
62384
|
+
* The Secretary is hired without a team — users create teams explicitly.
|
|
62385
|
+
* Skips if any agents already exist for the org.
|
|
61358
62386
|
*/
|
|
61359
|
-
async seedDefaultTeam(orgId2,
|
|
61360
|
-
const
|
|
61361
|
-
if (
|
|
62387
|
+
async seedDefaultTeam(orgId2, _ownerUserId) {
|
|
62388
|
+
const existingAgents = this.agentManager.listAgents();
|
|
62389
|
+
if (existingAgents.length > 0)
|
|
61362
62390
|
return;
|
|
61363
|
-
log49.info("Seeding
|
|
62391
|
+
log49.info("Seeding Secretary agent for org", { orgId: orgId2 });
|
|
61364
62392
|
try {
|
|
61365
|
-
const team = await this.createTeam(orgId2, "My Team", "Your primary team \u2014 you and your personal AI Secretary.");
|
|
61366
|
-
const owner = this.humans.get(ownerUserId);
|
|
61367
|
-
if (owner) {
|
|
61368
|
-
this.addMemberToTeam(team.id, ownerUserId, "human");
|
|
61369
|
-
}
|
|
61370
62393
|
const secretary = await this.hireAgent({
|
|
61371
62394
|
name: "Secretary",
|
|
61372
62395
|
roleName: "secretary",
|
|
61373
62396
|
orgId: orgId2,
|
|
61374
|
-
|
|
61375
|
-
agentRole: "manager",
|
|
62397
|
+
agentRole: "worker",
|
|
61376
62398
|
skills: ["agent-building", "team-building", "skill-building"]
|
|
61377
62399
|
});
|
|
61378
|
-
|
|
61379
|
-
managerId: secretary.id,
|
|
61380
|
-
managerType: "agent"
|
|
61381
|
-
});
|
|
61382
|
-
log49.info("Default team seeded", {
|
|
61383
|
-
teamId: team.id,
|
|
62400
|
+
log49.info("Secretary agent seeded", {
|
|
61384
62401
|
secretaryId: secretary.id
|
|
61385
62402
|
});
|
|
61386
62403
|
} catch (error) {
|
|
61387
|
-
log49.warn("Failed to seed
|
|
62404
|
+
log49.warn("Failed to seed Secretary agent", { error: String(error) });
|
|
61388
62405
|
}
|
|
61389
62406
|
}
|
|
61390
62407
|
static BUILDING_SKILLS = /* @__PURE__ */ new Set(["agent-building", "team-building", "skill-building"]);
|
|
@@ -72202,6 +73219,9 @@ ${deliverablesSummary}` : ""
|
|
|
72202
73219
|
],
|
|
72203
73220
|
allowFreeform: true
|
|
72204
73221
|
}).then((result) => {
|
|
73222
|
+
const current = this.tasks.get(task.id);
|
|
73223
|
+
if (!current || current.status !== "review")
|
|
73224
|
+
return;
|
|
72205
73225
|
if (result.approved) {
|
|
72206
73226
|
this.updateTaskStatus(task.id, "completed", task.reviewerId, false, false, "human", "Review approved");
|
|
72207
73227
|
} else {
|
|
@@ -72470,6 +73490,7 @@ Action: ${guidance}` : ""
|
|
|
72470
73490
|
};
|
|
72471
73491
|
for (const t of tasks)
|
|
72472
73492
|
statusCounts[t.status]++;
|
|
73493
|
+
const stuckBlockedCount = tasks.filter((t) => t.status === "blocked" && this.areBlockersSatisfied(t)).length;
|
|
72473
73494
|
const agentMap = /* @__PURE__ */ new Map();
|
|
72474
73495
|
for (const t of tasks) {
|
|
72475
73496
|
if (!t.assignedAgentId)
|
|
@@ -72502,6 +73523,7 @@ Action: ${guidance}` : ""
|
|
|
72502
73523
|
return {
|
|
72503
73524
|
statusCounts,
|
|
72504
73525
|
totalTasks: tasks.length,
|
|
73526
|
+
stuckBlockedCount,
|
|
72505
73527
|
agentWorkload,
|
|
72506
73528
|
recentActivity,
|
|
72507
73529
|
averageCompletionTimeMs
|
|
@@ -77830,6 +78852,7 @@ ${cleanText}`,
|
|
|
77830
78852
|
title: body["title"],
|
|
77831
78853
|
summary: body["summary"],
|
|
77832
78854
|
reference: body["reference"],
|
|
78855
|
+
format: body["format"],
|
|
77833
78856
|
tags: body["tags"],
|
|
77834
78857
|
taskId: body["taskId"],
|
|
77835
78858
|
agentId: body["agentId"],
|
|
@@ -77857,6 +78880,7 @@ ${cleanText}`,
|
|
|
77857
78880
|
title: body["title"],
|
|
77858
78881
|
summary: body["summary"],
|
|
77859
78882
|
reference: body["reference"],
|
|
78883
|
+
format: body["format"],
|
|
77860
78884
|
tags: body["tags"],
|
|
77861
78885
|
status: body["status"],
|
|
77862
78886
|
type: body["type"]
|
|
@@ -79434,6 +80458,7 @@ EXPLANATION_END`;
|
|
|
79434
80458
|
title: body["title"],
|
|
79435
80459
|
summary: body["summary"] ?? body["content"],
|
|
79436
80460
|
reference: body["reference"],
|
|
80461
|
+
format: body["format"],
|
|
79437
80462
|
tags: body["tags"],
|
|
79438
80463
|
agentId: token.markusAgentId,
|
|
79439
80464
|
projectId: body["projectId"]
|
|
@@ -81142,12 +82167,6 @@ EXPLANATION_END`;
|
|
|
81142
82167
|
} catch {
|
|
81143
82168
|
}
|
|
81144
82169
|
}
|
|
81145
|
-
const billingSummary = this.billingService?.getUsageSummary(orgId2);
|
|
81146
|
-
if (billingSummary) {
|
|
81147
|
-
llmTokens = Math.max(llmTokens, billingSummary.llmTokens);
|
|
81148
|
-
toolCalls = Math.max(toolCalls, billingSummary.toolCalls);
|
|
81149
|
-
messages = Math.max(messages, billingSummary.messages);
|
|
81150
|
-
}
|
|
81151
82170
|
this.json(res, 200, {
|
|
81152
82171
|
usage: {
|
|
81153
82172
|
orgId: orgId2,
|
|
@@ -81155,7 +82174,7 @@ EXPLANATION_END`;
|
|
|
81155
82174
|
llmTokens,
|
|
81156
82175
|
toolCalls,
|
|
81157
82176
|
messages,
|
|
81158
|
-
storageBytes:
|
|
82177
|
+
storageBytes: this.billingService?.getUsageSummary(orgId2)?.storageBytes ?? 0
|
|
81159
82178
|
},
|
|
81160
82179
|
plan
|
|
81161
82180
|
});
|
|
@@ -81180,7 +82199,8 @@ EXPLANATION_END`;
|
|
|
81180
82199
|
requestCount: stats.requestCount,
|
|
81181
82200
|
toolCalls: stats.toolCalls,
|
|
81182
82201
|
messages: stats.requestsToday,
|
|
81183
|
-
estimatedCost: stats.estimatedCost
|
|
82202
|
+
estimatedCost: stats.estimatedCost,
|
|
82203
|
+
costToday: stats.costToday
|
|
81184
82204
|
};
|
|
81185
82205
|
} catch {
|
|
81186
82206
|
return {
|
|
@@ -81195,7 +82215,8 @@ EXPLANATION_END`;
|
|
|
81195
82215
|
requestCount: 0,
|
|
81196
82216
|
toolCalls: 0,
|
|
81197
82217
|
messages: 0,
|
|
81198
|
-
estimatedCost: 0
|
|
82218
|
+
estimatedCost: 0,
|
|
82219
|
+
costToday: 0
|
|
81199
82220
|
};
|
|
81200
82221
|
}
|
|
81201
82222
|
});
|
|
@@ -81427,23 +82448,31 @@ EXPLANATION_END`;
|
|
|
81427
82448
|
return;
|
|
81428
82449
|
}
|
|
81429
82450
|
const body = await this.readBody(req);
|
|
81430
|
-
const { defaultProvider } = body;
|
|
81431
|
-
if (!defaultProvider) {
|
|
81432
|
-
this.json(res, 400, { error: "defaultProvider is required" });
|
|
82451
|
+
const { defaultProvider, autoFallback } = body;
|
|
82452
|
+
if (!defaultProvider && autoFallback === void 0) {
|
|
82453
|
+
this.json(res, 400, { error: "defaultProvider or autoFallback is required" });
|
|
81433
82454
|
return;
|
|
81434
82455
|
}
|
|
81435
82456
|
try {
|
|
81436
|
-
|
|
82457
|
+
const configUpdates = {};
|
|
82458
|
+
if (defaultProvider) {
|
|
82459
|
+
this.llmRouter.setDefaultProvider(defaultProvider);
|
|
82460
|
+
configUpdates.defaultProvider = defaultProvider;
|
|
82461
|
+
}
|
|
82462
|
+
if (typeof autoFallback === "boolean") {
|
|
82463
|
+
this.llmRouter.setAutoFallback(autoFallback);
|
|
82464
|
+
configUpdates.autoFallback = autoFallback;
|
|
82465
|
+
}
|
|
81437
82466
|
try {
|
|
81438
|
-
saveConfig({ llm:
|
|
82467
|
+
saveConfig({ llm: configUpdates }, this.markusConfigPath);
|
|
81439
82468
|
} catch (e) {
|
|
81440
|
-
log56.warn("Failed to persist
|
|
82469
|
+
log56.warn("Failed to persist LLM settings to config file", { error: String(e) });
|
|
81441
82470
|
}
|
|
81442
82471
|
this.auditService?.record({
|
|
81443
82472
|
orgId: "system",
|
|
81444
82473
|
type: "settings_changed",
|
|
81445
|
-
action: "
|
|
81446
|
-
detail: `defaultProvider=${defaultProvider}
|
|
82474
|
+
action: "llm_settings",
|
|
82475
|
+
detail: `${defaultProvider ? `defaultProvider=${defaultProvider}` : ""}${autoFallback !== void 0 ? ` autoFallback=${autoFallback}` : ""}`.trim(),
|
|
81447
82476
|
userId: auth.userId,
|
|
81448
82477
|
success: true
|
|
81449
82478
|
});
|
|
@@ -81567,6 +82596,70 @@ EXPLANATION_END`;
|
|
|
81567
82596
|
});
|
|
81568
82597
|
return;
|
|
81569
82598
|
}
|
|
82599
|
+
if (path === "/api/settings/search" && req.method === "GET") {
|
|
82600
|
+
const { loadConfig: loadCfg } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
82601
|
+
const currentConfig = loadCfg(this.markusConfigPath);
|
|
82602
|
+
const search = currentConfig.integrations?.search ?? {};
|
|
82603
|
+
const mask = (key2) => key2 ? "***" + key2.slice(-4) : "";
|
|
82604
|
+
this.json(res, 200, {
|
|
82605
|
+
serper: { configured: !!search.serperApiKey || !!process.env["SERPER_API_KEY"], preview: mask(search.serperApiKey || process.env["SERPER_API_KEY"]) },
|
|
82606
|
+
brave: { configured: !!search.braveApiKey || !!process.env["BRAVE_SEARCH_API_KEY"], preview: mask(search.braveApiKey || process.env["BRAVE_SEARCH_API_KEY"]) },
|
|
82607
|
+
bocha: { configured: !!search.bochaApiKey || !!process.env["BOCHA_API_KEY"], preview: mask(search.bochaApiKey || process.env["BOCHA_API_KEY"]) }
|
|
82608
|
+
});
|
|
82609
|
+
return;
|
|
82610
|
+
}
|
|
82611
|
+
if (path === "/api/settings/search" && req.method === "POST") {
|
|
82612
|
+
const auth = await this.requireAuth(req, res);
|
|
82613
|
+
if (!auth)
|
|
82614
|
+
return;
|
|
82615
|
+
const body = await this.readBody(req);
|
|
82616
|
+
const updates = {};
|
|
82617
|
+
if (typeof body["serperApiKey"] === "string") {
|
|
82618
|
+
updates.serperApiKey = body["serperApiKey"] || void 0;
|
|
82619
|
+
if (body["serperApiKey"])
|
|
82620
|
+
process.env["SERPER_API_KEY"] = body["serperApiKey"];
|
|
82621
|
+
else
|
|
82622
|
+
delete process.env["SERPER_API_KEY"];
|
|
82623
|
+
}
|
|
82624
|
+
if (typeof body["braveApiKey"] === "string") {
|
|
82625
|
+
updates.braveApiKey = body["braveApiKey"] || void 0;
|
|
82626
|
+
if (body["braveApiKey"])
|
|
82627
|
+
process.env["BRAVE_SEARCH_API_KEY"] = body["braveApiKey"];
|
|
82628
|
+
else
|
|
82629
|
+
delete process.env["BRAVE_SEARCH_API_KEY"];
|
|
82630
|
+
}
|
|
82631
|
+
if (typeof body["bochaApiKey"] === "string") {
|
|
82632
|
+
updates.bochaApiKey = body["bochaApiKey"] || void 0;
|
|
82633
|
+
if (body["bochaApiKey"])
|
|
82634
|
+
process.env["BOCHA_API_KEY"] = body["bochaApiKey"];
|
|
82635
|
+
else
|
|
82636
|
+
delete process.env["BOCHA_API_KEY"];
|
|
82637
|
+
}
|
|
82638
|
+
try {
|
|
82639
|
+
saveConfig({ integrations: { search: updates } }, this.markusConfigPath);
|
|
82640
|
+
} catch (e) {
|
|
82641
|
+
log56.warn("Failed to persist search settings", { error: String(e) });
|
|
82642
|
+
}
|
|
82643
|
+
this.auditService?.record({
|
|
82644
|
+
orgId: "system",
|
|
82645
|
+
type: "settings_changed",
|
|
82646
|
+
action: "search",
|
|
82647
|
+
detail: "Search API key settings updated",
|
|
82648
|
+
userId: auth.userId,
|
|
82649
|
+
success: true,
|
|
82650
|
+
metadata: { keys: Object.keys(updates) }
|
|
82651
|
+
});
|
|
82652
|
+
const { loadConfig: loadCfg } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
82653
|
+
const currentConfig = loadCfg(this.markusConfigPath);
|
|
82654
|
+
const search = currentConfig.integrations?.search ?? {};
|
|
82655
|
+
const mask = (key2) => key2 ? "***" + key2.slice(-4) : "";
|
|
82656
|
+
this.json(res, 200, {
|
|
82657
|
+
serper: { configured: !!search.serperApiKey || !!process.env["SERPER_API_KEY"], preview: mask(search.serperApiKey || process.env["SERPER_API_KEY"]) },
|
|
82658
|
+
brave: { configured: !!search.braveApiKey || !!process.env["BRAVE_SEARCH_API_KEY"], preview: mask(search.braveApiKey || process.env["BRAVE_SEARCH_API_KEY"]) },
|
|
82659
|
+
bocha: { configured: !!search.bochaApiKey || !!process.env["BOCHA_API_KEY"], preview: mask(search.bochaApiKey || process.env["BOCHA_API_KEY"]) }
|
|
82660
|
+
});
|
|
82661
|
+
return;
|
|
82662
|
+
}
|
|
81570
82663
|
if (path === "/api/settings/llm/models" && req.method === "GET") {
|
|
81571
82664
|
if (!this.llmRouter) {
|
|
81572
82665
|
this.json(res, 200, { models: [] });
|
|
@@ -82833,6 +83926,8 @@ EXPLANATION_END`;
|
|
|
82833
83926
|
const home = homedir22();
|
|
82834
83927
|
const results = {};
|
|
82835
83928
|
const mdExts = [".md", ".markdown"];
|
|
83929
|
+
const htmlExts = [".html", ".htm"];
|
|
83930
|
+
const jsonExts = [".json"];
|
|
82836
83931
|
const imageExts = [".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"];
|
|
82837
83932
|
for (const p of paths.slice(0, 50)) {
|
|
82838
83933
|
try {
|
|
@@ -82848,6 +83943,10 @@ EXPLANATION_END`;
|
|
|
82848
83943
|
let type = "text";
|
|
82849
83944
|
if (mdExts.includes(ext))
|
|
82850
83945
|
type = "markdown";
|
|
83946
|
+
else if (htmlExts.includes(ext))
|
|
83947
|
+
type = "html";
|
|
83948
|
+
else if (jsonExts.includes(ext))
|
|
83949
|
+
type = "json";
|
|
82851
83950
|
else if (imageExts.includes(ext))
|
|
82852
83951
|
type = "image";
|
|
82853
83952
|
else if (!isFile)
|
|
@@ -82881,6 +83980,27 @@ EXPLANATION_END`;
|
|
|
82881
83980
|
return;
|
|
82882
83981
|
}
|
|
82883
83982
|
const stat = statSync6(resolved);
|
|
83983
|
+
if (stat.isDirectory()) {
|
|
83984
|
+
const { readdirSync: readdirSync13 } = await import("node:fs");
|
|
83985
|
+
const { join: join30, extname: extDir } = await import("node:path");
|
|
83986
|
+
const entries2 = readdirSync13(resolved, { withFileTypes: true }).filter((e) => !e.name.startsWith(".")).map((e) => {
|
|
83987
|
+
const full = join30(resolved, e.name);
|
|
83988
|
+
const isDir = e.isDirectory();
|
|
83989
|
+
let size;
|
|
83990
|
+
try {
|
|
83991
|
+
if (!isDir)
|
|
83992
|
+
size = statSync6(full).size;
|
|
83993
|
+
} catch {
|
|
83994
|
+
}
|
|
83995
|
+
return { name: e.name, path: full, isDirectory: isDir, size, ext: isDir ? "" : extDir(e.name).toLowerCase() };
|
|
83996
|
+
}).sort((a, b) => {
|
|
83997
|
+
if (a.isDirectory !== b.isDirectory)
|
|
83998
|
+
return a.isDirectory ? -1 : 1;
|
|
83999
|
+
return a.name.localeCompare(b.name);
|
|
84000
|
+
});
|
|
84001
|
+
this.json(res, 200, { type: "directory", name: resolved.split("/").pop(), path: resolved, entries: entries2 });
|
|
84002
|
+
return;
|
|
84003
|
+
}
|
|
82884
84004
|
if (!stat.isFile()) {
|
|
82885
84005
|
this.json(res, 400, { error: "Path is not a file" });
|
|
82886
84006
|
return;
|
|
@@ -82904,8 +84024,20 @@ EXPLANATION_END`;
|
|
|
82904
84024
|
} else {
|
|
82905
84025
|
const content = readFileSync26(resolved, "utf-8");
|
|
82906
84026
|
const mdExts = [".md", ".markdown"];
|
|
84027
|
+
const htmlExts = [".html", ".htm"];
|
|
84028
|
+
const jsonExts = [".json"];
|
|
84029
|
+
const csvExts = [".csv", ".tsv"];
|
|
84030
|
+
let fileType = "text";
|
|
84031
|
+
if (mdExts.includes(ext))
|
|
84032
|
+
fileType = "markdown";
|
|
84033
|
+
else if (htmlExts.includes(ext))
|
|
84034
|
+
fileType = "html";
|
|
84035
|
+
else if (jsonExts.includes(ext))
|
|
84036
|
+
fileType = "json";
|
|
84037
|
+
else if (csvExts.includes(ext))
|
|
84038
|
+
fileType = "csv";
|
|
82907
84039
|
this.json(res, 200, {
|
|
82908
|
-
type:
|
|
84040
|
+
type: fileType,
|
|
82909
84041
|
name: resolved.split("/").pop(),
|
|
82910
84042
|
content
|
|
82911
84043
|
});
|
|
@@ -83845,6 +84977,7 @@ EXPLANATION_END`;
|
|
|
83845
84977
|
exact("/api/settings/llm/models", "GET"),
|
|
83846
84978
|
exact("/api/settings/agent", "GET", "POST"),
|
|
83847
84979
|
exact("/api/settings/browser", "GET", "POST"),
|
|
84980
|
+
exact("/api/settings/search", "GET", "POST"),
|
|
83848
84981
|
exact("/api/settings/env-models", "GET", "POST"),
|
|
83849
84982
|
exact("/api/settings/detect-ollama", "GET"),
|
|
83850
84983
|
exact("/api/settings/export", "POST"),
|
|
@@ -84068,6 +85201,7 @@ EXPLANATION_END`;
|
|
|
84068
85201
|
statusCounts: taskDashboard.statusCounts,
|
|
84069
85202
|
successRate: taskSuccessRate,
|
|
84070
85203
|
blockedCount: blockedTasks,
|
|
85204
|
+
stuckBlockedCount: taskDashboard.stuckBlockedCount,
|
|
84071
85205
|
averageCompletionTimeMs: taskDashboard.averageCompletionTimeMs,
|
|
84072
85206
|
recentActivity: taskDashboard.recentActivity.slice(0, 10)
|
|
84073
85207
|
},
|
|
@@ -84680,7 +85814,7 @@ var init_hitl_service = __esm({
|
|
|
84680
85814
|
});
|
|
84681
85815
|
|
|
84682
85816
|
// ../org-manager/dist/billing-service.js
|
|
84683
|
-
import { randomBytes as
|
|
85817
|
+
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
84684
85818
|
var log58, DEFAULT_PLANS, keyCounter, BillingService;
|
|
84685
85819
|
var init_billing_service = __esm({
|
|
84686
85820
|
"../org-manager/dist/billing-service.js"() {
|
|
@@ -84814,7 +85948,7 @@ var init_billing_service = __esm({
|
|
|
84814
85948
|
}
|
|
84815
85949
|
createAPIKey(orgId2, name, scopes = ["*"], expiresInDays) {
|
|
84816
85950
|
const id = `mk_${(++keyCounter).toString(36)}_${Date.now().toString(36)}`;
|
|
84817
|
-
const key2 = `mk_${
|
|
85951
|
+
const key2 = `mk_${randomBytes5(32).toString("hex")}`;
|
|
84818
85952
|
const now3 = /* @__PURE__ */ new Date();
|
|
84819
85953
|
const apiKey = {
|
|
84820
85954
|
id,
|
|
@@ -86166,6 +87300,8 @@ var init_deliverable_service = __esm({
|
|
|
86166
87300
|
summary: opts.summary,
|
|
86167
87301
|
tags: opts.tags ?? existing.tags
|
|
86168
87302
|
};
|
|
87303
|
+
if (opts.format !== void 0)
|
|
87304
|
+
patch.format = opts.format;
|
|
86169
87305
|
if (opts.artifactType !== void 0)
|
|
86170
87306
|
patch.artifactType = opts.artifactType;
|
|
86171
87307
|
if (opts.artifactData !== void 0)
|
|
@@ -86194,6 +87330,7 @@ var init_deliverable_service = __esm({
|
|
|
86194
87330
|
title: opts.title,
|
|
86195
87331
|
summary: opts.summary,
|
|
86196
87332
|
reference: ref ?? "",
|
|
87333
|
+
format: opts.format,
|
|
86197
87334
|
tags: opts.tags ?? [],
|
|
86198
87335
|
status: "active",
|
|
86199
87336
|
taskId: opts.taskId,
|
|
@@ -86214,6 +87351,7 @@ var init_deliverable_service = __esm({
|
|
|
86214
87351
|
title: opts.title,
|
|
86215
87352
|
summary: opts.summary,
|
|
86216
87353
|
reference: ref ?? "",
|
|
87354
|
+
format: opts.format,
|
|
86217
87355
|
tags: opts.tags ?? [],
|
|
86218
87356
|
status: "active",
|
|
86219
87357
|
taskId: opts.taskId,
|
|
@@ -86301,6 +87439,8 @@ var init_deliverable_service = __esm({
|
|
|
86301
87439
|
d.summary = data.summary;
|
|
86302
87440
|
if (data.reference !== void 0)
|
|
86303
87441
|
d.reference = data.reference;
|
|
87442
|
+
if (data.format !== void 0)
|
|
87443
|
+
d.format = data.format;
|
|
86304
87444
|
if (data.tags !== void 0)
|
|
86305
87445
|
d.tags = data.tags;
|
|
86306
87446
|
if (data.status !== void 0)
|
|
@@ -86480,6 +87620,7 @@ var init_deliverable_service = __esm({
|
|
|
86480
87620
|
title: r.title,
|
|
86481
87621
|
summary: r.summary,
|
|
86482
87622
|
reference: r.reference,
|
|
87623
|
+
format: r.format ?? void 0,
|
|
86483
87624
|
tags: this.parseTags(r.tags),
|
|
86484
87625
|
status: r.status,
|
|
86485
87626
|
taskId: r.taskId ?? void 0,
|
|
@@ -86736,12 +87877,16 @@ var init_report_service = __esm({
|
|
|
86736
87877
|
}
|
|
86737
87878
|
buildCostSummary(scopeId, start, end) {
|
|
86738
87879
|
const usage = this.billingService.getUsageSummaryForPeriod(scopeId, start, end);
|
|
87880
|
+
const input = Math.round(usage.llmTokens * 0.7);
|
|
87881
|
+
const output = usage.llmTokens - input;
|
|
87882
|
+
const estimatedCost = input / 1e6 * 3 + output / 1e6 * 15;
|
|
87883
|
+
const cost = Math.round(estimatedCost * 1e4) / 1e4;
|
|
86739
87884
|
return {
|
|
86740
87885
|
totalTokens: usage.llmTokens,
|
|
86741
|
-
totalEstimatedCost:
|
|
87886
|
+
totalEstimatedCost: cost,
|
|
86742
87887
|
byAgent: [],
|
|
86743
87888
|
byCategory: [
|
|
86744
|
-
{ category: "llm_tokens", tokens: usage.llmTokens, cost
|
|
87889
|
+
{ category: "llm_tokens", tokens: usage.llmTokens, cost },
|
|
86745
87890
|
{ category: "tool_calls", tokens: 0, cost: 0 }
|
|
86746
87891
|
],
|
|
86747
87892
|
trend: "stable"
|
|
@@ -87065,17 +88210,21 @@ var init_stale_detector = __esm({
|
|
|
87065
88210
|
});
|
|
87066
88211
|
|
|
87067
88212
|
// ../org-manager/dist/scheduled-task-runner.js
|
|
87068
|
-
var log69, ScheduledTaskRunner;
|
|
88213
|
+
var log69, MIN_STAGGER_MS, MAX_STAGGER_MS, ScheduledTaskRunner;
|
|
87069
88214
|
var init_scheduled_task_runner = __esm({
|
|
87070
88215
|
"../org-manager/dist/scheduled-task-runner.js"() {
|
|
87071
88216
|
"use strict";
|
|
87072
88217
|
init_dist();
|
|
87073
88218
|
log69 = createLogger("scheduled-task-runner");
|
|
88219
|
+
MIN_STAGGER_MS = 2 * 6e4;
|
|
88220
|
+
MAX_STAGGER_MS = 15 * 6e4;
|
|
87074
88221
|
ScheduledTaskRunner = class {
|
|
87075
88222
|
taskService;
|
|
87076
88223
|
pollIntervalMs;
|
|
87077
88224
|
timer;
|
|
88225
|
+
staggerTimers = [];
|
|
87078
88226
|
running = false;
|
|
88227
|
+
startedAt = 0;
|
|
87079
88228
|
constructor(taskService, pollIntervalMs = 6e4) {
|
|
87080
88229
|
this.taskService = taskService;
|
|
87081
88230
|
this.pollIntervalMs = pollIntervalMs;
|
|
@@ -87084,6 +88233,8 @@ var init_scheduled_task_runner = __esm({
|
|
|
87084
88233
|
if (this.running)
|
|
87085
88234
|
return;
|
|
87086
88235
|
this.running = true;
|
|
88236
|
+
this.startedAt = Date.now();
|
|
88237
|
+
this.tick().catch((e) => log69.error("Initial scheduled task tick failed", { error: String(e) }));
|
|
87087
88238
|
this.timer = setInterval(() => {
|
|
87088
88239
|
this.tick().catch((e) => log69.error("Scheduled task tick failed", { error: String(e) }));
|
|
87089
88240
|
}, this.pollIntervalMs);
|
|
@@ -87094,15 +88245,26 @@ var init_scheduled_task_runner = __esm({
|
|
|
87094
88245
|
clearInterval(this.timer);
|
|
87095
88246
|
this.timer = void 0;
|
|
87096
88247
|
}
|
|
88248
|
+
for (const t of this.staggerTimers)
|
|
88249
|
+
clearTimeout(t);
|
|
88250
|
+
this.staggerTimers = [];
|
|
87097
88251
|
this.running = false;
|
|
87098
88252
|
log69.info("ScheduledTaskRunner stopped");
|
|
87099
88253
|
}
|
|
87100
88254
|
isRunning() {
|
|
87101
88255
|
return this.running;
|
|
87102
88256
|
}
|
|
88257
|
+
/**
|
|
88258
|
+
* Returns true during the startup grace period (first poll cycle after
|
|
88259
|
+
* start). Used to stagger overdue tasks instead of firing them all at once.
|
|
88260
|
+
*/
|
|
88261
|
+
isStartupPhase() {
|
|
88262
|
+
return Date.now() - this.startedAt < this.pollIntervalMs;
|
|
88263
|
+
}
|
|
87103
88264
|
async tick() {
|
|
87104
88265
|
const scheduledTasks = this.taskService.listScheduledTasks();
|
|
87105
88266
|
const now3 = Date.now();
|
|
88267
|
+
const startup = this.isStartupPhase();
|
|
87106
88268
|
for (const task of scheduledTasks) {
|
|
87107
88269
|
if (!task.scheduleConfig)
|
|
87108
88270
|
continue;
|
|
@@ -87119,6 +88281,22 @@ var init_scheduled_task_runner = __esm({
|
|
|
87119
88281
|
if (config.paused) {
|
|
87120
88282
|
continue;
|
|
87121
88283
|
}
|
|
88284
|
+
if (startup && nextRun < this.startedAt) {
|
|
88285
|
+
const delay = MIN_STAGGER_MS + Math.random() * (MAX_STAGGER_MS - MIN_STAGGER_MS);
|
|
88286
|
+
log69.info("Staggering overdue scheduled task", {
|
|
88287
|
+
taskId: task.id,
|
|
88288
|
+
title: task.title,
|
|
88289
|
+
overdueBy: `${Math.round((now3 - nextRun) / 6e4)}m`,
|
|
88290
|
+
firingIn: `${Math.round(delay / 6e4)}m`
|
|
88291
|
+
});
|
|
88292
|
+
const timer = setTimeout(() => {
|
|
88293
|
+
if (!this.running)
|
|
88294
|
+
return;
|
|
88295
|
+
this.fireScheduledTask(task).catch((e) => log69.error("Failed to fire staggered scheduled task", { taskId: task.id, error: String(e) }));
|
|
88296
|
+
}, delay);
|
|
88297
|
+
this.staggerTimers.push(timer);
|
|
88298
|
+
continue;
|
|
88299
|
+
}
|
|
87122
88300
|
try {
|
|
87123
88301
|
await this.fireScheduledTask(task);
|
|
87124
88302
|
} catch (e) {
|
|
@@ -87218,7 +88396,8 @@ function openSqlite(dbPath) {
|
|
|
87218
88396
|
{ table: "projects", column: "created_by", sql: "ALTER TABLE projects ADD COLUMN created_by TEXT" },
|
|
87219
88397
|
{ table: "approvals", column: "target_user_id", sql: "ALTER TABLE approvals ADD COLUMN target_user_id TEXT" },
|
|
87220
88398
|
{ table: "users", column: "deleted_at", sql: "ALTER TABLE users ADD COLUMN deleted_at TEXT" },
|
|
87221
|
-
{ table: "agents", column: "deleted_at", sql: "ALTER TABLE agents ADD COLUMN deleted_at TEXT" }
|
|
88399
|
+
{ table: "agents", column: "deleted_at", sql: "ALTER TABLE agents ADD COLUMN deleted_at TEXT" },
|
|
88400
|
+
{ table: "deliverables", column: "format", sql: "ALTER TABLE deliverables ADD COLUMN format TEXT" }
|
|
87222
88401
|
];
|
|
87223
88402
|
for (const m of migrations) {
|
|
87224
88403
|
const cols = _db.prepare(`PRAGMA table_info(${m.table})`).all();
|
|
@@ -87523,6 +88702,7 @@ CREATE TABLE IF NOT EXISTS deliverables (
|
|
|
87523
88702
|
title TEXT NOT NULL,
|
|
87524
88703
|
summary TEXT NOT NULL DEFAULT '',
|
|
87525
88704
|
reference TEXT NOT NULL DEFAULT '',
|
|
88705
|
+
format TEXT,
|
|
87526
88706
|
tags TEXT NOT NULL DEFAULT '[]',
|
|
87527
88707
|
status TEXT NOT NULL DEFAULT 'active',
|
|
87528
88708
|
task_id TEXT,
|
|
@@ -89500,11 +90680,11 @@ CREATE INDEX IF NOT EXISTS idx_st_entity ON status_transitions(entity_type, enti
|
|
|
89500
90680
|
async create(data) {
|
|
89501
90681
|
const n2 = now2();
|
|
89502
90682
|
this.db.prepare(`
|
|
89503
|
-
INSERT INTO deliverables (id, type, title, summary, reference, tags, status,
|
|
90683
|
+
INSERT INTO deliverables (id, type, title, summary, reference, format, tags, status,
|
|
89504
90684
|
task_id, agent_id, project_id, requirement_id, diff_stats, test_results,
|
|
89505
90685
|
artifact_type, artifact_data, access_count, created_at, updated_at)
|
|
89506
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
|
|
89507
|
-
`).run(data.id, data.type, data.title, data.summary, data.reference ?? "", toJson(data.tags ?? []), data.status ?? "active", data.taskId ?? null, data.agentId ?? null, data.projectId ?? null, data.requirementId ?? null, data.diffStats ? toJson(data.diffStats) : null, data.testResults ? toJson(data.testResults) : null, data.artifactType ?? null, data.artifactData ? toJson(data.artifactData) : null, n2, n2);
|
|
90686
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
|
|
90687
|
+
`).run(data.id, data.type, data.title, data.summary, data.reference ?? "", data.format ?? null, toJson(data.tags ?? []), data.status ?? "active", data.taskId ?? null, data.agentId ?? null, data.projectId ?? null, data.requirementId ?? null, data.diffStats ? toJson(data.diffStats) : null, data.testResults ? toJson(data.testResults) : null, data.artifactType ?? null, data.artifactData ? toJson(data.artifactData) : null, n2, n2);
|
|
89508
90688
|
return this.findById(data.id);
|
|
89509
90689
|
}
|
|
89510
90690
|
async findById(id) {
|
|
@@ -89567,6 +90747,10 @@ CREATE INDEX IF NOT EXISTS idx_st_entity ON status_transitions(entity_type, enti
|
|
|
89567
90747
|
sets.push("reference = ?");
|
|
89568
90748
|
vals.push(patch.reference);
|
|
89569
90749
|
}
|
|
90750
|
+
if (patch.format !== void 0) {
|
|
90751
|
+
sets.push("format = ?");
|
|
90752
|
+
vals.push(patch.format);
|
|
90753
|
+
}
|
|
89570
90754
|
if (patch.type !== void 0) {
|
|
89571
90755
|
sets.push("type = ?");
|
|
89572
90756
|
vals.push(patch.type);
|
|
@@ -89615,6 +90799,7 @@ CREATE INDEX IF NOT EXISTS idx_st_entity ON status_transitions(entity_type, enti
|
|
|
89615
90799
|
title: r["title"],
|
|
89616
90800
|
summary: r["summary"],
|
|
89617
90801
|
reference: r["reference"],
|
|
90802
|
+
format: r["format"] ?? null,
|
|
89618
90803
|
tags: fromJson(r["tags"]) ?? [],
|
|
89619
90804
|
status: r["status"],
|
|
89620
90805
|
taskId: r["task_id"],
|
|
@@ -91154,6 +92339,7 @@ var init_logger2 = __esm({
|
|
|
91154
92339
|
|
|
91155
92340
|
// src/utils/browser.ts
|
|
91156
92341
|
import { exec } from "node:child_process";
|
|
92342
|
+
import { get as httpGet } from "node:http";
|
|
91157
92343
|
import { platform as platform2 } from "node:os";
|
|
91158
92344
|
function openBrowser(url) {
|
|
91159
92345
|
if (process.env["NO_BROWSER"]) return;
|
|
@@ -91164,6 +92350,27 @@ function openBrowser(url) {
|
|
|
91164
92350
|
}
|
|
91165
92351
|
});
|
|
91166
92352
|
}
|
|
92353
|
+
function openBrowserAfterHealthCheck(uiUrl, healthUrl, intervalMs = 500, maxMs = 3e4) {
|
|
92354
|
+
if (process.env["NO_BROWSER"]) return;
|
|
92355
|
+
const deadline = Date.now() + maxMs;
|
|
92356
|
+
const check2 = () => {
|
|
92357
|
+
const req = httpGet(healthUrl, (res) => {
|
|
92358
|
+
res.resume();
|
|
92359
|
+
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 400) {
|
|
92360
|
+
openBrowser(uiUrl);
|
|
92361
|
+
} else if (Date.now() < deadline) {
|
|
92362
|
+
setTimeout(check2, intervalMs);
|
|
92363
|
+
}
|
|
92364
|
+
});
|
|
92365
|
+
req.on("error", () => {
|
|
92366
|
+
if (Date.now() < deadline) setTimeout(check2, intervalMs);
|
|
92367
|
+
});
|
|
92368
|
+
req.setTimeout(2e3, () => {
|
|
92369
|
+
req.destroy();
|
|
92370
|
+
});
|
|
92371
|
+
};
|
|
92372
|
+
check2();
|
|
92373
|
+
}
|
|
91167
92374
|
var init_browser = __esm({
|
|
91168
92375
|
"src/utils/browser.ts"() {
|
|
91169
92376
|
"use strict";
|
|
@@ -92106,6 +93313,9 @@ async function createServices(config) {
|
|
|
92106
93313
|
llmRouter.setProviderEnabled(name, false);
|
|
92107
93314
|
}
|
|
92108
93315
|
}
|
|
93316
|
+
if (config.llm.autoFallback === false) {
|
|
93317
|
+
llmRouter.setAutoFallback(false);
|
|
93318
|
+
}
|
|
92109
93319
|
if (config.llm.customModels) {
|
|
92110
93320
|
for (const [providerName, models] of Object.entries(config.llm.customModels)) {
|
|
92111
93321
|
for (const model of models) {
|
|
@@ -92280,6 +93490,9 @@ async function startServer(config, values) {
|
|
|
92280
93490
|
if (config.integrations?.search?.braveApiKey && !process.env["BRAVE_SEARCH_API_KEY"]) {
|
|
92281
93491
|
process.env["BRAVE_SEARCH_API_KEY"] = config.integrations.search.braveApiKey;
|
|
92282
93492
|
}
|
|
93493
|
+
if (config.integrations?.search?.bochaApiKey && !process.env["BOCHA_API_KEY"]) {
|
|
93494
|
+
process.env["BOCHA_API_KEY"] = config.integrations.search.bochaApiKey;
|
|
93495
|
+
}
|
|
92283
93496
|
const apiPort = Number(values["port"]) || config.server.apiPort;
|
|
92284
93497
|
const {
|
|
92285
93498
|
orgService,
|
|
@@ -92529,20 +93742,37 @@ async function startServer(config, values) {
|
|
|
92529
93742
|
const sessionUserId = targetUserId || defaultSessionUserId;
|
|
92530
93743
|
const mainSession = storage.chatSessionRepo.getOrCreateMainSession(agentId2, sessionUserId);
|
|
92531
93744
|
const agent = agentManager.getAgent(agentId2);
|
|
93745
|
+
const contextParts = [];
|
|
93746
|
+
if (taskId2) contextParts.push(`task_id=${taskId2}`);
|
|
93747
|
+
if (requirementId2) contextParts.push(`requirement_id=${requirementId2}`);
|
|
93748
|
+
if (priority && priority !== "normal") contextParts.push(`priority=${priority}`);
|
|
93749
|
+
const contextSuffix = contextParts.length > 0 ? `
|
|
93750
|
+
|
|
93751
|
+
<!-- notify_context: ${contextParts.join(", ")} -->` : "";
|
|
92532
93752
|
const formattedMsg = `**${title}**
|
|
92533
93753
|
|
|
92534
|
-
${body}`;
|
|
93754
|
+
${body}${contextSuffix}`;
|
|
93755
|
+
const msgMetadata = {
|
|
93756
|
+
notifyUser: true,
|
|
93757
|
+
priority: priority ?? "normal",
|
|
93758
|
+
...taskId2 ? { taskId: taskId2 } : {},
|
|
93759
|
+
...requirementId2 ? { requirementId: requirementId2 } : {}
|
|
93760
|
+
};
|
|
92535
93761
|
const msg = storage.chatSessionRepo.appendMessage(
|
|
92536
93762
|
mainSession.id,
|
|
92537
93763
|
agentId2,
|
|
92538
93764
|
"assistant",
|
|
92539
93765
|
formattedMsg,
|
|
92540
93766
|
0,
|
|
92541
|
-
|
|
93767
|
+
msgMetadata
|
|
92542
93768
|
);
|
|
92543
93769
|
storage.chatSessionRepo.updateLastMessage(mainSession.id);
|
|
92544
93770
|
ws.broadcastProactiveMessage(agentId2, agent.config.name, mainSession.id, msg.id, formattedMsg, {
|
|
92545
|
-
isMainSession: true
|
|
93771
|
+
isMainSession: true,
|
|
93772
|
+
notifyUser: true,
|
|
93773
|
+
priority: priority ?? "normal",
|
|
93774
|
+
taskId: taskId2,
|
|
93775
|
+
requirementId: requirementId2
|
|
92546
93776
|
}, sessionUserId);
|
|
92547
93777
|
const hasTask = !!taskId2;
|
|
92548
93778
|
hitlService.notify({
|
|
@@ -93186,13 +94416,9 @@ ${reason}`;
|
|
|
93186
94416
|
const logFile = getStartupLogFile();
|
|
93187
94417
|
const logFileName = logFile.split("/").pop() ?? logFile;
|
|
93188
94418
|
const uiUrl = `http://localhost:${apiPort}`;
|
|
94419
|
+
progress.finish(uiUrl);
|
|
93189
94420
|
if (!process.env["NO_BROWSER"] && webUiDir) {
|
|
93190
|
-
|
|
93191
|
-
setTimeout(() => {
|
|
93192
|
-
openBrowser(uiUrl);
|
|
93193
|
-
}, 500);
|
|
93194
|
-
} else {
|
|
93195
|
-
progress.finish(uiUrl);
|
|
94421
|
+
openBrowserAfterHealthCheck(uiUrl, `${uiUrl}/api/health`);
|
|
93196
94422
|
}
|
|
93197
94423
|
checkForUpdate().then((info4) => {
|
|
93198
94424
|
if (info4.updateAvailable) {
|
|
@@ -96301,7 +97527,7 @@ var connect_exports = {};
|
|
|
96301
97527
|
__export(connect_exports, {
|
|
96302
97528
|
registerConnectCommands: () => registerConnectCommands
|
|
96303
97529
|
});
|
|
96304
|
-
import { randomBytes as
|
|
97530
|
+
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
96305
97531
|
function registerConnectCommands(program2) {
|
|
96306
97532
|
const root = program2.command("connect").description("Connect / disconnect external agent platforms");
|
|
96307
97533
|
root.command("scan").description("Scan for installed agent platforms that can be connected").action(async (_opts, cmd) => {
|
|
@@ -96360,7 +97586,7 @@ function registerConnectCommands(program2) {
|
|
|
96360
97586
|
fail(`Unknown platform "${platform3}". Run \`markus connect list\` to see available connectors.`);
|
|
96361
97587
|
return;
|
|
96362
97588
|
}
|
|
96363
|
-
const agentId2 = opts.agentId || `${platform3}-${
|
|
97589
|
+
const agentId2 = opts.agentId || `${platform3}-${randomBytes6(4).toString("hex")}`;
|
|
96364
97590
|
const agentName = opts.agentName || connector.defaultAgentName || `${connector.displayName} Agent`;
|
|
96365
97591
|
const capabilities = opts.capabilities ? String(opts.capabilities).split(",").map((s2) => s2.trim()).filter(Boolean) : connector.defaultCapabilities ?? [];
|
|
96366
97592
|
const client = createClient(g);
|
|
@@ -96534,7 +97760,7 @@ __export(install_agent_exports, {
|
|
|
96534
97760
|
registerInstallAgentCommands: () => registerInstallAgentCommands
|
|
96535
97761
|
});
|
|
96536
97762
|
import { execSync as execSync5 } from "node:child_process";
|
|
96537
|
-
import { randomBytes as
|
|
97763
|
+
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
96538
97764
|
function registerInstallAgentCommands(program2) {
|
|
96539
97765
|
program2.command("install <platform>").description("Install an external agent platform and connect it to Markus").option("--org-id <id>", "Organization ID", "default").option("--agent-name <name>", "Agent display name").option("--skip-install", "Skip npm install (platform already installed)").option("--skip-init", "Skip platform initialization").option("--skip-connect", "Only install, do not register with Markus").action(async (platform3, opts, cmd) => {
|
|
96540
97766
|
const g = cmd.optsWithGlobals();
|
|
@@ -96590,7 +97816,7 @@ function registerInstallAgentCommands(program2) {
|
|
|
96590
97816
|
}
|
|
96591
97817
|
const client = createClient(g);
|
|
96592
97818
|
const serverUrl = g.server || process.env["MARKUS_API_URL"] || "http://localhost:8056";
|
|
96593
|
-
const agentId2 = `${platform3}-${
|
|
97819
|
+
const agentId2 = `${platform3}-${randomBytes7(4).toString("hex")}`;
|
|
96594
97820
|
const agentName = opts.agentName || connector.defaultAgentName || `${connector.displayName} Agent`;
|
|
96595
97821
|
const capabilities = connector.defaultCapabilities ?? [];
|
|
96596
97822
|
try {
|