Merge branch origin/copilot/add-codex-digest-agent into main

This commit is contained in:
Alexa Amundson
2025-11-25 13:44:35 -06:00
6 changed files with 579 additions and 0 deletions

84
base-agent.template.json Normal file
View File

@@ -0,0 +1,84 @@
{
"$schema": "./schemas/agent-spec.schema.json",
"description": "Base template for creating new Lucidia agents. Copy and customize for your agent.",
"template": {
"id": "{{agent-id}}",
"name": "{{Agent Display Name}}",
"role": "{{role: interpreter | sentinel | documenter | validator | orchestrator}}",
"source": "bot/{{agent-name}}.js",
"traits": [
"{{trait-1}}",
"{{trait-2}}"
],
"inputs": ["{{input-type-1}}", "{{input-type-2}}"],
"outputs": ["{{output-type-1}}", "{{output-type-2}}"],
"triggers": ["{{trigger-type::value}}"],
"inherits_from": "{{base-agent-type or null}}"
},
"available_roles": [
{
"role": "interpreter",
"description": "Processes and interprets data, generates summaries and insights",
"base_template": "base-interpreter-agent"
},
{
"role": "sentinel",
"description": "Monitors for specific events and triggers alerts",
"base_template": "base-sentinel-agent"
},
{
"role": "documenter",
"description": "Creates and maintains documentation from project data",
"base_template": "base-documenter-agent"
},
{
"role": "validator",
"description": "Validates code quality, tests, and compliance",
"base_template": "base-validator-agent"
},
{
"role": "orchestrator",
"description": "Coordinates other agents and manages workflows",
"base_template": "base-orchestrator-agent"
}
],
"available_trigger_types": [
{
"type": "cron",
"syntax": "cron::{schedule}",
"examples": ["cron::weekly", "cron::daily", "cron::hourly", "cron::0 9 * * 1"]
},
{
"type": "command",
"syntax": "command::{command text}",
"examples": ["command::summarize agent performance", "command::generate docs"]
},
{
"type": "reaction",
"syntax": "reaction::{emoji}",
"examples": ["reaction::🛟", "reaction::❌", "reaction::✅"]
},
{
"type": "event",
"syntax": "event::{github_event}",
"examples": ["event::pr_merged", "event::issue_created", "event::test_complete"]
},
{
"type": "alert",
"syntax": "alert::{agent-id}",
"examples": ["alert::guardian-agent", "alert::qa-agent"]
}
],
"common_traits": [
"executive-tone",
"emoji-native",
"math-ratio-logic",
"markdown-output",
"verbose-logging",
"alert-driven",
"test-aware",
"coverage-focused",
"strategic-planning",
"changelog-aware"
]
}

136
bot/digest.js Normal file
View File

