Repository navigation
Expand file tree
/
Copy pathagent.js
More file actions
140 lines (117 loc) · 4.23 KB
/
Copy pathagent.js
File metadata and controls
140 lines (117 loc) · 4.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/usr/bin/env node
/**
* Taskify Agent — a simple heartbeat loop that picks up issues and works on them.
*
* Usage: node agent.mjs [--api http://localhost:3005] [--agent-id a3] [--interval 10]
*/
var API = 'http://localhost:3005/db/taskify'
var AGENT_ID = 'a3' // Engineer by default
var INTERVAL = 15 // seconds between heartbeats
// Parse CLI args
process.argv.forEach(function(arg, i) {
if (arg === '--api' && process.argv[i + 1]) API = process.argv[i + 1] + '/db/taskify'
if (arg === '--agent-id' && process.argv[i + 1]) AGENT_ID = process.argv[i + 1]
if (arg === '--interval' && process.argv[i + 1]) INTERVAL = parseInt(process.argv[i + 1], 10)
})
async function fetchJSON(url) {
var res = await fetch(url)
return res.json()
}
async function putJSON(url, data) {
await fetch(url, {
method: 'PUT',
headers: { 'Content-Type': 'application/ld+json' },
body: JSON.stringify(data)
})
}
async function logActivity(action, entityType, entityId) {
var id = 'ev-' + Date.now()
await putJSON(API + '/activity/' + id, {
'@id': '#' + id,
'@type': 'Activity',
id: id,
actorType: 'agent',
actorId: AGENT_ID,
action: action,
entityType: entityType,
entityId: entityId,
agentId: AGENT_ID,
createdAt: new Date().toISOString()
})
}
async function getAgent() {
try {
return await fetchJSON(API + '/agents/' + AGENT_ID)
} catch (e) {
return null
}
}
async function getIssues() {
var listing = await fetchJSON(API + '/issues/')
var items = listing.contains || listing['ldp:contains'] || []
var urls = items.map(function(item) { return typeof item === 'string' ? item : item['@id'] })
return Promise.all(urls.map(function(url) { return fetchJSON(url) }))
}
async function heartbeat() {
var agent = await getAgent()
if (!agent) {
console.log('[agent] Agent ' + AGENT_ID + ' not found in /db/')
return
}
console.log('[agent] ' + agent.name + ' (' + agent.role + ') — heartbeat')
// Update heartbeat timestamp
agent.lastHeartbeatAt = new Date().toISOString()
agent.updatedAt = agent.lastHeartbeatAt
agent.status = 'running'
await putJSON(API + '/agents/' + AGENT_ID, agent)
// Get all issues
var issues = await getIssues()
// Find issues assigned to this agent
var myIssues = issues.filter(function(i) { return i.assigneeAgentId === AGENT_ID })
var inProgress = myIssues.filter(function(i) { return i.status === 'in_progress' })
var todos = myIssues.filter(function(i) { return i.status === 'todo' })
console.log('[agent] My issues: ' + myIssues.length + ' total, ' + inProgress.length + ' in progress, ' + todos.length + ' todo')
// If we have an in-progress issue, "work" on it and complete it
if (inProgress.length > 0) {
var issue = inProgress[0]
console.log('[agent] Completing: ' + (issue.identifier || issue.id) + ' — ' + issue.title)
issue.status = 'done'
issue.updatedAt = new Date().toISOString()
var issueId = issue.id || issue['@id'].replace('#issue-', '')
await putJSON(API + '/issues/' + issueId, issue)
await logActivity('issue.completed', 'issue', issueId)
console.log('[agent] ✅ Done: ' + (issue.identifier || issue.id))
return
}
// If we have a todo issue, check it out
if (todos.length > 0) {
var issue = todos[0]
console.log('[agent] Checking out: ' + (issue.identifier || issue.id) + ' — ' + issue.title)
issue.status = 'in_progress'
issue.updatedAt = new Date().toISOString()
var issueId = issue.id || issue['@id'].replace('#issue-', '')
await putJSON(API + '/issues/' + issueId, issue)
await logActivity('issue.checked_out', 'issue', issueId)
console.log('[agent] 📥 Checked out: ' + (issue.identifier || issue.id))
return
}
// Nothing to do
console.log('[agent] No work to do — going idle')
agent.status = 'idle'
agent.updatedAt = new Date().toISOString()
await putJSON(API + '/agents/' + AGENT_ID, agent)
}
// Main loop
console.log('[agent] Starting agent ' + AGENT_ID)
console.log('[agent] API: ' + API)
console.log('[agent] Heartbeat every ' + INTERVAL + 's')
console.log('')
async function loop() {
try {
await heartbeat()
} catch (err) {
console.error('[agent] Error:', err.message)
}
setTimeout(loop, INTERVAL * 1000)
}
loop()