titan-agent 5.4.0 → 5.4.2
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/agent/agent.js +1 -1
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/agentLoop.js +77 -12
- package/dist/agent/agentLoop.js.map +1 -1
- package/dist/agent/agentWakeup.js +8 -3
- package/dist/agent/agentWakeup.js.map +1 -1
- package/dist/agent/commandPost.js +6 -1
- package/dist/agent/commandPost.js.map +1 -1
- package/dist/agent/heartbeatScheduler.js +36 -4
- package/dist/agent/heartbeatScheduler.js.map +1 -1
- package/dist/agent/toolRunner.js +30 -0
- package/dist/agent/toolRunner.js.map +1 -1
- package/dist/config/config.js +30 -8
- package/dist/config/config.js.map +1 -1
- package/dist/config/schema.js +10 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/eval/record.js +1 -1
- package/dist/eval/record.js.map +1 -1
- package/dist/gateway/server.js +26 -0
- package/dist/gateway/server.js.map +1 -1
- package/dist/mesh/transport.js +60 -8
- package/dist/mesh/transport.js.map +1 -1
- package/dist/providers/anthropic.js +3 -2
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/base.js.map +1 -1
- package/dist/providers/google.js +94 -20
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/modelCapabilities.js +59 -0
- package/dist/providers/modelCapabilities.js.map +1 -0
- package/dist/providers/ollama.js +3 -2
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai.js +4 -3
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openai_compat.js +3 -2
- package/dist/providers/openai_compat.js.map +1 -1
- package/dist/providers/router.js +63 -21
- package/dist/providers/router.js.map +1 -1
- package/dist/skills/registry.js +176 -163
- package/dist/skills/registry.js.map +1 -1
- package/dist/telemetry/activityLog.js +1 -1
- package/dist/telemetry/activityLog.js.map +1 -1
- package/dist/utils/constants.js +2 -2
- package/dist/utils/constants.js.map +1 -1
- package/docs/AGENT-HIERARCHY.md +154 -0
- package/docs/superpowers/plans/2026-04-29-titan-production-fix.md +241 -0
- package/package.json +2 -2
- package/scripts/start-workers.sh +39 -0
- package/scripts/task-feeder.ts +38 -0
package/dist/eval/record.js
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
import { existsSync, mkdirSync, readdirSync, writeFileSync, statSync, rmSync } from "fs";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { createHash } from "crypto";
|
|
5
|
+
import { loadConfig } from "../config/config.js";
|
|
5
6
|
let _retentionDaysOverride;
|
|
6
7
|
const AUTO_DIR = join(process.cwd(), "tests", "fixtures", "tapes", "auto");
|
|
7
8
|
const DEFAULT_RETENTION_DAYS = 30;
|
|
8
9
|
function getRetentionDays() {
|
|
9
10
|
if (_retentionDaysOverride !== void 0) return _retentionDaysOverride;
|
|
10
11
|
try {
|
|
11
|
-
const { loadConfig } = require("../config/config.js");
|
|
12
12
|
const config = loadConfig();
|
|
13
13
|
const days = config.eval?.autoCorpus?.retentionDays;
|
|
14
14
|
if (typeof days === "number" && days >= 0) return days;
|
package/dist/eval/record.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/eval/record.ts"],"sourcesContent":["/**\n * TITAN — Auto-Corpus Expansion (Phase 6)\n *\n * When a production trace fails eval, automatically add it to the tape corpus.\n * Deduplication prevents bloating. Configurable retention purges old auto-tapes.\n */\nimport { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, statSync, rmSync } from 'fs';\nimport { join } from 'path';\nimport { createHash } from 'crypto';\nimport type { EvalCase, EvalResult } from './harness.js';\n\nlet _retentionDaysOverride: number | undefined;\n\nconst AUTO_DIR = join(process.cwd(), 'tests', 'fixtures', 'tapes', 'auto');\nconst DEFAULT_RETENTION_DAYS = 30;\n\n/**\n * Read the auto-corpus retention days from titan.json config.\n * Falls back to DEFAULT_RETENTION_DAYS if config fails to load.\n */\nexport function getRetentionDays(): number {\n if (_retentionDaysOverride !== undefined) return _retentionDaysOverride;\n try {\n const
|
|
1
|
+
{"version":3,"sources":["../../src/eval/record.ts"],"sourcesContent":["/**\n * TITAN — Auto-Corpus Expansion (Phase 6)\n *\n * When a production trace fails eval, automatically add it to the tape corpus.\n * Deduplication prevents bloating. Configurable retention purges old auto-tapes.\n */\nimport { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, statSync, rmSync } from 'fs';\nimport { join } from 'path';\nimport { createHash } from 'crypto';\nimport { loadConfig } from '../config/config.js';\nimport type { EvalCase, EvalResult } from './harness.js';\n\nlet _retentionDaysOverride: number | undefined;\n\nconst AUTO_DIR = join(process.cwd(), 'tests', 'fixtures', 'tapes', 'auto');\nconst DEFAULT_RETENTION_DAYS = 30;\n\n/**\n * Read the auto-corpus retention days from titan.json config.\n * Falls back to DEFAULT_RETENTION_DAYS if config fails to load.\n *\n * Note: pre-fix this used `require('../config/config.js')` inside the\n * function body to defer module load. Switched to a static ESM import\n * because (a) ESLint forbids `require()` style imports under\n * `@typescript-eslint/no-require-imports` and (b) there is no circular\n * dependency — config.ts does not import this module. The try/catch\n * still handles a thrown `loadConfig()` from a malformed titan.json.\n */\nexport function getRetentionDays(): number {\n if (_retentionDaysOverride !== undefined) return _retentionDaysOverride;\n try {\n const config = loadConfig();\n const days = config.eval?.autoCorpus?.retentionDays;\n if (typeof days === 'number' && days >= 0) return days;\n } catch {\n // loadConfig() can throw on malformed titan.json — fall back to default.\n }\n return DEFAULT_RETENTION_DAYS;\n}\n\n/** Test-only: override the retention days without touching config files */\nexport function _setRetentionDaysOverride(days: number | undefined): void {\n _retentionDaysOverride = days;\n}\n\n/** Compute a stable hash of the input for deduplication */\nfunction hashInput(input: string): string {\n return createHash('sha256').update(input).digest('hex').slice(0, 16);\n}\n\n/** Ensure the auto-tape directory exists */\nfunction ensureAutoDir(): void {\n if (!existsSync(AUTO_DIR)) {\n mkdirSync(AUTO_DIR, { recursive: true });\n }\n}\n\n/** Build a tape filename from metadata */\nfunction buildTapeName(suite: string, name: string, timestamp: number, inputHash: string): string {\n const safeSuite = suite.replace(/[^a-z0-9_-]/gi, '_');\n const safeName = name.replace(/[^a-z0-9_-]/gi, '_');\n return `${timestamp}_${safeSuite}_${safeName}_${inputHash}.json`;\n}\n\n/** Check if an auto-tape with the same input hash already exists */\nfunction hasExistingTape(inputHash: string): boolean {\n if (!existsSync(AUTO_DIR)) return false;\n const files = readdirSync(AUTO_DIR);\n return files.some(f => f.includes(`_${inputHash}.json`));\n}\n\nexport interface RecordOptions {\n suite?: string;\n name?: string;\n retentionDays?: number;\n}\n\nexport interface RecordedTape {\n path: string;\n deduplicated: boolean;\n inputHash: string;\n}\n\n/**\n * Record a failed eval trace as a new auto-tape.\n *\n * Returns the path to the written file, or null if deduplicated.\n * Throws on I/O errors.\n */\nexport function recordFailedTrace(\n input: string,\n expected: EvalCase,\n actual: EvalResult,\n options: RecordOptions = {},\n): RecordedTape {\n ensureAutoDir();\n\n const inputHash = hashInput(input);\n\n if (hasExistingTape(inputHash)) {\n return { path: '', deduplicated: true, inputHash };\n }\n\n const timestamp = Date.now();\n const suite = options.suite || 'unknown';\n const name = options.name || expected.name || 'untitled';\n const filename = buildTapeName(suite, name, timestamp, inputHash);\n const filepath = join(AUTO_DIR, filename);\n\n const tape = {\n name,\n suite,\n model: 'auto-corpus',\n recorded_at: new Date(timestamp).toISOString(),\n titan_version: process.env.npm_package_version || '0.0.0',\n input,\n expected: {\n tools: expected.expectedTools,\n toolSequence: expected.expectedToolSequence,\n content: expected.expectedContent?.toString(),\n forbiddenTools: expected.forbiddenTools,\n },\n actual: {\n passed: actual.passed,\n errors: actual.errors,\n toolsUsed: actual.toolsUsed,\n content: actual.content,\n },\n exchanges: [],\n };\n\n writeFileSync(filepath, JSON.stringify(tape, null, 2), 'utf-8');\n\n return { path: filepath, deduplicated: false, inputHash };\n}\n\n/**\n * Purge auto-tapes older than the retention threshold.\n *\n * Returns the number of files removed.\n */\nexport function purgeOldAutoTapes(retentionDays?: number): number {\n const days = retentionDays ?? getRetentionDays();\n if (days === 0) return 0; // 0 = never purge\n if (!existsSync(AUTO_DIR)) return 0;\n\n const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;\n const files = readdirSync(AUTO_DIR);\n let removed = 0;\n\n for (const file of files) {\n const filepath = join(AUTO_DIR, file);\n try {\n const stats = statSync(filepath);\n if (stats.mtimeMs < cutoff) {\n rmSync(filepath);\n removed++;\n }\n } catch {\n // Ignore stat/rm errors on individual files\n }\n }\n\n return removed;\n}\n\n/**\n * List all auto-tapes with metadata.\n */\nexport function listAutoTapes(): Array<{ name: string; path: string; size: number; mtime: Date }> {\n if (!existsSync(AUTO_DIR)) return [];\n\n return readdirSync(AUTO_DIR)\n .filter(f => f.endsWith('.json'))\n .map(f => {\n const filepath = join(AUTO_DIR, f);\n const stats = statSync(filepath);\n return {\n name: f,\n path: filepath,\n size: stats.size,\n mtime: stats.mtime,\n };\n })\n .sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n}\n"],"mappings":"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","names":[]}
|
package/dist/gateway/server.js
CHANGED
|
@@ -66,6 +66,7 @@ import { initAutopilot, stopAutopilot, runAutopilotNow, getAutopilotStatus, getR
|
|
|
66
66
|
import { initDaemon, stopDaemon, getDaemonStatus, pauseDaemonManual, resumeDaemon, titanEvents } from "../agent/daemon.js";
|
|
67
67
|
import { initCommandPost, shutdownCommandPost, isCommandPostEnabled, getDashboard as getCPDashboard, getRegisteredAgents, reportHeartbeat, removeAgent, checkoutTask, checkinTask, getActiveCheckouts, getBudgetPolicies, createBudgetPolicy, updateBudgetPolicy, deleteBudgetPolicy, getActivity, getGoalTree, getAncestryChain, validateGoalAncestry, validateGoalParentAssignment, sweepExpiredCheckoutsManual, getStaleAgents, enforceBudgetForAgent, getBudgetPolicyForAgent, createIssue, updateIssue, getIssue, listIssues, searchIssues, checkoutIssue, deleteIssue, addIssueComment, getIssueComments, createApproval, approveApproval, rejectApproval, listApprovals, replyToApproval, snoozeApproval, unsnoozeApproval, batchApprove, batchReject, getAgentMessages, markAgentMessageRead, startRun, listRuns, getOrgTree, updateRegisteredAgent } from "../agent/commandPost.js";
|
|
68
68
|
import { initWakeupSystem, getAgentInbox, queueWakeup, getWakeupRequest, cancelWakeup, drainPendingResults } from "../agent/agentWakeup.js";
|
|
69
|
+
import { initHeartbeatScheduler } from "../agent/heartbeatScheduler.js";
|
|
69
70
|
import { queryAuditLog, getAuditStats } from "../agent/auditLog.js";
|
|
70
71
|
import { listGoals, createGoal, getGoal, deleteGoal, updateGoal, completeSubtask, addSubtask, dedupeGoalsBulk } from "../agent/goals.js";
|
|
71
72
|
import { startTunnel, stopTunnel, getTunnelStatus } from "../utils/tunnel.js";
|
|
@@ -3201,6 +3202,21 @@ data: ${JSON.stringify({ timestamp: Date.now() })}
|
|
|
3201
3202
|
safeWrite(`event: round
|
|
3202
3203
|
data: ${JSON.stringify({ round, maxRounds, timestamp: Date.now() })}
|
|
3203
3204
|
|
|
3205
|
+
`);
|
|
3206
|
+
},
|
|
3207
|
+
// Dedicated `retry` SSE event so the UI can show a status indicator.
|
|
3208
|
+
// Pre-fix the router yielded retry banners as `text` chunks which
|
|
3209
|
+
// ended up in the user-visible message; this isolates the signal.
|
|
3210
|
+
onRetry: (info) => {
|
|
3211
|
+
safeWrite(`event: retry
|
|
3212
|
+
data: ${JSON.stringify({ ...info, timestamp: Date.now() })}
|
|
3213
|
+
|
|
3214
|
+
`);
|
|
3215
|
+
},
|
|
3216
|
+
onFailover: (info) => {
|
|
3217
|
+
safeWrite(`event: failover
|
|
3218
|
+
data: ${JSON.stringify({ ...info, timestamp: Date.now() })}
|
|
3219
|
+
|
|
3204
3220
|
`);
|
|
3205
3221
|
}
|
|
3206
3222
|
},
|
|
@@ -5122,6 +5138,15 @@ data: ${JSON.stringify(data)}
|
|
|
5122
5138
|
const ok = reportHeartbeat(req.params.id);
|
|
5123
5139
|
res.json({ success: ok });
|
|
5124
5140
|
});
|
|
5141
|
+
app.post("/api/command-post/agents/:id/fire", async (req, res) => {
|
|
5142
|
+
try {
|
|
5143
|
+
const { fireHeartbeat } = await import("../agent/heartbeatScheduler.js");
|
|
5144
|
+
await fireHeartbeat(req.params.id);
|
|
5145
|
+
res.json({ success: true });
|
|
5146
|
+
} catch (err) {
|
|
5147
|
+
res.status(500).json({ success: false, error: err.message });
|
|
5148
|
+
}
|
|
5149
|
+
});
|
|
5125
5150
|
app.delete("/api/command-post/agents/:id", (req, res) => {
|
|
5126
5151
|
const ok = removeAgent(req.params.id);
|
|
5127
5152
|
if (!ok) {
|
|
@@ -9062,6 +9087,7 @@ td{padding:10px 12px;font-size:14px;vertical-align:middle}
|
|
|
9062
9087
|
if (config.commandPost?.enabled) {
|
|
9063
9088
|
initCommandPost(config.commandPost);
|
|
9064
9089
|
initWakeupSystem();
|
|
9090
|
+
initHeartbeatScheduler();
|
|
9065
9091
|
logger.info(COMPONENT, "Command Post governance layer initialized (wakeup system active)");
|
|
9066
9092
|
try {
|
|
9067
9093
|
const { ensureSpecialistsRegistered } = await import("../agent/specialists.js");
|