@@ -0,0 +1,136 @@
// bot/digest.js
// Codex Digest Agent - interprets emoji digests and weekly stats
/**
* Codex Digest Agent
* Role: Interpreter
* Traits: executive-tone, emoji-native, math-ratio-logic, markdown-output
*/
class CodexDigestAgent {
constructor() {
this.agentId = "codex-digest-agent";
this.role = "interpreter";
}
/**
* Process emoji digest input and generate markdown summary
* @param {Object} input - Input containing emoji-digest and weekly-stats
* @returns {Object} - Output containing markdown-summary and action-recommendations
*/
process(input) {
const { emojiDigest = {}, weeklyStats = {} } = input;
const summary = this.generateMarkdownSummary(emojiDigest, weeklyStats);
const recommendations = this.generateActionRecommendations(weeklyStats);
return {
markdownSummary: summary,
actionRecommendations: recommendations,
};
}
/**
* Generate a markdown summary from the emoji digest
* @param {Object} emojiDigest - Emoji status mappings
* @param {Object} weeklyStats - Weekly statistics
* @returns {string} - Markdown formatted summary
*/
generateMarkdownSummary(emojiDigest, weeklyStats) {
const lines = [
"# 📊 Weekly Codex Digest Report",
"",
"## Status Overview",
"",
];
// Process emoji digest
if (Object.keys(emojiDigest).length > 0) {
lines.push("| Emoji | Status | Count |");
lines.push("|-------|--------|-------|");
for (const [emoji, data] of Object.entries(emojiDigest)) {
const status = data.status || "Unknown";
const count = data.count || 0;
lines.push(`| ${emoji} | ${status} | ${count} |`);
}
lines.push("");
}
// Process weekly stats
if (Object.keys(weeklyStats).length > 0) {
lines.push("## 📈 Weekly Statistics");
lines.push("");
for (const [key, value] of Object.entries(weeklyStats)) {
lines.push(`- **${key}**: ${value}`);
}
lines.push("");
}
lines.push(`*Generated by ${this.agentId} at ${new Date().toISOString()}*`);
return lines.join("\n");
}
/**
* Generate action recommendations based on stats
* @param {Object} weeklyStats - Weekly statistics
* @returns {Array<string>} - List of recommended actions
*/
generateActionRecommendations(weeklyStats) {
const recommendations = [];
const escalations = weeklyStats.escalations || 0;
const blocked = weeklyStats.blocked || 0;
const completionRate = weeklyStats.completionRate || 0;
if (escalations > 10) {
recommendations.push("🚨 High escalation count detected. Trigger planner-agent for resource reallocation.");
}
if (blocked > 5) {
recommendations.push("⚠️ Multiple blocked items. Review blockers with team leads.");
}
if (completionRate < 70) {
recommendations.push("📉 Completion rate below target. Consider sprint capacity adjustment.");
}
if (recommendations.length === 0) {
recommendations.push("✅ All metrics within healthy ranges. Continue current workflow.");
}
return recommendations;
}
}
// Export for use in other modules
module.exports = { CodexDigestAgent };
// CLI execution
if (require.main === module) {
console.log("🤖 Codex Digest Agent Activated");
const agent = new CodexDigestAgent();
// Example input for testing
const sampleInput = {
emojiDigest: {
"✅": { status: "Done", count: 15 },
"🟡": { status: "In Progress", count: 8 },
"❌": { status: "Blocked", count: 2 },
"🛟": { status: "Escalation", count: 3 },
},
weeklyStats: {
totalTasks: 30,
completed: 15,
inProgress: 8,
blocked: 2,
escalations: 3,
completionRate: 50,
},
};
const result = agent.process(sampleInput);
console.log(result.markdownSummary);
console.log("\n📋 Recommendations:");
result.actionRecommendations.forEach((rec) => console.log(` ${rec}`));
}

135
docs/agent-registry.md Normal file
View File

@@ -0,0 +1,135 @@
# 🤖 Lucidia Agent Registry
The Lucidia Agent Registry (`lucidia.agent-spec.json`) defines all agents available in the BlackRoad OS orchestration system.
## Overview
Agents are runnable processes that can be triggered by:
- **Cron schedules** (e.g., `cron::weekly`)
- **Commands** (e.g., `command::summarize agent performance`)
- **Reactions** (e.g., `reaction::🛟`)
- **Events** (e.g., `event::pr_merged`)
- **Alerts from other agents** (e.g., `alert::guardian-agent`)
## Registered Agents
### 🧠 Codex Digest Agent
| Property | Value |
|----------|-------|
| **ID** | `codex-digest-agent` |
| **Role** | Interpreter |
| **Source** | `bot/digest.js` |
| **Triggers** | `cron::weekly`, `command::summarize agent performance` |
**Traits:** executive-tone, emoji-native, math-ratio-logic, markdown-output
**Inputs:** emoji-digest, weekly-stats
**Outputs:** markdown-summary, action-recommendations
---
### 🛡️ Guardian Agent
| Property | Value |
|----------|-------|
| **ID** | `guardian-agent` |
| **Role** | Sentinel |
| **Source** | `bot/guardian.js` |
| **Triggers** | `reaction::🛟`, `reaction::❌` |
**Traits:** alert-driven, emoji-native, escalation-handler
**Alerts:** planner-agent
---
### 📝 Scribe Agent
| Property | Value |
|----------|-------|
| **ID** | `scribe-agent` |
| **Role** | Documenter |
| **Source** | `bot/scribe.js` |
| **Triggers** | `event::pr_merged`, `command::generate docs` |
**Traits:** verbose-logging, markdown-output, changelog-aware
---
### ✅ QA Agent
| Property | Value |
|----------|-------|
| **ID** | `qa-agent` |
| **Role** | Validator |
| **Source** | `bot/qa.js` |
| **Triggers** | `event::test_complete`, `cron::daily` |
**Traits:** test-aware, coverage-focused, regression-detector
---
### 📋 Planner Agent
| Property | Value |
|----------|-------|
| **ID** | `planner-agent` |
| **Role** | Orchestrator |
| **Source** | `bot/planner.js` |
| **Triggers** | `alert::guardian-agent`, `cron::hourly`, `command::replan` |
**Traits:** strategic-planning, priority-aware, resource-optimizer
---
## Creating New Agents
Use the `base-agent.template.json` as a starting point for new agents:
```json
{
"id": "my-new-agent",
"name": "My New Agent",
"role": "interpreter",
"source": "bot/my-new-agent.js",
"traits": ["trait-1", "trait-2"],
"inputs": ["input-type"],
"outputs": ["output-type"],
"triggers": ["cron::daily"],
"inherits_from": "base-interpreter-agent"
}
```
## Agent Roles
| Role | Description |
|------|-------------|
| **interpreter** | Processes and interprets data, generates summaries |
| **sentinel** | Monitors for specific events and triggers alerts |
| **documenter** | Creates and maintains documentation |
| **validator** | Validates code quality, tests, and compliance |
| **orchestrator** | Coordinates other agents and manages workflows |
## Orchestration Flows
Agents can be chained together using orchestration flows:
```yaml
if escalations > 10:
trigger: codex-digest-agent
then: planner-agent
```
## Integration
The registry integrates with:
- ✅ GitHub Actions via reaction triggers
- ✅ Lucidia Prism Console for visualization
- ✅ RoadChain smart triggers for deployment
- ✅ Emoji Bot Config (`emoji-bot-config.yml`)
---
*Powered by BlackRoad OS 🖤🛣️*

