@sebastianandreasson/pi-autonomous-agents 0.15.0 → 0.15.1
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/package.json
CHANGED
|
@@ -118,6 +118,55 @@ function mergeSpanSummary(requestState) {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
function getSpanSignal(requestState) {
|
|
122
|
+
const spans = Array.isArray(requestState?.spans) ? requestState.spans : []
|
|
123
|
+
let toolSpanCount = 0
|
|
124
|
+
|
|
125
|
+
for (const span of spans) {
|
|
126
|
+
const kind = String(span?.spanKind ?? '').trim()
|
|
127
|
+
if (kind === 'tool_call' || kind === 'tool_result') {
|
|
128
|
+
toolSpanCount += 1
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
spanCount: spans.length,
|
|
134
|
+
toolSpanCount,
|
|
135
|
+
toolNameCount: requestState?.toolNames?.size ?? 0,
|
|
136
|
+
fileCount: requestState?.files?.size ?? 0,
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function shouldPreferSnapshot(currentState, candidateState) {
|
|
141
|
+
const current = getSpanSignal(currentState)
|
|
142
|
+
const candidate = getSpanSignal(candidateState)
|
|
143
|
+
|
|
144
|
+
const currentHasToolContext = current.toolSpanCount > 0 || current.toolNameCount > 0 || current.fileCount > 0
|
|
145
|
+
const candidateHasToolContext = candidate.toolSpanCount > 0 || candidate.toolNameCount > 0 || candidate.fileCount > 0
|
|
146
|
+
|
|
147
|
+
if (candidateHasToolContext && !currentHasToolContext) {
|
|
148
|
+
return true
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (candidate.fileCount !== current.fileCount) {
|
|
152
|
+
return candidate.fileCount > current.fileCount
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (candidate.toolSpanCount !== current.toolSpanCount) {
|
|
156
|
+
return candidate.toolSpanCount > current.toolSpanCount
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (candidate.toolNameCount !== current.toolNameCount) {
|
|
160
|
+
return candidate.toolNameCount > current.toolNameCount
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (current.spanCount === 0 && candidate.spanCount > 0) {
|
|
164
|
+
return true
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return false
|
|
168
|
+
}
|
|
169
|
+
|
|
121
170
|
function applyAssistantMessage(requestState, message) {
|
|
122
171
|
requestState.provider = String(message?.provider ?? requestState.provider ?? '').trim()
|
|
123
172
|
requestState.model = String(message?.model ?? requestState.model ?? '').trim()
|
|
@@ -289,6 +338,23 @@ export function createRequestTelemetryExtension({ cwd = process.cwd() } = {}) {
|
|
|
289
338
|
})
|
|
290
339
|
}
|
|
291
340
|
|
|
341
|
+
function createComparableRequestState(baseState) {
|
|
342
|
+
return createRequestState({
|
|
343
|
+
sessionId: baseState.sessionId,
|
|
344
|
+
turnIndex: baseState.turnIndex,
|
|
345
|
+
startedAt: baseState.startedAt,
|
|
346
|
+
model: baseState.model,
|
|
347
|
+
metadata: {
|
|
348
|
+
runId: baseState.runId,
|
|
349
|
+
iteration: baseState.iteration,
|
|
350
|
+
phase: baseState.phase,
|
|
351
|
+
role: baseState.role,
|
|
352
|
+
kind: baseState.kind,
|
|
353
|
+
task: baseState.task,
|
|
354
|
+
},
|
|
355
|
+
})
|
|
356
|
+
}
|
|
357
|
+
|
|
292
358
|
function createFallbackRequest() {
|
|
293
359
|
const requestState = createProviderRequest()
|
|
294
360
|
|
|
@@ -417,7 +483,37 @@ export function createRequestTelemetryExtension({ cwd = process.cwd() } = {}) {
|
|
|
417
483
|
|
|
418
484
|
pi.on('before_provider_request', (event) => {
|
|
419
485
|
const requestState = createProviderRequest()
|
|
420
|
-
|
|
486
|
+
const providerApplied = applyProviderPayloadSnapshot(requestState, event?.payload)
|
|
487
|
+
|
|
488
|
+
const contextCandidate = createComparableRequestState(requestState)
|
|
489
|
+
const contextApplied = applyContextSnapshot(contextCandidate)
|
|
490
|
+
if (contextApplied && shouldPreferSnapshot(requestState, contextCandidate)) {
|
|
491
|
+
requestState.contextMessages = contextCandidate.contextMessages
|
|
492
|
+
requestState.spans = contextCandidate.spans
|
|
493
|
+
requestState.spanSource = contextCandidate.spanSource
|
|
494
|
+
requestState.contextMessageCount = contextCandidate.contextMessageCount
|
|
495
|
+
requestState.spanCount = contextCandidate.spanCount
|
|
496
|
+
requestState.textChars = contextCandidate.textChars
|
|
497
|
+
requestState.textBytes = contextCandidate.textBytes
|
|
498
|
+
requestState.toolNames = contextCandidate.toolNames
|
|
499
|
+
requestState.files = contextCandidate.files
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const sessionHistoryCandidate = createComparableRequestState(requestState)
|
|
503
|
+
const sessionHistoryApplied = applySessionHistorySnapshot(sessionHistoryCandidate)
|
|
504
|
+
if (sessionHistoryApplied && shouldPreferSnapshot(requestState, sessionHistoryCandidate)) {
|
|
505
|
+
requestState.contextMessages = sessionHistoryCandidate.contextMessages
|
|
506
|
+
requestState.spans = sessionHistoryCandidate.spans
|
|
507
|
+
requestState.spanSource = sessionHistoryCandidate.spanSource
|
|
508
|
+
requestState.contextMessageCount = sessionHistoryCandidate.contextMessageCount
|
|
509
|
+
requestState.spanCount = sessionHistoryCandidate.spanCount
|
|
510
|
+
requestState.textChars = sessionHistoryCandidate.textChars
|
|
511
|
+
requestState.textBytes = sessionHistoryCandidate.textBytes
|
|
512
|
+
requestState.toolNames = sessionHistoryCandidate.toolNames
|
|
513
|
+
requestState.files = sessionHistoryCandidate.files
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (!providerApplied && requestState.spans.length === 0 && !contextApplied && !sessionHistoryApplied) {
|
|
421
517
|
applySessionHistorySnapshot(requestState)
|
|
422
518
|
}
|
|
423
519
|
state.pendingRequests.push(requestState)
|
|
@@ -427,6 +427,84 @@ function parseStructuredTextArray(items) {
|
|
|
427
427
|
return parts
|
|
428
428
|
}
|
|
429
429
|
|
|
430
|
+
function normalizeProviderToolCalls(toolCalls) {
|
|
431
|
+
if (!Array.isArray(toolCalls)) {
|
|
432
|
+
return []
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const parts = []
|
|
436
|
+
for (const item of toolCalls) {
|
|
437
|
+
const object = asObject(item)
|
|
438
|
+
const functionObject = asObject(object.function)
|
|
439
|
+
const id = normalizeString(object.id ?? object.call_id, '')
|
|
440
|
+
const name = normalizeString(
|
|
441
|
+
functionObject.name
|
|
442
|
+
?? object.name,
|
|
443
|
+
''
|
|
444
|
+
)
|
|
445
|
+
const argumentsValue = parseJsonLikeString(
|
|
446
|
+
functionObject.arguments
|
|
447
|
+
?? object.arguments
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
if (name === '' && id === '' && argumentsValue === undefined) {
|
|
451
|
+
continue
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
parts.push({
|
|
455
|
+
type: 'toolCall',
|
|
456
|
+
id,
|
|
457
|
+
name,
|
|
458
|
+
arguments: argumentsValue,
|
|
459
|
+
})
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
return parts
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function normalizeMessageContent(content) {
|
|
466
|
+
if (typeof content === 'string') {
|
|
467
|
+
return [{ type: 'text', text: content }]
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (Array.isArray(content)) {
|
|
471
|
+
return parseStructuredTextArray(content)
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return []
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function normalizeProviderRoleMessage(object) {
|
|
478
|
+
const role = normalizeString(object.role, '')
|
|
479
|
+
if (role === '') {
|
|
480
|
+
return null
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (role === 'tool') {
|
|
484
|
+
return {
|
|
485
|
+
role: 'toolResult',
|
|
486
|
+
toolCallId: normalizeString(object.tool_call_id ?? object.call_id ?? object.id, ''),
|
|
487
|
+
toolName: normalizeString(object.name, ''),
|
|
488
|
+
details: object,
|
|
489
|
+
content: [{
|
|
490
|
+
type: 'text',
|
|
491
|
+
text: typeof object.content === 'string' ? object.content : safeJson(object.content),
|
|
492
|
+
}],
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const content = normalizeMessageContent(object.content)
|
|
497
|
+
const toolCalls = normalizeProviderToolCalls(object.tool_calls)
|
|
498
|
+
|
|
499
|
+
return {
|
|
500
|
+
role,
|
|
501
|
+
content: [...content, ...toolCalls],
|
|
502
|
+
toolCallId: normalizeString(object.toolCallId ?? object.tool_call_id ?? object.call_id, ''),
|
|
503
|
+
toolName: normalizeString(object.toolName ?? object.name, ''),
|
|
504
|
+
details: object.details,
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
430
508
|
function convertProviderInputItemToMessage(item) {
|
|
431
509
|
const object = asObject(item)
|
|
432
510
|
|
|
@@ -470,20 +548,7 @@ function convertProviderInputItemToMessage(item) {
|
|
|
470
548
|
}
|
|
471
549
|
|
|
472
550
|
if (object.role) {
|
|
473
|
-
|
|
474
|
-
return {
|
|
475
|
-
role: normalizeString(object.role, ''),
|
|
476
|
-
content: [{ type: 'text', text: object.content }],
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
return {
|
|
481
|
-
role: normalizeString(object.role, ''),
|
|
482
|
-
content: parseStructuredTextArray(object.content),
|
|
483
|
-
toolCallId: normalizeString(object.toolCallId, ''),
|
|
484
|
-
toolName: normalizeString(object.toolName, ''),
|
|
485
|
-
details: object.details,
|
|
486
|
-
}
|
|
551
|
+
return normalizeProviderRoleMessage(object)
|
|
487
552
|
}
|
|
488
553
|
|
|
489
554
|
const normalized = normalizeTextPart(object)
|
|
@@ -505,6 +570,22 @@ export function extractMessagesFromProviderPayload(payload) {
|
|
|
505
570
|
|
|
506
571
|
if (Array.isArray(object.messages)) {
|
|
507
572
|
return object.messages
|
|
573
|
+
.map((item) => {
|
|
574
|
+
if (typeof item === 'string') {
|
|
575
|
+
return {
|
|
576
|
+
role: 'user',
|
|
577
|
+
content: [{ type: 'text', text: item }],
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
if (!item || typeof item !== 'object') {
|
|
581
|
+
return null
|
|
582
|
+
}
|
|
583
|
+
if (item.role) {
|
|
584
|
+
return normalizeProviderRoleMessage(asObject(item))
|
|
585
|
+
}
|
|
586
|
+
return convertProviderInputItemToMessage(item)
|
|
587
|
+
})
|
|
588
|
+
.filter((message) => normalizeString(message?.role, '') !== '')
|
|
508
589
|
}
|
|
509
590
|
|
|
510
591
|
if (typeof object.input === 'string') {
|
package/src/pi-sdk-turn.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
2
|
import process from 'node:process'
|
|
3
|
+
import { setMaxListeners } from 'node:events'
|
|
3
4
|
import { pathToFileURL } from 'node:url'
|
|
4
5
|
import {
|
|
5
6
|
formatHeartbeatReason,
|
|
@@ -154,6 +155,16 @@ function applyRequestTelemetryEnv(request) {
|
|
|
154
155
|
}
|
|
155
156
|
}
|
|
156
157
|
|
|
158
|
+
function relaxAbortSignalListenerLimit(signal) {
|
|
159
|
+
if (!signal || typeof signal !== 'object') {
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
setMaxListeners(0, signal)
|
|
165
|
+
} catch {}
|
|
166
|
+
}
|
|
167
|
+
|
|
157
168
|
function deriveTokenAttributionKind({ activeToolName, pendingToolNames, pendingFiles, lastAssistantActivity }) {
|
|
158
169
|
if (String(activeToolName ?? '').trim() !== '') {
|
|
159
170
|
return 'tool_running'
|
|
@@ -484,6 +495,7 @@ export async function runSdkTurnWithPi(pi, request) {
|
|
|
484
495
|
let tokenUsageEvents = 0
|
|
485
496
|
let tokenUsage = createEmptyTokenUsage()
|
|
486
497
|
let lastAssistantActivity = ''
|
|
498
|
+
let abortSignalLimitRelaxed = false
|
|
487
499
|
const pendingToolNames = new Set()
|
|
488
500
|
const pendingFiles = new Set()
|
|
489
501
|
const events = []
|
|
@@ -569,6 +581,10 @@ export async function runSdkTurnWithPi(pi, request) {
|
|
|
569
581
|
lastEventAt = Date.now()
|
|
570
582
|
|
|
571
583
|
if (event.type === 'agent_start') {
|
|
584
|
+
if (!abortSignalLimitRelaxed) {
|
|
585
|
+
relaxAbortSignalListenerLimit(session?.agent?.signal)
|
|
586
|
+
abortSignalLimitRelaxed = true
|
|
587
|
+
}
|
|
572
588
|
agentStarted = true
|
|
573
589
|
emitLiveFeed(request, {
|
|
574
590
|
type: 'agent_start',
|