@sebastianandreasson/pi-autonomous-agents 0.2.0 → 0.4.0
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/README.md +18 -3
- package/SETUP.md +9 -0
- package/docs/PI_SUPERVISOR.md +11 -11
- package/package.json +3 -3
- package/pi.config.json +1 -0
- package/src/index.mjs +1 -0
- package/src/pi-client.mjs +37 -0
- package/src/pi-config.mjs +51 -18
- package/src/pi-history.mjs +2 -0
- package/src/pi-preflight.mjs +48 -17
- package/src/pi-prompts.mjs +339 -103
- package/src/pi-repo.mjs +65 -3
- package/src/pi-report.mjs +11 -0
- package/src/pi-rpc-adapter.mjs +73 -0
- package/src/pi-supervisor.mjs +465 -26
- package/src/pi-telemetry.mjs +15 -1
- package/templates/DEVELOPER.md +3 -0
- package/templates/TESTER.md +7 -4
- package/templates/pi.config.example.json +4 -1
package/src/pi-report.mjs
CHANGED
|
@@ -35,6 +35,17 @@ async function main() {
|
|
|
35
35
|
console.log(`- ${kind}: ${count}`)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
const iterationSummaries = recent.filter((event) => event.kind === 'iteration_summary')
|
|
39
|
+
const warningsByIteration = iterationSummaries
|
|
40
|
+
.filter((event) => String(event.riskWarnings ?? '').trim() !== '')
|
|
41
|
+
|
|
42
|
+
if (warningsByIteration.length > 0) {
|
|
43
|
+
console.log('\nLarge file warnings:')
|
|
44
|
+
for (const event of warningsByIteration.slice(-5)) {
|
|
45
|
+
console.log(`- iteration ${event.iteration}: ${event.riskWarnings}`)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
38
49
|
const last = recent.at(-1)
|
|
39
50
|
if (!last) {
|
|
40
51
|
return
|
package/src/pi-rpc-adapter.mjs
CHANGED
|
@@ -54,6 +54,44 @@ function extractToolTarget(toolName, args) {
|
|
|
54
54
|
return ''
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
function extractShellCommand(args) {
|
|
58
|
+
if (!args || typeof args !== 'object') {
|
|
59
|
+
return ''
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (typeof args.command === 'string') {
|
|
63
|
+
return args.command
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (typeof args.cmd === 'string') {
|
|
67
|
+
return args.cmd
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return ''
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function isLargeShellRead(command) {
|
|
74
|
+
const text = String(command ?? '').trim()
|
|
75
|
+
if (text === '') {
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (/^\s*cat\s+\S+/.test(text)) {
|
|
80
|
+
return true
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const sedMatch = text.match(/sed\s+-n\s+['"]?(\d+)\s*,\s*(\d+)p['"]?/)
|
|
84
|
+
if (sedMatch) {
|
|
85
|
+
const start = Number.parseInt(sedMatch[1], 10)
|
|
86
|
+
const end = Number.parseInt(sedMatch[2], 10)
|
|
87
|
+
if (Number.isFinite(start) && Number.isFinite(end) && end >= start) {
|
|
88
|
+
return (end - start) >= 120
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
94
|
+
|
|
57
95
|
function extractAssistantText(message) {
|
|
58
96
|
if (!message || message.role !== 'assistant' || !Array.isArray(message.content)) {
|
|
59
97
|
return ''
|
|
@@ -121,6 +159,7 @@ async function run() {
|
|
|
121
159
|
const pending = new Map()
|
|
122
160
|
let requestCounter = 0
|
|
123
161
|
const streamTerminal = request.streamTerminal === true
|
|
162
|
+
const requestedModel = typeof request.model === 'string' ? request.model : ''
|
|
124
163
|
const loopRepeatThreshold = Number.isFinite(Number(request.loopRepeatThreshold))
|
|
125
164
|
? Number(request.loopRepeatThreshold)
|
|
126
165
|
: 12
|
|
@@ -294,6 +333,7 @@ async function run() {
|
|
|
294
333
|
activeToolName = String(data.toolName ?? '')
|
|
295
334
|
activeToolStartedAt = Date.now()
|
|
296
335
|
const target = extractToolTarget(data.toolName, data.args)
|
|
336
|
+
const shellCommand = data.toolName === 'bash' ? extractShellCommand(data.args) : ''
|
|
297
337
|
if (signature === lastToolSignature) {
|
|
298
338
|
repeatedToolCount += 1
|
|
299
339
|
} else {
|
|
@@ -324,6 +364,9 @@ async function run() {
|
|
|
324
364
|
}
|
|
325
365
|
|
|
326
366
|
writeLive(`[PI tool:start] ${data.toolName}${suffix}\n`)
|
|
367
|
+
if (data.toolName === 'bash' && isLargeShellRead(shellCommand)) {
|
|
368
|
+
writeLive('[PI warning] large bash file read detected; prefer read or a smaller exact window to avoid truncated context.\n')
|
|
369
|
+
}
|
|
327
370
|
}
|
|
328
371
|
|
|
329
372
|
if (data.type === 'tool_execution_end') {
|
|
@@ -416,6 +459,9 @@ async function run() {
|
|
|
416
459
|
await waitForAgentEnd()
|
|
417
460
|
|
|
418
461
|
if (heartbeatTimedOut) {
|
|
462
|
+
const toolCalls = events.filter((event) => event.type === 'tool_execution_start').length
|
|
463
|
+
const toolErrors = events.filter((event) => event.type === 'tool_execution_end' && event.isError).length
|
|
464
|
+
const messageUpdates = events.filter((event) => event.type === 'message_update').length
|
|
419
465
|
console.log(JSON.stringify({
|
|
420
466
|
sessionId: request.sessionId ?? '',
|
|
421
467
|
sessionFile: request.sessionFile ?? '',
|
|
@@ -438,6 +484,15 @@ async function run() {
|
|
|
438
484
|
continueAccepted ? 'continue_accepted=true' : '',
|
|
439
485
|
continueRejected ? 'continue_rejected=true' : '',
|
|
440
486
|
].join(' '),
|
|
487
|
+
role: '',
|
|
488
|
+
model: requestedModel,
|
|
489
|
+
toolCalls,
|
|
490
|
+
toolErrors,
|
|
491
|
+
messageUpdates,
|
|
492
|
+
stopReason: '',
|
|
493
|
+
loopDetected: false,
|
|
494
|
+
loopSignature: '',
|
|
495
|
+
terminalReason: 'heartbeat_timeout',
|
|
441
496
|
}))
|
|
442
497
|
return
|
|
443
498
|
}
|
|
@@ -464,6 +519,15 @@ async function run() {
|
|
|
464
519
|
: assistantError !== '' || (assistantText === '' && toolCalls === 0 && messageUpdates === 0)
|
|
465
520
|
? 'failed'
|
|
466
521
|
: 'success'
|
|
522
|
+
const terminalReason = loopDetected
|
|
523
|
+
? 'loop_detected'
|
|
524
|
+
: assistantError !== ''
|
|
525
|
+
? 'assistant_error'
|
|
526
|
+
: assistantStopReason === 'length'
|
|
527
|
+
? 'assistant_stop_length'
|
|
528
|
+
: status === 'failed'
|
|
529
|
+
? 'empty_agent_turn'
|
|
530
|
+
: 'agent_completed'
|
|
467
531
|
const notes = [
|
|
468
532
|
`PI session ${state.data.sessionId}`,
|
|
469
533
|
`pi_pid=${child.pid ?? 'unknown'}`,
|
|
@@ -494,6 +558,15 @@ async function run() {
|
|
|
494
558
|
status,
|
|
495
559
|
output,
|
|
496
560
|
notes,
|
|
561
|
+
role: '',
|
|
562
|
+
model: requestedModel,
|
|
563
|
+
toolCalls,
|
|
564
|
+
toolErrors,
|
|
565
|
+
messageUpdates,
|
|
566
|
+
stopReason: assistantStopReason,
|
|
567
|
+
loopDetected,
|
|
568
|
+
loopSignature,
|
|
569
|
+
terminalReason,
|
|
497
570
|
}))
|
|
498
571
|
} finally {
|
|
499
572
|
if (heartbeatInterval) {
|