82
lucidia.agent-spec.json Normal file
View File

@@ -0,0 +1,82 @@
{
"$schema": "./schemas/agent-spec.schema.json",
"version": "1.0.0",
"agents": [
{
"id": "codex-digest-agent",
"name": "Codex Digest Agent",
"role": "interpreter",
"source": "bot/digest.js",
"traits": [
"executive-tone",
"emoji-native",
"math-ratio-logic",
"markdown-output"
],
"inputs": ["emoji-digest", "weekly-stats"],
"outputs": ["markdown-summary", "action-recommendations"],
"triggers": ["cron::weekly", "command::summarize agent performance"],
"inherits_from": "base-interpreter-agent"
},
{
"id": "guardian-agent",
"name": "Guardian Agent",
"role": "sentinel",
"source": "bot/guardian.js",
"traits": [
"alert-driven",
"emoji-native",
"escalation-handler"
],
"inputs": ["escalation-events", "reaction-triggers"],
"outputs": ["alert-notifications", "status-updates"],
"triggers": ["reaction::🛟", "reaction::❌"],
"alerts": ["planner-agent"]
},
{
"id": "scribe-agent",
"name": "Scribe Agent",
"role": "documenter",
"source": "bot/scribe.js",
"traits": [
"verbose-logging",
"markdown-output",
"changelog-aware"
],
"inputs": ["commit-history", "pr-metadata"],
"outputs": ["documentation", "changelog-entries"],
"triggers": ["event::pr_merged", "command::generate docs"],
"inherits_from": "base-documenter-agent"
},
{
"id": "qa-agent",
"name": "QA Agent",
"role": "validator",
"source": "bot/qa.js",
"traits": [
"test-aware",
"coverage-focused",
"regression-detector"
],
"inputs": ["test-results", "coverage-reports"],
"outputs": ["test-summaries", "regression-alerts"],
"triggers": ["event::test_complete", "cron::daily"],
"inherits_from": "base-validator-agent"
},
{
"id": "planner-agent",
"name": "Planner Agent",
"role": "orchestrator",
"source": "bot/planner.js",
"traits": [
"strategic-planning",
"priority-aware",
"resource-optimizer"
],
"inputs": ["agent-alerts", "project-status", "escalations"],
"outputs": ["task-assignments", "priority-updates", "workflow-triggers"],
"triggers": ["alert::guardian-agent", "cron::hourly", "command::replan"],
"inherits_from": "base-orchestrator-agent"
}
]
}

76
tests/agentSpec.test.ts Normal file
View File

