@markus-global/cli 0.6.6 → 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 +1716 -540
- 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-DhcJVLZt.js +0 -351
- package/dist/web-ui/assets/index-vQ1EQK83.css +0 -1
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) {
|
|
@@ -6400,8 +6496,15 @@ var init_context_engine = __esm({
|
|
|
6400
6496
|
stable.push("**Large file writing**: NEVER write a document >200 lines in a single `file_write` call. Write section by section: `file_write` the first section, then `file_edit` to append each subsequent section.");
|
|
6401
6497
|
stable.push("**Error handling**: If a tool call fails, analyze the error and try a different approach \u2014 do NOT repeat the same failing action.");
|
|
6402
6498
|
stable.push("**Subagent delegation**: For heavy subtasks needing many tool calls or lots of file reading, delegate to `spawn_subagent` to keep your context lean. Use `spawn_subagents` to run independent subtasks in parallel.");
|
|
6403
|
-
stable.push("**Built-in tools over CLI**: ALWAYS prefer built-in tools (`task_create`, `task_assign`, `
|
|
6404
|
-
stable.push('**No auto-install/deploy**: NEVER automatically install or deploy agents, teams, or skills via `
|
|
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.");
|
|
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.');
|
|
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.");
|
|
6405
6508
|
stable.push("");
|
|
6406
6509
|
stable.push("\n## Task & Requirement Workflow");
|
|
6407
6510
|
stable.push("");
|
|
@@ -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 {
|
|
@@ -8255,7 +8395,7 @@ var init_tool_selector = __esm({
|
|
|
8255
8395
|
"\u5206\u914D",
|
|
8256
8396
|
"\u8DEF\u7531"
|
|
8257
8397
|
],
|
|
8258
|
-
toolNames: ["team_list", "team_status", "delegate_message"
|
|
8398
|
+
toolNames: ["team_list", "team_status", "delegate_message"]
|
|
8259
8399
|
},
|
|
8260
8400
|
{
|
|
8261
8401
|
name: "deliverables",
|
|
@@ -8287,7 +8427,7 @@ var init_tool_selector = __esm({
|
|
|
8287
8427
|
toolNames: ["deliverable_create", "deliverable_search", "deliverable_list", "deliverable_update"]
|
|
8288
8428
|
},
|
|
8289
8429
|
{
|
|
8290
|
-
name: "
|
|
8430
|
+
name: "packages",
|
|
8291
8431
|
keywords: [
|
|
8292
8432
|
"builder",
|
|
8293
8433
|
"artifact",
|
|
@@ -8295,11 +8435,16 @@ var init_tool_selector = __esm({
|
|
|
8295
8435
|
"skill",
|
|
8296
8436
|
"package",
|
|
8297
8437
|
"hub",
|
|
8438
|
+
"hire",
|
|
8439
|
+
"install agent",
|
|
8440
|
+
"install team",
|
|
8298
8441
|
"\u90E8\u7F72",
|
|
8299
8442
|
"\u5DE5\u4EF6",
|
|
8300
|
-
"\u6280\u80FD\u5305"
|
|
8443
|
+
"\u6280\u80FD\u5305",
|
|
8444
|
+
"\u62DB\u8058",
|
|
8445
|
+
"\u5B89\u88C5"
|
|
8301
8446
|
],
|
|
8302
|
-
toolNames: ["
|
|
8447
|
+
toolNames: ["package_list", "package_install", "hub_search", "hub_install"]
|
|
8303
8448
|
}
|
|
8304
8449
|
];
|
|
8305
8450
|
BASE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -8331,11 +8476,12 @@ var init_tool_selector = __esm({
|
|
|
8331
8476
|
selected.add(name);
|
|
8332
8477
|
}
|
|
8333
8478
|
if (opts.isManager) {
|
|
8334
|
-
const
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8479
|
+
for (const group of this.groups) {
|
|
8480
|
+
if (group.name === "manager" || group.name === "packages") {
|
|
8481
|
+
for (const name of group.toolNames) {
|
|
8482
|
+
if (opts.allTools.has(name))
|
|
8483
|
+
selected.add(name);
|
|
8484
|
+
}
|
|
8339
8485
|
}
|
|
8340
8486
|
}
|
|
8341
8487
|
}
|
|
@@ -8426,7 +8572,8 @@ var init_tool_selector = __esm({
|
|
|
8426
8572
|
title: { type: "string", description: "Short headline (1 line)" },
|
|
8427
8573
|
body: { type: "string", description: "Full message content. Be thorough \u2014 this is what the recipient reads in chat." },
|
|
8428
8574
|
priority: { type: "string", enum: ["low", "normal", "high", "urgent"], description: "Default: normal" },
|
|
8429
|
-
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)." }
|
|
8430
8577
|
},
|
|
8431
8578
|
required: ["title", "body"]
|
|
8432
8579
|
}
|
|
@@ -8474,6 +8621,22 @@ var init_tool_selector = __esm({
|
|
|
8474
8621
|
required: ["operation"]
|
|
8475
8622
|
}
|
|
8476
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
|
+
});
|
|
8477
8640
|
log10.debug("Tool selection complete", {
|
|
8478
8641
|
total: opts.allTools.size,
|
|
8479
8642
|
selected: result.length,
|
|
@@ -8638,8 +8801,310 @@ var init_security = __esm({
|
|
|
8638
8801
|
}
|
|
8639
8802
|
});
|
|
8640
8803
|
|
|
8641
|
-
// ../core/dist/tools/shell.js
|
|
8804
|
+
// ../core/dist/tools/shell-session.js
|
|
8642
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";
|
|
8643
9108
|
import { resolve as resolve4, normalize, sep } from "node:path";
|
|
8644
9109
|
function injectGitCommitMeta(command, meta) {
|
|
8645
9110
|
if (!meta)
|
|
@@ -8712,6 +9177,10 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8712
9177
|
timeout_ms: {
|
|
8713
9178
|
type: "number",
|
|
8714
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."
|
|
8715
9184
|
}
|
|
8716
9185
|
},
|
|
8717
9186
|
required: ["command"]
|
|
@@ -8768,22 +9237,71 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8768
9237
|
}
|
|
8769
9238
|
}
|
|
8770
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
|
+
}
|
|
8771
9266
|
return new Promise((resolve20) => {
|
|
8772
|
-
|
|
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], {
|
|
8773
9275
|
cwd: effectiveCwd ?? void 0,
|
|
8774
9276
|
stdio: ["ignore", "pipe", "pipe"],
|
|
9277
|
+
detached: true,
|
|
8775
9278
|
env: { ...process.env }
|
|
8776
9279
|
});
|
|
9280
|
+
child.unref();
|
|
8777
9281
|
let stdout = "";
|
|
8778
9282
|
let stderr = "";
|
|
8779
9283
|
let killed = false;
|
|
8780
9284
|
const maxBuffer = 10 * 1024 * 1024;
|
|
8781
9285
|
const timeout = setTimeout(() => {
|
|
8782
9286
|
killed = true;
|
|
8783
|
-
|
|
9287
|
+
try {
|
|
9288
|
+
process.kill(-child.pid, "SIGTERM");
|
|
9289
|
+
} catch {
|
|
9290
|
+
}
|
|
8784
9291
|
setTimeout(() => {
|
|
8785
|
-
|
|
8786
|
-
|
|
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
|
+
}));
|
|
8787
9305
|
}, 2e3);
|
|
8788
9306
|
}, timeoutMs);
|
|
8789
9307
|
let outputBuffer = "";
|
|
@@ -8822,27 +9340,29 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8822
9340
|
clearTimeout(flushTimer);
|
|
8823
9341
|
flushOutput();
|
|
8824
9342
|
}
|
|
9343
|
+
const cleanOut = sanitizeForLLM(stdout);
|
|
9344
|
+
const cleanErr = sanitizeForLLM(stderr);
|
|
8825
9345
|
if (killed) {
|
|
8826
|
-
|
|
9346
|
+
settle(JSON.stringify({
|
|
8827
9347
|
status: "error",
|
|
8828
9348
|
error: `Command timed out after ${timeoutMs}ms`,
|
|
8829
9349
|
exitCode: code,
|
|
8830
|
-
stdout:
|
|
8831
|
-
stderr:
|
|
9350
|
+
stdout: cleanOut.slice(0, 4e3),
|
|
9351
|
+
stderr: cleanErr.slice(0, 4e3)
|
|
8832
9352
|
}));
|
|
8833
9353
|
} else if (code !== 0) {
|
|
8834
|
-
|
|
9354
|
+
settle(JSON.stringify({
|
|
8835
9355
|
status: "error",
|
|
8836
|
-
error:
|
|
9356
|
+
error: cleanErr.trim() || `Process exited with code ${code}`,
|
|
8837
9357
|
exitCode: code,
|
|
8838
|
-
stdout:
|
|
8839
|
-
stderr:
|
|
9358
|
+
stdout: cleanOut.slice(0, 4e3),
|
|
9359
|
+
stderr: cleanErr.slice(0, 4e3)
|
|
8840
9360
|
}));
|
|
8841
9361
|
} else {
|
|
8842
|
-
|
|
9362
|
+
settle(JSON.stringify({
|
|
8843
9363
|
status: "success",
|
|
8844
|
-
stdout:
|
|
8845
|
-
stderr:
|
|
9364
|
+
stdout: cleanOut.trim() || void 0,
|
|
9365
|
+
stderr: cleanErr.trim() || void 0
|
|
8846
9366
|
}));
|
|
8847
9367
|
}
|
|
8848
9368
|
});
|
|
@@ -8852,11 +9372,11 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8852
9372
|
clearTimeout(flushTimer);
|
|
8853
9373
|
flushOutput();
|
|
8854
9374
|
}
|
|
8855
|
-
|
|
9375
|
+
settle(JSON.stringify({
|
|
8856
9376
|
status: "error",
|
|
8857
9377
|
error: err.message,
|
|
8858
|
-
stdout: stdout.slice(0, 4e3),
|
|
8859
|
-
stderr: stderr.slice(0, 4e3)
|
|
9378
|
+
stdout: sanitizeForLLM(stdout).slice(0, 4e3),
|
|
9379
|
+
stderr: sanitizeForLLM(stderr).slice(0, 4e3)
|
|
8860
9380
|
}));
|
|
8861
9381
|
});
|
|
8862
9382
|
});
|
|
@@ -8869,6 +9389,7 @@ var init_shell = __esm({
|
|
|
8869
9389
|
"use strict";
|
|
8870
9390
|
init_dist();
|
|
8871
9391
|
init_security();
|
|
9392
|
+
init_shell_session();
|
|
8872
9393
|
GIT_ALWAYS_DENY = [];
|
|
8873
9394
|
GIT_NEEDS_APPROVAL = [
|
|
8874
9395
|
{ pattern: /\bgit\s+push\s+--force/, label: "force push (--force)" },
|
|
@@ -41337,44 +41858,32 @@ async function searchBrave(query2, maxResults) {
|
|
|
41337
41858
|
date: r.page_age
|
|
41338
41859
|
}));
|
|
41339
41860
|
}
|
|
41340
|
-
async function
|
|
41341
|
-
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");
|
|
41342
41865
|
let res;
|
|
41343
41866
|
try {
|
|
41344
|
-
res = await proxyFetch(
|
|
41345
|
-
|
|
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 })
|
|
41346
41874
|
});
|
|
41347
41875
|
} catch (err) {
|
|
41348
41876
|
throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
41349
41877
|
}
|
|
41350
41878
|
if (!res.ok)
|
|
41351
41879
|
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
41352
|
-
const
|
|
41353
|
-
|
|
41354
|
-
|
|
41355
|
-
|
|
41356
|
-
|
|
41357
|
-
|
|
41358
|
-
|
|
41359
|
-
const results = [];
|
|
41360
|
-
const algoRegex = /<li[^>]*class="b_algo"[^>]*>([\s\S]*?)<\/li>/g;
|
|
41361
|
-
let match2;
|
|
41362
|
-
while ((match2 = algoRegex.exec(html)) !== null) {
|
|
41363
|
-
if (results.length >= max)
|
|
41364
|
-
break;
|
|
41365
|
-
const item = match2[1];
|
|
41366
|
-
const linkMatch = item.match(/<a[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/i);
|
|
41367
|
-
if (!linkMatch)
|
|
41368
|
-
continue;
|
|
41369
|
-
const url = linkMatch[1];
|
|
41370
|
-
const title = stripHtml(linkMatch[2]);
|
|
41371
|
-
if (!url || !title)
|
|
41372
|
-
continue;
|
|
41373
|
-
const snippetMatch = item.match(/<p[^>]*>([\s\S]*?)<\/p>/i);
|
|
41374
|
-
const snippet = snippetMatch ? stripHtml(snippetMatch[1]) : "";
|
|
41375
|
-
results.push({ title, url, snippet });
|
|
41376
|
-
}
|
|
41377
|
-
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
|
+
}));
|
|
41378
41887
|
}
|
|
41379
41888
|
async function searchDuckDuckGo(query2, maxResults) {
|
|
41380
41889
|
const encoded = encodeURIComponent(query2);
|
|
@@ -41464,7 +41973,7 @@ function parseDDGHtml(html, maxResults) {
|
|
|
41464
41973
|
function stripHtml(html) {
|
|
41465
41974
|
return html.replace(/<[^>]*>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'").replace(/ /g, " ").replace(/\s+/g, " ").trim();
|
|
41466
41975
|
}
|
|
41467
|
-
var SEARCH_TIMEOUT_MS, _dispatcher, WebSearchTool,
|
|
41976
|
+
var SEARCH_TIMEOUT_MS, _dispatcher, WebSearchTool, DDG_UA, DDG_ENDPOINTS;
|
|
41468
41977
|
var init_web_search = __esm({
|
|
41469
41978
|
"../core/dist/tools/web-search.js"() {
|
|
41470
41979
|
"use strict";
|
|
@@ -41493,7 +42002,7 @@ var init_web_search = __esm({
|
|
|
41493
42002
|
const backends = [
|
|
41494
42003
|
{ name: "Serper", fn: searchSerper },
|
|
41495
42004
|
{ name: "Brave", fn: searchBrave },
|
|
41496
|
-
{ name: "
|
|
42005
|
+
{ name: "Bocha", fn: searchBocha },
|
|
41497
42006
|
{ name: "DuckDuckGo", fn: searchDuckDuckGo }
|
|
41498
42007
|
];
|
|
41499
42008
|
const errors = [];
|
|
@@ -41525,7 +42034,6 @@ var init_web_search = __esm({
|
|
|
41525
42034
|
});
|
|
41526
42035
|
}
|
|
41527
42036
|
};
|
|
41528
|
-
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";
|
|
41529
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";
|
|
41530
42038
|
DDG_ENDPOINTS = [
|
|
41531
42039
|
"https://lite.duckduckgo.com/lite/",
|
|
@@ -42100,7 +42608,7 @@ var init_patch = __esm({
|
|
|
42100
42608
|
});
|
|
42101
42609
|
|
|
42102
42610
|
// ../core/dist/tools/process-manager.js
|
|
42103
|
-
import { spawn as
|
|
42611
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
42104
42612
|
import { resolve as resolve7 } from "node:path";
|
|
42105
42613
|
function onBackgroundCompletion(cb) {
|
|
42106
42614
|
completionListeners.push(cb);
|
|
@@ -42168,7 +42676,7 @@ function createBackgroundExecTool(workspacePath) {
|
|
|
42168
42676
|
return JSON.stringify({ status: "denied", error: "Working directory must be within workspace" });
|
|
42169
42677
|
}
|
|
42170
42678
|
const id = `bg_${++sessionCounter}_${Date.now()}`;
|
|
42171
|
-
const child =
|
|
42679
|
+
const child = spawn3("sh", ["-c", command], {
|
|
42172
42680
|
cwd: effectiveCwd,
|
|
42173
42681
|
stdio: ["ignore", "pipe", "pipe"]
|
|
42174
42682
|
});
|
|
@@ -43386,6 +43894,8 @@ var init_attention = __esm({
|
|
|
43386
43894
|
triageToolHandlers;
|
|
43387
43895
|
triageChatFn;
|
|
43388
43896
|
lastTriageResult;
|
|
43897
|
+
/** True while a full-session deliberation is in progress (suppresses yield points). */
|
|
43898
|
+
isDeliberating = false;
|
|
43389
43899
|
/** Tracks whether the last yield-point decision was 'cancel' vs 'preempt'. */
|
|
43390
43900
|
lastYieldDecision;
|
|
43391
43901
|
unsubscribeNewItem;
|
|
@@ -43528,50 +44038,22 @@ var init_attention = __esm({
|
|
|
43528
44038
|
}
|
|
43529
44039
|
}
|
|
43530
44040
|
let triaged = false;
|
|
43531
|
-
if (this.mailbox.depth > 0 && this.
|
|
43532
|
-
|
|
43533
|
-
|
|
43534
|
-
|
|
43535
|
-
|
|
43536
|
-
|
|
43537
|
-
|
|
43538
|
-
|
|
43539
|
-
|
|
43540
|
-
} else {
|
|
43541
|
-
const redequeued = this.mailbox.dequeueById(item.id);
|
|
43542
|
-
if (redequeued)
|
|
43543
|
-
item = redequeued;
|
|
43544
|
-
}
|
|
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);
|
|
43545
44050
|
}
|
|
43546
|
-
|
|
43547
|
-
const
|
|
43548
|
-
|
|
43549
|
-
|
|
43550
|
-
|
|
43551
|
-
if (it.sourceType === "human_chat")
|
|
43552
|
-
return true;
|
|
43553
|
-
if (it.payload.extra?.triggerExecution)
|
|
43554
|
-
return true;
|
|
43555
|
-
return false;
|
|
43556
|
-
};
|
|
43557
|
-
for (const deferId of triageResult.deferItemIds) {
|
|
43558
|
-
if (isProtected(deferId))
|
|
43559
|
-
continue;
|
|
43560
|
-
this.mailbox.defer(deferId);
|
|
43561
|
-
}
|
|
43562
|
-
for (const dropId of triageResult.dropItemIds) {
|
|
43563
|
-
if (isProtected(dropId))
|
|
43564
|
-
continue;
|
|
43565
|
-
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);
|
|
43566
44056
|
}
|
|
43567
|
-
this.lastTriageResult = { ...triageResult, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
43568
|
-
this.delegate?.onTriageCompleted?.(triageResult);
|
|
43569
|
-
this.eventBus.emit("attention:triage", {
|
|
43570
|
-
agentId: this.agentId,
|
|
43571
|
-
triage: this.lastTriageResult
|
|
43572
|
-
});
|
|
43573
|
-
const triageDecision = this.recordDecision("triage", item, triageResult.reasoning);
|
|
43574
|
-
this.delegate?.onDecisionMade(triageDecision);
|
|
43575
44057
|
}
|
|
43576
44058
|
}
|
|
43577
44059
|
if (!triaged) {
|
|
@@ -43738,6 +44220,9 @@ var init_attention = __esm({
|
|
|
43738
44220
|
* - 'merge' → item was absorbed into current work (caller may inject into session)
|
|
43739
44221
|
*/
|
|
43740
44222
|
async checkYieldPoint() {
|
|
44223
|
+
if (this.isDeliberating) {
|
|
44224
|
+
return { decision: "continue" };
|
|
44225
|
+
}
|
|
43741
44226
|
if (!this.interruptSignal || !this.currentFocus) {
|
|
43742
44227
|
return { decision: "continue" };
|
|
43743
44228
|
}
|
|
@@ -43953,8 +44438,10 @@ var init_attention = __esm({
|
|
|
43953
44438
|
description: t.description,
|
|
43954
44439
|
inputSchema: t.inputSchema
|
|
43955
44440
|
}));
|
|
44441
|
+
const triageAgentName = ctx?.agentName ?? "Agent";
|
|
44442
|
+
const triageRoleHint = ctx?.agentRole ? ` Your role: ${ctx.agentRole}.` : "";
|
|
43956
44443
|
const messages = [
|
|
43957
|
-
{ 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 {` },
|
|
43958
44445
|
{ role: "user", content: prompt }
|
|
43959
44446
|
];
|
|
43960
44447
|
let iterations = 0;
|
|
@@ -44022,6 +44509,120 @@ var init_attention = __esm({
|
|
|
44022
44509
|
return null;
|
|
44023
44510
|
}
|
|
44024
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
|
+
}
|
|
44025
44626
|
buildTriagePrompt(headItem, ctx) {
|
|
44026
44627
|
const agentName = ctx?.agentName ?? "Agent";
|
|
44027
44628
|
const queuedItems = this.mailbox.getQueuedItems();
|
|
@@ -44143,6 +44744,7 @@ var init_attention = __esm({
|
|
|
44143
44744
|
processedItemId: this.lastTriageResult.processItemId,
|
|
44144
44745
|
deferredItemIds: this.lastTriageResult.deferItemIds,
|
|
44145
44746
|
droppedItemIds: this.lastTriageResult.dropItemIds,
|
|
44747
|
+
inlineCompletedIds: this.lastTriageResult.inlineCompletedIds ?? [],
|
|
44146
44748
|
timestamp: this.lastTriageResult.timestamp
|
|
44147
44749
|
} : void 0
|
|
44148
44750
|
};
|
|
@@ -44946,7 +45548,8 @@ var init_tool_loop_detector = __esm({
|
|
|
44946
45548
|
detectors: {
|
|
44947
45549
|
genericRepeat: true,
|
|
44948
45550
|
pingPong: true,
|
|
44949
|
-
noProgress: true
|
|
45551
|
+
noProgress: true,
|
|
45552
|
+
sameToolBurst: true
|
|
44950
45553
|
}
|
|
44951
45554
|
};
|
|
44952
45555
|
ToolLoopDetector = class {
|
|
@@ -44985,6 +45588,11 @@ var init_tool_loop_detector = __esm({
|
|
|
44985
45588
|
if (result.detected)
|
|
44986
45589
|
return result;
|
|
44987
45590
|
}
|
|
45591
|
+
if (this.config.detectors.sameToolBurst) {
|
|
45592
|
+
const result = this.detectSameToolBurst();
|
|
45593
|
+
if (result.detected)
|
|
45594
|
+
return result;
|
|
45595
|
+
}
|
|
44988
45596
|
return { detected: false, severity: "none", pattern: "", message: "" };
|
|
44989
45597
|
}
|
|
44990
45598
|
/**
|
|
@@ -45079,6 +45687,38 @@ var init_tool_loop_detector = __esm({
|
|
|
45079
45687
|
}
|
|
45080
45688
|
return noDetection();
|
|
45081
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
|
+
}
|
|
45082
45722
|
reset() {
|
|
45083
45723
|
this.history = [];
|
|
45084
45724
|
}
|
|
@@ -45308,6 +45948,7 @@ var init_agent2 = __esm({
|
|
|
45308
45948
|
semanticSearch;
|
|
45309
45949
|
currentSessionId;
|
|
45310
45950
|
currentInteractingUserId;
|
|
45951
|
+
pendingDeliberationResult;
|
|
45311
45952
|
dbSessionMap = /* @__PURE__ */ new Map();
|
|
45312
45953
|
orgContext;
|
|
45313
45954
|
contextMdPath;
|
|
@@ -45716,6 +46357,12 @@ ${notification.stdoutTail}`);
|
|
|
45716
46357
|
getAttentionController() {
|
|
45717
46358
|
return this.attentionController;
|
|
45718
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
|
+
}
|
|
45719
46366
|
/**
|
|
45720
46367
|
* Check yield point during task execution — called between LLM turns.
|
|
45721
46368
|
* Returns decision info so the tool loop can act on preemption or merges.
|
|
@@ -45764,12 +46411,20 @@ ${notification.stdoutTail}`);
|
|
|
45764
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) })) : [];
|
|
45765
46412
|
const activities = this.recentActivitySummaries();
|
|
45766
46413
|
const activeTaskIds = Array.from(this.activeTasks);
|
|
45767
|
-
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 };
|
|
45768
46415
|
},
|
|
45769
46416
|
onTriageCompleted: (result) => {
|
|
45770
46417
|
if (!result)
|
|
45771
46418
|
return;
|
|
45772
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);
|
|
45773
46428
|
}
|
|
45774
46429
|
};
|
|
45775
46430
|
}
|
|
@@ -45868,7 +46523,7 @@ ${notification.stdoutTail}`);
|
|
|
45868
46523
|
case "requirement_update": {
|
|
45869
46524
|
if (extra.actionRequired) {
|
|
45870
46525
|
const reqId = item.payload.requirementId ?? "unknown";
|
|
45871
|
-
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" }));
|
|
45872
46527
|
resolveResponse(reply);
|
|
45873
46528
|
return reply;
|
|
45874
46529
|
}
|
|
@@ -45881,7 +46536,7 @@ ${notification.stdoutTail}`);
|
|
|
45881
46536
|
}
|
|
45882
46537
|
case "requirement_comment": {
|
|
45883
46538
|
const reqId = item.payload.requirementId ?? "unknown";
|
|
45884
|
-
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" }));
|
|
45885
46540
|
resolveResponse(reply);
|
|
45886
46541
|
return reply;
|
|
45887
46542
|
}
|
|
@@ -45893,7 +46548,7 @@ ${notification.stdoutTail}`);
|
|
|
45893
46548
|
this.injectUserMessage(sessionId, item.payload.content);
|
|
45894
46549
|
} else {
|
|
45895
46550
|
const commentTaskId = taskId2 ?? "unknown";
|
|
45896
|
-
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" }));
|
|
45897
46552
|
}
|
|
45898
46553
|
resolveResponse("");
|
|
45899
46554
|
return;
|
|
@@ -46401,7 +47056,7 @@ ${conversationText}`
|
|
|
46401
47056
|
const filename = `${toolName}_${++this.toolResultCounter}_${Date.now()}.txt`;
|
|
46402
47057
|
const filepath = join9(offloadDir, filename);
|
|
46403
47058
|
writeFileSync8(filepath, result);
|
|
46404
|
-
const preview = result
|
|
47059
|
+
const preview = safeSlice(result, 0, previewSize);
|
|
46405
47060
|
const lineCount = result.split("\n").length;
|
|
46406
47061
|
return [
|
|
46407
47062
|
`[FULL output (${result.length} chars, ${lineCount} lines) saved to: ${filepath}]`,
|
|
@@ -46410,11 +47065,11 @@ ${conversationText}`
|
|
|
46410
47065
|
``,
|
|
46411
47066
|
preview,
|
|
46412
47067
|
``,
|
|
46413
|
-
`[... remaining ${result.length -
|
|
47068
|
+
`[... remaining ${result.length - preview.length} chars in file ...]`
|
|
46414
47069
|
].join("\n");
|
|
46415
47070
|
} catch {
|
|
46416
47071
|
const fallbackSize = isBrowserTool ? 3e4 : 8e3;
|
|
46417
|
-
return result
|
|
47072
|
+
return safeSlice(result, 0, fallbackSize) + `
|
|
46418
47073
|
|
|
46419
47074
|
[... output truncated at ${fallbackSize} of ${result.length} total chars due to file-save failure ...]`;
|
|
46420
47075
|
}
|
|
@@ -46629,6 +47284,109 @@ ${conversationText}`
|
|
|
46629
47284
|
lines.push(`Reasoning: ${result.reasoning}`);
|
|
46630
47285
|
this.currentCognition = lines.join("\n");
|
|
46631
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
|
+
}
|
|
46632
47390
|
getDynamicContext() {
|
|
46633
47391
|
const parts = [...this.dynamicContextProviders.values()].map((p) => p()).filter(Boolean);
|
|
46634
47392
|
for (const [name, instructions] of this.activatedSkillInstructions) {
|
|
@@ -46712,6 +47470,12 @@ ${instructions}
|
|
|
46712
47470
|
getUsageStats() {
|
|
46713
47471
|
return this.metricsCollector.getUsageStats();
|
|
46714
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
|
+
}
|
|
46715
47479
|
emitAudit(event) {
|
|
46716
47480
|
this.metricsCollector.recordAudit(event);
|
|
46717
47481
|
this.auditCallback?.(event);
|
|
@@ -47130,12 +47894,16 @@ ${block}
|
|
|
47130
47894
|
type: "llm_request",
|
|
47131
47895
|
action: "chat",
|
|
47132
47896
|
tokensUsed: tokensThisCall,
|
|
47897
|
+
inputTokens: response.usage.inputTokens,
|
|
47898
|
+
outputTokens: response.usage.outputTokens,
|
|
47899
|
+
cost: this.computeCallCost(response.usage.inputTokens, response.usage.outputTokens),
|
|
47133
47900
|
durationMs: Date.now() - llmStart,
|
|
47134
47901
|
success: true
|
|
47135
47902
|
});
|
|
47136
47903
|
let toolIterations = 0;
|
|
47137
47904
|
const effectiveMaxIter = options?.maxToolIterations ?? this._maxToolIterations;
|
|
47138
47905
|
const commentToolUsed = /* @__PURE__ */ new Set();
|
|
47906
|
+
const requirementActionToolUsed = /* @__PURE__ */ new Set();
|
|
47139
47907
|
while (response.finishReason === "tool_use" && response.toolCalls?.length || response.finishReason === "max_tokens") {
|
|
47140
47908
|
if (++toolIterations > effectiveMaxIter) {
|
|
47141
47909
|
log17.warn("Tool loop hit max iterations", {
|
|
@@ -47236,6 +48004,10 @@ ${block}
|
|
|
47236
48004
|
if (tc.name === "task_comment" || tc.name === "requirement_comment") {
|
|
47237
48005
|
commentToolUsed.add(tc.name);
|
|
47238
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
|
+
}
|
|
47239
48011
|
}
|
|
47240
48012
|
const loopCheck = this.loopDetector.check();
|
|
47241
48013
|
if (loopCheck.detected) {
|
|
@@ -47304,6 +48076,9 @@ ${chatYield.item.payload.content}`;
|
|
|
47304
48076
|
type: "llm_request",
|
|
47305
48077
|
action: "chat",
|
|
47306
48078
|
tokensUsed: tokens2,
|
|
48079
|
+
inputTokens: response.usage.inputTokens,
|
|
48080
|
+
outputTokens: response.usage.outputTokens,
|
|
48081
|
+
cost: this.computeCallCost(response.usage.inputTokens, response.usage.outputTokens),
|
|
47307
48082
|
durationMs: Date.now() - llmStart2,
|
|
47308
48083
|
success: true
|
|
47309
48084
|
});
|
|
@@ -47395,6 +48170,92 @@ ${chatYield.item.payload.content}`;
|
|
|
47395
48170
|
}, this.getEffectiveProvider()), "Chat LLM comment-reminder-final");
|
|
47396
48171
|
}
|
|
47397
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
|
+
}
|
|
47398
48259
|
const rawReply = sanitizeLLMReply(response.content);
|
|
47399
48260
|
const displayReply = stripCompletionMarker(rawReply);
|
|
47400
48261
|
const outputCheck = await this.guardrails.checkOutput(displayReply, { agentId: this.id });
|
|
@@ -47563,6 +48424,9 @@ ${chatYield.item.payload.content}`;
|
|
|
47563
48424
|
type: "llm_request",
|
|
47564
48425
|
action: "chat_stream",
|
|
47565
48426
|
tokensUsed: tokensThisCall,
|
|
48427
|
+
inputTokens: response.usage.inputTokens,
|
|
48428
|
+
outputTokens: response.usage.outputTokens,
|
|
48429
|
+
cost: this.computeCallCost(response.usage.inputTokens, response.usage.outputTokens),
|
|
47566
48430
|
durationMs: Date.now() - llmStart,
|
|
47567
48431
|
success: true
|
|
47568
48432
|
});
|
|
@@ -47741,6 +48605,9 @@ ${streamYield.item.payload.content}`;
|
|
|
47741
48605
|
type: "llm_request",
|
|
47742
48606
|
action: "chat_stream",
|
|
47743
48607
|
tokensUsed: tokens2,
|
|
48608
|
+
inputTokens: response.usage.inputTokens,
|
|
48609
|
+
outputTokens: response.usage.outputTokens,
|
|
48610
|
+
cost: this.computeCallCost(response.usage.inputTokens, response.usage.outputTokens),
|
|
47744
48611
|
durationMs: Date.now() - llmStart2,
|
|
47745
48612
|
success: true
|
|
47746
48613
|
});
|
|
@@ -48046,7 +48913,7 @@ ${streamYield.item.payload.content}`;
|
|
|
48046
48913
|
let taskLlmTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
48047
48914
|
this.updateTokensUsed(taskLlmTokens);
|
|
48048
48915
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
48049
|
-
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 });
|
|
48050
48917
|
while (response.finishReason === "tool_use" && response.toolCalls?.length || response.finishReason === "max_tokens") {
|
|
48051
48918
|
taskToolIterations++;
|
|
48052
48919
|
if (cancelToken?.cancelled) {
|
|
@@ -48238,7 +49105,7 @@ ${yieldResult.item.payload.content}`
|
|
|
48238
49105
|
taskLlmTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
48239
49106
|
this.updateTokensUsed(taskLlmTokens);
|
|
48240
49107
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
48241
|
-
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 });
|
|
48242
49109
|
}
|
|
48243
49110
|
if (cancelToken?.cancelled) {
|
|
48244
49111
|
flushText();
|
|
@@ -48478,7 +49345,7 @@ ${yieldResult.item.payload.content}`
|
|
|
48478
49345
|
let risTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
48479
49346
|
this.updateTokensUsed(risTokens);
|
|
48480
49347
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
48481
|
-
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 });
|
|
48482
49349
|
let toolIter = 0;
|
|
48483
49350
|
while (response.finishReason === "tool_use" && response.toolCalls?.length || response.finishReason === "max_tokens") {
|
|
48484
49351
|
if (++toolIter > 200)
|
|
@@ -48507,6 +49374,7 @@ ${yieldResult.item.payload.content}`
|
|
|
48507
49374
|
continue;
|
|
48508
49375
|
}
|
|
48509
49376
|
emit("tool_start", tc.name, { arguments: tc.arguments });
|
|
49377
|
+
this.emitActivityLog(actId, "tool_start", tc.name, { arguments: tc.arguments });
|
|
48510
49378
|
const toolStart = Date.now();
|
|
48511
49379
|
try {
|
|
48512
49380
|
let result = await this.executeTool(tc, void 0, sessionId);
|
|
@@ -48514,11 +49382,13 @@ ${yieldResult.item.payload.content}`
|
|
|
48514
49382
|
const isErr = isErrorResult2(result);
|
|
48515
49383
|
const durationMs = Date.now() - toolStart;
|
|
48516
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 });
|
|
48517
49386
|
this.emitAudit({ type: "tool_call", action: tc.name, durationMs, success: !isErr });
|
|
48518
49387
|
this.memory.appendMessage(sessionId, { role: "tool", content: result, toolCallId: tc.id });
|
|
48519
49388
|
} catch (toolErr) {
|
|
48520
49389
|
const durationMs = Date.now() - toolStart;
|
|
48521
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) });
|
|
48522
49392
|
this.emitAudit({ type: "tool_call", action: tc.name, durationMs, success: false });
|
|
48523
49393
|
this.memory.appendMessage(sessionId, { role: "tool", content: `Error: ${String(toolErr)}`, toolCallId: tc.id });
|
|
48524
49394
|
}
|
|
@@ -48540,11 +49410,14 @@ ${yieldResult.item.payload.content}`
|
|
|
48540
49410
|
risTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
48541
49411
|
this.updateTokensUsed(risTokens);
|
|
48542
49412
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
48543
|
-
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 });
|
|
48544
49414
|
}
|
|
48545
49415
|
flushText();
|
|
48546
49416
|
const rawReply = sanitizeLLMReply(response.content);
|
|
48547
49417
|
const displayReply = stripCompletionMarker(rawReply);
|
|
49418
|
+
if (displayReply.trim()) {
|
|
49419
|
+
this.emitActivityLog(actId, "text", displayReply);
|
|
49420
|
+
}
|
|
48548
49421
|
this.memory.appendMessage(sessionId, { role: "assistant", content: displayReply, reasoningContent: response.reasoningContent });
|
|
48549
49422
|
return rawReply;
|
|
48550
49423
|
} catch (error) {
|
|
@@ -48828,9 +49701,20 @@ ${d.text}
|
|
|
48828
49701
|
const explicitTaskId = toolCall.arguments.related_task_id;
|
|
48829
49702
|
const taskId2 = explicitTaskId ?? this.getCurrentTaskId();
|
|
48830
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(", ")} -->` : "";
|
|
48831
49715
|
const formattedMsg = `**${title}**
|
|
48832
49716
|
|
|
48833
|
-
${body}`;
|
|
49717
|
+
${body}${contextSuffix}`;
|
|
48834
49718
|
if (this.currentSessionId) {
|
|
48835
49719
|
this.memory.appendMessage(this.currentSessionId, {
|
|
48836
49720
|
role: "assistant",
|
|
@@ -48844,7 +49728,7 @@ ${body}`;
|
|
|
48844
49728
|
this.eventBus.emit("agent:notify-user", {
|
|
48845
49729
|
agentId: this.id,
|
|
48846
49730
|
sessionId: this.currentSessionId,
|
|
48847
|
-
targetUserId: this.currentInteractingUserId,
|
|
49731
|
+
targetUserId: explicitTargetUser ?? this.currentInteractingUserId,
|
|
48848
49732
|
title,
|
|
48849
49733
|
body,
|
|
48850
49734
|
priority,
|
|
@@ -48897,6 +49781,21 @@ ${body}`;
|
|
|
48897
49781
|
return JSON.stringify({ status: "error", message: `Failed to get user approval: ${String(err)}` });
|
|
48898
49782
|
}
|
|
48899
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
|
+
}
|
|
48900
49799
|
const profile = this.config.profile;
|
|
48901
49800
|
if (profile) {
|
|
48902
49801
|
if (profile.toolWhitelist && !profile.toolWhitelist.includes(toolCall.name)) {
|
|
@@ -49168,6 +50067,9 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
49168
50067
|
"**Report format** \u2014 create a deliverable via `deliverable_create`:",
|
|
49169
50068
|
`- **title**: "Daily Report \u2014 ${todayDate}"`,
|
|
49170
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',
|
|
49171
50073
|
"- **Content must be concise, clear, and accurate**:",
|
|
49172
50074
|
" 1. **My work today**: What you personally accomplished (tasks reviewed, approved/rejected, decisions made)",
|
|
49173
50075
|
" 2. **My team progress**: What each member of YOUR team accomplished today (use `team_status` to check). Focus on your own team only.",
|
|
@@ -49326,11 +50228,11 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
49326
50228
|
"notify_user",
|
|
49327
50229
|
"request_user_approval",
|
|
49328
50230
|
"recall_activity",
|
|
49329
|
-
"
|
|
49330
|
-
"
|
|
50231
|
+
"package_install",
|
|
50232
|
+
"package_list"
|
|
49331
50233
|
];
|
|
49332
50234
|
if (isManager) {
|
|
49333
|
-
baseTools.push("task_board_health", "task_cleanup_duplicates", "task_assign", "team_status", "deliverable_create", "deliverable_search"
|
|
50235
|
+
baseTools.push("task_board_health", "task_cleanup_duplicates", "task_assign", "team_status", "deliverable_create", "deliverable_search");
|
|
49334
50236
|
}
|
|
49335
50237
|
const HEARTBEAT_ALLOWED_TOOLS = new Set(baseTools);
|
|
49336
50238
|
const HEARTBEAT_MAX_RETRIES = 3;
|
|
@@ -49874,21 +50776,52 @@ ${sharedContent}` : roleContent;
|
|
|
49874
50776
|
});
|
|
49875
50777
|
|
|
49876
50778
|
// ../core/dist/tools/mcp-client.js
|
|
49877
|
-
import { spawn as
|
|
49878
|
-
var log18, MCPClientManager;
|
|
50779
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
50780
|
+
var log18, DEFAULT_IDLE_TIMEOUT_MS, MCPClientManager;
|
|
49879
50781
|
var init_mcp_client = __esm({
|
|
49880
50782
|
"../core/dist/tools/mcp-client.js"() {
|
|
49881
50783
|
"use strict";
|
|
49882
50784
|
init_dist();
|
|
49883
50785
|
log18 = createLogger("mcp-client");
|
|
50786
|
+
DEFAULT_IDLE_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
49884
50787
|
MCPClientManager = class _MCPClientManager {
|
|
49885
50788
|
servers = /* @__PURE__ */ new Map();
|
|
50789
|
+
serverConfigs = /* @__PURE__ */ new Map();
|
|
49886
50790
|
requestId = 0;
|
|
49887
50791
|
pendingRequests = /* @__PURE__ */ new Map();
|
|
49888
50792
|
stdoutBuffers = /* @__PURE__ */ new Map();
|
|
50793
|
+
idleTimers = /* @__PURE__ */ new Map();
|
|
50794
|
+
idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_MS;
|
|
49889
50795
|
static scopedKey(name, scopeId) {
|
|
49890
50796
|
return `${name}::${scopeId}`;
|
|
49891
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
|
+
}
|
|
49892
50825
|
/**
|
|
49893
50826
|
* Spawn an MCP server process, run JSON-RPC init handshake, list tools,
|
|
49894
50827
|
* and store under the given internal key. Shared by connect and connectScoped.
|
|
@@ -49899,8 +50832,9 @@ var init_mcp_client = __esm({
|
|
|
49899
50832
|
log18.info(`MCP server ${displayName} already connected, reusing (${existing.tools.length} tools)`);
|
|
49900
50833
|
return existing.tools;
|
|
49901
50834
|
}
|
|
50835
|
+
this.serverConfigs.set(key2, { displayName, config });
|
|
49902
50836
|
log18.info(`Connecting to MCP server: ${displayName}`, { command: config.command, key: key2 });
|
|
49903
|
-
const proc =
|
|
50837
|
+
const proc = spawn4(config.command, config.args ?? [], {
|
|
49904
50838
|
stdio: ["pipe", "pipe", "pipe"],
|
|
49905
50839
|
env: { ...process.env, ...config.env },
|
|
49906
50840
|
shell: process.platform === "win32"
|
|
@@ -49925,6 +50859,7 @@ var init_mcp_client = __esm({
|
|
|
49925
50859
|
}
|
|
49926
50860
|
this.servers.delete(key2);
|
|
49927
50861
|
this.stdoutBuffers.delete(proc);
|
|
50862
|
+
this.clearIdleTimer(key2);
|
|
49928
50863
|
for (const [id, req] of this.pendingRequests) {
|
|
49929
50864
|
if (req.proc !== proc)
|
|
49930
50865
|
continue;
|
|
@@ -49945,6 +50880,7 @@ var init_mcp_client = __esm({
|
|
|
49945
50880
|
const toolsResult = await this.sendRequest(proc, "tools/list", {});
|
|
49946
50881
|
const tools = toolsResult?.tools ?? [];
|
|
49947
50882
|
this.servers.set(key2, { process: proc, tools });
|
|
50883
|
+
this.resetIdleTimer(key2);
|
|
49948
50884
|
log18.info(`MCP server ${displayName} connected with ${tools.length} tools`);
|
|
49949
50885
|
return tools;
|
|
49950
50886
|
} catch (err) {
|
|
@@ -49964,19 +50900,27 @@ var init_mcp_client = __esm({
|
|
|
49964
50900
|
const key2 = _MCPClientManager.scopedKey(name, scopeId);
|
|
49965
50901
|
return this.connectByKey(key2, `${name}[${scopeId}]`, config);
|
|
49966
50902
|
}
|
|
49967
|
-
callToolByKey(key2, toolName, args) {
|
|
49968
|
-
|
|
49969
|
-
if (!server)
|
|
49970
|
-
|
|
49971
|
-
|
|
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", {
|
|
49972
50917
|
name: toolName,
|
|
49973
50918
|
arguments: args
|
|
49974
|
-
}).then((result) => {
|
|
49975
|
-
const content = result?.content;
|
|
49976
|
-
if (content?.[0]?.text)
|
|
49977
|
-
return content[0].text;
|
|
49978
|
-
return JSON.stringify(result);
|
|
49979
50919
|
});
|
|
50920
|
+
const content = result?.content;
|
|
50921
|
+
if (content?.[0]?.text)
|
|
50922
|
+
return content[0].text;
|
|
50923
|
+
return JSON.stringify(result);
|
|
49980
50924
|
}
|
|
49981
50925
|
async callTool(serverName, toolName, args) {
|
|
49982
50926
|
return this.callToolByKey(serverName, toolName, args);
|
|
@@ -50017,6 +50961,7 @@ var init_mcp_client = __esm({
|
|
|
50017
50961
|
async disconnectServer(name) {
|
|
50018
50962
|
const server = this.servers.get(name);
|
|
50019
50963
|
if (server) {
|
|
50964
|
+
this.clearIdleTimer(name);
|
|
50020
50965
|
server.process.kill();
|
|
50021
50966
|
this.servers.delete(name);
|
|
50022
50967
|
this.stdoutBuffers.delete(server.process);
|
|
@@ -50030,6 +50975,7 @@ var init_mcp_client = __esm({
|
|
|
50030
50975
|
/**
|
|
50031
50976
|
* Disconnect all scoped server instances belonging to a given scope (e.g. agent).
|
|
50032
50977
|
* Shared (non-scoped) servers are not affected.
|
|
50978
|
+
* The server configs are retained so the server can auto-reconnect on next tool call.
|
|
50033
50979
|
*/
|
|
50034
50980
|
async disconnectAllForScope(scopeId) {
|
|
50035
50981
|
const suffix = `::${scopeId}`;
|
|
@@ -50039,10 +50985,28 @@ var init_mcp_client = __esm({
|
|
|
50039
50985
|
}
|
|
50040
50986
|
}
|
|
50041
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
|
+
}
|
|
50042
51005
|
async disconnectAll() {
|
|
50043
51006
|
for (const name of [...this.servers.keys()]) {
|
|
50044
51007
|
await this.disconnectServer(name);
|
|
50045
51008
|
}
|
|
51009
|
+
this.serverConfigs.clear();
|
|
50046
51010
|
}
|
|
50047
51011
|
/**
|
|
50048
51012
|
* Accumulates stdout data into a line buffer and dispatches
|
|
@@ -50532,71 +51496,178 @@ var init_browser_session = __esm({
|
|
|
50532
51496
|
});
|
|
50533
51497
|
|
|
50534
51498
|
// ../core/dist/tools/manager.js
|
|
50535
|
-
function
|
|
51499
|
+
function createPackageTools(ctx) {
|
|
50536
51500
|
return [
|
|
50537
|
-
|
|
50538
|
-
|
|
50539
|
-
|
|
50540
|
-
|
|
50541
|
-
|
|
50542
|
-
|
|
50543
|
-
|
|
50544
|
-
type:
|
|
50545
|
-
|
|
50546
|
-
|
|
50547
|
-
|
|
50548
|
-
|
|
51501
|
+
{
|
|
51502
|
+
name: "package_list",
|
|
51503
|
+
description: 'List all available packages. type "agent": built-in roles (developer, content-writer, etc.) and custom agent packages. type "team": team templates (content-team, research-lab, etc.). type "skill": skill packages. Omit type to list all. Install with package_install. To find more online, use hub_search.',
|
|
51504
|
+
inputSchema: {
|
|
51505
|
+
type: "object",
|
|
51506
|
+
properties: {
|
|
51507
|
+
type: {
|
|
51508
|
+
type: "string",
|
|
51509
|
+
enum: ["agent", "team", "skill"],
|
|
51510
|
+
description: "Filter by type (optional). Omit to list all."
|
|
51511
|
+
}
|
|
51512
|
+
}
|
|
51513
|
+
},
|
|
51514
|
+
async execute(args) {
|
|
51515
|
+
const listArtifacts = ctx.listArtifacts?.();
|
|
51516
|
+
if (!listArtifacts)
|
|
51517
|
+
return JSON.stringify({ status: "error", error: "Package service is not available yet. Please try again later." });
|
|
51518
|
+
try {
|
|
51519
|
+
const type = args["type"];
|
|
51520
|
+
const artifacts = listArtifacts(type);
|
|
51521
|
+
const listTemplates = ctx.listTemplates?.();
|
|
51522
|
+
const roles = (!type || type === "agent") && listTemplates ? listTemplates() : [];
|
|
51523
|
+
const roleItems = roles.map((r) => ({
|
|
51524
|
+
type: "agent",
|
|
51525
|
+
source: "role",
|
|
51526
|
+
name: r.id ?? r.name,
|
|
51527
|
+
description: r.description ?? r.name,
|
|
51528
|
+
...r
|
|
51529
|
+
}));
|
|
51530
|
+
const items = [...roleItems, ...artifacts];
|
|
51531
|
+
return JSON.stringify({ items, count: items.length });
|
|
51532
|
+
} catch (error) {
|
|
51533
|
+
return JSON.stringify({ status: "error", error: String(error) });
|
|
51534
|
+
}
|
|
51535
|
+
}
|
|
51536
|
+
},
|
|
51537
|
+
{
|
|
51538
|
+
name: "package_install",
|
|
51539
|
+
description: 'Install a package into the live organization. type "agent": hire/install an agent (from a built-in role or a custom package). type "team": deploy a full team with all members, norms, and starter tasks. type "skill": install a skill package. Use package_list to see what is available.',
|
|
51540
|
+
inputSchema: {
|
|
51541
|
+
type: "object",
|
|
51542
|
+
properties: {
|
|
51543
|
+
type: {
|
|
51544
|
+
type: "string",
|
|
51545
|
+
enum: ["agent", "team", "skill"],
|
|
51546
|
+
description: "Package type"
|
|
51547
|
+
},
|
|
51548
|
+
name: { type: "string", description: "Package name (from package_list)" },
|
|
51549
|
+
agent_name: { type: "string", description: 'Display name for the new agent (required when installing from a built-in role, e.g. "developer")' },
|
|
51550
|
+
skills: {
|
|
51551
|
+
type: "array",
|
|
51552
|
+
items: { type: "string" },
|
|
51553
|
+
description: "Optional skill IDs to assign to the new agent"
|
|
50549
51554
|
}
|
|
50550
51555
|
},
|
|
50551
|
-
|
|
50552
|
-
|
|
50553
|
-
|
|
50554
|
-
|
|
50555
|
-
|
|
50556
|
-
|
|
51556
|
+
required: ["type", "name"]
|
|
51557
|
+
},
|
|
51558
|
+
async execute(args) {
|
|
51559
|
+
const installArtifact = ctx.installArtifact?.();
|
|
51560
|
+
if (!installArtifact)
|
|
51561
|
+
return JSON.stringify({ status: "error", error: "Package service is not available yet. Please try again later." });
|
|
51562
|
+
try {
|
|
51563
|
+
const type = args["type"]?.trim();
|
|
51564
|
+
const name = args["name"]?.trim();
|
|
51565
|
+
if (!type || !["agent", "team", "skill"].includes(type))
|
|
51566
|
+
return JSON.stringify({ status: "error", error: "type is required and must be one of: agent, team, skill" });
|
|
51567
|
+
if (!name)
|
|
51568
|
+
return JSON.stringify({ status: "error", error: "name is required \u2014 use package_list to see available packages" });
|
|
51569
|
+
if (type === "agent") {
|
|
51570
|
+
try {
|
|
51571
|
+
const result2 = await installArtifact(type, name);
|
|
51572
|
+
return JSON.stringify({
|
|
51573
|
+
status: "success",
|
|
51574
|
+
...result2,
|
|
51575
|
+
next_steps: "Installed successfully. Next: onboard new agent with project context via agent_send_message, then assign tasks via task_create."
|
|
51576
|
+
});
|
|
51577
|
+
} catch {
|
|
51578
|
+
const hireFromTemplate = ctx.hireFromTemplate?.();
|
|
51579
|
+
if (hireFromTemplate) {
|
|
51580
|
+
const agentName = args["agent_name"]?.trim();
|
|
51581
|
+
if (!agentName)
|
|
51582
|
+
return JSON.stringify({ status: "error", error: "agent_name is required when installing from a built-in role \u2014 provide a display name for the new agent" });
|
|
51583
|
+
const result2 = await hireFromTemplate(name, agentName, args["skills"]);
|
|
51584
|
+
return JSON.stringify({
|
|
51585
|
+
status: "success",
|
|
51586
|
+
type: "agent",
|
|
51587
|
+
agent: result2,
|
|
51588
|
+
next_steps: "Agent hired and started. Next: onboard with project context via agent_send_message, then assign tasks via task_create."
|
|
51589
|
+
});
|
|
51590
|
+
}
|
|
51591
|
+
throw new Error(`Agent package not found: ${name}. Use package_list to see available packages.`);
|
|
51592
|
+
}
|
|
50557
51593
|
}
|
|
51594
|
+
const result = await installArtifact(type, name);
|
|
51595
|
+
return JSON.stringify({
|
|
51596
|
+
status: "success",
|
|
51597
|
+
...result,
|
|
51598
|
+
...type === "team" ? {
|
|
51599
|
+
next_steps: "Installed successfully. Next: onboard new agent(s) with project context via agent_send_message, then assign initial tasks via task_create."
|
|
51600
|
+
} : {}
|
|
51601
|
+
});
|
|
51602
|
+
} catch (error) {
|
|
51603
|
+
return JSON.stringify({ status: "error", error: String(error) });
|
|
50558
51604
|
}
|
|
50559
51605
|
}
|
|
50560
|
-
|
|
50561
|
-
|
|
50562
|
-
|
|
50563
|
-
|
|
50564
|
-
|
|
50565
|
-
|
|
50566
|
-
|
|
50567
|
-
|
|
50568
|
-
type:
|
|
50569
|
-
|
|
50570
|
-
|
|
50571
|
-
description: "Artifact type"
|
|
50572
|
-
},
|
|
50573
|
-
name: { type: "string", description: "Artifact name (from builder_list)" }
|
|
51606
|
+
},
|
|
51607
|
+
{
|
|
51608
|
+
name: "hub_search",
|
|
51609
|
+
description: "Search Markus Hub for community-published agents, teams, and skills. Returns a list of available items with descriptions and popularity.",
|
|
51610
|
+
inputSchema: {
|
|
51611
|
+
type: "object",
|
|
51612
|
+
properties: {
|
|
51613
|
+
type: {
|
|
51614
|
+
type: "string",
|
|
51615
|
+
enum: ["agent", "team", "skill"],
|
|
51616
|
+
description: "Filter by item type (optional)"
|
|
50574
51617
|
},
|
|
50575
|
-
|
|
50576
|
-
|
|
50577
|
-
|
|
50578
|
-
try {
|
|
50579
|
-
const type = args["type"]?.trim();
|
|
50580
|
-
const name = args["name"]?.trim();
|
|
50581
|
-
if (!type || !["agent", "team", "skill"].includes(type))
|
|
50582
|
-
return JSON.stringify({ status: "error", error: "type is required and must be one of: agent, team, skill" });
|
|
50583
|
-
if (!name)
|
|
50584
|
-
return JSON.stringify({ status: "error", error: "name is required \u2014 provide the artifact name from builder_list" });
|
|
50585
|
-
const result = await ctx.installArtifact(type, name);
|
|
50586
|
-
const isAgentOrTeam = result.type === "agent" || result.type === "team";
|
|
50587
|
-
return JSON.stringify({
|
|
50588
|
-
status: "success",
|
|
50589
|
-
...result,
|
|
50590
|
-
...isAgentOrTeam ? {
|
|
50591
|
-
next_steps: "Installed successfully. Next: onboard new agent(s) with project context via agent_send_message, then assign initial tasks via task_create."
|
|
50592
|
-
} : {}
|
|
50593
|
-
});
|
|
50594
|
-
} catch (error) {
|
|
50595
|
-
return JSON.stringify({ status: "error", error: String(error) });
|
|
51618
|
+
query: {
|
|
51619
|
+
type: "string",
|
|
51620
|
+
description: "Search query (optional)"
|
|
50596
51621
|
}
|
|
50597
51622
|
}
|
|
51623
|
+
},
|
|
51624
|
+
async execute(args) {
|
|
51625
|
+
const searchHub = ctx.searchHub?.();
|
|
51626
|
+
if (!searchHub)
|
|
51627
|
+
return JSON.stringify({ status: "error", error: "Hub service is not available. Please try again later." });
|
|
51628
|
+
try {
|
|
51629
|
+
const items = await searchHub({
|
|
51630
|
+
type: args["type"],
|
|
51631
|
+
query: args["query"]
|
|
51632
|
+
});
|
|
51633
|
+
return JSON.stringify({ items, count: items.length });
|
|
51634
|
+
} catch (error) {
|
|
51635
|
+
return JSON.stringify({ status: "error", error: String(error) });
|
|
51636
|
+
}
|
|
50598
51637
|
}
|
|
50599
|
-
|
|
51638
|
+
},
|
|
51639
|
+
{
|
|
51640
|
+
name: "hub_install",
|
|
51641
|
+
description: "Download an item from Markus Hub and install it. Combines download, save as artifact, and install into a single step. For agents/teams: remember to onboard the new agent(s) after installation.",
|
|
51642
|
+
inputSchema: {
|
|
51643
|
+
type: "object",
|
|
51644
|
+
properties: {
|
|
51645
|
+
item_id: { type: "string", description: "Hub item ID (from hub_search results)" }
|
|
51646
|
+
},
|
|
51647
|
+
required: ["item_id"]
|
|
51648
|
+
},
|
|
51649
|
+
async execute(args) {
|
|
51650
|
+
const downloadAndInstall = ctx.downloadAndInstall?.();
|
|
51651
|
+
if (!downloadAndInstall)
|
|
51652
|
+
return JSON.stringify({ status: "error", error: "Hub service is not available. Please try again later." });
|
|
51653
|
+
try {
|
|
51654
|
+
const itemId = args["item_id"]?.trim();
|
|
51655
|
+
if (!itemId)
|
|
51656
|
+
return JSON.stringify({ status: "error", error: "item_id is required \u2014 use hub_search to find available items first" });
|
|
51657
|
+
const result = await downloadAndInstall(itemId);
|
|
51658
|
+
const isAgentOrTeam = result.type === "agent" || result.type === "team";
|
|
51659
|
+
return JSON.stringify({
|
|
51660
|
+
status: "success",
|
|
51661
|
+
...result,
|
|
51662
|
+
...isAgentOrTeam ? {
|
|
51663
|
+
next_steps: "Downloaded and installed from Hub. Next: onboard new agent(s) with project context via agent_send_message, then assign initial tasks via task_create."
|
|
51664
|
+
} : {}
|
|
51665
|
+
});
|
|
51666
|
+
} catch (error) {
|
|
51667
|
+
return JSON.stringify({ status: "error", error: String(error) });
|
|
51668
|
+
}
|
|
51669
|
+
}
|
|
51670
|
+
}
|
|
50600
51671
|
];
|
|
50601
51672
|
}
|
|
50602
51673
|
function createManagerTools(ctx) {
|
|
@@ -50717,40 +51788,6 @@ function createManagerTools(ctx) {
|
|
|
50717
51788
|
}
|
|
50718
51789
|
}
|
|
50719
51790
|
] : [],
|
|
50720
|
-
...ctx.listArtifacts ? [
|
|
50721
|
-
{
|
|
50722
|
-
name: "package_list",
|
|
50723
|
-
description: 'List all available packages. type "agent": built-in roles (developer, content-writer, etc.) and custom agent packages. type "team": team templates (content-team, research-lab, etc.). type "skill": skill packages. Omit type to list all. Install with package_install. To find more online, use hub_search.',
|
|
50724
|
-
inputSchema: {
|
|
50725
|
-
type: "object",
|
|
50726
|
-
properties: {
|
|
50727
|
-
type: {
|
|
50728
|
-
type: "string",
|
|
50729
|
-
enum: ["agent", "team", "skill"],
|
|
50730
|
-
description: "Filter by type (optional). Omit to list all."
|
|
50731
|
-
}
|
|
50732
|
-
}
|
|
50733
|
-
},
|
|
50734
|
-
async execute(args) {
|
|
50735
|
-
try {
|
|
50736
|
-
const type = args["type"];
|
|
50737
|
-
const artifacts = ctx.listArtifacts(type);
|
|
50738
|
-
const roles = (!type || type === "agent") && ctx.listTemplates ? ctx.listTemplates() : [];
|
|
50739
|
-
const roleItems = roles.map((r) => ({
|
|
50740
|
-
type: "agent",
|
|
50741
|
-
source: "role",
|
|
50742
|
-
name: r.id ?? r.name,
|
|
50743
|
-
description: r.description ?? r.name,
|
|
50744
|
-
...r
|
|
50745
|
-
}));
|
|
50746
|
-
const items = [...roleItems, ...artifacts];
|
|
50747
|
-
return JSON.stringify({ items, count: items.length });
|
|
50748
|
-
} catch (error) {
|
|
50749
|
-
return JSON.stringify({ status: "error", error: String(error) });
|
|
50750
|
-
}
|
|
50751
|
-
}
|
|
50752
|
-
}
|
|
50753
|
-
] : [],
|
|
50754
51791
|
...ctx.updateTeam ? [
|
|
50755
51792
|
{
|
|
50756
51793
|
name: "team_update",
|
|
@@ -50813,74 +51850,6 @@ function createManagerTools(ctx) {
|
|
|
50813
51850
|
}
|
|
50814
51851
|
}
|
|
50815
51852
|
}
|
|
50816
|
-
] : [],
|
|
50817
|
-
...ctx.installArtifact ? [
|
|
50818
|
-
{
|
|
50819
|
-
name: "package_install",
|
|
50820
|
-
description: 'Install a package into the live organization. type "agent": hire/install an agent (from a built-in role or a custom package). type "team": deploy a full team with all members, norms, and starter tasks. type "skill": install a skill package. Use package_list to see what is available.',
|
|
50821
|
-
inputSchema: {
|
|
50822
|
-
type: "object",
|
|
50823
|
-
properties: {
|
|
50824
|
-
type: {
|
|
50825
|
-
type: "string",
|
|
50826
|
-
enum: ["agent", "team", "skill"],
|
|
50827
|
-
description: "Package type"
|
|
50828
|
-
},
|
|
50829
|
-
name: { type: "string", description: "Package name (from package_list)" },
|
|
50830
|
-
agent_name: { type: "string", description: 'Display name for the new agent (required when installing from a built-in role, e.g. "developer")' },
|
|
50831
|
-
skills: {
|
|
50832
|
-
type: "array",
|
|
50833
|
-
items: { type: "string" },
|
|
50834
|
-
description: "Optional skill IDs to assign to the new agent"
|
|
50835
|
-
}
|
|
50836
|
-
},
|
|
50837
|
-
required: ["type", "name"]
|
|
50838
|
-
},
|
|
50839
|
-
async execute(args) {
|
|
50840
|
-
try {
|
|
50841
|
-
const type = args["type"]?.trim();
|
|
50842
|
-
const name = args["name"]?.trim();
|
|
50843
|
-
if (!type || !["agent", "team", "skill"].includes(type))
|
|
50844
|
-
return JSON.stringify({ status: "error", error: "type is required and must be one of: agent, team, skill" });
|
|
50845
|
-
if (!name)
|
|
50846
|
-
return JSON.stringify({ status: "error", error: "name is required \u2014 use package_list to see available packages" });
|
|
50847
|
-
if (type === "agent") {
|
|
50848
|
-
try {
|
|
50849
|
-
const result2 = await ctx.installArtifact(type, name);
|
|
50850
|
-
return JSON.stringify({
|
|
50851
|
-
status: "success",
|
|
50852
|
-
...result2,
|
|
50853
|
-
next_steps: "Installed successfully. Next: onboard new agent with project context via agent_send_message, then assign tasks via task_create."
|
|
50854
|
-
});
|
|
50855
|
-
} catch {
|
|
50856
|
-
if (ctx.hireFromTemplate) {
|
|
50857
|
-
const agentName = args["agent_name"]?.trim();
|
|
50858
|
-
if (!agentName)
|
|
50859
|
-
return JSON.stringify({ status: "error", error: "agent_name is required when installing from a built-in role \u2014 provide a display name for the new agent" });
|
|
50860
|
-
const result2 = await ctx.hireFromTemplate(name, agentName, args["skills"]);
|
|
50861
|
-
return JSON.stringify({
|
|
50862
|
-
status: "success",
|
|
50863
|
-
type: "agent",
|
|
50864
|
-
agent: result2,
|
|
50865
|
-
next_steps: "Agent hired and started. Next: onboard with project context via agent_send_message, then assign tasks via task_create."
|
|
50866
|
-
});
|
|
50867
|
-
}
|
|
50868
|
-
throw new Error(`Agent package not found: ${name}. Use package_list to see available packages.`);
|
|
50869
|
-
}
|
|
50870
|
-
}
|
|
50871
|
-
const result = await ctx.installArtifact(type, name);
|
|
50872
|
-
return JSON.stringify({
|
|
50873
|
-
status: "success",
|
|
50874
|
-
...result,
|
|
50875
|
-
...type === "team" ? {
|
|
50876
|
-
next_steps: "Installed successfully. Next: onboard new agent(s) with project context via agent_send_message, then assign initial tasks via task_create."
|
|
50877
|
-
} : {}
|
|
50878
|
-
});
|
|
50879
|
-
} catch (error) {
|
|
50880
|
-
return JSON.stringify({ status: "error", error: String(error) });
|
|
50881
|
-
}
|
|
50882
|
-
}
|
|
50883
|
-
}
|
|
50884
51853
|
] : []
|
|
50885
51854
|
];
|
|
50886
51855
|
}
|
|
@@ -50893,75 +51862,6 @@ var init_manager = __esm({
|
|
|
50893
51862
|
}
|
|
50894
51863
|
});
|
|
50895
51864
|
|
|
50896
|
-
// ../core/dist/tools/hub-tools.js
|
|
50897
|
-
function createHubTools(ctx) {
|
|
50898
|
-
return [
|
|
50899
|
-
{
|
|
50900
|
-
name: "hub_search",
|
|
50901
|
-
description: "Search Markus Hub for community-published agents, teams, and skills. Returns a list of available items with descriptions and popularity.",
|
|
50902
|
-
inputSchema: {
|
|
50903
|
-
type: "object",
|
|
50904
|
-
properties: {
|
|
50905
|
-
type: {
|
|
50906
|
-
type: "string",
|
|
50907
|
-
enum: ["agent", "team", "skill"],
|
|
50908
|
-
description: "Filter by item type (optional)"
|
|
50909
|
-
},
|
|
50910
|
-
query: {
|
|
50911
|
-
type: "string",
|
|
50912
|
-
description: "Search query (optional)"
|
|
50913
|
-
}
|
|
50914
|
-
}
|
|
50915
|
-
},
|
|
50916
|
-
async execute(args) {
|
|
50917
|
-
try {
|
|
50918
|
-
const items = await ctx.searchHub({
|
|
50919
|
-
type: args["type"],
|
|
50920
|
-
query: args["query"]
|
|
50921
|
-
});
|
|
50922
|
-
return JSON.stringify({ items, count: items.length });
|
|
50923
|
-
} catch (error) {
|
|
50924
|
-
return JSON.stringify({ status: "error", error: String(error) });
|
|
50925
|
-
}
|
|
50926
|
-
}
|
|
50927
|
-
},
|
|
50928
|
-
{
|
|
50929
|
-
name: "hub_install",
|
|
50930
|
-
description: "Download an item from Markus Hub and install it. Combines download, save as artifact, and install into a single step. For agents/teams: remember to onboard the new agent(s) after installation.",
|
|
50931
|
-
inputSchema: {
|
|
50932
|
-
type: "object",
|
|
50933
|
-
properties: {
|
|
50934
|
-
item_id: { type: "string", description: "Hub item ID (from hub_search results)" }
|
|
50935
|
-
},
|
|
50936
|
-
required: ["item_id"]
|
|
50937
|
-
},
|
|
50938
|
-
async execute(args) {
|
|
50939
|
-
try {
|
|
50940
|
-
const itemId = args["item_id"]?.trim();
|
|
50941
|
-
if (!itemId)
|
|
50942
|
-
return JSON.stringify({ status: "error", error: "item_id is required \u2014 use hub_search to find available items first" });
|
|
50943
|
-
const result = await ctx.downloadAndInstall(itemId);
|
|
50944
|
-
const isAgentOrTeam = result.type === "agent" || result.type === "team";
|
|
50945
|
-
return JSON.stringify({
|
|
50946
|
-
status: "success",
|
|
50947
|
-
...result,
|
|
50948
|
-
...isAgentOrTeam ? {
|
|
50949
|
-
next_steps: "Downloaded and installed from Hub. Next: onboard new agent(s) with project context via agent_send_message, then assign initial tasks via task_create."
|
|
50950
|
-
} : {}
|
|
50951
|
-
});
|
|
50952
|
-
} catch (error) {
|
|
50953
|
-
return JSON.stringify({ status: "error", error: String(error) });
|
|
50954
|
-
}
|
|
50955
|
-
}
|
|
50956
|
-
}
|
|
50957
|
-
];
|
|
50958
|
-
}
|
|
50959
|
-
var init_hub_tools = __esm({
|
|
50960
|
-
"../core/dist/tools/hub-tools.js"() {
|
|
50961
|
-
"use strict";
|
|
50962
|
-
}
|
|
50963
|
-
});
|
|
50964
|
-
|
|
50965
51865
|
// ../core/dist/tools/a2a.js
|
|
50966
51866
|
function createA2ATools(ctx) {
|
|
50967
51867
|
return [
|
|
@@ -52722,6 +53622,10 @@ function createProjectTools(ctx) {
|
|
|
52722
53622
|
type: "string",
|
|
52723
53623
|
description: "Path to the file or directory that contains the actual content (must already exist)"
|
|
52724
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
|
+
},
|
|
52725
53629
|
tags: { type: "string", description: "Comma-separated tags for discoverability" }
|
|
52726
53630
|
},
|
|
52727
53631
|
required: ["type", "title", "summary"]
|
|
@@ -52733,6 +53637,7 @@ function createProjectTools(ctx) {
|
|
|
52733
53637
|
title: args["title"],
|
|
52734
53638
|
summary: args["summary"],
|
|
52735
53639
|
reference: args["reference"],
|
|
53640
|
+
format: args["format"],
|
|
52736
53641
|
tags: args["tags"]
|
|
52737
53642
|
});
|
|
52738
53643
|
const resp = {
|
|
@@ -53980,7 +54885,6 @@ var init_agent_manager = __esm({
|
|
|
53980
54885
|
init_mcp_client();
|
|
53981
54886
|
init_browser_session();
|
|
53982
54887
|
init_manager();
|
|
53983
|
-
init_hub_tools();
|
|
53984
54888
|
init_a2a();
|
|
53985
54889
|
init_a2a_structured();
|
|
53986
54890
|
init_task_tools();
|
|
@@ -54020,6 +54924,9 @@ var init_agent_manager = __esm({
|
|
|
54020
54924
|
escalationHandler;
|
|
54021
54925
|
approvalHandler;
|
|
54022
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;
|
|
54023
54930
|
activityCallbacks;
|
|
54024
54931
|
recallCallbacks;
|
|
54025
54932
|
delegationManager;
|
|
@@ -54086,6 +54993,7 @@ var init_agent_manager = __esm({
|
|
|
54086
54993
|
title: opts.title,
|
|
54087
54994
|
summary: opts.summary,
|
|
54088
54995
|
reference: opts.reference,
|
|
54996
|
+
format: opts.format,
|
|
54089
54997
|
tags,
|
|
54090
54998
|
agentId: agentId2,
|
|
54091
54999
|
projectId
|
|
@@ -54808,26 +55716,6 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
54808
55716
|
findDuplicateTasks: this.taskService?.findDuplicateTasks ? (orgId2) => this.taskService.findDuplicateTasks(orgId2) : void 0,
|
|
54809
55717
|
cleanupDuplicateTasks: this.taskService?.cleanupDuplicateTasks ? (orgId2) => this.taskService.cleanupDuplicateTasks(orgId2) : void 0,
|
|
54810
55718
|
getTaskBoardHealth: this.taskService?.getTaskBoardHealth ? (orgId2) => this.taskService.getTaskBoardHealth(orgId2) : void 0,
|
|
54811
|
-
hireFromTemplate: this.templateRegistry ? async (templateId, name, skills) => {
|
|
54812
|
-
const newAgent = await this.createAgentFromTemplate({
|
|
54813
|
-
templateId,
|
|
54814
|
-
name,
|
|
54815
|
-
orgId: config.orgId ?? "default",
|
|
54816
|
-
teamId: config.teamId,
|
|
54817
|
-
overrides: skills ? { skills } : void 0
|
|
54818
|
-
});
|
|
54819
|
-
await this.startAgent(newAgent.id);
|
|
54820
|
-
return { id: newAgent.id, name: newAgent.config.name, role: newAgent.role.name };
|
|
54821
|
-
} : void 0,
|
|
54822
|
-
listTemplates: this.templateRegistry ? () => this.templateRegistry.list().map((t) => ({
|
|
54823
|
-
id: t.id,
|
|
54824
|
-
name: t.name,
|
|
54825
|
-
description: t.description,
|
|
54826
|
-
roleId: t.roleId,
|
|
54827
|
-
category: t.category ?? "general"
|
|
54828
|
-
})) : void 0,
|
|
54829
|
-
installArtifact: this.builderService ? (type, name) => this.builderService.installArtifact(type, name) : void 0,
|
|
54830
|
-
listArtifacts: this.builderService ? (type) => this.builderService.listArtifacts(type) : void 0,
|
|
54831
55719
|
updateTeam: this.teamUpdater ? async (teamId, data) => this.teamUpdater(teamId, data) : void 0,
|
|
54832
55720
|
updateAgentConfig: async (agentId2, data) => {
|
|
54833
55721
|
const targetAgent = this.getAgent(agentId2);
|
|
@@ -54843,23 +55731,33 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
54843
55731
|
for (const tool of managerTools) {
|
|
54844
55732
|
agent.registerTool(tool);
|
|
54845
55733
|
}
|
|
54846
|
-
const BUILDING_SKILLS = /* @__PURE__ */ new Set(["agent-building", "team-building", "skill-building"]);
|
|
54847
|
-
const hasBuilderSkill = config.skills?.some((s2) => BUILDING_SKILLS.has(s2));
|
|
54848
|
-
if (hasBuilderSkill && this.hubClient) {
|
|
54849
|
-
const hubTools = createHubTools({
|
|
54850
|
-
searchHub: (opts) => this.hubClient.search(opts),
|
|
54851
|
-
downloadAndInstall: (itemId) => this.hubClient.downloadAndInstall(itemId)
|
|
54852
|
-
});
|
|
54853
|
-
for (const tool of hubTools)
|
|
54854
|
-
agent.registerTool(tool);
|
|
54855
|
-
}
|
|
54856
55734
|
}
|
|
54857
|
-
|
|
54858
|
-
const
|
|
54859
|
-
installArtifact: (type, name) => this.builderService.installArtifact(type, name),
|
|
54860
|
-
listArtifacts: (type) => this.builderService.listArtifacts(type)
|
|
55735
|
+
{
|
|
55736
|
+
const packageTools = createPackageTools({
|
|
55737
|
+
installArtifact: () => this.builderService ? (type, name) => this.builderService.installArtifact(type, name) : void 0,
|
|
55738
|
+
listArtifacts: () => this.builderService ? (type) => this.builderService.listArtifacts(type) : void 0,
|
|
55739
|
+
hireFromTemplate: () => this.templateRegistry ? async (templateId, name, skills) => {
|
|
55740
|
+
const newAgent = await this.createAgentFromTemplate({
|
|
55741
|
+
templateId,
|
|
55742
|
+
name,
|
|
55743
|
+
orgId: config.orgId ?? "default",
|
|
55744
|
+
teamId: config.teamId,
|
|
55745
|
+
overrides: skills ? { skills } : void 0
|
|
55746
|
+
});
|
|
55747
|
+
await this.startAgent(newAgent.id);
|
|
55748
|
+
return { id: newAgent.id, name: newAgent.config.name, role: newAgent.role.name };
|
|
55749
|
+
} : void 0,
|
|
55750
|
+
listTemplates: () => this.templateRegistry ? () => this.templateRegistry.list().map((t) => ({
|
|
55751
|
+
id: t.id,
|
|
55752
|
+
name: t.name,
|
|
55753
|
+
description: t.description,
|
|
55754
|
+
roleId: t.roleId,
|
|
55755
|
+
category: t.category ?? "general"
|
|
55756
|
+
})) : void 0,
|
|
55757
|
+
searchHub: () => this.hubClient ? (opts) => this.hubClient.search(opts) : void 0,
|
|
55758
|
+
downloadAndInstall: () => this.hubClient ? (itemId) => this.hubClient.downloadAndInstall(itemId) : void 0
|
|
54861
55759
|
});
|
|
54862
|
-
for (const tool of
|
|
55760
|
+
for (const tool of packageTools)
|
|
54863
55761
|
agent.registerTool(tool);
|
|
54864
55762
|
}
|
|
54865
55763
|
const mcpConfigs = request.mcpServers ?? this.globalMcpServers;
|
|
@@ -54892,9 +55790,7 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
54892
55790
|
const ah = this.approvalHandler;
|
|
54893
55791
|
agent.setApprovalCallback(async (req) => ah(id, req));
|
|
54894
55792
|
}
|
|
54895
|
-
|
|
54896
|
-
agent.setStateChangeCallback(this.stateChangeHandler);
|
|
54897
|
-
}
|
|
55793
|
+
agent.setStateChangeCallback(this.buildStateChangeCallback());
|
|
54898
55794
|
if (this.activityCallbacks) {
|
|
54899
55795
|
agent.setActivityCallbacks(this.activityCallbacks);
|
|
54900
55796
|
}
|
|
@@ -55389,7 +56285,26 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55389
56285
|
findDuplicateTasks: this.taskService?.findDuplicateTasks ? (orgId2) => this.taskService.findDuplicateTasks(orgId2) : void 0,
|
|
55390
56286
|
cleanupDuplicateTasks: this.taskService?.cleanupDuplicateTasks ? (orgId2) => this.taskService.cleanupDuplicateTasks(orgId2) : void 0,
|
|
55391
56287
|
getTaskBoardHealth: this.taskService?.getTaskBoardHealth ? (orgId2) => this.taskService.getTaskBoardHealth(orgId2) : void 0,
|
|
55392
|
-
|
|
56288
|
+
updateTeam: this.teamUpdater ? async (teamId, data) => this.teamUpdater(teamId, data) : void 0,
|
|
56289
|
+
updateAgentConfig: async (agentId2, data) => {
|
|
56290
|
+
const targetAgent = this.getAgent(agentId2);
|
|
56291
|
+
if (data.name !== void 0) {
|
|
56292
|
+
targetAgent.config.name = data.name;
|
|
56293
|
+
}
|
|
56294
|
+
if (this.agentConfigPersister) {
|
|
56295
|
+
await this.agentConfigPersister(agentId2, data);
|
|
56296
|
+
}
|
|
56297
|
+
return { id: agentId2, name: targetAgent.config.name };
|
|
56298
|
+
}
|
|
56299
|
+
});
|
|
56300
|
+
for (const tool of managerTools)
|
|
56301
|
+
agent.registerTool(tool);
|
|
56302
|
+
}
|
|
56303
|
+
{
|
|
56304
|
+
const packageTools = createPackageTools({
|
|
56305
|
+
installArtifact: () => this.builderService ? (type, name) => this.builderService.installArtifact(type, name) : void 0,
|
|
56306
|
+
listArtifacts: () => this.builderService ? (type) => this.builderService.listArtifacts(type) : void 0,
|
|
56307
|
+
hireFromTemplate: () => this.templateRegistry ? async (templateId, name, skills) => {
|
|
55393
56308
|
const newAgent = await this.createAgentFromTemplate({
|
|
55394
56309
|
templateId,
|
|
55395
56310
|
name,
|
|
@@ -55400,46 +56315,17 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55400
56315
|
await this.startAgent(newAgent.id);
|
|
55401
56316
|
return { id: newAgent.id, name: newAgent.config.name, role: newAgent.role.name };
|
|
55402
56317
|
} : void 0,
|
|
55403
|
-
listTemplates: this.templateRegistry ? () => this.templateRegistry.list().map((t) => ({
|
|
56318
|
+
listTemplates: () => this.templateRegistry ? () => this.templateRegistry.list().map((t) => ({
|
|
55404
56319
|
id: t.id,
|
|
55405
56320
|
name: t.name,
|
|
55406
56321
|
description: t.description,
|
|
55407
56322
|
roleId: t.roleId,
|
|
55408
56323
|
category: t.category ?? "general"
|
|
55409
56324
|
})) : void 0,
|
|
55410
|
-
|
|
55411
|
-
|
|
55412
|
-
updateTeam: this.teamUpdater ? async (teamId, data) => this.teamUpdater(teamId, data) : void 0,
|
|
55413
|
-
updateAgentConfig: async (agentId2, data) => {
|
|
55414
|
-
const targetAgent = this.getAgent(agentId2);
|
|
55415
|
-
if (data.name !== void 0) {
|
|
55416
|
-
targetAgent.config.name = data.name;
|
|
55417
|
-
}
|
|
55418
|
-
if (this.agentConfigPersister) {
|
|
55419
|
-
await this.agentConfigPersister(agentId2, data);
|
|
55420
|
-
}
|
|
55421
|
-
return { id: agentId2, name: targetAgent.config.name };
|
|
55422
|
-
}
|
|
56325
|
+
searchHub: () => this.hubClient ? (opts) => this.hubClient.search(opts) : void 0,
|
|
56326
|
+
downloadAndInstall: () => this.hubClient ? (itemId) => this.hubClient.downloadAndInstall(itemId) : void 0
|
|
55423
56327
|
});
|
|
55424
|
-
for (const tool of
|
|
55425
|
-
agent.registerTool(tool);
|
|
55426
|
-
const BUILDING_SKILLS_R = /* @__PURE__ */ new Set(["agent-building", "team-building", "skill-building"]);
|
|
55427
|
-
const hasBuilderSkillR = config.skills?.some((s2) => BUILDING_SKILLS_R.has(s2));
|
|
55428
|
-
if (hasBuilderSkillR && this.hubClient) {
|
|
55429
|
-
const hubTools = createHubTools({
|
|
55430
|
-
searchHub: (opts) => this.hubClient.search(opts),
|
|
55431
|
-
downloadAndInstall: (itemId) => this.hubClient.downloadAndInstall(itemId)
|
|
55432
|
-
});
|
|
55433
|
-
for (const tool of hubTools)
|
|
55434
|
-
agent.registerTool(tool);
|
|
55435
|
-
}
|
|
55436
|
-
}
|
|
55437
|
-
if (this.builderService) {
|
|
55438
|
-
const builderTools = createBuilderTools({
|
|
55439
|
-
installArtifact: (type, name) => this.builderService.installArtifact(type, name),
|
|
55440
|
-
listArtifacts: (type) => this.builderService.listArtifacts(type)
|
|
55441
|
-
});
|
|
55442
|
-
for (const tool of builderTools)
|
|
56328
|
+
for (const tool of packageTools)
|
|
55443
56329
|
agent.registerTool(tool);
|
|
55444
56330
|
}
|
|
55445
56331
|
if (this.agentAuditCallback) {
|
|
@@ -55453,9 +56339,7 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55453
56339
|
const ah = this.approvalHandler;
|
|
55454
56340
|
agent.setApprovalCallback(async (req) => ah(id, req));
|
|
55455
56341
|
}
|
|
55456
|
-
|
|
55457
|
-
agent.setStateChangeCallback(this.stateChangeHandler);
|
|
55458
|
-
}
|
|
56342
|
+
agent.setStateChangeCallback(this.buildStateChangeCallback());
|
|
55459
56343
|
if (this.activityCallbacks) {
|
|
55460
56344
|
agent.setActivityCallbacks(this.activityCallbacks);
|
|
55461
56345
|
}
|
|
@@ -55519,6 +56403,9 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55519
56403
|
async stopAgent(agentId2) {
|
|
55520
56404
|
const agent = this.getAgent(agentId2);
|
|
55521
56405
|
await agent.stop();
|
|
56406
|
+
this.cancelMcpRelease(agentId2);
|
|
56407
|
+
this.browserSessionManager.cleanupAgent(agentId2);
|
|
56408
|
+
await this.mcpManager.removeAllForScope(agentId2);
|
|
55522
56409
|
}
|
|
55523
56410
|
async removeAgent(agentId2, opts) {
|
|
55524
56411
|
const agent = this.agents.get(agentId2);
|
|
@@ -55527,8 +56414,9 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55527
56414
|
await agent.stop();
|
|
55528
56415
|
} catch {
|
|
55529
56416
|
}
|
|
56417
|
+
this.cancelMcpRelease(agentId2);
|
|
55530
56418
|
this.browserSessionManager.cleanupAgent(agentId2);
|
|
55531
|
-
await this.mcpManager.
|
|
56419
|
+
await this.mcpManager.removeAllForScope(agentId2);
|
|
55532
56420
|
this.delegationManager.unregisterAgentCard(agentId2);
|
|
55533
56421
|
this.agents.delete(agentId2);
|
|
55534
56422
|
this.eventBus.emit("agent:removed", { agentId: agentId2 });
|
|
@@ -55596,13 +56484,49 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55596
56484
|
agent.setApprovalCallback(async (req) => handler4(id, req));
|
|
55597
56485
|
}
|
|
55598
56486
|
}
|
|
55599
|
-
|
|
55600
|
-
|
|
55601
|
-
|
|
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
|
+
}
|
|
55602
56500
|
this.delegationManager.updateAgentStatus(agentId2, state.status);
|
|
56501
|
+
if (this.stateChangeHandler) {
|
|
56502
|
+
this.stateChangeHandler(agentId2, state);
|
|
56503
|
+
}
|
|
55603
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;
|
|
55604
56528
|
for (const [, agent] of this.agents) {
|
|
55605
|
-
agent.setStateChangeCallback(this.
|
|
56529
|
+
agent.setStateChangeCallback(this.buildStateChangeCallback());
|
|
55606
56530
|
}
|
|
55607
56531
|
}
|
|
55608
56532
|
/**
|
|
@@ -55623,6 +56547,10 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55623
56547
|
"agent:resumed",
|
|
55624
56548
|
"agent:focus-changed",
|
|
55625
56549
|
"agent:message",
|
|
56550
|
+
"agent:notify-user",
|
|
56551
|
+
"agent:escalation",
|
|
56552
|
+
"agent:activity-log",
|
|
56553
|
+
"agent:activity_log",
|
|
55626
56554
|
"task:completed",
|
|
55627
56555
|
"task:failed",
|
|
55628
56556
|
"mailbox:new-item",
|
|
@@ -55860,6 +56788,7 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55860
56788
|
} catch {
|
|
55861
56789
|
}
|
|
55862
56790
|
}
|
|
56791
|
+
await this.mcpManager.disconnectAll();
|
|
55863
56792
|
log32.info("AgentManager shutdown complete \u2014 all metrics flushed");
|
|
55864
56793
|
}
|
|
55865
56794
|
// ─── Role Template Versioning & Sync ──────────────────────────────────────
|
|
@@ -56277,7 +57206,7 @@ var init_anthropic = __esm({
|
|
|
56277
57206
|
{
|
|
56278
57207
|
type: "tool_result",
|
|
56279
57208
|
tool_use_id: m.toolCallId ?? "",
|
|
56280
|
-
content: getTextContent(m.content)
|
|
57209
|
+
content: sanitizeForLLM(getTextContent(m.content))
|
|
56281
57210
|
}
|
|
56282
57211
|
]
|
|
56283
57212
|
};
|
|
@@ -56470,7 +57399,7 @@ var init_openai = __esm({
|
|
|
56470
57399
|
if (m.role === "tool") {
|
|
56471
57400
|
return {
|
|
56472
57401
|
role: "tool",
|
|
56473
|
-
content: getTextContent(m.content),
|
|
57402
|
+
content: sanitizeForLLM(getTextContent(m.content)),
|
|
56474
57403
|
tool_call_id: m.toolCallId ?? ""
|
|
56475
57404
|
};
|
|
56476
57405
|
}
|
|
@@ -56874,7 +57803,7 @@ var init_google = __esm({
|
|
|
56874
57803
|
parts: [{
|
|
56875
57804
|
functionResponse: {
|
|
56876
57805
|
name: msg.toolCallId ?? "unknown",
|
|
56877
|
-
response: { result: getTextContent(msg.content) }
|
|
57806
|
+
response: { result: sanitizeForLLM(getTextContent(msg.content)) }
|
|
56878
57807
|
}
|
|
56879
57808
|
}]
|
|
56880
57809
|
});
|
|
@@ -57096,7 +58025,7 @@ var init_ollama = __esm({
|
|
|
57096
58025
|
convertMessages(messages) {
|
|
57097
58026
|
return messages.map((m) => {
|
|
57098
58027
|
if (m.role === "tool") {
|
|
57099
|
-
return { role: "tool", content: getTextContent(m.content) };
|
|
58028
|
+
return { role: "tool", content: sanitizeForLLM(getTextContent(m.content)) };
|
|
57100
58029
|
}
|
|
57101
58030
|
if (m.toolCalls?.length) {
|
|
57102
58031
|
return {
|
|
@@ -57332,9 +58261,9 @@ var init_auth_profiles = __esm({
|
|
|
57332
58261
|
|
|
57333
58262
|
// ../core/dist/llm/oauth-manager.js
|
|
57334
58263
|
import { createServer } from "node:http";
|
|
57335
|
-
import { randomBytes as
|
|
58264
|
+
import { randomBytes as randomBytes3, createHash } from "node:crypto";
|
|
57336
58265
|
function generatePKCE() {
|
|
57337
|
-
const verifier =
|
|
58266
|
+
const verifier = randomBytes3(32).toString("base64url");
|
|
57338
58267
|
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
|
57339
58268
|
return { verifier, challenge };
|
|
57340
58269
|
}
|
|
@@ -57415,7 +58344,7 @@ var init_oauth_manager = __esm({
|
|
|
57415
58344
|
throw new Error(`Unknown OAuth provider: ${provider}`);
|
|
57416
58345
|
this.cancelPendingLogin(provider);
|
|
57417
58346
|
const { verifier, challenge } = generatePKCE();
|
|
57418
|
-
const state =
|
|
58347
|
+
const state = randomBytes3(16).toString("hex");
|
|
57419
58348
|
const port = config.callbackPort ?? 1455;
|
|
57420
58349
|
const redirectUri = `http://localhost:${port}/auth/callback`;
|
|
57421
58350
|
const promise = new Promise((resolve20, reject) => {
|
|
@@ -57704,6 +58633,7 @@ var init_router = __esm({
|
|
|
57704
58633
|
autoSelect = false;
|
|
57705
58634
|
providerTiers = [];
|
|
57706
58635
|
fallbackOrder = [];
|
|
58636
|
+
_autoFallback = true;
|
|
57707
58637
|
/** Health tracked per model: key = "providerName:modelId" */
|
|
57708
58638
|
modelHealth = /* @__PURE__ */ new Map();
|
|
57709
58639
|
/** Provider-level degradation for non-retryable (auth/billing) errors */
|
|
@@ -57992,6 +58922,12 @@ var init_router = __esm({
|
|
|
57992
58922
|
setFallbackOrder(order) {
|
|
57993
58923
|
this.fallbackOrder = order.filter((n2) => this.providers.has(n2));
|
|
57994
58924
|
}
|
|
58925
|
+
get autoFallback() {
|
|
58926
|
+
return this._autoFallback;
|
|
58927
|
+
}
|
|
58928
|
+
setAutoFallback(enabled) {
|
|
58929
|
+
this._autoFallback = enabled;
|
|
58930
|
+
}
|
|
57995
58931
|
static assessComplexity(request) {
|
|
57996
58932
|
const totalChars = request.messages.reduce((s2, m) => s2 + getTextContent(m.content).length, 0);
|
|
57997
58933
|
const toolCount = request.tools?.length ?? 0;
|
|
@@ -58043,6 +58979,8 @@ var init_router = __esm({
|
|
|
58043
58979
|
return this.defaultProvider;
|
|
58044
58980
|
}
|
|
58045
58981
|
getFallbacks(primary) {
|
|
58982
|
+
if (!this._autoFallback)
|
|
58983
|
+
return [];
|
|
58046
58984
|
const order = this.fallbackOrder.length > 0 ? this.fallbackOrder : [...this.providers.keys()];
|
|
58047
58985
|
return order.filter((n2) => n2 !== primary && this.isAvailable(n2));
|
|
58048
58986
|
}
|
|
@@ -58161,7 +59099,7 @@ var init_router = __esm({
|
|
|
58161
59099
|
} catch (error) {
|
|
58162
59100
|
lastError = error;
|
|
58163
59101
|
log35.error(`LLM request failed for ${primary}:${provider.model}`, { error: String(error) });
|
|
58164
|
-
if (!_LLMRouter.isNonRetryableError(error)) {
|
|
59102
|
+
if (this._autoFallback && !_LLMRouter.isNonRetryableError(error)) {
|
|
58165
59103
|
const altModel = this.findHealthyModel(primary);
|
|
58166
59104
|
if (altModel && altModel !== provider.model) {
|
|
58167
59105
|
log35.info(`Trying alternate model ${altModel} on ${primary}`);
|
|
@@ -58252,7 +59190,7 @@ var init_router = __esm({
|
|
|
58252
59190
|
throw lastError;
|
|
58253
59191
|
}
|
|
58254
59192
|
log35.error(`LLM stream request failed for ${primary}:${provider.model}`, { error: String(error) });
|
|
58255
|
-
if (!_LLMRouter.isNonRetryableError(error)) {
|
|
59193
|
+
if (this._autoFallback && !_LLMRouter.isNonRetryableError(error)) {
|
|
58256
59194
|
const altModel = this.findHealthyModel(primary);
|
|
58257
59195
|
if (altModel && altModel !== provider.model) {
|
|
58258
59196
|
log35.info(`Stream: trying alternate model ${altModel} on ${primary}`);
|
|
@@ -58383,7 +59321,7 @@ var init_router = __esm({
|
|
|
58383
59321
|
};
|
|
58384
59322
|
}
|
|
58385
59323
|
}
|
|
58386
|
-
return { defaultProvider: this.defaultProvider, providers };
|
|
59324
|
+
return { defaultProvider: this.defaultProvider, autoFallback: this._autoFallback, providers };
|
|
58387
59325
|
}
|
|
58388
59326
|
updateProviderModelConfig(providerName, config) {
|
|
58389
59327
|
this.customModelConfigs.set(providerName, {
|
|
@@ -58480,6 +59418,17 @@ var init_router = __esm({
|
|
|
58480
59418
|
const provider = this.providers.get(name);
|
|
58481
59419
|
return provider?.model ?? "";
|
|
58482
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
|
+
}
|
|
58483
59432
|
getModelInputTypes(providerName) {
|
|
58484
59433
|
const name = providerName ?? this.defaultProvider;
|
|
58485
59434
|
const provider = this.providers.get(name);
|
|
@@ -58638,7 +59587,7 @@ var init_enhanced_role_loader = __esm({
|
|
|
58638
59587
|
});
|
|
58639
59588
|
|
|
58640
59589
|
// ../core/dist/external-gateway.js
|
|
58641
|
-
import { createHmac, randomBytes as
|
|
59590
|
+
import { createHmac, randomBytes as randomBytes4, timingSafeEqual } from "node:crypto";
|
|
58642
59591
|
var log37, ExternalAgentGateway, GatewayError;
|
|
58643
59592
|
var init_external_gateway = __esm({
|
|
58644
59593
|
"../core/dist/external-gateway.js"() {
|
|
@@ -58817,7 +59766,7 @@ var init_external_gateway = __esm({
|
|
|
58817
59766
|
return payload;
|
|
58818
59767
|
}
|
|
58819
59768
|
async routeMessage(token, message) {
|
|
58820
|
-
const messageId = `gwmsg_${Date.now()}_${
|
|
59769
|
+
const messageId = `gwmsg_${Date.now()}_${randomBytes4(4).toString("hex")}`;
|
|
58821
59770
|
const key2 = this.registrationKey(token.externalAgentId, token.orgId);
|
|
58822
59771
|
const registration = this.registrations.get(key2);
|
|
58823
59772
|
if (registration) {
|
|
@@ -59334,7 +60283,6 @@ var init_tools = __esm({
|
|
|
59334
60283
|
init_memory();
|
|
59335
60284
|
init_subagent();
|
|
59336
60285
|
init_settings();
|
|
59337
|
-
init_hub_tools();
|
|
59338
60286
|
init_recall();
|
|
59339
60287
|
}
|
|
59340
60288
|
});
|
|
@@ -61432,39 +62380,28 @@ var init_org_service = __esm({
|
|
|
61432
62380
|
return p;
|
|
61433
62381
|
}
|
|
61434
62382
|
/**
|
|
61435
|
-
* Seed a
|
|
61436
|
-
*
|
|
61437
|
-
*
|
|
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.
|
|
61438
62386
|
*/
|
|
61439
|
-
async seedDefaultTeam(orgId2,
|
|
61440
|
-
const
|
|
61441
|
-
if (
|
|
62387
|
+
async seedDefaultTeam(orgId2, _ownerUserId) {
|
|
62388
|
+
const existingAgents = this.agentManager.listAgents();
|
|
62389
|
+
if (existingAgents.length > 0)
|
|
61442
62390
|
return;
|
|
61443
|
-
log49.info("Seeding
|
|
62391
|
+
log49.info("Seeding Secretary agent for org", { orgId: orgId2 });
|
|
61444
62392
|
try {
|
|
61445
|
-
const team = await this.createTeam(orgId2, "My Team", "Your primary team \u2014 you and your personal AI Secretary.");
|
|
61446
|
-
const owner = this.humans.get(ownerUserId);
|
|
61447
|
-
if (owner) {
|
|
61448
|
-
this.addMemberToTeam(team.id, ownerUserId, "human");
|
|
61449
|
-
}
|
|
61450
62393
|
const secretary = await this.hireAgent({
|
|
61451
62394
|
name: "Secretary",
|
|
61452
62395
|
roleName: "secretary",
|
|
61453
62396
|
orgId: orgId2,
|
|
61454
|
-
|
|
61455
|
-
agentRole: "manager",
|
|
62397
|
+
agentRole: "worker",
|
|
61456
62398
|
skills: ["agent-building", "team-building", "skill-building"]
|
|
61457
62399
|
});
|
|
61458
|
-
|
|
61459
|
-
managerId: secretary.id,
|
|
61460
|
-
managerType: "agent"
|
|
61461
|
-
});
|
|
61462
|
-
log49.info("Default team seeded", {
|
|
61463
|
-
teamId: team.id,
|
|
62400
|
+
log49.info("Secretary agent seeded", {
|
|
61464
62401
|
secretaryId: secretary.id
|
|
61465
62402
|
});
|
|
61466
62403
|
} catch (error) {
|
|
61467
|
-
log49.warn("Failed to seed
|
|
62404
|
+
log49.warn("Failed to seed Secretary agent", { error: String(error) });
|
|
61468
62405
|
}
|
|
61469
62406
|
}
|
|
61470
62407
|
static BUILDING_SKILLS = /* @__PURE__ */ new Set(["agent-building", "team-building", "skill-building"]);
|
|
@@ -70555,6 +71492,10 @@ var init_task_service = __esm({
|
|
|
70555
71492
|
taskCancelTokens = /* @__PURE__ */ new Map();
|
|
70556
71493
|
/** Tasks currently being reviewed — prevents duplicate review notifications */
|
|
70557
71494
|
activeReviews = /* @__PURE__ */ new Set();
|
|
71495
|
+
/** Tracks tasks where submitForReview was called in the current execution round.
|
|
71496
|
+
* Used to avoid false "did not call task_submit_review" when a fast reviewer
|
|
71497
|
+
* transitions the task back to in_progress before execution_finished fires. */
|
|
71498
|
+
tasksSubmittedForReview = /* @__PURE__ */ new Set();
|
|
70558
71499
|
webhooks = [];
|
|
70559
71500
|
timeoutCheckInterval;
|
|
70560
71501
|
projectService;
|
|
@@ -71588,7 +72529,12 @@ ${c.content}`;
|
|
|
71588
72529
|
if (entry.content === "completed" || entry.content === "execution_finished") {
|
|
71589
72530
|
const currentTask = this.tasks.get(taskId2);
|
|
71590
72531
|
const alreadyTerminal = currentTask && ["review", "completed", "failed", "cancelled", "archived"].includes(currentTask.status);
|
|
71591
|
-
|
|
72532
|
+
const didSubmit = this.tasksSubmittedForReview.has(taskId2);
|
|
72533
|
+
if (didSubmit) {
|
|
72534
|
+
this.tasksSubmittedForReview.delete(taskId2);
|
|
72535
|
+
log50.info("Task execution finished after submitForReview \u2014 skipping no-submit retry (reviewer may have transitioned status back)", { taskId: taskId2 });
|
|
72536
|
+
}
|
|
72537
|
+
if (!alreadyTerminal && !didSubmit && currentTask && currentTask.status === "in_progress") {
|
|
71592
72538
|
const nextAttempt = _retryAttempt + 1;
|
|
71593
72539
|
if (nextAttempt < _TaskService.MAX_IN_PROGRESS_RETRIES) {
|
|
71594
72540
|
const delayMs = withJitter(_TaskService.RETRY_DELAYS_MS[Math.min(_retryAttempt, _TaskService.RETRY_DELAYS_MS.length - 1)] ?? 3e5);
|
|
@@ -72201,6 +73147,9 @@ ${c.content}`;
|
|
|
72201
73147
|
if (from === "review" && to !== "review") {
|
|
72202
73148
|
this.activeReviews.delete(taskId2);
|
|
72203
73149
|
}
|
|
73150
|
+
if (TERMINAL_STATUSES.has(to)) {
|
|
73151
|
+
this.tasksSubmittedForReview.delete(taskId2);
|
|
73152
|
+
}
|
|
72204
73153
|
if (TERMINAL_STATUSES.has(to) && this.hitlService) {
|
|
72205
73154
|
const cancelled = this.hitlService.cancelApprovalsByDetail("taskId", taskId2, "system", `Task ${to}`);
|
|
72206
73155
|
if (cancelled > 0) {
|
|
@@ -72270,6 +73219,9 @@ ${deliverablesSummary}` : ""
|
|
|
72270
73219
|
],
|
|
72271
73220
|
allowFreeform: true
|
|
72272
73221
|
}).then((result) => {
|
|
73222
|
+
const current = this.tasks.get(task.id);
|
|
73223
|
+
if (!current || current.status !== "review")
|
|
73224
|
+
return;
|
|
72273
73225
|
if (result.approved) {
|
|
72274
73226
|
this.updateTaskStatus(task.id, "completed", task.reviewerId, false, false, "human", "Review approved");
|
|
72275
73227
|
} else {
|
|
@@ -72538,6 +73490,7 @@ Action: ${guidance}` : ""
|
|
|
72538
73490
|
};
|
|
72539
73491
|
for (const t of tasks)
|
|
72540
73492
|
statusCounts[t.status]++;
|
|
73493
|
+
const stuckBlockedCount = tasks.filter((t) => t.status === "blocked" && this.areBlockersSatisfied(t)).length;
|
|
72541
73494
|
const agentMap = /* @__PURE__ */ new Map();
|
|
72542
73495
|
for (const t of tasks) {
|
|
72543
73496
|
if (!t.assignedAgentId)
|
|
@@ -72558,7 +73511,7 @@ Action: ${guidance}` : ""
|
|
|
72558
73511
|
}
|
|
72559
73512
|
return { agentId: agentId2, agentName, activeTasks: counts.active, completedTasks: counts.completed };
|
|
72560
73513
|
});
|
|
72561
|
-
const recentActivity = [...tasks].sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()).slice(0, 20).map((t) => ({ taskId: t.id, title: t.title, status: t.status, updatedAt: t.updatedAt }));
|
|
73514
|
+
const recentActivity = [...tasks].filter((t) => t.status !== "archived").sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()).slice(0, 20).map((t) => ({ taskId: t.id, title: t.title, status: t.status, updatedAt: t.updatedAt }));
|
|
72562
73515
|
const completedTasks = tasks.filter((t) => t.status === "completed" && t.updatedAt && t.createdAt);
|
|
72563
73516
|
let averageCompletionTimeMs = null;
|
|
72564
73517
|
if (completedTasks.length > 0) {
|
|
@@ -72570,6 +73523,7 @@ Action: ${guidance}` : ""
|
|
|
72570
73523
|
return {
|
|
72571
73524
|
statusCounts,
|
|
72572
73525
|
totalTasks: tasks.length,
|
|
73526
|
+
stuckBlockedCount,
|
|
72573
73527
|
agentWorkload,
|
|
72574
73528
|
recentActivity,
|
|
72575
73529
|
averageCompletionTimeMs
|
|
@@ -73010,6 +73964,7 @@ Action: ${guidance}` : ""
|
|
|
73010
73964
|
success: true,
|
|
73011
73965
|
metadata: { deliverableCount: deliverables.length, reviewReportStatus: reviewReport?.overallStatus }
|
|
73012
73966
|
});
|
|
73967
|
+
this.tasksSubmittedForReview.add(task.id);
|
|
73013
73968
|
this.updateTaskStatus(task.id, "review", task.assignedAgentId, false, false, "agent", "Submitted for review");
|
|
73014
73969
|
log50.info(`Task submitted for review: ${task.title}`, { id: task.id });
|
|
73015
73970
|
return task;
|
|
@@ -73826,7 +74781,12 @@ ${task.description}`;
|
|
|
73826
74781
|
if (entry.type === "status" && (entry.content === "execution_finished" || entry.content === "completed")) {
|
|
73827
74782
|
const currentTask = this.tasks.get(taskId2);
|
|
73828
74783
|
const alreadyTerminal = currentTask && ["review", "completed", "failed", "cancelled", "archived"].includes(currentTask.status);
|
|
73829
|
-
|
|
74784
|
+
const didSubmit = this.tasksSubmittedForReview.has(taskId2);
|
|
74785
|
+
if (didSubmit) {
|
|
74786
|
+
this.tasksSubmittedForReview.delete(taskId2);
|
|
74787
|
+
log50.info("Fresh retry finished after submitForReview \u2014 skipping no-submit retry", { taskId: taskId2 });
|
|
74788
|
+
}
|
|
74789
|
+
if (!alreadyTerminal && !didSubmit && currentTask && currentTask.status === "in_progress") {
|
|
73830
74790
|
const delayMs = withJitter(_TaskService.RETRY_DELAYS_MS[0] ?? 1e4);
|
|
73831
74791
|
log50.warn(`Fresh retry finished without task_submit_review \u2014 auto-retrying in ${Math.round(delayMs / 1e3)}s`, { taskId: taskId2 });
|
|
73832
74792
|
this.addTaskNote(taskId2, `[System] Fresh retry finished without task_submit_review. Auto-retrying.`, "system");
|
|
@@ -77892,6 +78852,7 @@ ${cleanText}`,
|
|
|
77892
78852
|
title: body["title"],
|
|
77893
78853
|
summary: body["summary"],
|
|
77894
78854
|
reference: body["reference"],
|
|
78855
|
+
format: body["format"],
|
|
77895
78856
|
tags: body["tags"],
|
|
77896
78857
|
taskId: body["taskId"],
|
|
77897
78858
|
agentId: body["agentId"],
|
|
@@ -77919,6 +78880,7 @@ ${cleanText}`,
|
|
|
77919
78880
|
title: body["title"],
|
|
77920
78881
|
summary: body["summary"],
|
|
77921
78882
|
reference: body["reference"],
|
|
78883
|
+
format: body["format"],
|
|
77922
78884
|
tags: body["tags"],
|
|
77923
78885
|
status: body["status"],
|
|
77924
78886
|
type: body["type"]
|
|
@@ -79082,6 +80044,17 @@ EXPLANATION_END`;
|
|
|
79082
80044
|
name: t.name,
|
|
79083
80045
|
description: t.description
|
|
79084
80046
|
}));
|
|
80047
|
+
const virtualToolNames = new Set(toolList.map((t) => t.name));
|
|
80048
|
+
const VIRTUAL_TOOLS = [
|
|
80049
|
+
{ name: "discover_tools", description: "Discover and activate additional tools and skills available to this agent" },
|
|
80050
|
+
{ name: "notify_user", description: "Send a notification to a human team member (appears in chat + notification bell)" },
|
|
80051
|
+
{ name: "request_user_approval", description: "Request a decision or approval from a human (blocks until response)" },
|
|
80052
|
+
{ name: "recall_activity", description: "Query your own execution history and past activity logs" }
|
|
80053
|
+
];
|
|
80054
|
+
for (const vt of VIRTUAL_TOOLS) {
|
|
80055
|
+
if (!virtualToolNames.has(vt.name))
|
|
80056
|
+
toolList.push(vt);
|
|
80057
|
+
}
|
|
79085
80058
|
const hb = agent.heartbeat;
|
|
79086
80059
|
let heartbeatSummary = {};
|
|
79087
80060
|
try {
|
|
@@ -79485,6 +80458,7 @@ EXPLANATION_END`;
|
|
|
79485
80458
|
title: body["title"],
|
|
79486
80459
|
summary: body["summary"] ?? body["content"],
|
|
79487
80460
|
reference: body["reference"],
|
|
80461
|
+
format: body["format"],
|
|
79488
80462
|
tags: body["tags"],
|
|
79489
80463
|
agentId: token.markusAgentId,
|
|
79490
80464
|
projectId: body["projectId"]
|
|
@@ -81193,12 +82167,6 @@ EXPLANATION_END`;
|
|
|
81193
82167
|
} catch {
|
|
81194
82168
|
}
|
|
81195
82169
|
}
|
|
81196
|
-
const billingSummary = this.billingService?.getUsageSummary(orgId2);
|
|
81197
|
-
if (billingSummary) {
|
|
81198
|
-
llmTokens = Math.max(llmTokens, billingSummary.llmTokens);
|
|
81199
|
-
toolCalls = Math.max(toolCalls, billingSummary.toolCalls);
|
|
81200
|
-
messages = Math.max(messages, billingSummary.messages);
|
|
81201
|
-
}
|
|
81202
82170
|
this.json(res, 200, {
|
|
81203
82171
|
usage: {
|
|
81204
82172
|
orgId: orgId2,
|
|
@@ -81206,7 +82174,7 @@ EXPLANATION_END`;
|
|
|
81206
82174
|
llmTokens,
|
|
81207
82175
|
toolCalls,
|
|
81208
82176
|
messages,
|
|
81209
|
-
storageBytes:
|
|
82177
|
+
storageBytes: this.billingService?.getUsageSummary(orgId2)?.storageBytes ?? 0
|
|
81210
82178
|
},
|
|
81211
82179
|
plan
|
|
81212
82180
|
});
|
|
@@ -81231,7 +82199,8 @@ EXPLANATION_END`;
|
|
|
81231
82199
|
requestCount: stats.requestCount,
|
|
81232
82200
|
toolCalls: stats.toolCalls,
|
|
81233
82201
|
messages: stats.requestsToday,
|
|
81234
|
-
estimatedCost: stats.estimatedCost
|
|
82202
|
+
estimatedCost: stats.estimatedCost,
|
|
82203
|
+
costToday: stats.costToday
|
|
81235
82204
|
};
|
|
81236
82205
|
} catch {
|
|
81237
82206
|
return {
|
|
@@ -81246,7 +82215,8 @@ EXPLANATION_END`;
|
|
|
81246
82215
|
requestCount: 0,
|
|
81247
82216
|
toolCalls: 0,
|
|
81248
82217
|
messages: 0,
|
|
81249
|
-
estimatedCost: 0
|
|
82218
|
+
estimatedCost: 0,
|
|
82219
|
+
costToday: 0
|
|
81250
82220
|
};
|
|
81251
82221
|
}
|
|
81252
82222
|
});
|
|
@@ -81478,23 +82448,31 @@ EXPLANATION_END`;
|
|
|
81478
82448
|
return;
|
|
81479
82449
|
}
|
|
81480
82450
|
const body = await this.readBody(req);
|
|
81481
|
-
const { defaultProvider } = body;
|
|
81482
|
-
if (!defaultProvider) {
|
|
81483
|
-
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" });
|
|
81484
82454
|
return;
|
|
81485
82455
|
}
|
|
81486
82456
|
try {
|
|
81487
|
-
|
|
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
|
+
}
|
|
81488
82466
|
try {
|
|
81489
|
-
saveConfig({ llm:
|
|
82467
|
+
saveConfig({ llm: configUpdates }, this.markusConfigPath);
|
|
81490
82468
|
} catch (e) {
|
|
81491
|
-
log56.warn("Failed to persist
|
|
82469
|
+
log56.warn("Failed to persist LLM settings to config file", { error: String(e) });
|
|
81492
82470
|
}
|
|
81493
82471
|
this.auditService?.record({
|
|
81494
82472
|
orgId: "system",
|
|
81495
82473
|
type: "settings_changed",
|
|
81496
|
-
action: "
|
|
81497
|
-
detail: `defaultProvider=${defaultProvider}
|
|
82474
|
+
action: "llm_settings",
|
|
82475
|
+
detail: `${defaultProvider ? `defaultProvider=${defaultProvider}` : ""}${autoFallback !== void 0 ? ` autoFallback=${autoFallback}` : ""}`.trim(),
|
|
81498
82476
|
userId: auth.userId,
|
|
81499
82477
|
success: true
|
|
81500
82478
|
});
|
|
@@ -81618,6 +82596,70 @@ EXPLANATION_END`;
|
|
|
81618
82596
|
});
|
|
81619
82597
|
return;
|
|
81620
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
|
+
}
|
|
81621
82663
|
if (path === "/api/settings/llm/models" && req.method === "GET") {
|
|
81622
82664
|
if (!this.llmRouter) {
|
|
81623
82665
|
this.json(res, 200, { models: [] });
|
|
@@ -82884,6 +83926,8 @@ EXPLANATION_END`;
|
|
|
82884
83926
|
const home = homedir22();
|
|
82885
83927
|
const results = {};
|
|
82886
83928
|
const mdExts = [".md", ".markdown"];
|
|
83929
|
+
const htmlExts = [".html", ".htm"];
|
|
83930
|
+
const jsonExts = [".json"];
|
|
82887
83931
|
const imageExts = [".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"];
|
|
82888
83932
|
for (const p of paths.slice(0, 50)) {
|
|
82889
83933
|
try {
|
|
@@ -82899,6 +83943,10 @@ EXPLANATION_END`;
|
|
|
82899
83943
|
let type = "text";
|
|
82900
83944
|
if (mdExts.includes(ext))
|
|
82901
83945
|
type = "markdown";
|
|
83946
|
+
else if (htmlExts.includes(ext))
|
|
83947
|
+
type = "html";
|
|
83948
|
+
else if (jsonExts.includes(ext))
|
|
83949
|
+
type = "json";
|
|
82902
83950
|
else if (imageExts.includes(ext))
|
|
82903
83951
|
type = "image";
|
|
82904
83952
|
else if (!isFile)
|
|
@@ -82932,6 +83980,27 @@ EXPLANATION_END`;
|
|
|
82932
83980
|
return;
|
|
82933
83981
|
}
|
|
82934
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
|
+
}
|
|
82935
84004
|
if (!stat.isFile()) {
|
|
82936
84005
|
this.json(res, 400, { error: "Path is not a file" });
|
|
82937
84006
|
return;
|
|
@@ -82955,8 +84024,20 @@ EXPLANATION_END`;
|
|
|
82955
84024
|
} else {
|
|
82956
84025
|
const content = readFileSync26(resolved, "utf-8");
|
|
82957
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";
|
|
82958
84039
|
this.json(res, 200, {
|
|
82959
|
-
type:
|
|
84040
|
+
type: fileType,
|
|
82960
84041
|
name: resolved.split("/").pop(),
|
|
82961
84042
|
content
|
|
82962
84043
|
});
|
|
@@ -83896,6 +84977,7 @@ EXPLANATION_END`;
|
|
|
83896
84977
|
exact("/api/settings/llm/models", "GET"),
|
|
83897
84978
|
exact("/api/settings/agent", "GET", "POST"),
|
|
83898
84979
|
exact("/api/settings/browser", "GET", "POST"),
|
|
84980
|
+
exact("/api/settings/search", "GET", "POST"),
|
|
83899
84981
|
exact("/api/settings/env-models", "GET", "POST"),
|
|
83900
84982
|
exact("/api/settings/detect-ollama", "GET"),
|
|
83901
84983
|
exact("/api/settings/export", "POST"),
|
|
@@ -84096,7 +85178,8 @@ EXPLANATION_END`;
|
|
|
84096
85178
|
const criticalAgents = agentRanking.filter((a) => a.healthScore < 50);
|
|
84097
85179
|
const totalTokenCost = agentRanking.reduce((s2, a) => s2 + a.tokenUsage.cost, 0);
|
|
84098
85180
|
const totalInteractions = agentRanking.reduce((s2, a) => s2 + a.totalInteractions, 0);
|
|
84099
|
-
const
|
|
85181
|
+
const terminalTaskCount = taskDashboard.statusCounts.completed + taskDashboard.statusCounts.failed + taskDashboard.statusCounts.rejected;
|
|
85182
|
+
const taskSuccessRate = terminalTaskCount > 0 ? Math.round(taskDashboard.statusCounts.completed / terminalTaskCount * 100) : 0;
|
|
84100
85183
|
const blockedTasks = taskDashboard.statusCounts.blocked ?? 0;
|
|
84101
85184
|
return {
|
|
84102
85185
|
period,
|
|
@@ -84118,6 +85201,7 @@ EXPLANATION_END`;
|
|
|
84118
85201
|
statusCounts: taskDashboard.statusCounts,
|
|
84119
85202
|
successRate: taskSuccessRate,
|
|
84120
85203
|
blockedCount: blockedTasks,
|
|
85204
|
+
stuckBlockedCount: taskDashboard.stuckBlockedCount,
|
|
84121
85205
|
averageCompletionTimeMs: taskDashboard.averageCompletionTimeMs,
|
|
84122
85206
|
recentActivity: taskDashboard.recentActivity.slice(0, 10)
|
|
84123
85207
|
},
|
|
@@ -84730,7 +85814,7 @@ var init_hitl_service = __esm({
|
|
|
84730
85814
|
});
|
|
84731
85815
|
|
|
84732
85816
|
// ../org-manager/dist/billing-service.js
|
|
84733
|
-
import { randomBytes as
|
|
85817
|
+
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
84734
85818
|
var log58, DEFAULT_PLANS, keyCounter, BillingService;
|
|
84735
85819
|
var init_billing_service = __esm({
|
|
84736
85820
|
"../org-manager/dist/billing-service.js"() {
|
|
@@ -84864,7 +85948,7 @@ var init_billing_service = __esm({
|
|
|
84864
85948
|
}
|
|
84865
85949
|
createAPIKey(orgId2, name, scopes = ["*"], expiresInDays) {
|
|
84866
85950
|
const id = `mk_${(++keyCounter).toString(36)}_${Date.now().toString(36)}`;
|
|
84867
|
-
const key2 = `mk_${
|
|
85951
|
+
const key2 = `mk_${randomBytes5(32).toString("hex")}`;
|
|
84868
85952
|
const now3 = /* @__PURE__ */ new Date();
|
|
84869
85953
|
const apiKey = {
|
|
84870
85954
|
id,
|
|
@@ -86216,6 +87300,8 @@ var init_deliverable_service = __esm({
|
|
|
86216
87300
|
summary: opts.summary,
|
|
86217
87301
|
tags: opts.tags ?? existing.tags
|
|
86218
87302
|
};
|
|
87303
|
+
if (opts.format !== void 0)
|
|
87304
|
+
patch.format = opts.format;
|
|
86219
87305
|
if (opts.artifactType !== void 0)
|
|
86220
87306
|
patch.artifactType = opts.artifactType;
|
|
86221
87307
|
if (opts.artifactData !== void 0)
|
|
@@ -86244,6 +87330,7 @@ var init_deliverable_service = __esm({
|
|
|
86244
87330
|
title: opts.title,
|
|
86245
87331
|
summary: opts.summary,
|
|
86246
87332
|
reference: ref ?? "",
|
|
87333
|
+
format: opts.format,
|
|
86247
87334
|
tags: opts.tags ?? [],
|
|
86248
87335
|
status: "active",
|
|
86249
87336
|
taskId: opts.taskId,
|
|
@@ -86264,6 +87351,7 @@ var init_deliverable_service = __esm({
|
|
|
86264
87351
|
title: opts.title,
|
|
86265
87352
|
summary: opts.summary,
|
|
86266
87353
|
reference: ref ?? "",
|
|
87354
|
+
format: opts.format,
|
|
86267
87355
|
tags: opts.tags ?? [],
|
|
86268
87356
|
status: "active",
|
|
86269
87357
|
taskId: opts.taskId,
|
|
@@ -86351,6 +87439,8 @@ var init_deliverable_service = __esm({
|
|
|
86351
87439
|
d.summary = data.summary;
|
|
86352
87440
|
if (data.reference !== void 0)
|
|
86353
87441
|
d.reference = data.reference;
|
|
87442
|
+
if (data.format !== void 0)
|
|
87443
|
+
d.format = data.format;
|
|
86354
87444
|
if (data.tags !== void 0)
|
|
86355
87445
|
d.tags = data.tags;
|
|
86356
87446
|
if (data.status !== void 0)
|
|
@@ -86530,6 +87620,7 @@ var init_deliverable_service = __esm({
|
|
|
86530
87620
|
title: r.title,
|
|
86531
87621
|
summary: r.summary,
|
|
86532
87622
|
reference: r.reference,
|
|
87623
|
+
format: r.format ?? void 0,
|
|
86533
87624
|
tags: this.parseTags(r.tags),
|
|
86534
87625
|
status: r.status,
|
|
86535
87626
|
taskId: r.taskId ?? void 0,
|
|
@@ -86786,12 +87877,16 @@ var init_report_service = __esm({
|
|
|
86786
87877
|
}
|
|
86787
87878
|
buildCostSummary(scopeId, start, end) {
|
|
86788
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;
|
|
86789
87884
|
return {
|
|
86790
87885
|
totalTokens: usage.llmTokens,
|
|
86791
|
-
totalEstimatedCost:
|
|
87886
|
+
totalEstimatedCost: cost,
|
|
86792
87887
|
byAgent: [],
|
|
86793
87888
|
byCategory: [
|
|
86794
|
-
{ category: "llm_tokens", tokens: usage.llmTokens, cost
|
|
87889
|
+
{ category: "llm_tokens", tokens: usage.llmTokens, cost },
|
|
86795
87890
|
{ category: "tool_calls", tokens: 0, cost: 0 }
|
|
86796
87891
|
],
|
|
86797
87892
|
trend: "stable"
|
|
@@ -87115,17 +88210,21 @@ var init_stale_detector = __esm({
|
|
|
87115
88210
|
});
|
|
87116
88211
|
|
|
87117
88212
|
// ../org-manager/dist/scheduled-task-runner.js
|
|
87118
|
-
var log69, ScheduledTaskRunner;
|
|
88213
|
+
var log69, MIN_STAGGER_MS, MAX_STAGGER_MS, ScheduledTaskRunner;
|
|
87119
88214
|
var init_scheduled_task_runner = __esm({
|
|
87120
88215
|
"../org-manager/dist/scheduled-task-runner.js"() {
|
|
87121
88216
|
"use strict";
|
|
87122
88217
|
init_dist();
|
|
87123
88218
|
log69 = createLogger("scheduled-task-runner");
|
|
88219
|
+
MIN_STAGGER_MS = 2 * 6e4;
|
|
88220
|
+
MAX_STAGGER_MS = 15 * 6e4;
|
|
87124
88221
|
ScheduledTaskRunner = class {
|
|
87125
88222
|
taskService;
|
|
87126
88223
|
pollIntervalMs;
|
|
87127
88224
|
timer;
|
|
88225
|
+
staggerTimers = [];
|
|
87128
88226
|
running = false;
|
|
88227
|
+
startedAt = 0;
|
|
87129
88228
|
constructor(taskService, pollIntervalMs = 6e4) {
|
|
87130
88229
|
this.taskService = taskService;
|
|
87131
88230
|
this.pollIntervalMs = pollIntervalMs;
|
|
@@ -87134,6 +88233,8 @@ var init_scheduled_task_runner = __esm({
|
|
|
87134
88233
|
if (this.running)
|
|
87135
88234
|
return;
|
|
87136
88235
|
this.running = true;
|
|
88236
|
+
this.startedAt = Date.now();
|
|
88237
|
+
this.tick().catch((e) => log69.error("Initial scheduled task tick failed", { error: String(e) }));
|
|
87137
88238
|
this.timer = setInterval(() => {
|
|
87138
88239
|
this.tick().catch((e) => log69.error("Scheduled task tick failed", { error: String(e) }));
|
|
87139
88240
|
}, this.pollIntervalMs);
|
|
@@ -87144,15 +88245,26 @@ var init_scheduled_task_runner = __esm({
|
|
|
87144
88245
|
clearInterval(this.timer);
|
|
87145
88246
|
this.timer = void 0;
|
|
87146
88247
|
}
|
|
88248
|
+
for (const t of this.staggerTimers)
|
|
88249
|
+
clearTimeout(t);
|
|
88250
|
+
this.staggerTimers = [];
|
|
87147
88251
|
this.running = false;
|
|
87148
88252
|
log69.info("ScheduledTaskRunner stopped");
|
|
87149
88253
|
}
|
|
87150
88254
|
isRunning() {
|
|
87151
88255
|
return this.running;
|
|
87152
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
|
+
}
|
|
87153
88264
|
async tick() {
|
|
87154
88265
|
const scheduledTasks = this.taskService.listScheduledTasks();
|
|
87155
88266
|
const now3 = Date.now();
|
|
88267
|
+
const startup = this.isStartupPhase();
|
|
87156
88268
|
for (const task of scheduledTasks) {
|
|
87157
88269
|
if (!task.scheduleConfig)
|
|
87158
88270
|
continue;
|
|
@@ -87169,6 +88281,22 @@ var init_scheduled_task_runner = __esm({
|
|
|
87169
88281
|
if (config.paused) {
|
|
87170
88282
|
continue;
|
|
87171
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
|
+
}
|
|
87172
88300
|
try {
|
|
87173
88301
|
await this.fireScheduledTask(task);
|
|
87174
88302
|
} catch (e) {
|
|
@@ -87268,7 +88396,8 @@ function openSqlite(dbPath) {
|
|
|
87268
88396
|
{ table: "projects", column: "created_by", sql: "ALTER TABLE projects ADD COLUMN created_by TEXT" },
|
|
87269
88397
|
{ table: "approvals", column: "target_user_id", sql: "ALTER TABLE approvals ADD COLUMN target_user_id TEXT" },
|
|
87270
88398
|
{ table: "users", column: "deleted_at", sql: "ALTER TABLE users ADD COLUMN deleted_at TEXT" },
|
|
87271
|
-
{ 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" }
|
|
87272
88401
|
];
|
|
87273
88402
|
for (const m of migrations) {
|
|
87274
88403
|
const cols = _db.prepare(`PRAGMA table_info(${m.table})`).all();
|
|
@@ -87573,6 +88702,7 @@ CREATE TABLE IF NOT EXISTS deliverables (
|
|
|
87573
88702
|
title TEXT NOT NULL,
|
|
87574
88703
|
summary TEXT NOT NULL DEFAULT '',
|
|
87575
88704
|
reference TEXT NOT NULL DEFAULT '',
|
|
88705
|
+
format TEXT,
|
|
87576
88706
|
tags TEXT NOT NULL DEFAULT '[]',
|
|
87577
88707
|
status TEXT NOT NULL DEFAULT 'active',
|
|
87578
88708
|
task_id TEXT,
|
|
@@ -89550,11 +90680,11 @@ CREATE INDEX IF NOT EXISTS idx_st_entity ON status_transitions(entity_type, enti
|
|
|
89550
90680
|
async create(data) {
|
|
89551
90681
|
const n2 = now2();
|
|
89552
90682
|
this.db.prepare(`
|
|
89553
|
-
INSERT INTO deliverables (id, type, title, summary, reference, tags, status,
|
|
90683
|
+
INSERT INTO deliverables (id, type, title, summary, reference, format, tags, status,
|
|
89554
90684
|
task_id, agent_id, project_id, requirement_id, diff_stats, test_results,
|
|
89555
90685
|
artifact_type, artifact_data, access_count, created_at, updated_at)
|
|
89556
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
|
|
89557
|
-
`).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);
|
|
89558
90688
|
return this.findById(data.id);
|
|
89559
90689
|
}
|
|
89560
90690
|
async findById(id) {
|
|
@@ -89617,6 +90747,10 @@ CREATE INDEX IF NOT EXISTS idx_st_entity ON status_transitions(entity_type, enti
|
|
|
89617
90747
|
sets.push("reference = ?");
|
|
89618
90748
|
vals.push(patch.reference);
|
|
89619
90749
|
}
|
|
90750
|
+
if (patch.format !== void 0) {
|
|
90751
|
+
sets.push("format = ?");
|
|
90752
|
+
vals.push(patch.format);
|
|
90753
|
+
}
|
|
89620
90754
|
if (patch.type !== void 0) {
|
|
89621
90755
|
sets.push("type = ?");
|
|
89622
90756
|
vals.push(patch.type);
|
|
@@ -89665,6 +90799,7 @@ CREATE INDEX IF NOT EXISTS idx_st_entity ON status_transitions(entity_type, enti
|
|
|
89665
90799
|
title: r["title"],
|
|
89666
90800
|
summary: r["summary"],
|
|
89667
90801
|
reference: r["reference"],
|
|
90802
|
+
format: r["format"] ?? null,
|
|
89668
90803
|
tags: fromJson(r["tags"]) ?? [],
|
|
89669
90804
|
status: r["status"],
|
|
89670
90805
|
taskId: r["task_id"],
|
|
@@ -91204,6 +92339,7 @@ var init_logger2 = __esm({
|
|
|
91204
92339
|
|
|
91205
92340
|
// src/utils/browser.ts
|
|
91206
92341
|
import { exec } from "node:child_process";
|
|
92342
|
+
import { get as httpGet } from "node:http";
|
|
91207
92343
|
import { platform as platform2 } from "node:os";
|
|
91208
92344
|
function openBrowser(url) {
|
|
91209
92345
|
if (process.env["NO_BROWSER"]) return;
|
|
@@ -91214,6 +92350,27 @@ function openBrowser(url) {
|
|
|
91214
92350
|
}
|
|
91215
92351
|
});
|
|
91216
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
|
+
}
|
|
91217
92374
|
var init_browser = __esm({
|
|
91218
92375
|
"src/utils/browser.ts"() {
|
|
91219
92376
|
"use strict";
|
|
@@ -92156,6 +93313,9 @@ async function createServices(config) {
|
|
|
92156
93313
|
llmRouter.setProviderEnabled(name, false);
|
|
92157
93314
|
}
|
|
92158
93315
|
}
|
|
93316
|
+
if (config.llm.autoFallback === false) {
|
|
93317
|
+
llmRouter.setAutoFallback(false);
|
|
93318
|
+
}
|
|
92159
93319
|
if (config.llm.customModels) {
|
|
92160
93320
|
for (const [providerName, models] of Object.entries(config.llm.customModels)) {
|
|
92161
93321
|
for (const model of models) {
|
|
@@ -92330,6 +93490,9 @@ async function startServer(config, values) {
|
|
|
92330
93490
|
if (config.integrations?.search?.braveApiKey && !process.env["BRAVE_SEARCH_API_KEY"]) {
|
|
92331
93491
|
process.env["BRAVE_SEARCH_API_KEY"] = config.integrations.search.braveApiKey;
|
|
92332
93492
|
}
|
|
93493
|
+
if (config.integrations?.search?.bochaApiKey && !process.env["BOCHA_API_KEY"]) {
|
|
93494
|
+
process.env["BOCHA_API_KEY"] = config.integrations.search.bochaApiKey;
|
|
93495
|
+
}
|
|
92333
93496
|
const apiPort = Number(values["port"]) || config.server.apiPort;
|
|
92334
93497
|
const {
|
|
92335
93498
|
orgService,
|
|
@@ -92579,20 +93742,37 @@ async function startServer(config, values) {
|
|
|
92579
93742
|
const sessionUserId = targetUserId || defaultSessionUserId;
|
|
92580
93743
|
const mainSession = storage.chatSessionRepo.getOrCreateMainSession(agentId2, sessionUserId);
|
|
92581
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(", ")} -->` : "";
|
|
92582
93752
|
const formattedMsg = `**${title}**
|
|
92583
93753
|
|
|
92584
|
-
${body}`;
|
|
93754
|
+
${body}${contextSuffix}`;
|
|
93755
|
+
const msgMetadata = {
|
|
93756
|
+
notifyUser: true,
|
|
93757
|
+
priority: priority ?? "normal",
|
|
93758
|
+
...taskId2 ? { taskId: taskId2 } : {},
|
|
93759
|
+
...requirementId2 ? { requirementId: requirementId2 } : {}
|
|
93760
|
+
};
|
|
92585
93761
|
const msg = storage.chatSessionRepo.appendMessage(
|
|
92586
93762
|
mainSession.id,
|
|
92587
93763
|
agentId2,
|
|
92588
93764
|
"assistant",
|
|
92589
93765
|
formattedMsg,
|
|
92590
93766
|
0,
|
|
92591
|
-
|
|
93767
|
+
msgMetadata
|
|
92592
93768
|
);
|
|
92593
93769
|
storage.chatSessionRepo.updateLastMessage(mainSession.id);
|
|
92594
93770
|
ws.broadcastProactiveMessage(agentId2, agent.config.name, mainSession.id, msg.id, formattedMsg, {
|
|
92595
|
-
isMainSession: true
|
|
93771
|
+
isMainSession: true,
|
|
93772
|
+
notifyUser: true,
|
|
93773
|
+
priority: priority ?? "normal",
|
|
93774
|
+
taskId: taskId2,
|
|
93775
|
+
requirementId: requirementId2
|
|
92596
93776
|
}, sessionUserId);
|
|
92597
93777
|
const hasTask = !!taskId2;
|
|
92598
93778
|
hitlService.notify({
|
|
@@ -93236,13 +94416,9 @@ ${reason}`;
|
|
|
93236
94416
|
const logFile = getStartupLogFile();
|
|
93237
94417
|
const logFileName = logFile.split("/").pop() ?? logFile;
|
|
93238
94418
|
const uiUrl = `http://localhost:${apiPort}`;
|
|
94419
|
+
progress.finish(uiUrl);
|
|
93239
94420
|
if (!process.env["NO_BROWSER"] && webUiDir) {
|
|
93240
|
-
|
|
93241
|
-
setTimeout(() => {
|
|
93242
|
-
openBrowser(uiUrl);
|
|
93243
|
-
}, 500);
|
|
93244
|
-
} else {
|
|
93245
|
-
progress.finish(uiUrl);
|
|
94421
|
+
openBrowserAfterHealthCheck(uiUrl, `${uiUrl}/api/health`);
|
|
93246
94422
|
}
|
|
93247
94423
|
checkForUpdate().then((info4) => {
|
|
93248
94424
|
if (info4.updateAvailable) {
|
|
@@ -96351,7 +97527,7 @@ var connect_exports = {};
|
|
|
96351
97527
|
__export(connect_exports, {
|
|
96352
97528
|
registerConnectCommands: () => registerConnectCommands
|
|
96353
97529
|
});
|
|
96354
|
-
import { randomBytes as
|
|
97530
|
+
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
96355
97531
|
function registerConnectCommands(program2) {
|
|
96356
97532
|
const root = program2.command("connect").description("Connect / disconnect external agent platforms");
|
|
96357
97533
|
root.command("scan").description("Scan for installed agent platforms that can be connected").action(async (_opts, cmd) => {
|
|
@@ -96410,7 +97586,7 @@ function registerConnectCommands(program2) {
|
|
|
96410
97586
|
fail(`Unknown platform "${platform3}". Run \`markus connect list\` to see available connectors.`);
|
|
96411
97587
|
return;
|
|
96412
97588
|
}
|
|
96413
|
-
const agentId2 = opts.agentId || `${platform3}-${
|
|
97589
|
+
const agentId2 = opts.agentId || `${platform3}-${randomBytes6(4).toString("hex")}`;
|
|
96414
97590
|
const agentName = opts.agentName || connector.defaultAgentName || `${connector.displayName} Agent`;
|
|
96415
97591
|
const capabilities = opts.capabilities ? String(opts.capabilities).split(",").map((s2) => s2.trim()).filter(Boolean) : connector.defaultCapabilities ?? [];
|
|
96416
97592
|
const client = createClient(g);
|
|
@@ -96584,7 +97760,7 @@ __export(install_agent_exports, {
|
|
|
96584
97760
|
registerInstallAgentCommands: () => registerInstallAgentCommands
|
|
96585
97761
|
});
|
|
96586
97762
|
import { execSync as execSync5 } from "node:child_process";
|
|
96587
|
-
import { randomBytes as
|
|
97763
|
+
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
96588
97764
|
function registerInstallAgentCommands(program2) {
|
|
96589
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) => {
|
|
96590
97766
|
const g = cmd.optsWithGlobals();
|
|
@@ -96640,7 +97816,7 @@ function registerInstallAgentCommands(program2) {
|
|
|
96640
97816
|
}
|
|
96641
97817
|
const client = createClient(g);
|
|
96642
97818
|
const serverUrl = g.server || process.env["MARKUS_API_URL"] || "http://localhost:8056";
|
|
96643
|
-
const agentId2 = `${platform3}-${
|
|
97819
|
+
const agentId2 = `${platform3}-${randomBytes7(4).toString("hex")}`;
|
|
96644
97820
|
const agentName = opts.agentName || connector.defaultAgentName || `${connector.displayName} Agent`;
|
|
96645
97821
|
const capabilities = connector.defaultCapabilities ?? [];
|
|
96646
97822
|
try {
|