@markus-global/cli 0.6.3 → 0.6.5
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.d.ts.map +1 -1
- package/dist/commands/start.js +39 -11
- package/dist/commands/start.js.map +1 -1
- package/dist/markus.mjs +1214 -339
- package/dist/web-ui/assets/index-DcnwpDqb.css +1 -0
- package/dist/web-ui/assets/index-tONQYLWM.js +351 -0
- package/dist/web-ui/index.html +2 -2
- package/dist/web-ui/logo.png +0 -0
- package/package.json +1 -1
- package/templates/roles/SHARED.md +3 -6
- package/templates/roles/developer/POLICIES.md +1 -1
- package/templates/roles/secretary/HEARTBEAT.md +1 -1
- package/templates/roles/secretary/ROLE.md +80 -4
- package/templates/skills/agent-building/SKILL.md +1 -1
- package/templates/skills/chrome-devtools/SKILL.md +56 -0
- package/templates/skills/image-generation/SKILL.md +183 -0
- package/templates/skills/image-generation/server.mjs +1269 -0
- package/templates/skills/image-generation/skill.json +26 -0
- package/templates/skills/markus-admin-cli/SKILL.md +1 -1
- package/templates/skills/self-evolution/SKILL.md +4 -4
- package/templates/skills/skill-building/SKILL.md +1 -1
- package/templates/skills/team-building/SKILL.md +1 -1
- package/templates/teams/content-team/ANNOUNCEMENT.md +28 -24
- package/templates/teams/content-team/NORMS.md +50 -48
- package/templates/teams/content-team/team.json +46 -16
- package/templates/teams/research-lab/ANNOUNCEMENT.md +24 -19
- package/templates/teams/research-lab/NORMS.md +77 -88
- package/templates/teams/research-lab/team.json +40 -14
- package/dist/web-ui/assets/index-C97PujBE.js +0 -351
- package/dist/web-ui/assets/index-Q4_kHftV.css +0 -1
package/dist/markus.mjs
CHANGED
|
@@ -6381,20 +6381,80 @@ var init_context_engine = __esm({
|
|
|
6381
6381
|
this.llmSummarizer = summarizer;
|
|
6382
6382
|
}
|
|
6383
6383
|
async buildSystemPrompt(opts) {
|
|
6384
|
-
const
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6384
|
+
const isDream = opts.scenario === "memory_consolidation";
|
|
6385
|
+
const stable = [];
|
|
6386
|
+
stable.push(opts.role.systemPrompt);
|
|
6387
|
+
if (opts.role.defaultPolicies.length > 0) {
|
|
6388
|
+
stable.push("\n## Policies");
|
|
6389
|
+
for (const policy of opts.role.defaultPolicies) {
|
|
6390
|
+
stable.push(`### ${policy.name}`);
|
|
6391
|
+
for (const rule of policy.rules) {
|
|
6392
|
+
stable.push(`- ${rule}`);
|
|
6393
|
+
}
|
|
6394
|
+
}
|
|
6395
|
+
}
|
|
6396
|
+
if (!isDream) {
|
|
6397
|
+
stable.push("\n## Tool Usage Rules");
|
|
6398
|
+
stable.push("**File editing discipline**: You MUST use `file_write` and `file_edit` for all file creation and modification. NEVER use `shell_execute` with `cat`, `echo`, `printf`, `tee`, pipes (`|`), output redirection (`>`, `>>`), heredocs (`<<`), or `sed`/`awk` to write or modify files \u2014 these bypass file access controls. `shell_execute` is for running commands (build, test, git, etc.), not for writing files.");
|
|
6399
|
+
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.");
|
|
6400
|
+
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.");
|
|
6401
|
+
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.");
|
|
6402
|
+
stable.push("**Built-in tools over CLI**: ALWAYS prefer built-in tools (`task_create`, `task_assign`, `team_hire_agent`, `builder_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.");
|
|
6403
|
+
stable.push('**No auto-install/deploy**: NEVER automatically install or deploy agents, teams, or skills via `builder_install`, `team_hire_agent`, 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.');
|
|
6404
|
+
stable.push("");
|
|
6405
|
+
stable.push("\n## Task & Requirement Workflow");
|
|
6406
|
+
stable.push("");
|
|
6407
|
+
stable.push("**Requirements** (governance gate):");
|
|
6408
|
+
stable.push("- `requirement_propose` \u2192 pending human approval \u2192 approved \u2192 link tasks via `requirement_id`");
|
|
6409
|
+
stable.push("- Every task MUST reference an approved `requirement_id`. Use `requirement_propose` first if no requirement exists.");
|
|
6410
|
+
stable.push("");
|
|
6411
|
+
stable.push("**Task lifecycle** \u2014 Create \u2192 Execute \u2192 Review \u2192 Complete:");
|
|
6412
|
+
stable.push('- **Create**: `task_create` (REQUIRED: `assigned_agent_id`, `reviewer_id`; optional `reviewer_type`: "agent"|"human"). Check `task_list` first to avoid duplicates.');
|
|
6413
|
+
stable.push("- **Execute**: Decompose with `subtask_create` \u2192 work through subtasks \u2192 `task_submit_review` with summary + deliverables (MANDATORY). System auto-fills `task_id` and `reviewer`.");
|
|
6414
|
+
stable.push('- **Review**: Reviewer approves with `task_update(status:"completed")` or rejects with `task_update(status:"in_progress", note:"what needs to change")` (auto-restarts execution). Workers MUST NOT set status=completed on their own tasks.');
|
|
6415
|
+
stable.push('- **Blockers**: Use `task_update(status:"blocked", note:"reason")` when unable to proceed.');
|
|
6416
|
+
stable.push("");
|
|
6417
|
+
stable.push("**Dependencies & DAG decomposition**:");
|
|
6418
|
+
stable.push("- **CRITICAL**: Use `blocked_by` to express ALL dependency relationships. If task B needs output from task A, B **MUST** include A's ID in `blocked_by`. Without this, tasks run in parallel and downstream tasks lack upstream deliverables.");
|
|
6419
|
+
stable.push("- For complex goals, create a DAG of tasks. Assign each to the best team member (`team_list`). Independent tasks run in parallel; dependent tasks wait for predecessors.");
|
|
6420
|
+
stable.push("- If consolidated output is needed, create a final synthesis task assigned to a manager, `blocked_by` ALL prerequisites.");
|
|
6421
|
+
stable.push("");
|
|
6422
|
+
stable.push("**Work discovery**: `list_projects` \u2192 `requirement_list` \u2192 `task_list`. Use `memory_save`/`memory_search` for personal notes; `deliverable_create`/`deliverable_search` for shared outputs.");
|
|
6423
|
+
stable.push("");
|
|
6424
|
+
stable.push("**Automatic status notifications** (do NOT duplicate manually):");
|
|
6425
|
+
stable.push("- When task status changes, the system **automatically** handles all side effects: execution start/cancel, reviewer notification, dependency unblocking.");
|
|
6426
|
+
stable.push("- Task status notifications are placed in assignees' mailboxes as **informational context only**.");
|
|
6427
|
+
stable.push("- Do NOT send A2A messages to notify about task status changes \u2014 only send A2A when you have substantive coordination needs beyond the status change itself.");
|
|
6428
|
+
stable.push("");
|
|
6429
|
+
stable.push("**Communicating with humans**:");
|
|
6430
|
+
stable.push("- `notify_user` \u2014 proactive message to a human team member: status updates, progress reports, findings, alerts. Appears in chat timeline AND notification bell. The human can reply. Write comprehensive body with full context. **This is the ONLY way to reach humans from non-chat contexts** (heartbeat, autonomous tasks, etc.).");
|
|
6431
|
+
stable.push("- `request_user_approval` \u2014 when you need a human decision, approval, or input. BLOCKS until the user responds. Supports custom options and freeform text. Do NOT use for routine updates.");
|
|
6432
|
+
stable.push("- `recall_activity` \u2014 query your own past execution logs by task or activity type. Use when you need to review what you did previously (e.g., to answer a follow-up question).");
|
|
6433
|
+
stable.push("");
|
|
6434
|
+
stable.push("**Communicating with other agents**:");
|
|
6435
|
+
stable.push("- `agent_send_message` \u2014 send a direct message to a peer agent. **By default this is asynchronous (fire-and-forget)**: the message enters their mailbox and you continue working without waiting. Set `wait_for_reply: true` only when you need the answer before you can proceed (rare \u2014 prefer async).");
|
|
6436
|
+
stable.push("- A2A messaging is inherently **non-blocking**. You send a message, the recipient processes it on their own schedule, and may reply later via their own `agent_send_message`. Do NOT spin-wait or poll for responses.");
|
|
6437
|
+
stable.push("- For substantial work requests, create a `task_create` assigned to the target agent instead of asking via message.");
|
|
6438
|
+
stable.push("- Do NOT use A2A messages for routine task status notifications \u2014 the system handles those automatically.");
|
|
6388
6439
|
}
|
|
6389
|
-
|
|
6440
|
+
const scenario = opts.scenario ?? "chat";
|
|
6441
|
+
stable.push(this.buildScenarioSection(scenario, { a2aWaitForReply: opts.a2aWaitForReply }));
|
|
6442
|
+
const semiStable = [];
|
|
6443
|
+
semiStable.push(this.buildIdentitySection({
|
|
6444
|
+
agentId: opts.agentId,
|
|
6445
|
+
agentName: opts.agentName,
|
|
6446
|
+
role: opts.role,
|
|
6447
|
+
identity: opts.identity,
|
|
6448
|
+
availableSkills: opts.availableSkills
|
|
6449
|
+
}));
|
|
6390
6450
|
const orgCtx = this.buildOrgContextSection(opts.orgContext, opts.contextMdPath);
|
|
6391
6451
|
if (orgCtx)
|
|
6392
|
-
|
|
6452
|
+
semiStable.push(orgCtx);
|
|
6393
6453
|
if (opts.teamAnnouncements?.trim()) {
|
|
6394
|
-
|
|
6454
|
+
semiStable.push("\n## Team Announcements\n" + opts.teamAnnouncements.trim());
|
|
6395
6455
|
}
|
|
6396
6456
|
if (opts.teamNorms?.trim()) {
|
|
6397
|
-
|
|
6457
|
+
semiStable.push("\n## Team Working Norms\n" + opts.teamNorms.trim());
|
|
6398
6458
|
}
|
|
6399
6459
|
if (opts.teamDataDir) {
|
|
6400
6460
|
const lines = ["\n## Team Data Directory", `Path: \`${opts.teamDataDir}\``, "Files:", "- `ANNOUNCEMENT.md` \u2014 team announcements", "- `NORMS.md` \u2014 team working norms"];
|
|
@@ -6403,50 +6463,32 @@ var init_context_engine = __esm({
|
|
|
6403
6463
|
} else {
|
|
6404
6464
|
lines.push("\nRead and follow the announcements and norms above. If you need changes, ask the team manager.");
|
|
6405
6465
|
}
|
|
6406
|
-
|
|
6407
|
-
}
|
|
6408
|
-
if (opts.projectContext) {
|
|
6409
|
-
const { project, repositories, governanceRules, teamRole } = opts.projectContext;
|
|
6410
|
-
parts.push("\n## Current Project");
|
|
6411
|
-
parts.push(`- Project: **${project.name}** (${project.status})`);
|
|
6412
|
-
if (project.description)
|
|
6413
|
-
parts.push(`- ${project.description.slice(0, SYSTEM_PROJECT_DESC_CHARS)}`);
|
|
6414
|
-
if (repositories?.length) {
|
|
6415
|
-
for (const repo of repositories) {
|
|
6416
|
-
parts.push(`- Repository: \`${repo.localPath}\` (${repo.role}, default branch: \`${repo.defaultBranch}\`)`);
|
|
6417
|
-
}
|
|
6418
|
-
}
|
|
6419
|
-
parts.push("");
|
|
6420
|
-
parts.push("Some git operations (switching to existing branches, pushing to protected branches, merge, rebase) require human approval \u2014 the system will pause and ask the reviewer. If denied, you will receive a reason; read it and adjust your approach.");
|
|
6421
|
-
if (teamRole)
|
|
6422
|
-
parts.push(`- Your role: ${teamRole}`);
|
|
6423
|
-
if (governanceRules)
|
|
6424
|
-
parts.push(`- Governance: ${governanceRules}`);
|
|
6466
|
+
semiStable.push(lines.join("\n"));
|
|
6425
6467
|
}
|
|
6426
6468
|
if (opts.agentWorkspace) {
|
|
6427
|
-
|
|
6428
|
-
|
|
6469
|
+
semiStable.push("\n## Your Workspace");
|
|
6470
|
+
semiStable.push(`- Working directory: \`${opts.agentWorkspace.primaryWorkspace}\``);
|
|
6429
6471
|
if (opts.agentWorkspace.sharedWorkspace) {
|
|
6430
|
-
|
|
6472
|
+
semiStable.push(`- Shared workspace: \`${opts.agentWorkspace.sharedWorkspace}\` (all agents can read/write here)`);
|
|
6431
6473
|
}
|
|
6432
6474
|
const artifactsDir = opts.agentWorkspace.builderArtifactsDir ?? "~/.markus/builder-artifacts";
|
|
6433
6475
|
if (opts.agentWorkspace.builderArtifactsDir) {
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6476
|
+
semiStable.push(`- Builder artifacts directory: \`${artifactsDir}/\``);
|
|
6477
|
+
semiStable.push(" When creating agents, teams, or skills, place them in the correct subdirectory:");
|
|
6478
|
+
semiStable.push(` - Agents \u2192 \`${artifactsDir}/agents/{agent-name}/\``);
|
|
6479
|
+
semiStable.push(` - Teams \u2192 \`${artifactsDir}/teams/{team-name}/\``);
|
|
6480
|
+
semiStable.push(` - Skills \u2192 \`${artifactsDir}/skills/{skill-name}/\``);
|
|
6481
|
+
semiStable.push(" The Builder page and install system ONLY recognize these paths.");
|
|
6440
6482
|
}
|
|
6441
6483
|
if (opts.agentDataDir) {
|
|
6442
|
-
|
|
6484
|
+
semiStable.push(`- Agent data directory: \`${opts.agentDataDir}\` (your ROLE.md, MEMORY.md, and personal files)`);
|
|
6443
6485
|
}
|
|
6444
|
-
|
|
6445
|
-
|
|
6486
|
+
semiStable.push("- IMPORTANT: Always use **absolute paths** in file operations. Relative paths are error-prone.");
|
|
6487
|
+
semiStable.push("- You can directly read files in the shared workspace using `file_read` \u2014 no need to request them from other agents.");
|
|
6446
6488
|
} else if (opts.agentDataDir) {
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6489
|
+
semiStable.push("\n## Your Workspace");
|
|
6490
|
+
semiStable.push(`- Agent data directory: \`${opts.agentDataDir}\` (your ROLE.md, MEMORY.md, and personal files)`);
|
|
6491
|
+
semiStable.push("- IMPORTANT: Always use **absolute paths** in file operations. Relative paths are error-prone.");
|
|
6450
6492
|
}
|
|
6451
6493
|
if (opts.agentWorkspace?.sharedWorkspace) {
|
|
6452
6494
|
const userMdPath = `${opts.agentWorkspace.sharedWorkspace}/USER.md`;
|
|
@@ -6454,206 +6496,186 @@ var init_context_engine = __esm({
|
|
|
6454
6496
|
if (existsSync8(userMdPath)) {
|
|
6455
6497
|
const userProfile = readFileSync6(userMdPath, "utf-8").trim();
|
|
6456
6498
|
if (userProfile) {
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6499
|
+
semiStable.push("\n## About the Owner");
|
|
6500
|
+
semiStable.push(userProfile.slice(0, SYSTEM_USER_PROFILE_CHARS));
|
|
6501
|
+
semiStable.push("\n_This profile is maintained by the Secretary. If you notice new preferences or patterns from the owner, mention them to the Secretary via `agent_send_message`._");
|
|
6460
6502
|
}
|
|
6461
6503
|
}
|
|
6462
6504
|
} catch {
|
|
6463
6505
|
}
|
|
6464
6506
|
}
|
|
6465
6507
|
if (opts.trustLevel) {
|
|
6466
|
-
|
|
6467
|
-
|
|
6508
|
+
semiStable.push("\n## Your Trust Level");
|
|
6509
|
+
semiStable.push(`- Level: **${opts.trustLevel.level}** (score: ${opts.trustLevel.score})`);
|
|
6468
6510
|
if (opts.trustLevel.level === "probation") {
|
|
6469
|
-
|
|
6511
|
+
semiStable.push("- You are on probation. All your task creations require human approval. Focus on quality to build trust.");
|
|
6470
6512
|
} else if (opts.trustLevel.level === "standard") {
|
|
6471
|
-
|
|
6513
|
+
semiStable.push("- You are a standard-level agent. Routine tasks may auto-approve; significant tasks need manager approval.");
|
|
6472
6514
|
} else if (opts.trustLevel.level === "trusted") {
|
|
6473
|
-
|
|
6515
|
+
semiStable.push("- You are a trusted agent. You have a proven track record and higher autonomy.");
|
|
6474
6516
|
} else if (opts.trustLevel.level === "senior") {
|
|
6475
|
-
|
|
6517
|
+
semiStable.push("- You are a senior agent. You have the highest autonomy. Routine tasks auto-approve.");
|
|
6518
|
+
}
|
|
6519
|
+
}
|
|
6520
|
+
if (opts.environment) {
|
|
6521
|
+
semiStable.push(this.buildEnvironmentSection(opts.environment));
|
|
6522
|
+
}
|
|
6523
|
+
const longTermMem = opts.memory.getLongTermMemory();
|
|
6524
|
+
if (longTermMem) {
|
|
6525
|
+
semiStable.push("\n## Your Knowledge");
|
|
6526
|
+
semiStable.push(longTermMem.slice(0, SYSTEM_KNOWLEDGE_CHARS));
|
|
6527
|
+
}
|
|
6528
|
+
const dynamic = [];
|
|
6529
|
+
if (opts.projectContext) {
|
|
6530
|
+
const { project, repositories, governanceRules, teamRole } = opts.projectContext;
|
|
6531
|
+
dynamic.push("\n## Current Project");
|
|
6532
|
+
dynamic.push(`- Project: **${project.name}** (${project.status})`);
|
|
6533
|
+
if (project.description)
|
|
6534
|
+
dynamic.push(`- ${project.description.slice(0, SYSTEM_PROJECT_DESC_CHARS)}`);
|
|
6535
|
+
if (repositories?.length) {
|
|
6536
|
+
for (const repo of repositories) {
|
|
6537
|
+
dynamic.push(`- Repository: \`${repo.localPath}\` (${repo.role}, default branch: \`${repo.defaultBranch}\`)`);
|
|
6538
|
+
}
|
|
6476
6539
|
}
|
|
6540
|
+
dynamic.push("");
|
|
6541
|
+
dynamic.push("Some git operations (switching to existing branches, pushing to protected branches, merge, rebase) require human approval \u2014 the system will pause and ask the reviewer. If denied, you will receive a reason; read it and adjust your approach.");
|
|
6542
|
+
if (teamRole)
|
|
6543
|
+
dynamic.push(`- Your role: ${teamRole}`);
|
|
6544
|
+
if (governanceRules)
|
|
6545
|
+
dynamic.push(`- Governance: ${governanceRules}`);
|
|
6477
6546
|
}
|
|
6478
6547
|
if (opts.announcements?.length) {
|
|
6479
|
-
|
|
6548
|
+
dynamic.push("\n## System Announcements");
|
|
6480
6549
|
for (const a of opts.announcements) {
|
|
6481
6550
|
const prefix = a.priority === "urgent" ? "[URGENT] " : a.priority === "high" ? "[HIGH] " : "[INFO] ";
|
|
6482
|
-
|
|
6551
|
+
dynamic.push(`- ${prefix}${a.title}: ${a.content}`);
|
|
6483
6552
|
}
|
|
6484
6553
|
}
|
|
6485
6554
|
if (opts.recentFeedback?.length) {
|
|
6486
|
-
|
|
6555
|
+
dynamic.push("\n## Human Feedback (recent)");
|
|
6487
6556
|
for (const fb of opts.recentFeedback) {
|
|
6488
6557
|
const urgency = fb.priority === "critical" ? "[CRITICAL] " : fb.priority === "important" ? "[IMPORTANT] " : "";
|
|
6489
6558
|
const anchor = fb.anchor ? ` (re: ${fb.anchor.section}${fb.anchor.itemId ? "/" + fb.anchor.itemId : ""})` : "";
|
|
6490
|
-
|
|
6559
|
+
dynamic.push(`- ${urgency}**${fb.authorName}**${anchor}: ${fb.content}`);
|
|
6491
6560
|
}
|
|
6492
6561
|
}
|
|
6493
6562
|
if (opts.projectDeliverables?.length) {
|
|
6494
|
-
|
|
6563
|
+
dynamic.push("\n## Project Deliverables (key entries)");
|
|
6495
6564
|
for (const k of opts.projectDeliverables) {
|
|
6496
|
-
|
|
6565
|
+
dynamic.push(`- **[${k.category}]** ${k.title}: ${k.content.slice(0, SYSTEM_DELIVERABLE_PREVIEW_CHARS)}`);
|
|
6497
6566
|
}
|
|
6498
6567
|
}
|
|
6499
|
-
if (opts.role.defaultPolicies.length > 0) {
|
|
6500
|
-
parts.push("\n## Policies");
|
|
6501
|
-
for (const policy of opts.role.defaultPolicies) {
|
|
6502
|
-
parts.push(`### ${policy.name}`);
|
|
6503
|
-
for (const rule of policy.rules) {
|
|
6504
|
-
parts.push(`- ${rule}`);
|
|
6505
|
-
}
|
|
6506
|
-
}
|
|
6507
|
-
}
|
|
6508
|
-
const longTermMem = opts.memory.getLongTermMemory();
|
|
6509
|
-
if (longTermMem) {
|
|
6510
|
-
parts.push("\n## Your Knowledge");
|
|
6511
|
-
parts.push(longTermMem.slice(0, SYSTEM_KNOWLEDGE_CHARS));
|
|
6512
|
-
}
|
|
6513
|
-
const alreadyShownIds = /* @__PURE__ */ new Set();
|
|
6514
|
-
const isDream = opts.scenario === "memory_consolidation";
|
|
6515
6568
|
if (!isDream && (opts.deliverableContext || opts.knowledgeContext)) {
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
}
|
|
6519
|
-
const cpp = opts.cognitiveContext;
|
|
6520
|
-
if (cpp && !cpp.isEmpty) {
|
|
6521
|
-
if (cpp.cognitiveContext) {
|
|
6522
|
-
parts.push("\n## Cognitive Context");
|
|
6523
|
-
parts.push(cpp.cognitiveContext);
|
|
6524
|
-
}
|
|
6525
|
-
if (cpp.retrievedContext) {
|
|
6526
|
-
parts.push("\n## Retrieved Context");
|
|
6527
|
-
parts.push(cpp.retrievedContext);
|
|
6528
|
-
}
|
|
6529
|
-
if (cpp.reflection) {
|
|
6530
|
-
parts.push("\n## Reflection");
|
|
6531
|
-
parts.push(cpp.reflection);
|
|
6532
|
-
}
|
|
6533
|
-
} else if (!isDream) {
|
|
6534
|
-
const relevantMemories = await this.retrieveRelevantMemories(opts.memory, opts.currentQuery, opts.agentId, alreadyShownIds);
|
|
6535
|
-
if (relevantMemories.length > 0) {
|
|
6536
|
-
parts.push("\n## Relevant Memories");
|
|
6537
|
-
for (const mem of relevantMemories) {
|
|
6538
|
-
const ts = mem.timestamp ? new Date(mem.timestamp).toLocaleDateString() : "";
|
|
6539
|
-
parts.push(`- [${ts}] ${mem.content}`);
|
|
6540
|
-
}
|
|
6541
|
-
}
|
|
6569
|
+
dynamic.push("\n## Shared Deliverables");
|
|
6570
|
+
dynamic.push((opts.deliverableContext ?? opts.knowledgeContext ?? "").slice(0, SYSTEM_DELIVERABLES_CHARS));
|
|
6542
6571
|
}
|
|
6543
6572
|
if (!isDream) {
|
|
6544
6573
|
if (opts.assignedTasks && opts.assignedTasks.length > 0) {
|
|
6545
6574
|
const priorityOrder = ["critical", "high", "medium", "low"];
|
|
6546
6575
|
const byPriority = (a, b) => priorityOrder.indexOf(a.priority ?? "medium") - priorityOrder.indexOf(b.priority ?? "medium");
|
|
6576
|
+
const CLOSED_STATUSES = /* @__PURE__ */ new Set(["completed", "cancelled", "failed", "archived", "rejected"]);
|
|
6547
6577
|
const myTasks = opts.assignedTasks.filter((t) => t.assignedAgentId === opts.agentId);
|
|
6548
6578
|
const otherTasks = opts.assignedTasks.filter((t) => t.assignedAgentId !== opts.agentId);
|
|
6549
|
-
const myActive = myTasks.filter((t) => !
|
|
6550
|
-
const myDone = myTasks.filter((t) =>
|
|
6579
|
+
const myActive = myTasks.filter((t) => !CLOSED_STATUSES.has(t.status)).sort(byPriority);
|
|
6580
|
+
const myDone = myTasks.filter((t) => CLOSED_STATUSES.has(t.status));
|
|
6551
6581
|
const MY_TASK_LIMIT = SYSTEM_MY_TASKS_MAX;
|
|
6552
6582
|
const TEAM_TASK_LIMIT = SYSTEM_TEAM_TASKS_MAX;
|
|
6553
|
-
|
|
6554
|
-
|
|
6583
|
+
dynamic.push("\n## Task Board");
|
|
6584
|
+
dynamic.push("### My Tasks (assigned to you):");
|
|
6555
6585
|
if (myActive.length > 0) {
|
|
6556
6586
|
const shown = myActive.slice(0, MY_TASK_LIMIT);
|
|
6557
6587
|
for (const t of shown) {
|
|
6558
|
-
|
|
6588
|
+
dynamic.push(`- [${t.status.toUpperCase()}] **${t.title}** (ID: \`${t.id}\`, priority: ${t.priority})`);
|
|
6559
6589
|
if (t.description)
|
|
6560
|
-
|
|
6590
|
+
dynamic.push(` ${t.description.slice(0, SYSTEM_TASK_DESC_CHARS)}`);
|
|
6561
6591
|
}
|
|
6562
6592
|
if (myActive.length > MY_TASK_LIMIT) {
|
|
6563
|
-
|
|
6593
|
+
dynamic.push(`_(${myActive.length - MY_TASK_LIMIT} more active tasks not shown \u2014 use \`task_list\` for full list)_`);
|
|
6564
6594
|
}
|
|
6565
6595
|
} else {
|
|
6566
|
-
|
|
6596
|
+
dynamic.push("No active tasks assigned to you.");
|
|
6567
6597
|
}
|
|
6568
6598
|
if (myDone.length > 0) {
|
|
6569
|
-
|
|
6599
|
+
dynamic.push(`_(${myDone.length} completed/closed tasks)_`);
|
|
6570
6600
|
}
|
|
6571
6601
|
if (otherTasks.length > 0) {
|
|
6572
|
-
const otherActive = otherTasks.filter((t) => !
|
|
6573
|
-
const otherDone = otherTasks.filter((t) =>
|
|
6602
|
+
const otherActive = otherTasks.filter((t) => !CLOSED_STATUSES.has(t.status)).sort(byPriority);
|
|
6603
|
+
const otherDone = otherTasks.filter((t) => CLOSED_STATUSES.has(t.status));
|
|
6574
6604
|
if (otherActive.length > 0) {
|
|
6575
|
-
|
|
6605
|
+
dynamic.push("### Team Tasks (assigned to others):");
|
|
6576
6606
|
const shown = otherActive.slice(0, TEAM_TASK_LIMIT);
|
|
6577
6607
|
for (const t of shown) {
|
|
6578
6608
|
const owner = t.assignedAgentName ?? t.assignedAgentId ?? "unassigned";
|
|
6579
|
-
|
|
6609
|
+
dynamic.push(`- [${t.status.toUpperCase()}] **${t.title}** (ID: \`${t.id}\`, assignee: ${owner}, priority: ${t.priority})`);
|
|
6580
6610
|
}
|
|
6581
6611
|
if (otherActive.length > TEAM_TASK_LIMIT) {
|
|
6582
|
-
|
|
6612
|
+
dynamic.push(`_(${otherActive.length - TEAM_TASK_LIMIT} more team tasks not shown)_`);
|
|
6583
6613
|
}
|
|
6584
6614
|
}
|
|
6585
6615
|
if (otherDone.length > 0) {
|
|
6586
|
-
|
|
6616
|
+
dynamic.push(`_(${otherDone.length} other completed/closed tasks)_`);
|
|
6587
6617
|
}
|
|
6588
6618
|
}
|
|
6589
6619
|
} else {
|
|
6590
|
-
|
|
6591
|
-
|
|
6620
|
+
dynamic.push("\n## Task Board");
|
|
6621
|
+
dynamic.push("No tasks on the board.");
|
|
6592
6622
|
}
|
|
6593
|
-
parts.push("");
|
|
6594
|
-
parts.push("### Task & Requirement Workflow");
|
|
6595
|
-
parts.push("");
|
|
6596
|
-
parts.push("**Requirements** (governance gate):");
|
|
6597
|
-
parts.push("- `requirement_propose` \u2192 pending human approval \u2192 approved \u2192 link tasks via `requirement_id`");
|
|
6598
|
-
parts.push("- When governance requires it, every task MUST reference an approved `requirement_id`.");
|
|
6599
|
-
parts.push("");
|
|
6600
|
-
parts.push("**Task lifecycle** \u2014 Create \u2192 Execute \u2192 Review \u2192 Complete:");
|
|
6601
|
-
parts.push('- **Create**: `task_create` (REQUIRED: `assigned_agent_id`, `reviewer_id`; optional `reviewer_type`: "agent"|"human"). Check `task_list` first to avoid duplicates.');
|
|
6602
|
-
parts.push("- **Execute**: Decompose with `subtask_create` \u2192 work through subtasks \u2192 `task_submit_review` with summary + deliverables (MANDATORY). System auto-fills `task_id` and `reviewer`.");
|
|
6603
|
-
parts.push('- **Review**: Reviewer approves with `task_update(status:"completed")` or rejects with `task_update(status:"in_progress", note:"what needs to change")` (auto-restarts execution). Workers MUST NOT set status=completed on their own tasks.');
|
|
6604
|
-
parts.push('- **Blockers**: Use `task_update(status:"blocked", note:"reason")` when unable to proceed.');
|
|
6605
|
-
parts.push("");
|
|
6606
|
-
parts.push("**Dependencies & DAG decomposition**:");
|
|
6607
|
-
parts.push("- **CRITICAL**: Use `blocked_by` to express ALL dependency relationships. If task B needs output from task A, B **MUST** include A's ID in `blocked_by`. Without this, tasks run in parallel and downstream tasks lack upstream deliverables.");
|
|
6608
|
-
parts.push("- For complex goals, create a DAG of tasks. Assign each to the best team member (`team_list`). Independent tasks run in parallel; dependent tasks wait for predecessors.");
|
|
6609
|
-
parts.push("- If consolidated output is needed, create a final synthesis task assigned to a manager, `blocked_by` ALL prerequisites.");
|
|
6610
|
-
parts.push("");
|
|
6611
|
-
parts.push("**Work discovery**: `list_projects` \u2192 `requirement_list` \u2192 `task_list`. Use `memory_save`/`memory_search` for personal notes; `deliverable_create`/`deliverable_search` for shared outputs.");
|
|
6612
|
-
parts.push("");
|
|
6613
|
-
parts.push("**Automatic status notifications** (do NOT duplicate manually):");
|
|
6614
|
-
parts.push("- When task status changes, the system **automatically** handles all side effects: execution start/cancel, reviewer notification, dependency unblocking.");
|
|
6615
|
-
parts.push("- Task status notifications are placed in assignees' mailboxes as **informational context only**.");
|
|
6616
|
-
parts.push("- Do NOT send A2A messages to notify about task status changes \u2014 only send A2A when you have substantive coordination needs beyond the status change itself.");
|
|
6617
|
-
parts.push("");
|
|
6618
|
-
parts.push("**Communicating with humans**:");
|
|
6619
|
-
parts.push("- `notify_user` \u2014 proactive message to a human team member: status updates, progress reports, findings, alerts. Appears in chat timeline AND notification bell. The human can reply. Write comprehensive body with full context. **This is the ONLY way to reach humans from non-chat contexts** (heartbeat, autonomous tasks, etc.).");
|
|
6620
|
-
parts.push("- `request_user_approval` \u2014 when you need a human decision, approval, or input. BLOCKS until the user responds. Supports custom options and freeform text. Do NOT use for routine updates.");
|
|
6621
|
-
parts.push("- `recall_activity` \u2014 query your own past execution logs by task or activity type. Use when you need to review what you did previously (e.g., to answer a follow-up question).");
|
|
6622
|
-
parts.push("");
|
|
6623
|
-
parts.push("**Communicating with other agents**:");
|
|
6624
|
-
parts.push("- `agent_send_message` \u2014 send a direct message to a peer agent. Use for coordination, questions, sharing context, or instructions. The message enters their mailbox and they will process it.");
|
|
6625
|
-
parts.push("- For substantial work requests, create a `task_create` assigned to the target agent instead of asking via message.");
|
|
6626
|
-
parts.push("- Do NOT use A2A messages for routine task status notifications \u2014 the system handles those automatically.");
|
|
6627
6623
|
}
|
|
6628
|
-
if (opts.
|
|
6629
|
-
|
|
6624
|
+
if (opts.dynamicContext) {
|
|
6625
|
+
dynamic.push(opts.dynamicContext);
|
|
6626
|
+
}
|
|
6627
|
+
const alreadyShownIds = /* @__PURE__ */ new Set();
|
|
6628
|
+
const cpp = opts.cognitiveContext;
|
|
6629
|
+
if (cpp && !cpp.isEmpty) {
|
|
6630
|
+
if (cpp.cognitiveContext) {
|
|
6631
|
+
dynamic.push("\n## Cognitive Context");
|
|
6632
|
+
dynamic.push(cpp.cognitiveContext);
|
|
6633
|
+
}
|
|
6634
|
+
if (cpp.retrievedContext) {
|
|
6635
|
+
dynamic.push("\n## Retrieved Context");
|
|
6636
|
+
dynamic.push(cpp.retrievedContext);
|
|
6637
|
+
}
|
|
6638
|
+
if (cpp.reflection) {
|
|
6639
|
+
dynamic.push("\n## Reflection");
|
|
6640
|
+
dynamic.push(cpp.reflection);
|
|
6641
|
+
}
|
|
6642
|
+
} else if (!isDream) {
|
|
6643
|
+
const relevantMemories = await this.retrieveRelevantMemories(opts.memory, opts.currentQuery, opts.agentId, alreadyShownIds);
|
|
6644
|
+
if (relevantMemories.length > 0) {
|
|
6645
|
+
dynamic.push("\n## Relevant Memories");
|
|
6646
|
+
for (const mem of relevantMemories) {
|
|
6647
|
+
const ts = mem.timestamp ? new Date(mem.timestamp).toLocaleDateString() : "";
|
|
6648
|
+
dynamic.push(`- [${ts}] ${mem.content}`);
|
|
6649
|
+
}
|
|
6650
|
+
}
|
|
6651
|
+
}
|
|
6652
|
+
if (!isDream && opts.mailboxContext) {
|
|
6653
|
+
dynamic.push(this.buildMailboxSection(opts.mailboxContext));
|
|
6630
6654
|
}
|
|
6631
6655
|
if (!isDream && opts.senderIdentity) {
|
|
6632
|
-
|
|
6656
|
+
dynamic.push(`
|
|
6633
6657
|
## Current Conversation`);
|
|
6634
|
-
|
|
6658
|
+
dynamic.push(`You are now talking to **${opts.senderIdentity.name}** (${opts.senderIdentity.role}).`);
|
|
6659
|
+
if (opts.senderIdentity.isFirstConversation) {
|
|
6660
|
+
dynamic.push("**This is their first conversation** \u2014 they have never used Markus before. Follow your onboarding protocol if you have one.");
|
|
6661
|
+
}
|
|
6635
6662
|
if (opts.senderIdentity.role === "owner") {
|
|
6636
|
-
|
|
6663
|
+
dynamic.push("This person is the organization owner. Their instructions have the highest priority. Be proactive in reporting and responsive to their needs.");
|
|
6637
6664
|
} else if (opts.senderIdentity.role === "admin") {
|
|
6638
|
-
|
|
6665
|
+
dynamic.push("This person is an administrator. Cooperate actively and share progress proactively.");
|
|
6639
6666
|
} else if (opts.senderIdentity.role === "guest") {
|
|
6640
|
-
|
|
6667
|
+
dynamic.push("This person is an external guest. Be polite but cautious \u2014 do not expose internal sensitive information.");
|
|
6641
6668
|
}
|
|
6642
6669
|
}
|
|
6643
6670
|
if (!isDream) {
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6671
|
+
dynamic.push("\n## Tool Usage Rules");
|
|
6672
|
+
dynamic.push("**File editing discipline**: You MUST use `file_write` and `file_edit` for all file creation and modification. NEVER use `shell_execute` with `cat`, `echo`, `printf`, `tee`, pipes (`|`), output redirection (`>`, `>>`), heredocs (`<<`), or `sed`/`awk` to write or modify files \u2014 these bypass file access controls. `shell_execute` is for running commands (build, test, git, etc.), not for writing files.");
|
|
6673
|
+
dynamic.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.");
|
|
6674
|
+
dynamic.push("**Error handling**: If a tool call fails, analyze the error and try a different approach \u2014 do NOT repeat the same failing action.");
|
|
6675
|
+
dynamic.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.");
|
|
6676
|
+
dynamic.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.");
|
|
6677
|
+
dynamic.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.');
|
|
6651
6678
|
}
|
|
6652
|
-
if (!isDream && opts.mailboxContext) {
|
|
6653
|
-
parts.push(this.buildMailboxSection(opts.mailboxContext));
|
|
6654
|
-
}
|
|
6655
|
-
const scenario = opts.scenario ?? "chat";
|
|
6656
|
-
parts.push(this.buildScenarioSection(scenario, { a2aWaitForReply: opts.a2aWaitForReply }));
|
|
6657
6679
|
const now2 = /* @__PURE__ */ new Date();
|
|
6658
6680
|
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
6659
6681
|
const offset = now2.getTimezoneOffset();
|
|
@@ -6662,10 +6684,23 @@ var init_context_engine = __esm({
|
|
|
6662
6684
|
const absM = String(Math.abs(offset) % 60).padStart(2, "0");
|
|
6663
6685
|
const pad = (n) => String(n).padStart(2, "0");
|
|
6664
6686
|
const localStr = `${now2.getFullYear()}-${pad(now2.getMonth() + 1)}-${pad(now2.getDate())} ${pad(now2.getHours())}:${pad(now2.getMinutes())}:${pad(now2.getSeconds())}`;
|
|
6665
|
-
|
|
6687
|
+
dynamic.push(`
|
|
6666
6688
|
---
|
|
6667
6689
|
Current date and time: ${localStr} (${tz}, UTC${sign}${absH}:${absM})`);
|
|
6668
|
-
|
|
6690
|
+
const stableText = stable.join("\n");
|
|
6691
|
+
const semiStableText = semiStable.join("\n");
|
|
6692
|
+
const dynamicText = dynamic.join("\n");
|
|
6693
|
+
const segments = [];
|
|
6694
|
+
if (stableText)
|
|
6695
|
+
segments.push({ content: stableText, cacheBreakpoint: true });
|
|
6696
|
+
if (semiStableText)
|
|
6697
|
+
segments.push({ content: semiStableText, cacheBreakpoint: true });
|
|
6698
|
+
if (dynamicText)
|
|
6699
|
+
segments.push({ content: dynamicText });
|
|
6700
|
+
return {
|
|
6701
|
+
text: segments.map((s) => s.content).join("\n"),
|
|
6702
|
+
segments
|
|
6703
|
+
};
|
|
6669
6704
|
}
|
|
6670
6705
|
buildMailboxSection(ctx) {
|
|
6671
6706
|
const lines = ["\n## Your Attention State"];
|
|
@@ -6799,11 +6834,17 @@ ${ctx.mergedContent.slice(0, SYSTEM_MAILBOX_MERGED_CHARS)}`);
|
|
|
6799
6834
|
lines.push('- Give a generic acknowledgment like "Got it, will look into it" without substantive content');
|
|
6800
6835
|
lines.push("- Ignore prior comments that provide important context for the current discussion");
|
|
6801
6836
|
lines.push("");
|
|
6802
|
-
lines.push("**
|
|
6803
|
-
lines.push(
|
|
6804
|
-
lines.push("
|
|
6805
|
-
lines.push(
|
|
6806
|
-
lines.push("
|
|
6837
|
+
lines.push("**MANDATORY outcome \u2014 you MUST end with exactly one of these:**");
|
|
6838
|
+
lines.push("1. Call `task_comment` or `requirement_comment` tool to post your reply, OR");
|
|
6839
|
+
lines.push("2. Output `[NO_REPLY_NEEDED]` in your text to explicitly signal that no response is warranted.");
|
|
6840
|
+
lines.push("");
|
|
6841
|
+
lines.push("If you finish without doing either of the above, the system will automatically retry your turn \u2014 your text output alone is NEVER sufficient.");
|
|
6842
|
+
lines.push("");
|
|
6843
|
+
lines.push("**When to use `[NO_REPLY_NEEDED]` \u2014 do NOT reply when:**");
|
|
6844
|
+
lines.push('- The comment is just an acknowledgment ("Got it", "Will do", "Thanks", "Agreed")');
|
|
6845
|
+
lines.push("- Both parties have reached agreement or the discussion is resolved");
|
|
6846
|
+
lines.push('- Your reply would only be "Sounds good", "Agreed", or similar zero-information response');
|
|
6847
|
+
lines.push("- The comment does not ask a question, request action, or contain information you need to correct");
|
|
6807
6848
|
lines.push("- **Principle**: only comment when your reply adds **new information** or requests a **decision**. Avoid comment ping-pong.");
|
|
6808
6849
|
break;
|
|
6809
6850
|
case "review":
|
|
@@ -6917,8 +6958,7 @@ ${ctx.mergedContent.slice(0, SYSTEM_MAILBOX_MERGED_CHARS)}`);
|
|
|
6917
6958
|
lines.push("6. **Hiring & Team Building** \u2014 Two phases: CREATE then INSTALL (only when user requests).");
|
|
6918
6959
|
lines.push(" a) *Creating* (design the artifact): activate `agent-building` or `team-building` skill \u2192 write artifact files. Or `hub_search` to browse community packages.");
|
|
6919
6960
|
lines.push(" b) *Installing* (deploy into org \u2014 ONLY when user explicitly asks to install/deploy/hire):");
|
|
6920
|
-
lines.push(" -
|
|
6921
|
-
lines.push(" - Install artifact: `builder_install` (for custom-built or Hub-downloaded packages)");
|
|
6961
|
+
lines.push(" - `package_list` \u2192 `package_install` (type: agent/team/skill)");
|
|
6922
6962
|
lines.push(" - Hub one-step: `hub_install` (download + install)");
|
|
6923
6963
|
lines.push(" c) After install: onboard via `agent_send_message` (project context) \u2192 `task_create` (initial work)");
|
|
6924
6964
|
lines.push(" **IMPORTANT**: NEVER auto-install. Creating an artifact does NOT mean deploying it. Wait for explicit user request.");
|
|
@@ -7049,7 +7089,8 @@ ${ctx.mergedContent.slice(0, SYSTEM_MAILBOX_MERGED_CHARS)}`);
|
|
|
7049
7089
|
totalUsed,
|
|
7050
7090
|
available,
|
|
7051
7091
|
usagePercent: Math.round(usagePercent * 10) / 10
|
|
7052
|
-
}
|
|
7092
|
+
},
|
|
7093
|
+
systemCacheSegments: opts.systemCacheSegments
|
|
7053
7094
|
};
|
|
7054
7095
|
}
|
|
7055
7096
|
/**
|
|
@@ -8213,7 +8254,7 @@ var init_tool_selector = __esm({
|
|
|
8213
8254
|
"\u5206\u914D",
|
|
8214
8255
|
"\u8DEF\u7531"
|
|
8215
8256
|
],
|
|
8216
|
-
toolNames: ["team_list", "team_status", "delegate_message", "
|
|
8257
|
+
toolNames: ["team_list", "team_status", "delegate_message", "package_list", "package_install"]
|
|
8217
8258
|
},
|
|
8218
8259
|
{
|
|
8219
8260
|
name: "deliverables",
|
|
@@ -8243,6 +8284,21 @@ var init_tool_selector = __esm({
|
|
|
8243
8284
|
"\u7ECF\u9A8C"
|
|
8244
8285
|
],
|
|
8245
8286
|
toolNames: ["deliverable_create", "deliverable_search", "deliverable_list", "deliverable_update"]
|
|
8287
|
+
},
|
|
8288
|
+
{
|
|
8289
|
+
name: "builder",
|
|
8290
|
+
keywords: [
|
|
8291
|
+
"builder",
|
|
8292
|
+
"artifact",
|
|
8293
|
+
"deploy",
|
|
8294
|
+
"skill",
|
|
8295
|
+
"package",
|
|
8296
|
+
"hub",
|
|
8297
|
+
"\u90E8\u7F72",
|
|
8298
|
+
"\u5DE5\u4EF6",
|
|
8299
|
+
"\u6280\u80FD\u5305"
|
|
8300
|
+
],
|
|
8301
|
+
toolNames: ["builder_install", "builder_list"]
|
|
8246
8302
|
}
|
|
8247
8303
|
];
|
|
8248
8304
|
BASE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -41280,6 +41336,45 @@ async function searchBrave(query2, maxResults) {
|
|
|
41280
41336
|
date: r.page_age
|
|
41281
41337
|
}));
|
|
41282
41338
|
}
|
|
41339
|
+
async function searchBing(query2, maxResults) {
|
|
41340
|
+
const encoded = encodeURIComponent(query2);
|
|
41341
|
+
let res;
|
|
41342
|
+
try {
|
|
41343
|
+
res = await proxyFetch(`https://www.bing.com/search?q=${encoded}`, {
|
|
41344
|
+
headers: { "User-Agent": BING_UA }
|
|
41345
|
+
});
|
|
41346
|
+
} catch (err) {
|
|
41347
|
+
throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
41348
|
+
}
|
|
41349
|
+
if (!res.ok)
|
|
41350
|
+
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
41351
|
+
const html = await res.text();
|
|
41352
|
+
const results = parseBingHtml(html, maxResults);
|
|
41353
|
+
if (results.length === 0)
|
|
41354
|
+
throw new Error("Parsed 0 results from Bing");
|
|
41355
|
+
return results;
|
|
41356
|
+
}
|
|
41357
|
+
function parseBingHtml(html, max) {
|
|
41358
|
+
const results = [];
|
|
41359
|
+
const algoRegex = /<li[^>]*class="b_algo"[^>]*>([\s\S]*?)<\/li>/g;
|
|
41360
|
+
let match;
|
|
41361
|
+
while ((match = algoRegex.exec(html)) !== null) {
|
|
41362
|
+
if (results.length >= max)
|
|
41363
|
+
break;
|
|
41364
|
+
const item = match[1];
|
|
41365
|
+
const linkMatch = item.match(/<a[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/i);
|
|
41366
|
+
if (!linkMatch)
|
|
41367
|
+
continue;
|
|
41368
|
+
const url = linkMatch[1];
|
|
41369
|
+
const title = stripHtml(linkMatch[2]);
|
|
41370
|
+
if (!url || !title)
|
|
41371
|
+
continue;
|
|
41372
|
+
const snippetMatch = item.match(/<p[^>]*>([\s\S]*?)<\/p>/i);
|
|
41373
|
+
const snippet = snippetMatch ? stripHtml(snippetMatch[1]) : "";
|
|
41374
|
+
results.push({ title, url, snippet });
|
|
41375
|
+
}
|
|
41376
|
+
return results;
|
|
41377
|
+
}
|
|
41283
41378
|
async function searchDuckDuckGo(query2, maxResults) {
|
|
41284
41379
|
const encoded = encodeURIComponent(query2);
|
|
41285
41380
|
let lastError;
|
|
@@ -41368,7 +41463,7 @@ function parseDDGHtml(html, maxResults) {
|
|
|
41368
41463
|
function stripHtml(html) {
|
|
41369
41464
|
return html.replace(/<[^>]*>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'").replace(/ /g, " ").replace(/\s+/g, " ").trim();
|
|
41370
41465
|
}
|
|
41371
|
-
var SEARCH_TIMEOUT_MS, _dispatcher, WebSearchTool, DDG_UA, DDG_ENDPOINTS;
|
|
41466
|
+
var SEARCH_TIMEOUT_MS, _dispatcher, WebSearchTool, BING_UA, DDG_UA, DDG_ENDPOINTS;
|
|
41372
41467
|
var init_web_search = __esm({
|
|
41373
41468
|
"../core/dist/tools/web-search.js"() {
|
|
41374
41469
|
"use strict";
|
|
@@ -41397,6 +41492,7 @@ var init_web_search = __esm({
|
|
|
41397
41492
|
const backends = [
|
|
41398
41493
|
{ name: "Serper", fn: searchSerper },
|
|
41399
41494
|
{ name: "Brave", fn: searchBrave },
|
|
41495
|
+
{ name: "Bing", fn: searchBing },
|
|
41400
41496
|
{ name: "DuckDuckGo", fn: searchDuckDuckGo }
|
|
41401
41497
|
];
|
|
41402
41498
|
const errors = [];
|
|
@@ -41428,6 +41524,7 @@ var init_web_search = __esm({
|
|
|
41428
41524
|
});
|
|
41429
41525
|
}
|
|
41430
41526
|
};
|
|
41527
|
+
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";
|
|
41431
41528
|
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";
|
|
41432
41529
|
DDG_ENDPOINTS = [
|
|
41433
41530
|
"https://lite.duckduckgo.com/lite/",
|
|
@@ -45500,6 +45597,7 @@ ${notification.stdoutTail}`);
|
|
|
45500
45597
|
senderId,
|
|
45501
45598
|
senderName: senderInfo?.name,
|
|
45502
45599
|
senderRole: senderInfo?.role,
|
|
45600
|
+
isFirstConversation: senderInfo?.isFirstConversation,
|
|
45503
45601
|
responsePromise: { resolve: resolve20, reject }
|
|
45504
45602
|
}
|
|
45505
45603
|
});
|
|
@@ -45529,6 +45627,7 @@ ${notification.stdoutTail}`);
|
|
|
45529
45627
|
senderId,
|
|
45530
45628
|
senderName: senderInfo?.name,
|
|
45531
45629
|
senderRole: senderInfo?.role,
|
|
45630
|
+
isFirstConversation: senderInfo?.isFirstConversation,
|
|
45532
45631
|
responsePromise: { resolve: resolve20, reject }
|
|
45533
45632
|
}
|
|
45534
45633
|
});
|
|
@@ -45675,7 +45774,7 @@ ${notification.stdoutTail}`);
|
|
|
45675
45774
|
this.currentInteractingUserId = item.metadata.senderId;
|
|
45676
45775
|
}
|
|
45677
45776
|
const extra = item.payload.extra ?? {};
|
|
45678
|
-
const senderInfo = item.metadata?.senderName ? { name: item.metadata.senderName, role: item.metadata.senderRole ?? "user" } : void 0;
|
|
45777
|
+
const senderInfo = item.metadata?.senderName ? { name: item.metadata.senderName, role: item.metadata.senderRole ?? "user", isFirstConversation: item.metadata.isFirstConversation } : void 0;
|
|
45679
45778
|
const resolveResponse = (reply) => {
|
|
45680
45779
|
if (typeof item.metadata?.responsePromise?.resolve === "function") {
|
|
45681
45780
|
item.metadata.responsePromise.resolve(stripCompletionMarker(reply));
|
|
@@ -46410,6 +46509,9 @@ ${conversationText}`
|
|
|
46410
46509
|
setIdentityContext(ctx) {
|
|
46411
46510
|
this.identityContext = ctx;
|
|
46412
46511
|
}
|
|
46512
|
+
getTeamName() {
|
|
46513
|
+
return this.identityContext?.team?.name;
|
|
46514
|
+
}
|
|
46413
46515
|
addDynamicContextProvider(provider, key2) {
|
|
46414
46516
|
const providerKey = key2 ?? `provider_${this.dynamicContextProviders.size}`;
|
|
46415
46517
|
this.dynamicContextProviders.set(providerKey, provider);
|
|
@@ -46942,7 +47044,7 @@ ${block}
|
|
|
46942
47044
|
await counter.ensureReady();
|
|
46943
47045
|
}
|
|
46944
47046
|
const cognitiveContext = await this.prepareCognitiveContext(scenario, effectiveMessage, senderId);
|
|
46945
|
-
const systemPrompt = await this.contextEngine.buildSystemPrompt({
|
|
47047
|
+
const { text: systemPrompt, segments: systemCacheSegments } = await this.contextEngine.buildSystemPrompt({
|
|
46946
47048
|
agentId: this.id,
|
|
46947
47049
|
agentName: this.config.name,
|
|
46948
47050
|
role: this.role,
|
|
@@ -46985,7 +47087,8 @@ ${block}
|
|
|
46985
47087
|
agentId: this.id,
|
|
46986
47088
|
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
46987
47089
|
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
46988
|
-
toolDefinitions: llmTools
|
|
47090
|
+
toolDefinitions: llmTools,
|
|
47091
|
+
systemCacheSegments
|
|
46989
47092
|
});
|
|
46990
47093
|
const messages = prepared.messages;
|
|
46991
47094
|
log17.debug("Context usage for chat", { usagePercent: prepared.usage.usagePercent, totalUsed: prepared.usage.totalUsed });
|
|
@@ -46998,7 +47101,8 @@ ${block}
|
|
|
46998
47101
|
messages,
|
|
46999
47102
|
tools: llmTools.length > 0 ? llmTools : void 0,
|
|
47000
47103
|
metadata: this.getLLMMetadata(sessionId),
|
|
47001
|
-
compaction: useCompaction
|
|
47104
|
+
compaction: useCompaction,
|
|
47105
|
+
systemCacheSegments
|
|
47002
47106
|
}, this.getEffectiveProvider()), "Chat LLM call");
|
|
47003
47107
|
const tokensThisCall = response.usage.inputTokens + response.usage.outputTokens;
|
|
47004
47108
|
this.updateTokensUsed(tokensThisCall);
|
|
@@ -47012,6 +47116,7 @@ ${block}
|
|
|
47012
47116
|
});
|
|
47013
47117
|
let toolIterations = 0;
|
|
47014
47118
|
const effectiveMaxIter = options?.maxToolIterations ?? this._maxToolIterations;
|
|
47119
|
+
const commentToolUsed = /* @__PURE__ */ new Set();
|
|
47015
47120
|
while (response.finishReason === "tool_use" && response.toolCalls?.length || response.finishReason === "max_tokens") {
|
|
47016
47121
|
if (++toolIterations > effectiveMaxIter) {
|
|
47017
47122
|
log17.warn("Tool loop hit max iterations", {
|
|
@@ -47109,6 +47214,9 @@ ${block}
|
|
|
47109
47214
|
for (let i = 0; i < response.toolCalls.length; i++) {
|
|
47110
47215
|
const tc = response.toolCalls[i];
|
|
47111
47216
|
this.loopDetector.record(tc.name, tc.arguments ?? {}, toolResults[i]?.content ?? "");
|
|
47217
|
+
if (tc.name === "task_comment" || tc.name === "requirement_comment") {
|
|
47218
|
+
commentToolUsed.add(tc.name);
|
|
47219
|
+
}
|
|
47112
47220
|
}
|
|
47113
47221
|
const loopCheck = this.loopDetector.check();
|
|
47114
47222
|
if (loopCheck.detected) {
|
|
@@ -47158,7 +47266,8 @@ ${chatYield.item.payload.content}`;
|
|
|
47158
47266
|
agentId: this.id,
|
|
47159
47267
|
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
47160
47268
|
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
47161
|
-
toolDefinitions: llmTools
|
|
47269
|
+
toolDefinitions: llmTools,
|
|
47270
|
+
systemCacheSegments
|
|
47162
47271
|
});
|
|
47163
47272
|
const updatedMessages = prepared2.messages;
|
|
47164
47273
|
const llmStart2 = Date.now();
|
|
@@ -47166,7 +47275,8 @@ ${chatYield.item.payload.content}`;
|
|
|
47166
47275
|
messages: updatedMessages,
|
|
47167
47276
|
tools: llmTools.length > 0 ? llmTools : void 0,
|
|
47168
47277
|
metadata: this.getLLMMetadata(sessionId),
|
|
47169
|
-
compaction: useCompaction
|
|
47278
|
+
compaction: useCompaction,
|
|
47279
|
+
systemCacheSegments
|
|
47170
47280
|
}, this.getEffectiveProvider()), "Chat LLM continuation");
|
|
47171
47281
|
const tokens2 = response.usage.inputTokens + response.usage.outputTokens;
|
|
47172
47282
|
this.updateTokensUsed(tokens2);
|
|
@@ -47179,6 +47289,93 @@ ${chatYield.item.payload.content}`;
|
|
|
47179
47289
|
success: true
|
|
47180
47290
|
});
|
|
47181
47291
|
}
|
|
47292
|
+
const hasNoReplyMarker = /\[NO_REPLY_NEEDED\]/i.test(response.content ?? "");
|
|
47293
|
+
if (scenario === "comment_response" && commentToolUsed.size === 0 && !hasNoReplyMarker && toolIterations < effectiveMaxIter) {
|
|
47294
|
+
this.memory.appendMessage(sessionId, {
|
|
47295
|
+
role: "assistant",
|
|
47296
|
+
content: response.content,
|
|
47297
|
+
toolCalls: response.toolCalls,
|
|
47298
|
+
reasoningContent: response.reasoningContent
|
|
47299
|
+
});
|
|
47300
|
+
this.memory.appendMessage(sessionId, {
|
|
47301
|
+
role: "user",
|
|
47302
|
+
content: "[SYSTEM] You are about to end your turn WITHOUT posting a reply and WITHOUT marking [NO_REPLY_NEEDED]. In this scenario your text output is NOT visible to anyone. You MUST either: (1) call `task_comment` or `requirement_comment` tool to post your reply in the comment thread, OR (2) output exactly [NO_REPLY_NEEDED] if you have determined that no response is warranted. Do it now."
|
|
47303
|
+
});
|
|
47304
|
+
const reminderMessages = this.memory.getRecentMessages(sessionId, maxHistory);
|
|
47305
|
+
const preparedReminder = await this.contextEngine.prepareMessages({
|
|
47306
|
+
systemPrompt,
|
|
47307
|
+
sessionMessages: reminderMessages,
|
|
47308
|
+
memory: this.memory,
|
|
47309
|
+
sessionId,
|
|
47310
|
+
agentId: this.id,
|
|
47311
|
+
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
47312
|
+
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
47313
|
+
toolDefinitions: llmTools,
|
|
47314
|
+
systemCacheSegments
|
|
47315
|
+
});
|
|
47316
|
+
response = await this.withNetworkRetry(() => this.llmRouter.chat({
|
|
47317
|
+
messages: preparedReminder.messages,
|
|
47318
|
+
tools: llmTools.length > 0 ? llmTools : void 0,
|
|
47319
|
+
metadata: this.getLLMMetadata(sessionId),
|
|
47320
|
+
compaction: useCompaction,
|
|
47321
|
+
systemCacheSegments
|
|
47322
|
+
}, this.getEffectiveProvider()), "Chat LLM comment-reminder");
|
|
47323
|
+
if (response.finishReason === "tool_use" && response.toolCalls?.length) {
|
|
47324
|
+
const currentActId = this.state.currentActivity?.id;
|
|
47325
|
+
this.memory.appendMessage(sessionId, {
|
|
47326
|
+
role: "assistant",
|
|
47327
|
+
content: response.content,
|
|
47328
|
+
toolCalls: response.toolCalls,
|
|
47329
|
+
reasoningContent: response.reasoningContent
|
|
47330
|
+
});
|
|
47331
|
+
const toolResults = await Promise.all(response.toolCalls.map(async (tc) => {
|
|
47332
|
+
const toolStart = Date.now();
|
|
47333
|
+
if (currentActId) {
|
|
47334
|
+
this.emitActivityLog(currentActId, "tool_start", tc.name, { arguments: tc.arguments });
|
|
47335
|
+
}
|
|
47336
|
+
try {
|
|
47337
|
+
let result = await this.executeTool(tc, void 0, sessionId);
|
|
47338
|
+
result = this.offloadLargeResult(tc.name, result);
|
|
47339
|
+
if (currentActId) {
|
|
47340
|
+
this.emitActivityLog(currentActId, "tool_end", tc.name, {
|
|
47341
|
+
durationMs: Date.now() - toolStart,
|
|
47342
|
+
success: !isErrorResult2(result),
|
|
47343
|
+
arguments: tc.arguments,
|
|
47344
|
+
result
|
|
47345
|
+
});
|
|
47346
|
+
}
|
|
47347
|
+
return { toolCallId: tc.id, content: result, error: false };
|
|
47348
|
+
} catch (toolErr) {
|
|
47349
|
+
if (currentActId) {
|
|
47350
|
+
this.emitActivityLog(currentActId, "error", `Tool ${tc.name} failed: ${String(toolErr)}`);
|
|
47351
|
+
}
|
|
47352
|
+
return { toolCallId: tc.id, content: `Error: ${String(toolErr)}`, error: true };
|
|
47353
|
+
}
|
|
47354
|
+
}));
|
|
47355
|
+
for (const tr of toolResults) {
|
|
47356
|
+
this.memory.appendMessage(sessionId, { role: "tool", content: tr.content, toolCallId: tr.toolCallId });
|
|
47357
|
+
}
|
|
47358
|
+
const finalMessages = this.memory.getRecentMessages(sessionId, maxHistory);
|
|
47359
|
+
const preparedFinal = await this.contextEngine.prepareMessages({
|
|
47360
|
+
systemPrompt,
|
|
47361
|
+
sessionMessages: finalMessages,
|
|
47362
|
+
memory: this.memory,
|
|
47363
|
+
sessionId,
|
|
47364
|
+
agentId: this.id,
|
|
47365
|
+
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
47366
|
+
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
47367
|
+
toolDefinitions: llmTools,
|
|
47368
|
+
systemCacheSegments
|
|
47369
|
+
});
|
|
47370
|
+
response = await this.withNetworkRetry(() => this.llmRouter.chat({
|
|
47371
|
+
messages: preparedFinal.messages,
|
|
47372
|
+
tools: llmTools.length > 0 ? llmTools : void 0,
|
|
47373
|
+
metadata: this.getLLMMetadata(sessionId),
|
|
47374
|
+
compaction: useCompaction,
|
|
47375
|
+
systemCacheSegments
|
|
47376
|
+
}, this.getEffectiveProvider()), "Chat LLM comment-reminder-final");
|
|
47377
|
+
}
|
|
47378
|
+
}
|
|
47182
47379
|
const rawReply = sanitizeLLMReply(response.content);
|
|
47183
47380
|
const displayReply = stripCompletionMarker(rawReply);
|
|
47184
47381
|
const outputCheck = await this.guardrails.checkOutput(displayReply, { agentId: this.id });
|
|
@@ -47264,7 +47461,7 @@ ${chatYield.item.payload.content}`;
|
|
|
47264
47461
|
const userContent = await this.buildUserContent(userMessage, images, fileNames);
|
|
47265
47462
|
this.memory.appendMessage(this.currentSessionId, { role: "user", content: userContent });
|
|
47266
47463
|
const cognitiveContext = await this.prepareCognitiveContext("chat", effectiveMessage, senderId);
|
|
47267
|
-
const systemPrompt = await this.contextEngine.buildSystemPrompt({
|
|
47464
|
+
const { text: systemPrompt, segments: systemCacheSegments } = await this.contextEngine.buildSystemPrompt({
|
|
47268
47465
|
agentId: this.id,
|
|
47269
47466
|
agentName: this.config.name,
|
|
47270
47467
|
role: this.role,
|
|
@@ -47300,7 +47497,8 @@ ${chatYield.item.payload.content}`;
|
|
|
47300
47497
|
agentId: this.id,
|
|
47301
47498
|
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
47302
47499
|
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
47303
|
-
toolDefinitions: llmTools
|
|
47500
|
+
toolDefinitions: llmTools,
|
|
47501
|
+
systemCacheSegments
|
|
47304
47502
|
});
|
|
47305
47503
|
const messages = preparedStream.messages;
|
|
47306
47504
|
log17.debug("Context usage for stream", { usagePercent: preparedStream.usage.usagePercent });
|
|
@@ -47336,7 +47534,7 @@ ${chatYield.item.payload.content}`;
|
|
|
47336
47534
|
try {
|
|
47337
47535
|
this.checkDailyTokenBudget();
|
|
47338
47536
|
const llmStart = Date.now();
|
|
47339
|
-
let response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(this.currentSessionId), compaction: useCompaction }, wrappedOnEvent, this.getEffectiveProvider(), abortController.signal), "Stream LLM call", abortController.signal);
|
|
47537
|
+
let response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(this.currentSessionId), compaction: useCompaction, systemCacheSegments }, wrappedOnEvent, this.getEffectiveProvider(), abortController.signal), "Stream LLM call", abortController.signal);
|
|
47340
47538
|
streamMarkerDelta.flush();
|
|
47341
47539
|
const tokensThisCall = response.usage.inputTokens + response.usage.outputTokens;
|
|
47342
47540
|
this.updateTokensUsed(tokensThisCall);
|
|
@@ -47494,7 +47692,8 @@ ${streamYield.item.payload.content}`;
|
|
|
47494
47692
|
agentId: this.id,
|
|
47495
47693
|
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
47496
47694
|
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
47497
|
-
toolDefinitions: llmTools
|
|
47695
|
+
toolDefinitions: llmTools,
|
|
47696
|
+
systemCacheSegments
|
|
47498
47697
|
});
|
|
47499
47698
|
const updatedMessages = preparedCont.messages;
|
|
47500
47699
|
if (cancelToken?.cancelled) {
|
|
@@ -47513,7 +47712,7 @@ ${streamYield.item.payload.content}`;
|
|
|
47513
47712
|
return lastResponseContent || "";
|
|
47514
47713
|
}
|
|
47515
47714
|
const llmStart2 = Date.now();
|
|
47516
|
-
response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages: updatedMessages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(this.currentSessionId), compaction: useCompaction }, wrappedOnEvent, this.getEffectiveProvider(), abortController.signal), "Stream LLM continuation", abortController.signal);
|
|
47715
|
+
response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages: updatedMessages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(this.currentSessionId), compaction: useCompaction, systemCacheSegments }, wrappedOnEvent, this.getEffectiveProvider(), abortController.signal), "Stream LLM continuation", abortController.signal);
|
|
47517
47716
|
streamMarkerDelta.flush();
|
|
47518
47717
|
const tokens2 = response.usage.inputTokens + response.usage.outputTokens;
|
|
47519
47718
|
this.updateTokensUsed(tokens2);
|
|
@@ -47751,7 +47950,7 @@ ${streamYield.item.payload.content}`;
|
|
|
47751
47950
|
this.memory.appendMessage(sessionId, { role: "user", content: taskPrompt });
|
|
47752
47951
|
}
|
|
47753
47952
|
const cognitiveContext = await this.prepareCognitiveContext("task_execution", taskPrompt);
|
|
47754
|
-
const systemPrompt = await this.contextEngine.buildSystemPrompt({
|
|
47953
|
+
const { text: systemPrompt, segments: systemCacheSegments } = await this.contextEngine.buildSystemPrompt({
|
|
47755
47954
|
agentId: this.id,
|
|
47756
47955
|
agentName: this.config.name,
|
|
47757
47956
|
role: this.role,
|
|
@@ -47818,12 +48017,13 @@ ${streamYield.item.payload.content}`;
|
|
|
47818
48017
|
agentId: this.id,
|
|
47819
48018
|
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
47820
48019
|
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
47821
|
-
toolDefinitions: llmTools
|
|
48020
|
+
toolDefinitions: llmTools,
|
|
48021
|
+
systemCacheSegments
|
|
47822
48022
|
});
|
|
47823
48023
|
const messages = preparedTask.messages;
|
|
47824
48024
|
log17.debug("Context usage for task execution", { taskId: taskId2, usagePercent: preparedTask.usage.usagePercent, totalUsed: preparedTask.usage.totalUsed });
|
|
47825
48025
|
let taskLlmStart = Date.now();
|
|
47826
|
-
let response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(sessionId), compaction: useCompaction }, handleStreamEvent, this.getEffectiveProvider(), abortController.signal), "Task execution LLM call", abortController.signal);
|
|
48026
|
+
let response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(sessionId), compaction: useCompaction, systemCacheSegments }, handleStreamEvent, this.getEffectiveProvider(), abortController.signal), "Task execution LLM call", abortController.signal);
|
|
47827
48027
|
let taskLlmTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
47828
48028
|
this.updateTokensUsed(taskLlmTokens);
|
|
47829
48029
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
@@ -48005,14 +48205,16 @@ ${yieldResult.item.payload.content}`
|
|
|
48005
48205
|
agentId: this.id,
|
|
48006
48206
|
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
48007
48207
|
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
48008
|
-
toolDefinitions: llmTools
|
|
48208
|
+
toolDefinitions: llmTools,
|
|
48209
|
+
systemCacheSegments
|
|
48009
48210
|
});
|
|
48010
48211
|
taskLlmStart = Date.now();
|
|
48011
48212
|
response = await this.withNetworkRetry(() => this.llmRouter.chatStream({
|
|
48012
48213
|
messages: preparedTaskCont.messages,
|
|
48013
48214
|
tools: llmTools.length > 0 ? llmTools : void 0,
|
|
48014
48215
|
metadata: this.getLLMMetadata(sessionId),
|
|
48015
|
-
compaction: useCompaction
|
|
48216
|
+
compaction: useCompaction,
|
|
48217
|
+
systemCacheSegments
|
|
48016
48218
|
}, handleStreamEvent, this.getEffectiveProvider(), abortController.signal), "Task execution LLM continuation", abortController.signal);
|
|
48017
48219
|
taskLlmTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
48018
48220
|
this.updateTokensUsed(taskLlmTokens);
|
|
@@ -48054,14 +48256,16 @@ ${yieldResult.item.payload.content}`
|
|
|
48054
48256
|
agentId: this.id,
|
|
48055
48257
|
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
48056
48258
|
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
48057
|
-
toolDefinitions: llmTools
|
|
48259
|
+
toolDefinitions: llmTools,
|
|
48260
|
+
systemCacheSegments
|
|
48058
48261
|
});
|
|
48059
48262
|
taskLlmStart = Date.now();
|
|
48060
48263
|
response = await this.withNetworkRetry(() => this.llmRouter.chatStream({
|
|
48061
48264
|
messages: preparedFinal.messages,
|
|
48062
48265
|
tools: llmTools.length > 0 ? llmTools : void 0,
|
|
48063
48266
|
metadata: this.getLLMMetadata(sessionId),
|
|
48064
|
-
compaction: useCompaction
|
|
48267
|
+
compaction: useCompaction,
|
|
48268
|
+
systemCacheSegments
|
|
48065
48269
|
}, handleStreamEvent, this.getEffectiveProvider(), abortController.signal), "Task execution final submit reminder", abortController.signal);
|
|
48066
48270
|
taskLlmTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
48067
48271
|
this.updateTokensUsed(taskLlmTokens);
|
|
@@ -48185,7 +48389,7 @@ ${yieldResult.item.payload.content}`
|
|
|
48185
48389
|
this.memory.getOrCreateSession(this.id, sessionId);
|
|
48186
48390
|
this.memory.appendMessage(sessionId, { role: "user", content: userMessage });
|
|
48187
48391
|
const cognitiveContext = await this.prepareCognitiveContext("chat", userMessage);
|
|
48188
|
-
const systemPrompt = await this.contextEngine.buildSystemPrompt({
|
|
48392
|
+
const { text: systemPrompt, segments: systemCacheSegments } = await this.contextEngine.buildSystemPrompt({
|
|
48189
48393
|
agentId: this.id,
|
|
48190
48394
|
agentName: this.config.name,
|
|
48191
48395
|
role: this.role,
|
|
@@ -48246,11 +48450,12 @@ ${yieldResult.item.payload.content}`
|
|
|
48246
48450
|
agentId: this.id,
|
|
48247
48451
|
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
48248
48452
|
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
48249
|
-
toolDefinitions: llmTools
|
|
48453
|
+
toolDefinitions: llmTools,
|
|
48454
|
+
systemCacheSegments
|
|
48250
48455
|
});
|
|
48251
48456
|
const messages = prepared.messages;
|
|
48252
48457
|
let risLlmStart = Date.now();
|
|
48253
|
-
let response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(sessionId), compaction: useCompaction }, handleStreamEvent, this.getEffectiveProvider()), "RespondInSession LLM call");
|
|
48458
|
+
let response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(sessionId), compaction: useCompaction, systemCacheSegments }, handleStreamEvent, this.getEffectiveProvider()), "RespondInSession LLM call");
|
|
48254
48459
|
let risTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
48255
48460
|
this.updateTokensUsed(risTokens);
|
|
48256
48461
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
@@ -48308,10 +48513,11 @@ ${yieldResult.item.payload.content}`
|
|
|
48308
48513
|
agentId: this.id,
|
|
48309
48514
|
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
48310
48515
|
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
48311
|
-
toolDefinitions: llmTools
|
|
48516
|
+
toolDefinitions: llmTools,
|
|
48517
|
+
systemCacheSegments
|
|
48312
48518
|
});
|
|
48313
48519
|
risLlmStart = Date.now();
|
|
48314
|
-
response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages: preparedCont.messages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(sessionId), compaction: useCompaction }, handleStreamEvent, this.getEffectiveProvider()), "RespondInSession LLM continuation");
|
|
48520
|
+
response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages: preparedCont.messages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(sessionId), compaction: useCompaction, systemCacheSegments }, handleStreamEvent, this.getEffectiveProvider()), "RespondInSession LLM continuation");
|
|
48315
48521
|
risTokens = response.usage.inputTokens + response.usage.outputTokens;
|
|
48316
48522
|
this.updateTokensUsed(risTokens);
|
|
48317
48523
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
@@ -48860,6 +49066,19 @@ ${escalationReason}`;
|
|
|
48860
49066
|
}
|
|
48861
49067
|
async handleHeartbeat(ctx) {
|
|
48862
49068
|
log17.info("Processing heartbeat check-in");
|
|
49069
|
+
const queuedNonHeartbeat = this.mailbox.getQueuedItems().filter((i) => i.sourceType !== "heartbeat" && i.status === "queued").length;
|
|
49070
|
+
const fingerprint = `q:${queuedNonHeartbeat}`;
|
|
49071
|
+
if (fingerprint === this.lastHeartbeatFingerprint && queuedNonHeartbeat === 0) {
|
|
49072
|
+
this.consecutiveIdleHeartbeats++;
|
|
49073
|
+
log17.info("Heartbeat: no changes detected, skipping LLM call", {
|
|
49074
|
+
consecutiveIdle: this.consecutiveIdleHeartbeats
|
|
49075
|
+
});
|
|
49076
|
+
this.state.lastHeartbeat = (/* @__PURE__ */ new Date()).toISOString();
|
|
49077
|
+
this.metricsCollector.recordHeartbeat(true);
|
|
49078
|
+
return;
|
|
49079
|
+
}
|
|
49080
|
+
this.lastHeartbeatFingerprint = fingerprint;
|
|
49081
|
+
this.consecutiveIdleHeartbeats = 0;
|
|
48863
49082
|
const activityId = this.startActivity("heartbeat", "Heartbeat check-in", {});
|
|
48864
49083
|
let lastHeartbeatSummary = "";
|
|
48865
49084
|
try {
|
|
@@ -48958,8 +49177,8 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
48958
49177
|
"- Common sections: `procedures`, `conventions`, `preferences`, `domain-knowledge`.",
|
|
48959
49178
|
"",
|
|
48960
49179
|
"**Shareable skills** (for team-wide practices):",
|
|
48961
|
-
'- Check existing skills first: `discover_tools({ mode: "list_skills" })` and `
|
|
48962
|
-
"- To update an existing skill: edit files in `~/.markus/builder-artifacts/skills/{name}/`, bump version, re-install with `
|
|
49180
|
+
'- Check existing skills first: `discover_tools({ mode: "list_skills" })` and `package_list`.',
|
|
49181
|
+
"- To update an existing skill: edit files in `~/.markus/builder-artifacts/skills/{name}/`, bump version, re-install with `package_install`.",
|
|
48963
49182
|
"",
|
|
48964
49183
|
"**Direct self-evolution** (simplest and most impactful):",
|
|
48965
49184
|
"- **Update ROLE.md** \u2014 When you discover a behavioral rule, working style, or guiding principle that should always apply, append it to your ROLE.md via `file_edit`. ROLE.md is loaded into every conversation, so changes take effect immediately. Read first, then append. No need to accumulate 3 insights \u2014 even a single validated lesson can warrant a role update if it is fundamental.",
|
|
@@ -48971,7 +49190,7 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
48971
49190
|
'| Single insight / gotcha | `memory_save` with tags: `["insight"]` |',
|
|
48972
49191
|
'| Tool tip or preference | `memory_save` with tags: `["insight", "tool:<name>"]` |',
|
|
48973
49192
|
'| Multi-step repeatable workflow | `memory_update_longterm({ section: "procedures", mode: "patch" })` |',
|
|
48974
|
-
"| Practice worth sharing with the team | Create skill via **skill-building**, then install with `
|
|
49193
|
+
"| Practice worth sharing with the team | Create skill via **skill-building**, then install with `package_install` |",
|
|
48975
49194
|
"| Behavioral rule or guiding principle | Update ROLE.md (`file_read` \u2192 `file_edit` to append) |",
|
|
48976
49195
|
"| New recurring check for your patrol | Update HEARTBEAT.md (`file_read` \u2192 `file_edit`) |",
|
|
48977
49196
|
"",
|
|
@@ -49077,10 +49296,12 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
49077
49296
|
"discover_tools",
|
|
49078
49297
|
"notify_user",
|
|
49079
49298
|
"request_user_approval",
|
|
49080
|
-
"recall_activity"
|
|
49299
|
+
"recall_activity",
|
|
49300
|
+
"builder_install",
|
|
49301
|
+
"builder_list"
|
|
49081
49302
|
];
|
|
49082
49303
|
if (isManager) {
|
|
49083
|
-
baseTools.push("task_board_health", "task_cleanup_duplicates", "task_assign", "team_status", "deliverable_create", "deliverable_search", "
|
|
49304
|
+
baseTools.push("task_board_health", "task_cleanup_duplicates", "task_assign", "team_status", "deliverable_create", "deliverable_search", "package_install", "package_list");
|
|
49084
49305
|
}
|
|
49085
49306
|
const HEARTBEAT_ALLOWED_TOOLS = new Set(baseTools);
|
|
49086
49307
|
const HEARTBEAT_MAX_RETRIES = 3;
|
|
@@ -49177,12 +49398,15 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
49177
49398
|
* 2. Memory dream: prune, deduplicate, merge (once per day)
|
|
49178
49399
|
*/
|
|
49179
49400
|
lastDreamDate = "";
|
|
49401
|
+
lastHeartbeatFingerprint = "";
|
|
49402
|
+
consecutiveIdleHeartbeats = 0;
|
|
49180
49403
|
async consolidateMemory() {
|
|
49181
49404
|
try {
|
|
49182
49405
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
49183
49406
|
const entries2 = this.memory.getEntries();
|
|
49184
|
-
|
|
49185
|
-
|
|
49407
|
+
const dreamKey = entries2.length > 500 ? `${today}_${Math.floor(Date.now() / (6 * 36e5))}` : today;
|
|
49408
|
+
if (entries2.length >= 50 && this.lastDreamDate !== dreamKey) {
|
|
49409
|
+
this.lastDreamDate = dreamKey;
|
|
49186
49410
|
await this.dreamConsolidateMemory(entries2);
|
|
49187
49411
|
this.pruneMemoryMd();
|
|
49188
49412
|
}
|
|
@@ -49196,7 +49420,7 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
49196
49420
|
* outdated items, and merge opportunities. Apply changes programmatically.
|
|
49197
49421
|
*/
|
|
49198
49422
|
async dreamConsolidateMemory(entries2) {
|
|
49199
|
-
const MAX_ENTRIES_FOR_LLM =
|
|
49423
|
+
const MAX_ENTRIES_FOR_LLM = 500;
|
|
49200
49424
|
const truncated = entries2.length > MAX_ENTRIES_FOR_LLM;
|
|
49201
49425
|
const batch = truncated ? entries2.slice(-MAX_ENTRIES_FOR_LLM) : entries2;
|
|
49202
49426
|
const entryList = batch.map((e, i) => {
|
|
@@ -49267,8 +49491,8 @@ ${knowledgePreview}
|
|
|
49267
49491
|
return;
|
|
49268
49492
|
}
|
|
49269
49493
|
const rawPlan = JSON.parse(jsonMatch[0]);
|
|
49270
|
-
const MAX_REMOVE_PER_CYCLE =
|
|
49271
|
-
const MAX_MERGE_PER_CYCLE =
|
|
49494
|
+
const MAX_REMOVE_PER_CYCLE = 50;
|
|
49495
|
+
const MAX_MERGE_PER_CYCLE = 20;
|
|
49272
49496
|
const entryIds = new Set(batch.map((e) => e.id));
|
|
49273
49497
|
const plan = {
|
|
49274
49498
|
remove: (rawPlan.remove ?? []).filter((id) => entryIds.has(id)).slice(0, MAX_REMOVE_PER_CYCLE),
|
|
@@ -49389,6 +49613,52 @@ ${promo.content}` : promo.content;
|
|
|
49389
49613
|
if (!inDailyReport)
|
|
49390
49614
|
afterSectionPrune.push(line);
|
|
49391
49615
|
}
|
|
49616
|
+
const sections = [];
|
|
49617
|
+
let currentHeading = "";
|
|
49618
|
+
let currentBody = [];
|
|
49619
|
+
let sectionStart = 0;
|
|
49620
|
+
for (let i = 0; i <= afterSectionPrune.length; i++) {
|
|
49621
|
+
const line = i < afterSectionPrune.length ? afterSectionPrune[i] : void 0;
|
|
49622
|
+
const isHeading = line !== void 0 && /^#{1,3}\s/.test(line);
|
|
49623
|
+
if (isHeading || line === void 0) {
|
|
49624
|
+
if (currentHeading || currentBody.length > 0) {
|
|
49625
|
+
sections.push({
|
|
49626
|
+
heading: currentHeading,
|
|
49627
|
+
body: currentBody.join("\n").trim(),
|
|
49628
|
+
startIdx: sectionStart
|
|
49629
|
+
});
|
|
49630
|
+
}
|
|
49631
|
+
currentHeading = line ?? "";
|
|
49632
|
+
currentBody = [];
|
|
49633
|
+
sectionStart = i;
|
|
49634
|
+
} else {
|
|
49635
|
+
currentBody.push(line);
|
|
49636
|
+
}
|
|
49637
|
+
}
|
|
49638
|
+
const headingLastIdx = /* @__PURE__ */ new Map();
|
|
49639
|
+
const normalizeHeading = (h) => h.replace(/^#+\s*/, "").trim().toLowerCase();
|
|
49640
|
+
for (let i = 0; i < sections.length; i++) {
|
|
49641
|
+
const key2 = normalizeHeading(sections[i].heading);
|
|
49642
|
+
if (key2)
|
|
49643
|
+
headingLastIdx.set(key2, i);
|
|
49644
|
+
}
|
|
49645
|
+
const deduped = [];
|
|
49646
|
+
for (let i = 0; i < sections.length; i++) {
|
|
49647
|
+
const s = sections[i];
|
|
49648
|
+
const key2 = normalizeHeading(s.heading);
|
|
49649
|
+
if (key2 && headingLastIdx.get(key2) !== i && headingLastIdx.has(key2)) {
|
|
49650
|
+
continue;
|
|
49651
|
+
}
|
|
49652
|
+
deduped.push(s);
|
|
49653
|
+
}
|
|
49654
|
+
afterSectionPrune.length = 0;
|
|
49655
|
+
for (const s of deduped) {
|
|
49656
|
+
if (s.heading)
|
|
49657
|
+
afterSectionPrune.push(s.heading);
|
|
49658
|
+
if (s.body)
|
|
49659
|
+
afterSectionPrune.push(s.body);
|
|
49660
|
+
afterSectionPrune.push("");
|
|
49661
|
+
}
|
|
49392
49662
|
const outputLines = [];
|
|
49393
49663
|
let inThinkBlock = false;
|
|
49394
49664
|
for (const line of afterSectionPrune) {
|
|
@@ -50181,6 +50451,73 @@ var init_browser_session = __esm({
|
|
|
50181
50451
|
});
|
|
50182
50452
|
|
|
50183
50453
|
// ../core/dist/tools/manager.js
|
|
50454
|
+
function createBuilderTools(ctx) {
|
|
50455
|
+
return [
|
|
50456
|
+
...ctx.listArtifacts ? [
|
|
50457
|
+
{
|
|
50458
|
+
name: "builder_list",
|
|
50459
|
+
description: "List builder artifacts (custom-created or Hub-downloaded agent/team/skill packages). These can be installed with builder_install.",
|
|
50460
|
+
inputSchema: {
|
|
50461
|
+
type: "object",
|
|
50462
|
+
properties: {
|
|
50463
|
+
type: {
|
|
50464
|
+
type: "string",
|
|
50465
|
+
enum: ["agent", "team", "skill"],
|
|
50466
|
+
description: "Filter by artifact type (optional)"
|
|
50467
|
+
}
|
|
50468
|
+
}
|
|
50469
|
+
},
|
|
50470
|
+
async execute(args) {
|
|
50471
|
+
try {
|
|
50472
|
+
const artifacts = ctx.listArtifacts(args["type"]);
|
|
50473
|
+
return JSON.stringify({ artifacts, count: artifacts.length });
|
|
50474
|
+
} catch (error) {
|
|
50475
|
+
return JSON.stringify({ status: "error", error: String(error) });
|
|
50476
|
+
}
|
|
50477
|
+
}
|
|
50478
|
+
}
|
|
50479
|
+
] : [],
|
|
50480
|
+
...ctx.installArtifact ? [
|
|
50481
|
+
{
|
|
50482
|
+
name: "builder_install",
|
|
50483
|
+
description: "Install a builder artifact \u2014 deploys an agent, team, or skill package into the live organization. For agents/teams: after installation, onboard with project context and assign initial tasks.",
|
|
50484
|
+
inputSchema: {
|
|
50485
|
+
type: "object",
|
|
50486
|
+
properties: {
|
|
50487
|
+
type: {
|
|
50488
|
+
type: "string",
|
|
50489
|
+
enum: ["agent", "team", "skill"],
|
|
50490
|
+
description: "Artifact type"
|
|
50491
|
+
},
|
|
50492
|
+
name: { type: "string", description: "Artifact name (from builder_list)" }
|
|
50493
|
+
},
|
|
50494
|
+
required: ["type", "name"]
|
|
50495
|
+
},
|
|
50496
|
+
async execute(args) {
|
|
50497
|
+
try {
|
|
50498
|
+
const type = args["type"]?.trim();
|
|
50499
|
+
const name = args["name"]?.trim();
|
|
50500
|
+
if (!type || !["agent", "team", "skill"].includes(type))
|
|
50501
|
+
return JSON.stringify({ status: "error", error: "type is required and must be one of: agent, team, skill" });
|
|
50502
|
+
if (!name)
|
|
50503
|
+
return JSON.stringify({ status: "error", error: "name is required \u2014 provide the artifact name from builder_list" });
|
|
50504
|
+
const result = await ctx.installArtifact(type, name);
|
|
50505
|
+
const isAgentOrTeam = result.type === "agent" || result.type === "team";
|
|
50506
|
+
return JSON.stringify({
|
|
50507
|
+
status: "success",
|
|
50508
|
+
...result,
|
|
50509
|
+
...isAgentOrTeam ? {
|
|
50510
|
+
next_steps: "Installed successfully. Next: onboard new agent(s) with project context via agent_send_message, then assign initial tasks via task_create."
|
|
50511
|
+
} : {}
|
|
50512
|
+
});
|
|
50513
|
+
} catch (error) {
|
|
50514
|
+
return JSON.stringify({ status: "error", error: String(error) });
|
|
50515
|
+
}
|
|
50516
|
+
}
|
|
50517
|
+
}
|
|
50518
|
+
] : []
|
|
50519
|
+
];
|
|
50520
|
+
}
|
|
50184
50521
|
function createManagerTools(ctx) {
|
|
50185
50522
|
return [
|
|
50186
50523
|
{
|
|
@@ -50299,79 +50636,34 @@ function createManagerTools(ctx) {
|
|
|
50299
50636
|
}
|
|
50300
50637
|
}
|
|
50301
50638
|
] : [],
|
|
50302
|
-
...ctx.listTemplates ? [
|
|
50303
|
-
{
|
|
50304
|
-
name: "team_list_templates",
|
|
50305
|
-
description: "List available agent templates that can be hired. Each template has a role, description, and category.",
|
|
50306
|
-
inputSchema: {
|
|
50307
|
-
type: "object",
|
|
50308
|
-
properties: {}
|
|
50309
|
-
},
|
|
50310
|
-
async execute() {
|
|
50311
|
-
try {
|
|
50312
|
-
const templates = ctx.listTemplates();
|
|
50313
|
-
return JSON.stringify({ templates, count: templates.length });
|
|
50314
|
-
} catch (error) {
|
|
50315
|
-
return JSON.stringify({ status: "error", error: String(error) });
|
|
50316
|
-
}
|
|
50317
|
-
}
|
|
50318
|
-
}
|
|
50319
|
-
] : [],
|
|
50320
|
-
...ctx.hireFromTemplate ? [
|
|
50321
|
-
{
|
|
50322
|
-
name: "team_hire_agent",
|
|
50323
|
-
description: "Hire a new agent from a template and add them to your team. After hiring, onboard the agent: send a welcome message with project context via agent_send_message, then assign initial tasks via task_create.",
|
|
50324
|
-
inputSchema: {
|
|
50325
|
-
type: "object",
|
|
50326
|
-
properties: {
|
|
50327
|
-
template_id: { type: "string", description: "Template ID (from team_list_templates)" },
|
|
50328
|
-
name: { type: "string", description: "Display name for the new agent" },
|
|
50329
|
-
skills: {
|
|
50330
|
-
type: "array",
|
|
50331
|
-
items: { type: "string" },
|
|
50332
|
-
description: "Optional skill IDs to assign"
|
|
50333
|
-
}
|
|
50334
|
-
},
|
|
50335
|
-
required: ["template_id", "name"]
|
|
50336
|
-
},
|
|
50337
|
-
async execute(args) {
|
|
50338
|
-
try {
|
|
50339
|
-
const templateId = args["template_id"]?.trim();
|
|
50340
|
-
const name = args["name"]?.trim();
|
|
50341
|
-
if (!templateId)
|
|
50342
|
-
return JSON.stringify({ status: "error", error: "template_id is required" });
|
|
50343
|
-
if (!name)
|
|
50344
|
-
return JSON.stringify({ status: "error", error: "name is required \u2014 please provide a display name for the new agent" });
|
|
50345
|
-
const result = await ctx.hireFromTemplate(templateId, name, args["skills"]);
|
|
50346
|
-
return JSON.stringify({
|
|
50347
|
-
status: "success",
|
|
50348
|
-
agent: result,
|
|
50349
|
-
next_steps: "Agent created and started. Next: onboard them with project context via agent_send_message, then assign initial tasks via task_create."
|
|
50350
|
-
});
|
|
50351
|
-
} catch (error) {
|
|
50352
|
-
return JSON.stringify({ status: "error", error: String(error) });
|
|
50353
|
-
}
|
|
50354
|
-
}
|
|
50355
|
-
}
|
|
50356
|
-
] : [],
|
|
50357
50639
|
...ctx.listArtifacts ? [
|
|
50358
50640
|
{
|
|
50359
|
-
name: "
|
|
50360
|
-
description:
|
|
50641
|
+
name: "package_list",
|
|
50642
|
+
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.',
|
|
50361
50643
|
inputSchema: {
|
|
50362
50644
|
type: "object",
|
|
50363
50645
|
properties: {
|
|
50364
50646
|
type: {
|
|
50365
50647
|
type: "string",
|
|
50366
50648
|
enum: ["agent", "team", "skill"],
|
|
50367
|
-
description: "Filter by
|
|
50649
|
+
description: "Filter by type (optional). Omit to list all."
|
|
50368
50650
|
}
|
|
50369
50651
|
}
|
|
50370
50652
|
},
|
|
50371
50653
|
async execute(args) {
|
|
50372
50654
|
try {
|
|
50373
|
-
const
|
|
50374
|
-
|
|
50655
|
+
const type = args["type"];
|
|
50656
|
+
const artifacts = ctx.listArtifacts(type);
|
|
50657
|
+
const roles = (!type || type === "agent") && ctx.listTemplates ? ctx.listTemplates() : [];
|
|
50658
|
+
const roleItems = roles.map((r) => ({
|
|
50659
|
+
type: "agent",
|
|
50660
|
+
source: "role",
|
|
50661
|
+
name: r.id ?? r.name,
|
|
50662
|
+
description: r.description ?? r.name,
|
|
50663
|
+
...r
|
|
50664
|
+
}));
|
|
50665
|
+
const items = [...roleItems, ...artifacts];
|
|
50666
|
+
return JSON.stringify({ items, count: items.length });
|
|
50375
50667
|
} catch (error) {
|
|
50376
50668
|
return JSON.stringify({ status: "error", error: String(error) });
|
|
50377
50669
|
}
|
|
@@ -50443,17 +50735,23 @@ function createManagerTools(ctx) {
|
|
|
50443
50735
|
] : [],
|
|
50444
50736
|
...ctx.installArtifact ? [
|
|
50445
50737
|
{
|
|
50446
|
-
name: "
|
|
50447
|
-
description:
|
|
50738
|
+
name: "package_install",
|
|
50739
|
+
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.',
|
|
50448
50740
|
inputSchema: {
|
|
50449
50741
|
type: "object",
|
|
50450
50742
|
properties: {
|
|
50451
50743
|
type: {
|
|
50452
50744
|
type: "string",
|
|
50453
50745
|
enum: ["agent", "team", "skill"],
|
|
50454
|
-
description: "
|
|
50746
|
+
description: "Package type"
|
|
50455
50747
|
},
|
|
50456
|
-
name: { type: "string", description: "
|
|
50748
|
+
name: { type: "string", description: "Package name (from package_list)" },
|
|
50749
|
+
agent_name: { type: "string", description: 'Display name for the new agent (required when installing from a built-in role, e.g. "developer")' },
|
|
50750
|
+
skills: {
|
|
50751
|
+
type: "array",
|
|
50752
|
+
items: { type: "string" },
|
|
50753
|
+
description: "Optional skill IDs to assign to the new agent"
|
|
50754
|
+
}
|
|
50457
50755
|
},
|
|
50458
50756
|
required: ["type", "name"]
|
|
50459
50757
|
},
|
|
@@ -50464,13 +50762,36 @@ function createManagerTools(ctx) {
|
|
|
50464
50762
|
if (!type || !["agent", "team", "skill"].includes(type))
|
|
50465
50763
|
return JSON.stringify({ status: "error", error: "type is required and must be one of: agent, team, skill" });
|
|
50466
50764
|
if (!name)
|
|
50467
|
-
return JSON.stringify({ status: "error", error: "name is required \u2014
|
|
50765
|
+
return JSON.stringify({ status: "error", error: "name is required \u2014 use package_list to see available packages" });
|
|
50766
|
+
if (type === "agent") {
|
|
50767
|
+
try {
|
|
50768
|
+
const result2 = await ctx.installArtifact(type, name);
|
|
50769
|
+
return JSON.stringify({
|
|
50770
|
+
status: "success",
|
|
50771
|
+
...result2,
|
|
50772
|
+
next_steps: "Installed successfully. Next: onboard new agent with project context via agent_send_message, then assign tasks via task_create."
|
|
50773
|
+
});
|
|
50774
|
+
} catch {
|
|
50775
|
+
if (ctx.hireFromTemplate) {
|
|
50776
|
+
const agentName = args["agent_name"]?.trim();
|
|
50777
|
+
if (!agentName)
|
|
50778
|
+
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" });
|
|
50779
|
+
const result2 = await ctx.hireFromTemplate(name, agentName, args["skills"]);
|
|
50780
|
+
return JSON.stringify({
|
|
50781
|
+
status: "success",
|
|
50782
|
+
type: "agent",
|
|
50783
|
+
agent: result2,
|
|
50784
|
+
next_steps: "Agent hired and started. Next: onboard with project context via agent_send_message, then assign tasks via task_create."
|
|
50785
|
+
});
|
|
50786
|
+
}
|
|
50787
|
+
throw new Error(`Agent package not found: ${name}. Use package_list to see available packages.`);
|
|
50788
|
+
}
|
|
50789
|
+
}
|
|
50468
50790
|
const result = await ctx.installArtifact(type, name);
|
|
50469
|
-
const isAgentOrTeam = result.type === "agent" || result.type === "team";
|
|
50470
50791
|
return JSON.stringify({
|
|
50471
50792
|
status: "success",
|
|
50472
50793
|
...result,
|
|
50473
|
-
...
|
|
50794
|
+
...type === "team" ? {
|
|
50474
50795
|
next_steps: "Installed successfully. Next: onboard new agent(s) with project context via agent_send_message, then assign initial tasks via task_create."
|
|
50475
50796
|
} : {}
|
|
50476
50797
|
});
|
|
@@ -50615,14 +50936,40 @@ function createA2ATools(ctx) {
|
|
|
50615
50936
|
},
|
|
50616
50937
|
{
|
|
50617
50938
|
name: "agent_list_colleagues",
|
|
50618
|
-
description: "List all other agents in your organization
|
|
50939
|
+
description: "List all other agents in your organization grouped by team. Shows team structure, roles, skills, and current status.",
|
|
50619
50940
|
inputSchema: {
|
|
50620
50941
|
type: "object",
|
|
50621
50942
|
properties: {}
|
|
50622
50943
|
},
|
|
50623
50944
|
async execute() {
|
|
50624
50945
|
const colleagues = ctx.listColleagues().filter((a) => a.id !== ctx.selfId);
|
|
50625
|
-
|
|
50946
|
+
const byTeam = /* @__PURE__ */ new Map();
|
|
50947
|
+
for (const c of colleagues) {
|
|
50948
|
+
const key2 = c.teamId ?? "__ungrouped__";
|
|
50949
|
+
if (!byTeam.has(key2))
|
|
50950
|
+
byTeam.set(key2, []);
|
|
50951
|
+
byTeam.get(key2).push(c);
|
|
50952
|
+
}
|
|
50953
|
+
const lines = [];
|
|
50954
|
+
lines.push(`Organization colleagues: ${colleagues.length} agents
|
|
50955
|
+
`);
|
|
50956
|
+
for (const [teamId, members] of byTeam) {
|
|
50957
|
+
const manager = members.find((m) => m.agentRole === "manager");
|
|
50958
|
+
const teamLabel = members[0]?.teamName ?? teamId;
|
|
50959
|
+
if (teamId === "__ungrouped__") {
|
|
50960
|
+
lines.push(`\u2500\u2500 Ungrouped \u2500\u2500`);
|
|
50961
|
+
} else {
|
|
50962
|
+
lines.push(`\u2500\u2500 Team: ${teamLabel}${manager ? ` (manager: ${manager.name})` : ""} \u2500\u2500`);
|
|
50963
|
+
}
|
|
50964
|
+
const sorted = [...members].sort((a, b) => a.agentRole === "manager" ? -1 : b.agentRole === "manager" ? 1 : 0);
|
|
50965
|
+
for (const m of sorted) {
|
|
50966
|
+
const badge = m.agentRole === "manager" ? " [Manager]" : "";
|
|
50967
|
+
const skills = m.skills?.length ? ` | skills: ${m.skills.join(", ")}` : "";
|
|
50968
|
+
lines.push(` \u2022 ${m.name} (${m.id})${badge} \u2014 ${m.role} | ${m.status}${skills}`);
|
|
50969
|
+
}
|
|
50970
|
+
lines.push("");
|
|
50971
|
+
}
|
|
50972
|
+
return lines.join("\n");
|
|
50626
50973
|
}
|
|
50627
50974
|
},
|
|
50628
50975
|
...ctx.sendGroupMessage ? [{
|
|
@@ -50710,7 +51057,7 @@ function createA2ATools(ctx) {
|
|
|
50710
51057
|
type: "string",
|
|
50711
51058
|
description: 'Required when scope="channel". The channel key (e.g., "group:<teamId>" for team chats, "dm:<id1>_<id2>" for DMs).'
|
|
50712
51059
|
},
|
|
50713
|
-
limit: { type: "number", description: "Number of items to fetch (default
|
|
51060
|
+
limit: { type: "number", description: "Number of items to fetch (default 80, max 200)." },
|
|
50714
51061
|
before: { type: "string", description: "ISO timestamp \u2014 fetch items older than this for pagination. Omit for most recent." }
|
|
50715
51062
|
},
|
|
50716
51063
|
required: ["scope"]
|
|
@@ -50722,11 +51069,11 @@ function createA2ATools(ctx) {
|
|
|
50722
51069
|
if (!channelKey) {
|
|
50723
51070
|
return JSON.stringify({ status: "error", error: 'channel_key is required when scope="channel"' });
|
|
50724
51071
|
}
|
|
50725
|
-
const limit = Math.min(args["limit"] ??
|
|
51072
|
+
const limit = Math.min(args["limit"] ?? 80, 200);
|
|
50726
51073
|
const before2 = args["before"];
|
|
50727
51074
|
try {
|
|
50728
51075
|
const result = await ctx.getChannelMessages(channelKey, limit, before2);
|
|
50729
|
-
const formatted = result.messages.map((m) => `[${m.createdAt}] ${m.senderType === "agent" ? `[agent] ${m.senderName}` : `[human] ${m.senderName}`}: ${m.text.slice(0,
|
|
51076
|
+
const formatted = result.messages.map((m) => `[${m.createdAt}] ${m.senderType === "agent" ? `[agent] ${m.senderName}` : `[human] ${m.senderName}`}: ${m.text.slice(0, 2e3)}`);
|
|
50730
51077
|
return JSON.stringify({
|
|
50731
51078
|
messages: formatted,
|
|
50732
51079
|
count: result.messages.length,
|
|
@@ -51182,6 +51529,15 @@ function createAgentTaskTools(ctx) {
|
|
|
51182
51529
|
items: { type: "string" },
|
|
51183
51530
|
description: "Update the list of task IDs that block this task. Only the task creator can modify this field. Pass an empty array to clear all blockers."
|
|
51184
51531
|
},
|
|
51532
|
+
reviewer_id: {
|
|
51533
|
+
type: "string",
|
|
51534
|
+
description: "New reviewer agent or human ID. Only the task creator or a manager can change the reviewer."
|
|
51535
|
+
},
|
|
51536
|
+
reviewer_type: {
|
|
51537
|
+
type: "string",
|
|
51538
|
+
enum: ["agent", "human"],
|
|
51539
|
+
description: "Whether the new reviewer is an agent or a human user. Required when changing reviewer_id."
|
|
51540
|
+
},
|
|
51185
51541
|
schedule: {
|
|
51186
51542
|
type: "object",
|
|
51187
51543
|
description: 'Update the schedule for a scheduled (recurring) task. Only works on tasks with taskType "scheduled". Set either "every" OR "cron", not both.',
|
|
@@ -51202,20 +51558,30 @@ function createAgentTaskTools(ctx) {
|
|
|
51202
51558
|
const note = args["note"];
|
|
51203
51559
|
const description = args["description"];
|
|
51204
51560
|
const blockedBy = args["blocked_by"];
|
|
51205
|
-
|
|
51561
|
+
const reviewerId = args["reviewer_id"];
|
|
51562
|
+
const reviewerType = args["reviewer_type"];
|
|
51563
|
+
if (blockedBy !== void 0 || reviewerId !== void 0) {
|
|
51206
51564
|
const existing = ctx.getTask ? await ctx.getTask(taskId2) : null;
|
|
51207
51565
|
const createdBy = existing?.["createdBy"];
|
|
51208
|
-
if (createdBy && createdBy !== ctx.agentId) {
|
|
51566
|
+
if (blockedBy !== void 0 && createdBy && createdBy !== ctx.agentId) {
|
|
51209
51567
|
return JSON.stringify({
|
|
51210
51568
|
status: "denied",
|
|
51211
51569
|
error: "Only the task creator can modify blocked_by. You are not the creator of this task."
|
|
51212
51570
|
});
|
|
51213
51571
|
}
|
|
51572
|
+
if (reviewerId !== void 0 && createdBy && createdBy !== ctx.agentId) {
|
|
51573
|
+
return JSON.stringify({
|
|
51574
|
+
status: "denied",
|
|
51575
|
+
error: "Only the task creator or a manager can change the reviewer."
|
|
51576
|
+
});
|
|
51577
|
+
}
|
|
51214
51578
|
}
|
|
51215
|
-
if ((description !== void 0 || blockedBy !== void 0) && ctx.updateTaskFields) {
|
|
51579
|
+
if ((description !== void 0 || blockedBy !== void 0 || reviewerId !== void 0) && ctx.updateTaskFields) {
|
|
51216
51580
|
await ctx.updateTaskFields(taskId2, {
|
|
51217
51581
|
...description !== void 0 ? { description } : {},
|
|
51218
|
-
...blockedBy !== void 0 ? { blockedBy } : {}
|
|
51582
|
+
...blockedBy !== void 0 ? { blockedBy } : {},
|
|
51583
|
+
...reviewerId !== void 0 ? { reviewerId } : {},
|
|
51584
|
+
...reviewerType !== void 0 ? { reviewerType } : {}
|
|
51219
51585
|
});
|
|
51220
51586
|
}
|
|
51221
51587
|
const schedule = args["schedule"];
|
|
@@ -51404,7 +51770,7 @@ function createAgentTaskTools(ctx) {
|
|
|
51404
51770
|
...ctx.addTaskNote ? [
|
|
51405
51771
|
{
|
|
51406
51772
|
name: "task_note",
|
|
51407
|
-
description: "Add a progress note
|
|
51773
|
+
description: "Add a one-way progress note to a task's timeline log without changing its status. Use this to record intermediate findings, decisions, or milestones. For interactive discussion with other agents or humans, use task_comment instead.",
|
|
51408
51774
|
inputSchema: {
|
|
51409
51775
|
type: "object",
|
|
51410
51776
|
properties: {
|
|
@@ -52642,6 +53008,48 @@ ${content}` : content;
|
|
|
52642
53008
|
log24.info("Agent updated long-term memory", { agentId: ctx.agentId, section: section4, mode, contentLen: content.length });
|
|
52643
53009
|
return JSON.stringify({ status: "updated", section: section4, mode });
|
|
52644
53010
|
}
|
|
53011
|
+
},
|
|
53012
|
+
{
|
|
53013
|
+
name: "memory_delete",
|
|
53014
|
+
description: "Delete specific entries from your memory buffer (memories.json). Use this to clean up outdated, incorrect, or redundant observations. Provide either a list of entry IDs (from memory_list/memory_search) or a tag to remove all entries with that tag. Maximum 20 entries per call.",
|
|
53015
|
+
inputSchema: {
|
|
53016
|
+
type: "object",
|
|
53017
|
+
properties: {
|
|
53018
|
+
ids: {
|
|
53019
|
+
type: "array",
|
|
53020
|
+
items: { type: "string" },
|
|
53021
|
+
description: "Array of memory entry IDs to delete. Use memory_list or memory_search to find IDs."
|
|
53022
|
+
},
|
|
53023
|
+
tag: {
|
|
53024
|
+
type: "string",
|
|
53025
|
+
description: "Delete all entries with this tag. Alternative to specifying individual IDs."
|
|
53026
|
+
}
|
|
53027
|
+
}
|
|
53028
|
+
},
|
|
53029
|
+
async execute(args) {
|
|
53030
|
+
const ids = args["ids"];
|
|
53031
|
+
const tag = args["tag"];
|
|
53032
|
+
if (!ids?.length && !tag) {
|
|
53033
|
+
return JSON.stringify({ status: "error", error: "Provide either ids or tag to delete." });
|
|
53034
|
+
}
|
|
53035
|
+
const MAX_DELETE = 20;
|
|
53036
|
+
let removed = 0;
|
|
53037
|
+
if (ids?.length) {
|
|
53038
|
+
const capped = ids.slice(0, MAX_DELETE);
|
|
53039
|
+
removed = ctx.memory.removeEntries(capped);
|
|
53040
|
+
if (ctx.semanticSearch?.isEnabled()) {
|
|
53041
|
+
for (const id of capped) {
|
|
53042
|
+
ctx.semanticSearch.deleteMemory(id).catch((err) => {
|
|
53043
|
+
log24.warn("Failed to remove memory from semantic index", { error: String(err) });
|
|
53044
|
+
});
|
|
53045
|
+
}
|
|
53046
|
+
}
|
|
53047
|
+
} else if (tag) {
|
|
53048
|
+
removed = ctx.memory.removeEntriesByTag(tag);
|
|
53049
|
+
}
|
|
53050
|
+
log24.info("Agent deleted memories", { agentId: ctx.agentId, removed, byTag: tag ?? null });
|
|
53051
|
+
return JSON.stringify({ status: "deleted", removed });
|
|
53052
|
+
}
|
|
52645
53053
|
}
|
|
52646
53054
|
];
|
|
52647
53055
|
}
|
|
@@ -54354,6 +54762,14 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
54354
54762
|
agent.registerTool(tool);
|
|
54355
54763
|
}
|
|
54356
54764
|
}
|
|
54765
|
+
if (this.builderService) {
|
|
54766
|
+
const builderTools = createBuilderTools({
|
|
54767
|
+
installArtifact: (type, name) => this.builderService.installArtifact(type, name),
|
|
54768
|
+
listArtifacts: (type) => this.builderService.listArtifacts(type)
|
|
54769
|
+
});
|
|
54770
|
+
for (const tool of builderTools)
|
|
54771
|
+
agent.registerTool(tool);
|
|
54772
|
+
}
|
|
54357
54773
|
const mcpConfigs = request.mcpServers ?? this.globalMcpServers;
|
|
54358
54774
|
if (mcpConfigs) {
|
|
54359
54775
|
for (const [serverName, serverConfig] of Object.entries(mcpConfigs)) {
|
|
@@ -54915,6 +55331,14 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
54915
55331
|
agent.registerTool(tool);
|
|
54916
55332
|
}
|
|
54917
55333
|
}
|
|
55334
|
+
if (this.builderService) {
|
|
55335
|
+
const builderTools = createBuilderTools({
|
|
55336
|
+
installArtifact: (type, name) => this.builderService.installArtifact(type, name),
|
|
55337
|
+
listArtifacts: (type) => this.builderService.listArtifacts(type)
|
|
55338
|
+
});
|
|
55339
|
+
for (const tool of builderTools)
|
|
55340
|
+
agent.registerTool(tool);
|
|
55341
|
+
}
|
|
54918
55342
|
if (this.agentAuditCallback) {
|
|
54919
55343
|
const cb = this.agentAuditCallback;
|
|
54920
55344
|
agent.setAuditCallback((event) => cb(id, event));
|
|
@@ -55141,6 +55565,7 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
55141
55565
|
skills: a.config.skills,
|
|
55142
55566
|
activeTaskCount: state.activeTaskCount ?? 0,
|
|
55143
55567
|
teamId: a.config.teamId,
|
|
55568
|
+
teamName: a.getTeamName(),
|
|
55144
55569
|
lastError: state.lastError,
|
|
55145
55570
|
lastErrorAt: state.lastErrorAt,
|
|
55146
55571
|
currentTaskId: state.currentTaskId,
|
|
@@ -55562,8 +55987,9 @@ var init_anthropic = __esm({
|
|
|
55562
55987
|
max_tokens: request.maxTokens ?? this.maxTokens,
|
|
55563
55988
|
messages
|
|
55564
55989
|
};
|
|
55565
|
-
if (systemMsg)
|
|
55566
|
-
body["system"] = getTextContent(systemMsg.content);
|
|
55990
|
+
if (systemMsg) {
|
|
55991
|
+
body["system"] = this.buildSystemContent(getTextContent(systemMsg.content), request.systemCacheSegments);
|
|
55992
|
+
}
|
|
55567
55993
|
if (request.temperature !== void 0)
|
|
55568
55994
|
body["temperature"] = request.temperature;
|
|
55569
55995
|
if (request.stopSequences?.length)
|
|
@@ -55603,8 +56029,9 @@ var init_anthropic = __esm({
|
|
|
55603
56029
|
messages,
|
|
55604
56030
|
stream: true
|
|
55605
56031
|
};
|
|
55606
|
-
if (systemMsg)
|
|
55607
|
-
body["system"] = getTextContent(systemMsg.content);
|
|
56032
|
+
if (systemMsg) {
|
|
56033
|
+
body["system"] = this.buildSystemContent(getTextContent(systemMsg.content), request.systemCacheSegments);
|
|
56034
|
+
}
|
|
55608
56035
|
if (request.temperature !== void 0)
|
|
55609
56036
|
body["temperature"] = request.temperature;
|
|
55610
56037
|
if (request.stopSequences?.length)
|
|
@@ -55789,6 +56216,21 @@ var init_anthropic = __esm({
|
|
|
55789
56216
|
isCompactionSupported() {
|
|
55790
56217
|
return this.model.startsWith("claude-opus-4") || this.model.startsWith("claude-sonnet-4");
|
|
55791
56218
|
}
|
|
56219
|
+
/**
|
|
56220
|
+
* Build the `system` field for the Anthropic API. When structured cache
|
|
56221
|
+
* segments are provided, returns an array of content blocks with
|
|
56222
|
+
* `cache_control` breakpoints so the API can cache stable prefixes.
|
|
56223
|
+
* Falls back to a plain string when no segments are available.
|
|
56224
|
+
*/
|
|
56225
|
+
buildSystemContent(plainText, segments) {
|
|
56226
|
+
if (!segments || segments.length <= 1)
|
|
56227
|
+
return plainText;
|
|
56228
|
+
return segments.filter((s) => s.content.length > 0).map((s) => ({
|
|
56229
|
+
type: "text",
|
|
56230
|
+
text: s.content,
|
|
56231
|
+
...s.cacheBreakpoint ? { cache_control: { type: "ephemeral" } } : {}
|
|
56232
|
+
}));
|
|
56233
|
+
}
|
|
55792
56234
|
convertResponse(data) {
|
|
55793
56235
|
let content = "";
|
|
55794
56236
|
let compactionContent;
|
|
@@ -57114,6 +57556,13 @@ var init_oauth_manager = __esm({
|
|
|
57114
57556
|
});
|
|
57115
57557
|
|
|
57116
57558
|
// ../core/dist/llm/router.js
|
|
57559
|
+
function maskApiKey(key2) {
|
|
57560
|
+
if (!key2)
|
|
57561
|
+
return void 0;
|
|
57562
|
+
if (key2.length <= 8)
|
|
57563
|
+
return "****";
|
|
57564
|
+
return key2.slice(0, 4) + "..." + key2.slice(-4);
|
|
57565
|
+
}
|
|
57117
57566
|
function buildTiers(providerNames, defaultProvider) {
|
|
57118
57567
|
const tiers = [];
|
|
57119
57568
|
if (providerNames.includes(defaultProvider)) {
|
|
@@ -57792,6 +58241,8 @@ var init_router = __esm({
|
|
|
57792
58241
|
const builtinModels = BUILTIN_MODEL_CATALOG.filter((m) => m.provider === name);
|
|
57793
58242
|
const customCatalogModels = this.customModelCatalog.get(name) ?? [];
|
|
57794
58243
|
const mergedModels = [...builtinModels, ...customCatalogModels.filter((cm) => !builtinModels.some((bm) => bm.id === cm.id))];
|
|
58244
|
+
const rawKey = p.apiKey ?? "";
|
|
58245
|
+
const keySource = oauthProfile?.authType === "oauth" ? "oauth" : rawKey ? "config" : void 0;
|
|
57795
58246
|
providers[name] = {
|
|
57796
58247
|
name,
|
|
57797
58248
|
displayName: PROVIDER_DISPLAY_NAMES[name] ?? name,
|
|
@@ -57799,6 +58250,8 @@ var init_router = __esm({
|
|
|
57799
58250
|
baseUrl: p.baseUrl,
|
|
57800
58251
|
configured: true,
|
|
57801
58252
|
enabled: this.isProviderEnabled(name),
|
|
58253
|
+
apiKeyPreview: maskApiKey(rawKey),
|
|
58254
|
+
apiKeySource: keySource,
|
|
57802
58255
|
contextWindow: customModels?.contextWindow ?? modelDef?.contextWindow,
|
|
57803
58256
|
maxOutputTokens: customModels?.maxOutputTokens ?? modelDef?.maxOutputTokens,
|
|
57804
58257
|
cost: customModels?.cost ?? modelDef?.cost,
|
|
@@ -59874,11 +60327,13 @@ function loadTeamTemplateFromDir(dirPath) {
|
|
|
59874
60327
|
name: m.name,
|
|
59875
60328
|
count: m.count,
|
|
59876
60329
|
role: m.role,
|
|
60330
|
+
description: m.description,
|
|
59877
60331
|
skills: m.skills ?? []
|
|
59878
60332
|
})),
|
|
59879
60333
|
tags: manifest.tags ?? [],
|
|
59880
60334
|
category: manifest.category,
|
|
59881
60335
|
icon: manifest.icon,
|
|
60336
|
+
starterTasks: manifest.starterTasks,
|
|
59882
60337
|
announcements: existsSync21(annPath) ? readFileSync16(annPath, "utf-8") : void 0,
|
|
59883
60338
|
norms: existsSync21(normsPath) ? readFileSync16(normsPath, "utf-8") : void 0,
|
|
59884
60339
|
i18n: manifest.i18n
|
|
@@ -60101,6 +60556,34 @@ var init_org_service = __esm({
|
|
|
60101
60556
|
listHumanUsers(orgId2) {
|
|
60102
60557
|
return [...this.humans.values()].filter((h) => h.orgId === orgId2);
|
|
60103
60558
|
}
|
|
60559
|
+
/**
|
|
60560
|
+
* Update (or insert) a user's in-memory identity without touching the DB.
|
|
60561
|
+
* Safe to call from auth endpoints that already persisted DB changes.
|
|
60562
|
+
* Never throws — logs warnings on failure.
|
|
60563
|
+
*/
|
|
60564
|
+
syncHumanIdentity(userId2, orgId2, name, role, email) {
|
|
60565
|
+
try {
|
|
60566
|
+
const existing = this.humans.get(userId2);
|
|
60567
|
+
if (existing) {
|
|
60568
|
+
existing.name = name;
|
|
60569
|
+
if (email !== void 0)
|
|
60570
|
+
existing.email = email;
|
|
60571
|
+
existing.role = role;
|
|
60572
|
+
} else {
|
|
60573
|
+
this.humans.set(userId2, {
|
|
60574
|
+
id: userId2,
|
|
60575
|
+
name,
|
|
60576
|
+
email,
|
|
60577
|
+
role,
|
|
60578
|
+
orgId: orgId2,
|
|
60579
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
60580
|
+
});
|
|
60581
|
+
}
|
|
60582
|
+
this.refreshIdentityContextsForOrg(orgId2);
|
|
60583
|
+
} catch (err) {
|
|
60584
|
+
log49.warn("syncHumanIdentity failed (non-fatal)", { userId: userId2, error: String(err) });
|
|
60585
|
+
}
|
|
60586
|
+
}
|
|
60104
60587
|
updateHumanUser(userId2, updates) {
|
|
60105
60588
|
const user = this.humans.get(userId2);
|
|
60106
60589
|
if (!user)
|
|
@@ -61178,10 +61661,12 @@ var init_task_service = __esm({
|
|
|
61178
61661
|
}
|
|
61179
61662
|
}
|
|
61180
61663
|
if (!isReviewerDuringReview) {
|
|
61181
|
-
|
|
61664
|
+
const terminalStatuses = /* @__PURE__ */ new Set(["completed", "accepted", "archived"]);
|
|
61665
|
+
const handledByInjection = task?.status === "in_progress" || task?.status && terminalStatuses.has(task.status);
|
|
61666
|
+
if (task?.assignedAgentId && !handledByInjection) {
|
|
61182
61667
|
enqueueFor(task.assignedAgentId, "task_comment", `New comment from ${authorName} on your assigned task`);
|
|
61183
61668
|
}
|
|
61184
|
-
if (task?.createdBy &&
|
|
61669
|
+
if (task?.createdBy && !handledByInjection) {
|
|
61185
61670
|
enqueueFor(task.createdBy, "task_comment", `New comment from ${authorName} on a task you created`);
|
|
61186
61671
|
}
|
|
61187
61672
|
}
|
|
@@ -62407,14 +62892,15 @@ ${c.content}`;
|
|
|
62407
62892
|
reviewer: task.reviewerId
|
|
62408
62893
|
});
|
|
62409
62894
|
if (this.hitlService && request.creatorRole !== "human" && task.status === "pending") {
|
|
62410
|
-
const
|
|
62895
|
+
const creatorId = request.createdBy ?? "system";
|
|
62896
|
+
const creatorName = this.resolveActorName(creatorId, "agent") ?? creatorId;
|
|
62411
62897
|
this.hitlService.requestApprovalAndWait({
|
|
62412
|
-
agentId:
|
|
62898
|
+
agentId: creatorId,
|
|
62413
62899
|
agentName: creatorName,
|
|
62414
62900
|
type: "custom",
|
|
62415
|
-
title:
|
|
62901
|
+
title: task.title,
|
|
62416
62902
|
description: `Agent "${creatorName}" wants to create task "${task.title}" (priority: ${task.priority}).`,
|
|
62417
|
-
details: { taskId: task.id, priority: task.priority }
|
|
62903
|
+
details: { taskId: task.id, taskTitle: task.title, priority: task.priority, subType: "task" }
|
|
62418
62904
|
}).then((result) => {
|
|
62419
62905
|
const current = this.tasks.get(task.id);
|
|
62420
62906
|
if (!current || current.status !== "pending")
|
|
@@ -62653,6 +63139,12 @@ ${c.content}`;
|
|
|
62653
63139
|
if (from === "review" && to !== "review") {
|
|
62654
63140
|
this.activeReviews.delete(taskId2);
|
|
62655
63141
|
}
|
|
63142
|
+
if (TERMINAL_STATUSES.has(to) && this.hitlService) {
|
|
63143
|
+
const cancelled = this.hitlService.cancelApprovalsByDetail("taskId", taskId2, "system", `Task ${to}`);
|
|
63144
|
+
if (cancelled > 0) {
|
|
63145
|
+
log50.info(`Cancelled ${cancelled} pending approval(s) for task ${taskId2} (status \u2192 ${to})`);
|
|
63146
|
+
}
|
|
63147
|
+
}
|
|
62656
63148
|
}
|
|
62657
63149
|
// ─── Stage 2: DB persistence ─────────────────────────────────────────────────
|
|
62658
63150
|
persistStatusChange(id, status, updatedBy) {
|
|
@@ -62701,12 +63193,14 @@ ${c.content}`;
|
|
|
62701
63193
|
Deliverables:
|
|
62702
63194
|
${deliverablesSummary}` : ""
|
|
62703
63195
|
].filter(Boolean).join("\n");
|
|
63196
|
+
const assigneeName = this.resolveActorName(task.assignedAgentId, "agent") ?? task.assignedAgentId;
|
|
62704
63197
|
this.hitlService.requestApprovalAndWait({
|
|
62705
63198
|
agentId: task.assignedAgentId,
|
|
62706
|
-
agentName:
|
|
63199
|
+
agentName: assigneeName,
|
|
62707
63200
|
type: "custom",
|
|
62708
63201
|
title: `Review: ${task.title}`,
|
|
62709
63202
|
description,
|
|
63203
|
+
details: { taskId: task.id, taskTitle: task.title, subType: "task_review" },
|
|
62710
63204
|
targetUserId: task.reviewerId,
|
|
62711
63205
|
options: [
|
|
62712
63206
|
{ id: "approve", label: "Approve" },
|
|
@@ -63061,6 +63555,12 @@ Action: ${guidance}` : ""
|
|
|
63061
63555
|
if (data.reviewerType !== void 0)
|
|
63062
63556
|
task.reviewerType = data.reviewerType;
|
|
63063
63557
|
if (data.blockedBy !== void 0) {
|
|
63558
|
+
if (data.blockedBy.length > 0) {
|
|
63559
|
+
const cycle = this.detectBlockedByCycle(id, data.blockedBy);
|
|
63560
|
+
if (cycle) {
|
|
63561
|
+
throw new Error(`Circular dependency detected: ${cycle.join(" \u2192 ")}. Cannot set blocked_by \u2014 this would create a deadlock.`);
|
|
63562
|
+
}
|
|
63563
|
+
}
|
|
63064
63564
|
task.blockedBy = data.blockedBy;
|
|
63065
63565
|
if (this.taskRepo && "updateBlockedBy" in this.taskRepo) {
|
|
63066
63566
|
this.taskRepo.updateBlockedBy(id, data.blockedBy).catch((err) => log50.warn("Failed to persist blockedBy to DB", { error: String(err) }));
|
|
@@ -63185,6 +63685,31 @@ Action: ${guidance}` : ""
|
|
|
63185
63685
|
this.cascadeCancelDependents(task);
|
|
63186
63686
|
}
|
|
63187
63687
|
}
|
|
63688
|
+
/**
|
|
63689
|
+
* Detect cycles in blocked_by dependencies using BFS.
|
|
63690
|
+
* Returns the cycle path if found, or null if no cycle exists.
|
|
63691
|
+
*/
|
|
63692
|
+
detectBlockedByCycle(taskId2, proposedBlockers) {
|
|
63693
|
+
for (const blockerId of proposedBlockers) {
|
|
63694
|
+
const visited = /* @__PURE__ */ new Set();
|
|
63695
|
+
const queue = [{ id: blockerId, path: [taskId2, blockerId] }];
|
|
63696
|
+
while (queue.length > 0) {
|
|
63697
|
+
const { id: current, path } = queue.shift();
|
|
63698
|
+
if (current === taskId2)
|
|
63699
|
+
return path;
|
|
63700
|
+
if (visited.has(current))
|
|
63701
|
+
continue;
|
|
63702
|
+
visited.add(current);
|
|
63703
|
+
const blockerTask = this.tasks.get(current);
|
|
63704
|
+
if (blockerTask?.blockedBy) {
|
|
63705
|
+
for (const nextId of blockerTask.blockedBy) {
|
|
63706
|
+
queue.push({ id: nextId, path: [...path, nextId] });
|
|
63707
|
+
}
|
|
63708
|
+
}
|
|
63709
|
+
}
|
|
63710
|
+
}
|
|
63711
|
+
return null;
|
|
63712
|
+
}
|
|
63188
63713
|
areBlockersSatisfied(task) {
|
|
63189
63714
|
if (!task.blockedBy?.length)
|
|
63190
63715
|
return true;
|
|
@@ -63704,7 +64229,7 @@ Action: ${guidance}` : ""
|
|
|
63704
64229
|
"",
|
|
63705
64230
|
'Save each lesson using `memory_save` with tags `["lesson", ...]`.',
|
|
63706
64231
|
'If it is a repeatable multi-step procedure, promote to SOP via `memory_update_longterm({ section: "sops", mode: "patch" })`.',
|
|
63707
|
-
"If the best practice would benefit other agents on the team, create a shareable skill via **skill-building** and install it with `
|
|
64232
|
+
"If the best practice would benefit other agents on the team, create a shareable skill via **skill-building** and install it with `package_install`.",
|
|
63708
64233
|
"",
|
|
63709
64234
|
"**Direct self-evolution** \u2014 consider the simplest, most impactful options:",
|
|
63710
64235
|
"- If this lesson reveals a behavioral rule that should always guide your work, append it to your ROLE.md via `file_edit`.",
|
|
@@ -63724,7 +64249,7 @@ Action: ${guidance}` : ""
|
|
|
63724
64249
|
"",
|
|
63725
64250
|
'If you identify a meaningful insight, save it using `memory_save` with tags `["lesson", "best-practice", ...]`.',
|
|
63726
64251
|
'If it is a multi-step workflow, promote to SOP via `memory_update_longterm({ section: "sops", mode: "patch" })`.',
|
|
63727
|
-
"If worth sharing with the team, create a skill via **skill-building** and install with `
|
|
64252
|
+
"If worth sharing with the team, create a skill via **skill-building** and install with `package_install`.",
|
|
63728
64253
|
"",
|
|
63729
64254
|
"**Direct self-evolution** \u2014 consider the simplest, most impactful options:",
|
|
63730
64255
|
"- If this success reveals a guiding principle or working style worth keeping, append it to your ROLE.md via `file_edit`.",
|
|
@@ -63977,7 +64502,7 @@ ${reason}`
|
|
|
63977
64502
|
updated.runAt = void 0;
|
|
63978
64503
|
}
|
|
63979
64504
|
if (fields.maxRuns !== void 0)
|
|
63980
|
-
updated.maxRuns = fields.maxRuns;
|
|
64505
|
+
updated.maxRuns = fields.maxRuns > 0 ? fields.maxRuns : void 0;
|
|
63981
64506
|
if (fields.timezone !== void 0)
|
|
63982
64507
|
updated.timezone = fields.timezone;
|
|
63983
64508
|
updated.nextRunAt = computeNextRunFromConfig(updated);
|
|
@@ -64347,8 +64872,10 @@ ${task.description}`;
|
|
|
64347
64872
|
content,
|
|
64348
64873
|
"",
|
|
64349
64874
|
`(This task "${task.title}" is already ${task.status}. You have full context from your execution above.`,
|
|
64350
|
-
"
|
|
64351
|
-
"
|
|
64875
|
+
"Your text response will be posted as a reply in the task comment thread automatically.",
|
|
64876
|
+
"Do NOT use the `task_comment` tool \u2014 your text output IS the reply visible to the commenter.",
|
|
64877
|
+
"If the feedback contains something worth remembering, save it to memory.",
|
|
64878
|
+
"You have all your tools available for taking action if appropriate.)"
|
|
64352
64879
|
].join("\n");
|
|
64353
64880
|
try {
|
|
64354
64881
|
log50.info("Triggering post-task agent reply", { taskId: taskId2, taskSessionId, agentId: agentId2, authorName });
|
|
@@ -64460,11 +64987,19 @@ var init_builder_service = __esm({
|
|
|
64460
64987
|
orgService;
|
|
64461
64988
|
skillRegistry;
|
|
64462
64989
|
wsBroadcast;
|
|
64990
|
+
taskService;
|
|
64991
|
+
builtinTeamTemplatesDir;
|
|
64463
64992
|
constructor(orgService, skillRegistry, wsBroadcast) {
|
|
64464
64993
|
this.orgService = orgService;
|
|
64465
64994
|
this.skillRegistry = skillRegistry;
|
|
64466
64995
|
this.wsBroadcast = wsBroadcast;
|
|
64467
64996
|
}
|
|
64997
|
+
setTaskService(taskService) {
|
|
64998
|
+
this.taskService = taskService;
|
|
64999
|
+
}
|
|
65000
|
+
setBuiltinTeamTemplatesDir(dir) {
|
|
65001
|
+
this.builtinTeamTemplatesDir = dir;
|
|
65002
|
+
}
|
|
64468
65003
|
get baseDir() {
|
|
64469
65004
|
return join20(homedir12(), ".markus", "builder-artifacts");
|
|
64470
65005
|
}
|
|
@@ -64497,14 +65032,42 @@ var init_builder_service = __esm({
|
|
|
64497
65032
|
});
|
|
64498
65033
|
}
|
|
64499
65034
|
}
|
|
65035
|
+
if ((!type || type === "team") && this.builtinTeamTemplatesDir && existsSync24(this.builtinTeamTemplatesDir)) {
|
|
65036
|
+
const artifactNames = new Set(artifacts.filter((a) => a.type === "team").map((a) => a.name));
|
|
65037
|
+
for (const entry of readdirSync8(this.builtinTeamTemplatesDir, { withFileTypes: true })) {
|
|
65038
|
+
if (!entry.isDirectory() || artifactNames.has(entry.name))
|
|
65039
|
+
continue;
|
|
65040
|
+
const tplDir = join20(this.builtinTeamTemplatesDir, entry.name);
|
|
65041
|
+
const manifest = readManifest(tplDir, "team", FS_HELPER);
|
|
65042
|
+
if (!manifest)
|
|
65043
|
+
continue;
|
|
65044
|
+
artifacts.push({
|
|
65045
|
+
type: "team",
|
|
65046
|
+
name: entry.name,
|
|
65047
|
+
description: manifest.description ?? void 0,
|
|
65048
|
+
meta: { ...manifest, source: "builtin" },
|
|
65049
|
+
path: tplDir,
|
|
65050
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
65051
|
+
});
|
|
65052
|
+
}
|
|
65053
|
+
}
|
|
64500
65054
|
artifacts.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
64501
65055
|
return artifacts;
|
|
64502
65056
|
}
|
|
64503
65057
|
async installArtifact(type, name) {
|
|
64504
65058
|
const typeDir = type === "agent" ? "agents" : type === "team" ? "teams" : "skills";
|
|
64505
|
-
|
|
65059
|
+
let artDir = join20(this.baseDir, typeDir, name);
|
|
64506
65060
|
if (!existsSync24(artDir)) {
|
|
64507
|
-
|
|
65061
|
+
if (type === "team" && this.builtinTeamTemplatesDir) {
|
|
65062
|
+
const builtinDir = join20(this.builtinTeamTemplatesDir, name);
|
|
65063
|
+
if (existsSync24(builtinDir)) {
|
|
65064
|
+
artDir = builtinDir;
|
|
65065
|
+
} else {
|
|
65066
|
+
throw new Error(`Team template not found: ${name}. Use package_list to see available packages.`);
|
|
65067
|
+
}
|
|
65068
|
+
} else {
|
|
65069
|
+
throw new Error(`Artifact not found: ${type}/${name}`);
|
|
65070
|
+
}
|
|
64508
65071
|
}
|
|
64509
65072
|
const installType = type;
|
|
64510
65073
|
const manifest = readManifest(artDir, installType, FS_HELPER);
|
|
@@ -64620,9 +65183,35 @@ var init_builder_service = __esm({
|
|
|
64620
65183
|
createdAgents.push({ id: agent.id, name: agent.config.name, role: agent.role.name });
|
|
64621
65184
|
}
|
|
64622
65185
|
}
|
|
65186
|
+
const starterTasks = manifest.starterTasks ?? manifest.team?.starterTasks ?? [];
|
|
65187
|
+
const createdTaskIds = [];
|
|
65188
|
+
if (starterTasks.length > 0 && this.taskService) {
|
|
65189
|
+
const managerId = createdAgents.find((a) => a.role === "manager" || members.find((m) => m.name === a.name)?.role === "manager")?.id ?? createdAgents[0]?.id;
|
|
65190
|
+
if (managerId) {
|
|
65191
|
+
for (const st of starterTasks) {
|
|
65192
|
+
try {
|
|
65193
|
+
const task = this.taskService.createTask({
|
|
65194
|
+
orgId: "default",
|
|
65195
|
+
title: st.title,
|
|
65196
|
+
description: st.description,
|
|
65197
|
+
priority: st.priority ?? "medium",
|
|
65198
|
+
assignedAgentId: managerId,
|
|
65199
|
+
reviewerId: managerId,
|
|
65200
|
+
reviewerType: "human",
|
|
65201
|
+
creatorRole: "human",
|
|
65202
|
+
taskType: "standard"
|
|
65203
|
+
});
|
|
65204
|
+
createdTaskIds.push(task.id);
|
|
65205
|
+
log51.info("installTeam: created starterTask", { taskId: task.id, title: st.title });
|
|
65206
|
+
} catch (err) {
|
|
65207
|
+
log51.warn("installTeam: failed to create starterTask", { title: st.title, error: String(err) });
|
|
65208
|
+
}
|
|
65209
|
+
}
|
|
65210
|
+
}
|
|
65211
|
+
}
|
|
64623
65212
|
return {
|
|
64624
65213
|
type: "team",
|
|
64625
|
-
installed: { team: { id: team.id, name: teamName }, agents: createdAgents }
|
|
65214
|
+
installed: { team: { id: team.id, name: teamName }, agents: createdAgents, starterTaskIds: createdTaskIds }
|
|
64626
65215
|
};
|
|
64627
65216
|
}
|
|
64628
65217
|
/**
|
|
@@ -65221,7 +65810,12 @@ var init_sse_handler = __esm({
|
|
|
65221
65810
|
replyLength: persistReply.length
|
|
65222
65811
|
});
|
|
65223
65812
|
if (this.options.wsBroadcaster) {
|
|
65224
|
-
this.options.wsBroadcaster.
|
|
65813
|
+
if (this.options.wsBroadcaster.broadcastProactiveMessage && this.sessionId) {
|
|
65814
|
+
const agentName = this.options.agent.config?.name ?? this.options.agentId;
|
|
65815
|
+
this.options.wsBroadcaster.broadcastProactiveMessage(this.options.agentId, agentName, this.sessionId, `ws_fallback_${Date.now()}`, persistReply, { isMainSession: true }, this.options.senderId);
|
|
65816
|
+
} else {
|
|
65817
|
+
this.options.wsBroadcaster.broadcastChat(this.options.agentId, persistReply, "agent");
|
|
65818
|
+
}
|
|
65225
65819
|
}
|
|
65226
65820
|
} else {
|
|
65227
65821
|
this.sseBuffer.send({
|
|
@@ -65943,7 +66537,7 @@ var init_api_server = __esm({
|
|
|
65943
66537
|
let channelContext = [];
|
|
65944
66538
|
if (this.storage) {
|
|
65945
66539
|
try {
|
|
65946
|
-
const recent = await this.storage.channelMessageRepo.getMessages(channelKey,
|
|
66540
|
+
const recent = await this.storage.channelMessageRepo.getMessages(channelKey, 80);
|
|
65947
66541
|
channelContext = (recent.messages ?? []).map((m) => ({
|
|
65948
66542
|
role: m.senderType === "agent" ? "assistant" : "user",
|
|
65949
66543
|
content: m.senderType === "agent" ? stripInternalBlocks(m.text) : `[${m.senderName}]: ${m.text}`
|
|
@@ -66036,6 +66630,7 @@ ${cleanText}`,
|
|
|
66036
66630
|
setSkillRegistry(registry) {
|
|
66037
66631
|
this.skillRegistry = registry;
|
|
66038
66632
|
this.builderService = new BuilderService(this.orgService, registry, (msg) => this.ws?.broadcast(msg));
|
|
66633
|
+
this.builderService.setTaskService(this.taskService);
|
|
66039
66634
|
}
|
|
66040
66635
|
getBuilderService() {
|
|
66041
66636
|
return this.builderService;
|
|
@@ -66513,13 +67108,33 @@ ${cleanText}`,
|
|
|
66513
67108
|
toolEventCollector: toolEvents,
|
|
66514
67109
|
waitForReply: isA2A ? true : void 0
|
|
66515
67110
|
});
|
|
67111
|
+
const emitNoResponse = () => {
|
|
67112
|
+
const evt = {
|
|
67113
|
+
type: "chat:agent_no_response",
|
|
67114
|
+
payload: { channel, agentId: agentId2 },
|
|
67115
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
67116
|
+
};
|
|
67117
|
+
if (channel.startsWith("dm:") || channel.startsWith("notes:")) {
|
|
67118
|
+
const parts = channel.startsWith("notes:") ? [channel.slice(6)] : channel.slice(3).split(":");
|
|
67119
|
+
this.ws.sendToUsers(parts, evt);
|
|
67120
|
+
} else {
|
|
67121
|
+
const humanIds = this.resolveChannelHumanIds(channel);
|
|
67122
|
+
if (humanIds.length > 0)
|
|
67123
|
+
this.ws.sendToUsers(humanIds, evt);
|
|
67124
|
+
else
|
|
67125
|
+
this.ws.broadcast(evt);
|
|
67126
|
+
}
|
|
67127
|
+
};
|
|
66516
67128
|
if (!reply || !reply.trim() || reply.includes("[NO_RESPONSE]")) {
|
|
67129
|
+
emitNoResponse();
|
|
66517
67130
|
return;
|
|
66518
67131
|
}
|
|
66519
67132
|
const { thinking, clean: rawClean } = extractThinkBlocks(reply);
|
|
66520
67133
|
const cleanReply = rawClean.replace(/\[NO_RESPONSE\]/gi, "").trim();
|
|
66521
|
-
if (!cleanReply)
|
|
67134
|
+
if (!cleanReply) {
|
|
67135
|
+
emitNoResponse();
|
|
66522
67136
|
return;
|
|
67137
|
+
}
|
|
66523
67138
|
const metadata = {};
|
|
66524
67139
|
if (thinking.length > 0)
|
|
66525
67140
|
metadata["thinking"] = thinking;
|
|
@@ -66622,7 +67237,7 @@ ${cleanText}`,
|
|
|
66622
67237
|
let channelContext = [];
|
|
66623
67238
|
if (this.storage) {
|
|
66624
67239
|
try {
|
|
66625
|
-
const recent = await this.storage.channelMessageRepo.getMessages(channel,
|
|
67240
|
+
const recent = await this.storage.channelMessageRepo.getMessages(channel, 80);
|
|
66626
67241
|
channelContext = (recent.messages ?? []).map((m) => ({
|
|
66627
67242
|
role: m.senderType === "agent" ? "assistant" : "user",
|
|
66628
67243
|
content: m.senderType === "agent" ? stripInternalBlocks(m.text) : `[${m.senderName}]: ${m.text}`
|
|
@@ -66688,6 +67303,24 @@ ${cleanText}`,
|
|
|
66688
67303
|
log56.warn("Failed to persist assistant message", { error: String(err) });
|
|
66689
67304
|
}
|
|
66690
67305
|
}
|
|
67306
|
+
triggerSecretaryWelcome(userId2, userName, userRole) {
|
|
67307
|
+
try {
|
|
67308
|
+
const mgr = this.orgService.getAgentManager();
|
|
67309
|
+
const agentList = mgr.listAgents();
|
|
67310
|
+
const secretaryInfo = agentList.find((a) => a.agentRole === "secretary" || a.role?.toLowerCase() === "secretary");
|
|
67311
|
+
if (!secretaryInfo)
|
|
67312
|
+
return;
|
|
67313
|
+
const secretary = mgr.getAgent(secretaryInfo.id);
|
|
67314
|
+
const welcomeMsg = `[SYSTEM] A new team member just joined: "${userName}" (role: ${userRole}, id: ${userId2}). They have completed their account setup. As their Secretary, proactively guide them through the system capabilities. Send them a welcome message using notify_user (target the new user by their id: ${userId2}) explaining what they can do in Markus \u2014 projects, tasks, deliverables, team collaboration, and how to work with AI agents. Help them get started with their first steps.`;
|
|
67315
|
+
secretary.sendMessage(welcomeMsg, userId2, {
|
|
67316
|
+
name: userName,
|
|
67317
|
+
role: userRole,
|
|
67318
|
+
isFirstConversation: true
|
|
67319
|
+
}, { sourceType: "human_chat", scenario: "chat" });
|
|
67320
|
+
} catch (err) {
|
|
67321
|
+
log56.warn("Failed to trigger secretary welcome for new user", { userId: userId2, error: String(err) });
|
|
67322
|
+
}
|
|
67323
|
+
}
|
|
66691
67324
|
start() {
|
|
66692
67325
|
this.server = createServer2((req, res) => this.handleRequest(req, res));
|
|
66693
67326
|
this.ws.attach(this.server);
|
|
@@ -66750,6 +67383,68 @@ ${cleanText}`,
|
|
|
66750
67383
|
await this.readBody(req);
|
|
66751
67384
|
}
|
|
66752
67385
|
}
|
|
67386
|
+
if (path === "/api/auth/status" && req.method === "GET") {
|
|
67387
|
+
if (!this.storage || !this.authEnabled) {
|
|
67388
|
+
this.json(res, 200, { initialized: true });
|
|
67389
|
+
return;
|
|
67390
|
+
}
|
|
67391
|
+
const allUsers = await this.storage.userRepo.listByOrg("default");
|
|
67392
|
+
const hasRealUsers = allUsers.some((u) => u.passwordHash && u.email !== "admin@markus.local");
|
|
67393
|
+
this.json(res, 200, { initialized: hasRealUsers });
|
|
67394
|
+
return;
|
|
67395
|
+
}
|
|
67396
|
+
if (path === "/api/auth/init" && req.method === "POST") {
|
|
67397
|
+
if (!this.storage) {
|
|
67398
|
+
this.json(res, 503, { error: "Storage not available" });
|
|
67399
|
+
return;
|
|
67400
|
+
}
|
|
67401
|
+
const allUsers = await this.storage.userRepo.listByOrg("default");
|
|
67402
|
+
const hasRealUsers = allUsers.some((u) => u.passwordHash && u.email !== "admin@markus.local");
|
|
67403
|
+
if (hasRealUsers) {
|
|
67404
|
+
this.json(res, 403, { error: "System already initialized" });
|
|
67405
|
+
return;
|
|
67406
|
+
}
|
|
67407
|
+
const body = await this.readBody(req);
|
|
67408
|
+
const name = (body["name"] ?? "").trim();
|
|
67409
|
+
const email = (body["email"] ?? "").trim().toLowerCase();
|
|
67410
|
+
const password = body["password"] ?? "";
|
|
67411
|
+
if (!name || !email || !password) {
|
|
67412
|
+
this.json(res, 400, { error: "name, email and password are required" });
|
|
67413
|
+
return;
|
|
67414
|
+
}
|
|
67415
|
+
if (password.length < 6) {
|
|
67416
|
+
this.json(res, 400, { error: "Password must be at least 6 characters" });
|
|
67417
|
+
return;
|
|
67418
|
+
}
|
|
67419
|
+
const hash = await hashPassword(password);
|
|
67420
|
+
const placeholder = allUsers.find((u) => u.role === "owner" && u.email === "admin@markus.local");
|
|
67421
|
+
let userId2;
|
|
67422
|
+
if (placeholder) {
|
|
67423
|
+
userId2 = placeholder.id;
|
|
67424
|
+
this.storage.userRepo.updateProfile(userId2, { name, email });
|
|
67425
|
+
await this.storage.userRepo.updatePassword(userId2, hash);
|
|
67426
|
+
} else {
|
|
67427
|
+
userId2 = userId();
|
|
67428
|
+
await this.storage.userRepo.upsert({
|
|
67429
|
+
id: userId2,
|
|
67430
|
+
orgId: "default",
|
|
67431
|
+
name,
|
|
67432
|
+
email,
|
|
67433
|
+
role: "owner",
|
|
67434
|
+
passwordHash: hash
|
|
67435
|
+
});
|
|
67436
|
+
}
|
|
67437
|
+
this.orgService.syncHumanIdentity(userId2, "default", name, "owner", email);
|
|
67438
|
+
await this.storage.userRepo.updateLastLogin(userId2);
|
|
67439
|
+
const exp = Math.floor(Date.now() / 1e3) + 7 * 24 * 3600;
|
|
67440
|
+
const token = await signToken({ userId: userId2, orgId: "default", role: "owner", exp }, this.jwtSecret);
|
|
67441
|
+
res.setHeader("Set-Cookie", `markus_token=${token}; HttpOnly; SameSite=Strict; Path=/; Max-Age=${7 * 24 * 3600}`);
|
|
67442
|
+
this.json(res, 200, {
|
|
67443
|
+
user: { id: userId2, name, email, role: "owner", orgId: "default" },
|
|
67444
|
+
needsOnboarding: true
|
|
67445
|
+
});
|
|
67446
|
+
return;
|
|
67447
|
+
}
|
|
66753
67448
|
if (path === "/api/auth/login" && req.method === "POST") {
|
|
66754
67449
|
const body = await this.readBody(req);
|
|
66755
67450
|
const email = (body["email"] ?? "").trim().toLowerCase();
|
|
@@ -66758,7 +67453,18 @@ ${cleanText}`,
|
|
|
66758
67453
|
this.json(res, 200, { user: { id: "anonymous", name: "Admin", role: "owner" } });
|
|
66759
67454
|
return;
|
|
66760
67455
|
}
|
|
66761
|
-
|
|
67456
|
+
let userRow = this.storage ? await this.storage.userRepo.findByEmail(email) : null;
|
|
67457
|
+
if (!userRow && this.storage) {
|
|
67458
|
+
const allUsers = await this.storage.userRepo.listByOrg("default");
|
|
67459
|
+
const unclaimedOwner = allUsers.find((u) => u.role === "owner" && !u.lastLoginAt && u.email === "admin@markus.local");
|
|
67460
|
+
if (unclaimedOwner && unclaimedOwner.passwordHash) {
|
|
67461
|
+
const ownerPasswordValid = await verifyPassword(password, unclaimedOwner.passwordHash);
|
|
67462
|
+
if (ownerPasswordValid) {
|
|
67463
|
+
this.storage.userRepo.updateProfile(unclaimedOwner.id, { email });
|
|
67464
|
+
userRow = { ...unclaimedOwner, email };
|
|
67465
|
+
}
|
|
67466
|
+
}
|
|
67467
|
+
}
|
|
66762
67468
|
if (!userRow || !userRow.passwordHash) {
|
|
66763
67469
|
this.json(res, 401, { error: "Invalid email or password" });
|
|
66764
67470
|
return;
|
|
@@ -66768,6 +67474,7 @@ ${cleanText}`,
|
|
|
66768
67474
|
this.json(res, 401, { error: "Invalid email or password" });
|
|
66769
67475
|
return;
|
|
66770
67476
|
}
|
|
67477
|
+
const isFirstLogin = !userRow.lastLoginAt;
|
|
66771
67478
|
await this.storage.userRepo.updateLastLogin(userRow.id);
|
|
66772
67479
|
const exp = Math.floor(Date.now() / 1e3) + 7 * 24 * 3600;
|
|
66773
67480
|
const token = await signToken({ userId: userRow.id, orgId: userRow.orgId, role: userRow.role, exp }, this.jwtSecret);
|
|
@@ -66780,7 +67487,8 @@ ${cleanText}`,
|
|
|
66780
67487
|
role: userRow.role,
|
|
66781
67488
|
orgId: userRow.orgId,
|
|
66782
67489
|
avatarUrl: userRow.avatarUrl ?? void 0
|
|
66783
|
-
}
|
|
67490
|
+
},
|
|
67491
|
+
needsOnboarding: isFirstLogin
|
|
66784
67492
|
});
|
|
66785
67493
|
return;
|
|
66786
67494
|
}
|
|
@@ -67072,6 +67780,18 @@ ${cleanText}`,
|
|
|
67072
67780
|
}
|
|
67073
67781
|
return;
|
|
67074
67782
|
}
|
|
67783
|
+
if (path === "/api/sessions/has-any" && req.method === "GET") {
|
|
67784
|
+
const authUser = await this.requireAuth(req, res);
|
|
67785
|
+
if (!authUser)
|
|
67786
|
+
return;
|
|
67787
|
+
if (!this.storage) {
|
|
67788
|
+
this.json(res, 200, { hasAny: false });
|
|
67789
|
+
return;
|
|
67790
|
+
}
|
|
67791
|
+
const hasAny = this.storage.chatSessionRepo.hasAnySessions(authUser.userId);
|
|
67792
|
+
this.json(res, 200, { hasAny });
|
|
67793
|
+
return;
|
|
67794
|
+
}
|
|
67075
67795
|
if (path.match(/^\/api\/agents\/[^/]+\/sessions$/) && req.method === "GET") {
|
|
67076
67796
|
const authUser = await this.getAuthUser(req);
|
|
67077
67797
|
const agentId2 = path.split("/")[3];
|
|
@@ -67162,7 +67882,7 @@ ${cleanText}`,
|
|
|
67162
67882
|
if (!this.storage)
|
|
67163
67883
|
return [];
|
|
67164
67884
|
try {
|
|
67165
|
-
const recent = await this.storage.channelMessageRepo.getMessages(channel,
|
|
67885
|
+
const recent = await this.storage.channelMessageRepo.getMessages(channel, 80);
|
|
67166
67886
|
return (recent.messages ?? []).map((m) => ({
|
|
67167
67887
|
role: m.senderType === "agent" ? "assistant" : "user",
|
|
67168
67888
|
content: m.senderType === "agent" ? stripInternalBlocks(m.text) : `[${m.senderName}]: ${m.text}`
|
|
@@ -67486,7 +68206,9 @@ ${cleanText}`,
|
|
|
67486
68206
|
const fileNames = body["fileNames"]?.filter(Boolean);
|
|
67487
68207
|
const isRetry = body["isRetry"];
|
|
67488
68208
|
const isResume = body["isResume"];
|
|
67489
|
-
const
|
|
68209
|
+
const baseSenderInfo = this.orgService.resolveHumanIdentity(senderId);
|
|
68210
|
+
const isFirstConversation = this.storage ? !this.storage.chatSessionRepo.hasAnySessions(senderId) : false;
|
|
68211
|
+
const senderInfo = baseSenderInfo ? { ...baseSenderInfo, isFirstConversation } : void 0;
|
|
67490
68212
|
const agent = this.orgService.getAgentManager().getAgent(agentId2);
|
|
67491
68213
|
this.ws.broadcastAgentUpdate(agentId2, "working");
|
|
67492
68214
|
if (!sessionId) {
|
|
@@ -67599,9 +68321,15 @@ ${cleanText}`,
|
|
|
67599
68321
|
return;
|
|
67600
68322
|
}
|
|
67601
68323
|
if (path === "/api/group-chats" && req.method === "GET") {
|
|
68324
|
+
const authUser = await this.requireAuth(req, res);
|
|
68325
|
+
if (!authUser)
|
|
68326
|
+
return;
|
|
67602
68327
|
const orgId2 = url.searchParams.get("orgId") ?? "default";
|
|
68328
|
+
const userId2 = authUser.userId;
|
|
68329
|
+
const isAdmin = authUser.role === "owner" || authUser.role === "admin";
|
|
67603
68330
|
const teams = this.orgService.listTeamsWithMembers(orgId2);
|
|
67604
|
-
const
|
|
68331
|
+
const filteredTeams = isAdmin ? teams : teams.filter((t) => t.members.some((m) => m.id === userId2));
|
|
68332
|
+
const teamChats = filteredTeams.map((t) => ({
|
|
67605
68333
|
id: `group:${t.id}`,
|
|
67606
68334
|
name: t.name,
|
|
67607
68335
|
type: "team",
|
|
@@ -67609,7 +68337,7 @@ ${cleanText}`,
|
|
|
67609
68337
|
memberCount: t.members.length,
|
|
67610
68338
|
channelKey: `group:${t.id}`
|
|
67611
68339
|
}));
|
|
67612
|
-
const customChats = this.storage?.groupChatRepo ? this.storage.groupChatRepo.list(orgId2).map((c) => ({
|
|
68340
|
+
const customChats = this.storage?.groupChatRepo ? (isAdmin ? this.storage.groupChatRepo.list(orgId2) : this.storage.groupChatRepo.listByMember(orgId2, userId2)).map((c) => ({
|
|
67613
68341
|
id: c.id,
|
|
67614
68342
|
name: c.name,
|
|
67615
68343
|
type: "custom",
|
|
@@ -71345,6 +72073,50 @@ EXPLANATION_END`;
|
|
|
71345
72073
|
this.json(res, 200, { success: read ?? false });
|
|
71346
72074
|
return;
|
|
71347
72075
|
}
|
|
72076
|
+
if (path === "/api/activity" && req.method === "GET") {
|
|
72077
|
+
const authUser = await this.requireAuth(req, res);
|
|
72078
|
+
if (!authUser)
|
|
72079
|
+
return;
|
|
72080
|
+
const userId2 = authUser.userId;
|
|
72081
|
+
const limit = Math.min(parseInt(url.searchParams.get("limit") ?? "50", 10), 200);
|
|
72082
|
+
const typeFilter = url.searchParams.get("type") ?? void 0;
|
|
72083
|
+
const items = [];
|
|
72084
|
+
if (!typeFilter || typeFilter === "notification") {
|
|
72085
|
+
const notifications = this.hitlService?.listNotifications(userId2, false, { limit }) ?? [];
|
|
72086
|
+
for (const n of notifications) {
|
|
72087
|
+
items.push({
|
|
72088
|
+
id: n.id,
|
|
72089
|
+
type: n.type,
|
|
72090
|
+
title: n.title,
|
|
72091
|
+
body: n.body,
|
|
72092
|
+
timestamp: n.createdAt,
|
|
72093
|
+
source: "notification",
|
|
72094
|
+
metadata: n.metadata
|
|
72095
|
+
});
|
|
72096
|
+
}
|
|
72097
|
+
}
|
|
72098
|
+
if ((!typeFilter || typeFilter === "task_comment") && this.storage?.taskCommentRepo) {
|
|
72099
|
+
try {
|
|
72100
|
+
const recentComments = this.storage.taskCommentRepo.listRecent?.(limit) ?? [];
|
|
72101
|
+
for (const c of recentComments) {
|
|
72102
|
+
items.push({
|
|
72103
|
+
id: c.id,
|
|
72104
|
+
type: "task_comment",
|
|
72105
|
+
title: `Comment on task ${c.taskId}`,
|
|
72106
|
+
body: typeof c.body === "string" ? c.body.slice(0, 300) : String(c.body ?? ""),
|
|
72107
|
+
timestamp: c.createdAt,
|
|
72108
|
+
source: "task_comment",
|
|
72109
|
+
metadata: { taskId: c.taskId, authorId: c.authorId, authorName: c.authorName }
|
|
72110
|
+
});
|
|
72111
|
+
}
|
|
72112
|
+
} catch {
|
|
72113
|
+
}
|
|
72114
|
+
}
|
|
72115
|
+
items.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
72116
|
+
const page = items.slice(0, limit);
|
|
72117
|
+
this.json(res, 200, { items: page, totalCount: items.length });
|
|
72118
|
+
return;
|
|
72119
|
+
}
|
|
71348
72120
|
if (path === "/api/usage" && req.method === "GET") {
|
|
71349
72121
|
const orgId2 = url.searchParams.get("orgId") ?? "default";
|
|
71350
72122
|
const plan = this.billingService?.getOrgPlan(orgId2);
|
|
@@ -73980,6 +74752,8 @@ EXPLANATION_END`;
|
|
|
73980
74752
|
exact("/api/notifications", "GET"),
|
|
73981
74753
|
exact("/api/notifications/mark-all-read", "POST"),
|
|
73982
74754
|
startsWith("/api/notifications/", "POST"),
|
|
74755
|
+
// ── Activity feed ─────────────────────────────────────────────────
|
|
74756
|
+
exact("/api/activity", "GET"),
|
|
73983
74757
|
// ── Users ────────────────────────────────────────────────────────────
|
|
73984
74758
|
exact("/api/users", "GET", "POST"),
|
|
73985
74759
|
regex(/^\/api\/users\/[^/]+$/, "PATCH"),
|
|
@@ -74595,7 +75369,7 @@ var init_hitl_service = __esm({
|
|
|
74595
75369
|
this.notify({
|
|
74596
75370
|
targetUserId: opts.targetUserId ?? "all",
|
|
74597
75371
|
type: "approval_request",
|
|
74598
|
-
title:
|
|
75372
|
+
title: opts.title,
|
|
74599
75373
|
body: opts.description,
|
|
74600
75374
|
priority: "high",
|
|
74601
75375
|
actionType: "navigate",
|
|
@@ -74612,6 +75386,14 @@ var init_hitl_service = __esm({
|
|
|
74612
75386
|
setTimeout(() => {
|
|
74613
75387
|
if (this.pendingResolvers.has(approval.id)) {
|
|
74614
75388
|
this.pendingResolvers.delete(approval.id);
|
|
75389
|
+
const a = this.approvals.get(approval.id);
|
|
75390
|
+
if (a && a.status === "pending") {
|
|
75391
|
+
a.status = "expired";
|
|
75392
|
+
a.respondedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
75393
|
+
a.responseComment = "Approval timed out";
|
|
75394
|
+
this.persistApproval(a);
|
|
75395
|
+
this.markApprovalNotificationsRead(a.id);
|
|
75396
|
+
}
|
|
74615
75397
|
resolve20({ approved: false, comment: "Approval timed out" });
|
|
74616
75398
|
}
|
|
74617
75399
|
}, opts.expiresInMs);
|
|
@@ -74639,6 +75421,35 @@ var init_hitl_service = __esm({
|
|
|
74639
75421
|
}
|
|
74640
75422
|
return approval;
|
|
74641
75423
|
}
|
|
75424
|
+
cancelApproval(id, cancelledBy, comment) {
|
|
75425
|
+
const approval = this.approvals.get(id);
|
|
75426
|
+
if (!approval || approval.status !== "pending")
|
|
75427
|
+
return void 0;
|
|
75428
|
+
approval.status = "cancelled";
|
|
75429
|
+
approval.respondedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
75430
|
+
approval.respondedBy = cancelledBy;
|
|
75431
|
+
if (comment)
|
|
75432
|
+
approval.responseComment = comment;
|
|
75433
|
+
this.persistApproval(approval);
|
|
75434
|
+
log57.info(`Approval ${id} cancelled by ${cancelledBy}`, { comment });
|
|
75435
|
+
this.markApprovalNotificationsRead(id);
|
|
75436
|
+
const resolve20 = this.pendingResolvers.get(id);
|
|
75437
|
+
if (resolve20) {
|
|
75438
|
+
this.pendingResolvers.delete(id);
|
|
75439
|
+
resolve20({ approved: false, comment: comment ?? "Approval cancelled" });
|
|
75440
|
+
}
|
|
75441
|
+
return approval;
|
|
75442
|
+
}
|
|
75443
|
+
cancelApprovalsByDetail(key2, value, cancelledBy, comment) {
|
|
75444
|
+
let count = 0;
|
|
75445
|
+
for (const approval of this.approvals.values()) {
|
|
75446
|
+
if (approval.status === "pending" && approval.details[key2] === value) {
|
|
75447
|
+
this.cancelApproval(approval.id, cancelledBy, comment);
|
|
75448
|
+
count++;
|
|
75449
|
+
}
|
|
75450
|
+
}
|
|
75451
|
+
return count;
|
|
75452
|
+
}
|
|
74642
75453
|
persistApproval(approval) {
|
|
74643
75454
|
if (!this.approvalRepo)
|
|
74644
75455
|
return;
|
|
@@ -75469,13 +76280,14 @@ var init_requirement_service = __esm({
|
|
|
75469
76280
|
}
|
|
75470
76281
|
this.broadcast("requirement:created", req);
|
|
75471
76282
|
if (this.hitlService && req.source === "agent") {
|
|
76283
|
+
const creatorName = this.resolveAgentName(req.createdBy);
|
|
75472
76284
|
this.hitlService.requestApprovalAndWait({
|
|
75473
76285
|
agentId: req.createdBy,
|
|
75474
|
-
agentName:
|
|
76286
|
+
agentName: creatorName,
|
|
75475
76287
|
type: "custom",
|
|
75476
|
-
title:
|
|
75477
|
-
description: `Agent "${
|
|
75478
|
-
details: { requirementId: req.id, priority: req.priority },
|
|
76288
|
+
title: req.title,
|
|
76289
|
+
description: `Agent "${creatorName}" proposed requirement "${req.title}" (priority: ${req.priority}).`,
|
|
76290
|
+
details: { requirementId: req.id, priority: req.priority, subType: "requirement" },
|
|
75479
76291
|
targetUserId: "all"
|
|
75480
76292
|
}).then((result) => {
|
|
75481
76293
|
const current = this.requirements.get(req.id);
|
|
@@ -75611,13 +76423,14 @@ var init_requirement_service = __esm({
|
|
|
75611
76423
|
this.broadcast("requirement:resubmitted", req);
|
|
75612
76424
|
log61.info("Requirement resubmitted for review", { id, hasUpdates: !!updates });
|
|
75613
76425
|
if (this.hitlService && req.source === "agent") {
|
|
76426
|
+
const creatorName = this.resolveAgentName(req.createdBy);
|
|
75614
76427
|
this.hitlService.requestApprovalAndWait({
|
|
75615
76428
|
agentId: req.createdBy,
|
|
75616
|
-
agentName:
|
|
76429
|
+
agentName: creatorName,
|
|
75617
76430
|
type: "custom",
|
|
75618
|
-
title:
|
|
75619
|
-
description: `Agent "${
|
|
75620
|
-
details: { requirementId: req.id, priority: req.priority },
|
|
76431
|
+
title: req.title,
|
|
76432
|
+
description: `Agent "${creatorName}" resubmitted requirement "${req.title}" (priority: ${req.priority}).`,
|
|
76433
|
+
details: { requirementId: req.id, priority: req.priority, subType: "requirement_resubmit" },
|
|
75621
76434
|
targetUserId: "all"
|
|
75622
76435
|
}).then((result) => {
|
|
75623
76436
|
const current = this.requirements.get(req.id);
|
|
@@ -75791,6 +76604,9 @@ var init_requirement_service = __esm({
|
|
|
75791
76604
|
const req = this.requirements.get(id);
|
|
75792
76605
|
if (!req)
|
|
75793
76606
|
throw new Error(`Requirement ${id} not found`);
|
|
76607
|
+
if (this.hitlService) {
|
|
76608
|
+
this.hitlService.cancelApprovalsByDetail("requirementId", id, cancelledBy ?? "system", "Requirement cancelled");
|
|
76609
|
+
}
|
|
75794
76610
|
const oldStatus = req.status;
|
|
75795
76611
|
req.status = "cancelled";
|
|
75796
76612
|
req.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -75884,6 +76700,9 @@ var init_requirement_service = __esm({
|
|
|
75884
76700
|
}
|
|
75885
76701
|
}
|
|
75886
76702
|
deleteRequirement(id) {
|
|
76703
|
+
if (this.hitlService) {
|
|
76704
|
+
this.hitlService.cancelApprovalsByDetail("requirementId", id, "system", "Requirement deleted");
|
|
76705
|
+
}
|
|
75887
76706
|
this.requirements.delete(id);
|
|
75888
76707
|
if (this.requirementRepo) {
|
|
75889
76708
|
this.requirementRepo.delete(id).catch((e) => log61.error("Failed to delete requirement from storage", { id, error: String(e) }));
|
|
@@ -75955,6 +76774,17 @@ var init_requirement_service = __esm({
|
|
|
75955
76774
|
});
|
|
75956
76775
|
}
|
|
75957
76776
|
}
|
|
76777
|
+
resolveAgentName(agentId2) {
|
|
76778
|
+
if (this.agentManager) {
|
|
76779
|
+
try {
|
|
76780
|
+
const agent = this.agentManager.getAgent(agentId2);
|
|
76781
|
+
if (agent)
|
|
76782
|
+
return agent.config?.name ?? agent.name ?? agentId2;
|
|
76783
|
+
} catch {
|
|
76784
|
+
}
|
|
76785
|
+
}
|
|
76786
|
+
return agentId2;
|
|
76787
|
+
}
|
|
75958
76788
|
broadcast(type, data) {
|
|
75959
76789
|
if (this.ws) {
|
|
75960
76790
|
this.ws.broadcast({
|
|
@@ -77106,13 +77936,19 @@ var init_stale_detector = __esm({
|
|
|
77106
77936
|
taskService;
|
|
77107
77937
|
config;
|
|
77108
77938
|
scanInterval;
|
|
77109
|
-
|
|
77939
|
+
onStaleItems;
|
|
77940
|
+
constructor(taskService, config, onStaleItems) {
|
|
77110
77941
|
this.taskService = taskService;
|
|
77111
77942
|
this.config = { ...DEFAULT_CONFIG4, ...config };
|
|
77943
|
+
this.onStaleItems = onStaleItems;
|
|
77112
77944
|
}
|
|
77113
77945
|
start(intervalMs = 36e5) {
|
|
77114
77946
|
this.scanInterval = setInterval(() => {
|
|
77115
|
-
this.scan().
|
|
77947
|
+
this.scan().then((items) => {
|
|
77948
|
+
if (items.length > 0 && this.onStaleItems) {
|
|
77949
|
+
this.onStaleItems(items);
|
|
77950
|
+
}
|
|
77951
|
+
}).catch((err) => log68.warn("Stale scan failed", { error: String(err) }));
|
|
77116
77952
|
}, intervalMs);
|
|
77117
77953
|
log68.info("Stale detector started", { intervalMs });
|
|
77118
77954
|
}
|
|
@@ -77208,7 +78044,7 @@ var init_scheduled_task_runner = __esm({
|
|
|
77208
78044
|
if (!task.scheduleConfig)
|
|
77209
78045
|
continue;
|
|
77210
78046
|
const config = task.scheduleConfig;
|
|
77211
|
-
if (config.maxRuns
|
|
78047
|
+
if (config.maxRuns && config.maxRuns > 0 && (config.currentRuns ?? 0) >= config.maxRuns) {
|
|
77212
78048
|
continue;
|
|
77213
78049
|
}
|
|
77214
78050
|
const nextRun = config.nextRunAt ? new Date(config.nextRunAt).getTime() : 0;
|
|
@@ -78717,6 +79553,10 @@ CREATE INDEX IF NOT EXISTS idx_st_entity ON status_transitions(entity_type, enti
|
|
|
78717
79553
|
}
|
|
78718
79554
|
return this.db.prepare("SELECT * FROM chat_sessions WHERE agent_id = ? ORDER BY is_main DESC, last_message_at DESC LIMIT ?").all(agentId2, limit).map((r) => this._mapSession(r));
|
|
78719
79555
|
}
|
|
79556
|
+
hasAnySessions(userId2) {
|
|
79557
|
+
const r = this.db.prepare("SELECT 1 FROM chat_sessions WHERE user_id = ? LIMIT 1").get(userId2);
|
|
79558
|
+
return r !== null && r !== void 0;
|
|
79559
|
+
}
|
|
78720
79560
|
getSession(sessionId) {
|
|
78721
79561
|
const r = this.db.prepare("SELECT * FROM chat_sessions WHERE id = ?").get(sessionId);
|
|
78722
79562
|
return r ? this._mapSession(r) : null;
|
|
@@ -80187,6 +81027,17 @@ CREATE INDEX IF NOT EXISTS idx_st_entity ON status_transitions(entity_type, enti
|
|
|
80187
81027
|
memberCount: r["member_count"]
|
|
80188
81028
|
}));
|
|
80189
81029
|
}
|
|
81030
|
+
listByMember(orgId2, memberId) {
|
|
81031
|
+
const rows = this.db.prepare(`SELECT g.*, (SELECT COUNT(*) FROM group_chat_members WHERE group_chat_id = g.id) AS member_count
|
|
81032
|
+
FROM group_chats g
|
|
81033
|
+
INNER JOIN group_chat_members m ON m.group_chat_id = g.id
|
|
81034
|
+
WHERE g.org_id = ? AND m.member_id = ?
|
|
81035
|
+
ORDER BY g.created_at DESC`).all(orgId2, memberId);
|
|
81036
|
+
return rows.map((r) => ({
|
|
81037
|
+
...this.mapRow(r),
|
|
81038
|
+
memberCount: r["member_count"]
|
|
81039
|
+
}));
|
|
81040
|
+
}
|
|
80190
81041
|
getById(id) {
|
|
80191
81042
|
const r = this.db.prepare("SELECT * FROM group_chats WHERE id = ?").get(id);
|
|
80192
81043
|
if (!r)
|
|
@@ -82081,10 +82932,10 @@ function registerStartCommand(program2) {
|
|
|
82081
82932
|
const configPath = globalOpts.config ?? getDefaultConfigPath();
|
|
82082
82933
|
if (opts.setup || !existsSync33(configPath)) {
|
|
82083
82934
|
if (!existsSync33(configPath)) {
|
|
82084
|
-
console.log(" No configuration found \u2014
|
|
82935
|
+
console.log(" No configuration found \u2014 auto-configuring from environment...\n");
|
|
82085
82936
|
}
|
|
82086
82937
|
const { quickInit: quickInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
82087
|
-
await quickInit2();
|
|
82938
|
+
await quickInit2({ nonInteractive: true });
|
|
82088
82939
|
}
|
|
82089
82940
|
const config = loadConfig(globalOpts.config);
|
|
82090
82941
|
await startServer(config, { port: globalOpts.port, config: globalOpts.config });
|
|
@@ -82327,7 +83178,8 @@ async function startServer(config, values) {
|
|
|
82327
83178
|
startupLog("INFO", " 2. \u4EA4\u4E92\u5F0F\u914D\u7F6E \u2192 \u6B63\u5728\u542F\u52A8\u5411\u5BFC...");
|
|
82328
83179
|
startupBlank();
|
|
82329
83180
|
const { quickInit: quickInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
82330
|
-
|
|
83181
|
+
startupLog("INFO", "\u81EA\u52A8\u4ECE\u73AF\u5883\u53D8\u91CF/\u5DF2\u77E5\u914D\u7F6E\u5BFC\u5165 LLM \u8BBE\u7F6E...");
|
|
83182
|
+
await quickInit2({ nonInteractive: true });
|
|
82331
83183
|
const { loadConfig: reloadConfig } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
82332
83184
|
const updatedConfig = reloadConfig(values["config"]);
|
|
82333
83185
|
for (const [name, cfg] of Object.entries(updatedConfig.llm?.providers ?? {})) {
|
|
@@ -82442,6 +83294,21 @@ async function startServer(config, values) {
|
|
|
82442
83294
|
const archiveService = new ArchiveService(taskService, projectService);
|
|
82443
83295
|
archiveService.setRequirementService(requirementService);
|
|
82444
83296
|
archiveService.start();
|
|
83297
|
+
const staleDetector = new StaleDetector(taskService, void 0, (items) => {
|
|
83298
|
+
for (const item of items) {
|
|
83299
|
+
hitlService.notify({
|
|
83300
|
+
targetUserId: "all",
|
|
83301
|
+
type: "system",
|
|
83302
|
+
title: item.type === "review_stale" ? "Stale review" : item.type === "stuck_task" ? "Stuck task" : "Unstarted task",
|
|
83303
|
+
body: item.message,
|
|
83304
|
+
priority: item.type === "review_stale" ? "high" : "normal",
|
|
83305
|
+
actionType: item.taskId ? "navigate" : "none",
|
|
83306
|
+
actionTarget: item.taskId ? JSON.stringify({ path: `/work?openTask=${item.taskId}` }) : void 0,
|
|
83307
|
+
metadata: { taskId: item.taskId, agentId: item.agentId, staleType: item.type }
|
|
83308
|
+
});
|
|
83309
|
+
}
|
|
83310
|
+
});
|
|
83311
|
+
staleDetector.start();
|
|
82445
83312
|
apiServer.setLLMRouter(llmRouter);
|
|
82446
83313
|
apiServer.setConfigPath(values["config"] ?? getDefaultConfigPath());
|
|
82447
83314
|
if (config.hub?.url) apiServer.setHubUrl(config.hub.url);
|
|
@@ -82475,6 +83342,10 @@ async function startServer(config, values) {
|
|
|
82475
83342
|
orgService.registerBuilderContextProviders(skillRegistry);
|
|
82476
83343
|
const builderService = apiServer.getBuilderService();
|
|
82477
83344
|
if (builderService) {
|
|
83345
|
+
const builtinTeamsDir = resolveTemplatesDir("teams");
|
|
83346
|
+
if (builtinTeamsDir && existsSync33(builtinTeamsDir)) {
|
|
83347
|
+
builderService.setBuiltinTeamTemplatesDir(builtinTeamsDir);
|
|
83348
|
+
}
|
|
82478
83349
|
agentManager.setBuilderService(builderService);
|
|
82479
83350
|
}
|
|
82480
83351
|
const hubClient = apiServer.getHubClient();
|
|
@@ -82506,6 +83377,7 @@ async function startServer(config, values) {
|
|
|
82506
83377
|
return { installed: result.installed, name: result.name, method: result.method };
|
|
82507
83378
|
});
|
|
82508
83379
|
agentManager.setUserApprovalRequester(async (opts) => {
|
|
83380
|
+
const taskTitle = opts.relatedTaskId ? taskService.getTask(opts.relatedTaskId)?.title : void 0;
|
|
82509
83381
|
return hitlService.requestApprovalAndWait({
|
|
82510
83382
|
agentId: opts.agentId,
|
|
82511
83383
|
agentName: opts.agentName,
|
|
@@ -82515,7 +83387,7 @@ async function startServer(config, values) {
|
|
|
82515
83387
|
targetUserId: ownerUserId,
|
|
82516
83388
|
options: opts.options,
|
|
82517
83389
|
allowFreeform: opts.allowFreeform,
|
|
82518
|
-
details: { priority: opts.priority, taskId: opts.relatedTaskId }
|
|
83390
|
+
details: { priority: opts.priority, taskId: opts.relatedTaskId, taskTitle }
|
|
82519
83391
|
});
|
|
82520
83392
|
});
|
|
82521
83393
|
agentManager.setUserNotifier((opts) => {
|
|
@@ -82591,7 +83463,8 @@ async function startServer(config, values) {
|
|
|
82591
83463
|
agentManager.getEventBus().on("agent:notify-user", async (evt) => {
|
|
82592
83464
|
const { agentId: agentId2, title, body, priority, taskId: taskId2, requirementId: requirementId2, targetUserId } = evt;
|
|
82593
83465
|
try {
|
|
82594
|
-
const
|
|
83466
|
+
const sessionUserId = targetUserId || defaultSessionUserId;
|
|
83467
|
+
const mainSession = storage.chatSessionRepo.getOrCreateMainSession(agentId2, sessionUserId);
|
|
82595
83468
|
const agent = agentManager.getAgent(agentId2);
|
|
82596
83469
|
const formattedMsg = `**${title}**
|
|
82597
83470
|
|
|
@@ -82607,7 +83480,7 @@ ${body}`;
|
|
|
82607
83480
|
storage.chatSessionRepo.updateLastMessage(mainSession.id);
|
|
82608
83481
|
ws.broadcastProactiveMessage(agentId2, agent.config.name, mainSession.id, msg.id, formattedMsg, {
|
|
82609
83482
|
isMainSession: true
|
|
82610
|
-
},
|
|
83483
|
+
}, sessionUserId);
|
|
82611
83484
|
const hasTask = !!taskId2;
|
|
82612
83485
|
hitlService.notify({
|
|
82613
83486
|
targetUserId: targetUserId ?? "all",
|
|
@@ -82771,13 +83644,14 @@ ${reason}`;
|
|
|
82771
83644
|
const reasonMatch = request.reason.match(/requires approval:\s*(.+?)\.?\s*Command:/);
|
|
82772
83645
|
title = reasonMatch ? `Git: ${reasonMatch[1]}` : "Shell: command approval";
|
|
82773
83646
|
}
|
|
83647
|
+
const taskTitle = request.taskId ? taskService.getTask(request.taskId)?.title : void 0;
|
|
82774
83648
|
const result = await hitlService.requestApprovalAndWait({
|
|
82775
83649
|
agentId: agentId2,
|
|
82776
83650
|
agentName,
|
|
82777
83651
|
type: "action",
|
|
82778
83652
|
title,
|
|
82779
83653
|
description: request.reason,
|
|
82780
|
-
details: { ...request.toolArgs, toolName: request.toolName, agentId: agentId2, taskId: request.taskId },
|
|
83654
|
+
details: { ...request.toolArgs, toolName: request.toolName, agentId: agentId2, taskId: request.taskId, taskTitle },
|
|
82781
83655
|
targetUserId: ownerUserId
|
|
82782
83656
|
});
|
|
82783
83657
|
auditService.record({
|
|
@@ -83278,6 +84152,7 @@ ${reason}`;
|
|
|
83278
84152
|
closeStartupLogger();
|
|
83279
84153
|
closeRuntimeLogger();
|
|
83280
84154
|
archiveService.stop();
|
|
84155
|
+
staleDetector.stop();
|
|
83281
84156
|
scheduledTaskRunner.stop();
|
|
83282
84157
|
apiServer.stop();
|
|
83283
84158
|
agentManager.shutdown().then(() => messageRouter.disconnectAll()).then(() => process.exit(0)).catch(() => process.exit(1));
|