@@ -0,0 +1,76 @@
import { describe, it, expect } from "vitest";
import fs from "fs";
import path from "path";
describe("lucidia.agent-spec.json", () => {
const specPath = path.resolve(__dirname, "../lucidia.agent-spec.json");
const spec = JSON.parse(fs.readFileSync(specPath, "utf-8"));
it("should have a valid version", () => {
expect(spec.version).toBe("1.0.0");
});
it("should have an agents array", () => {
expect(Array.isArray(spec.agents)).toBe(true);
expect(spec.agents.length).toBeGreaterThan(0);
});
it("should include codex-digest-agent", () => {
const codexAgent = spec.agents.find((a: any) => a.id === "codex-digest-agent");
expect(codexAgent).toBeDefined();
expect(codexAgent.role).toBe("interpreter");
expect(codexAgent.source).toBe("bot/digest.js");
expect(codexAgent.traits).toContain("emoji-native");
expect(codexAgent.triggers).toContain("cron::weekly");
});
it("should include guardian-agent", () => {
const guardianAgent = spec.agents.find((a: any) => a.id === "guardian-agent");
expect(guardianAgent).toBeDefined();
expect(guardianAgent.role).toBe("sentinel");
expect(guardianAgent.triggers).toContain("reaction::🛟");
expect(guardianAgent.alerts).toContain("planner-agent");
});
it("should include planner-agent referenced by guardian-agent", () => {
const plannerAgent = spec.agents.find((a: any) => a.id === "planner-agent");
expect(plannerAgent).toBeDefined();
expect(plannerAgent.role).toBe("orchestrator");
});
it("all agents should have required fields", () => {
spec.agents.forEach((agent: any) => {
expect(agent.id).toBeDefined();
expect(agent.role).toBeDefined();
expect(agent.triggers).toBeDefined();
expect(Array.isArray(agent.triggers)).toBe(true);
});
});
});
describe("base-agent.template.json", () => {
const templatePath = path.resolve(__dirname, "../base-agent.template.json");
const template = JSON.parse(fs.readFileSync(templatePath, "utf-8"));
it("should have a template object", () => {
expect(template.template).toBeDefined();
expect(template.template.id).toBeDefined();
expect(template.template.role).toBeDefined();
});
it("should have available roles", () => {
expect(Array.isArray(template.available_roles)).toBe(true);
const roleNames = template.available_roles.map((r: any) => r.role);
expect(roleNames).toContain("interpreter");
expect(roleNames).toContain("sentinel");
expect(roleNames).toContain("orchestrator");
});
it("should have trigger types documentation", () => {
expect(Array.isArray(template.available_trigger_types)).toBe(true);
const triggerTypes = template.available_trigger_types.map((t: any) => t.type);
expect(triggerTypes).toContain("cron");
expect(triggerTypes).toContain("reaction");
expect(triggerTypes).toContain("command");
});
});

66
tests/digestAgent.test.ts Normal file
View File

@@ -0,0 +1,66 @@
import { describe, it, expect } from "vitest";
const { CodexDigestAgent } = require("../bot/digest.js");
describe("CodexDigestAgent", () => {
it("should create an agent with correct id and role", () => {
const agent = new CodexDigestAgent();
expect(agent.agentId).toBe("codex-digest-agent");
expect(agent.role).toBe("interpreter");
});
it("should generate markdown summary from emoji digest", () => {
const agent = new CodexDigestAgent();
const input = {
emojiDigest: {
"✅": { status: "Done", count: 10 },
"🟡": { status: "In Progress", count: 5 },
},
weeklyStats: {
totalTasks: 15,
completed: 10,
},
};
const result = agent.process(input);
expect(result.markdownSummary).toContain("# 📊 Weekly Codex Digest Report");
expect(result.markdownSummary).toContain("✅");
expect(result.markdownSummary).toContain("Done");
expect(result.markdownSummary).toContain("10");
});
it("should generate action recommendations for high escalations", () => {
const agent = new CodexDigestAgent();
const input = {
emojiDigest: {},
weeklyStats: {
escalations: 15,
},
};
const result = agent.process(input);
expect(result.actionRecommendations).toContain(
"🚨 High escalation count detected. Trigger planner-agent for resource reallocation."
);
});
it("should generate healthy status when metrics are good", () => {
const agent = new CodexDigestAgent();
const input = {
emojiDigest: {},
weeklyStats: {
escalations: 0,
blocked: 0,
completionRate: 85,
},
};
const result = agent.process(input);
expect(result.actionRecommendations).toContain(
"✅ All metrics within healthy ranges. Continue current workflow."
);
});
});