mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-19 16:27:37 +00:00
Promote Patrol related-resource handoff evidence
This commit is contained in:
parent
8c7a01186e
commit
288bffe9cb
2 changed files with 84 additions and 5 deletions
|
|
@ -166,6 +166,51 @@ describe('patrolInvestigationContextModel', () => {
|
|||
expect(handoff.context.handoffContext).not.toContain('online to online');
|
||||
});
|
||||
|
||||
it('includes bounded related-resource context in assessment handoff evidence', () => {
|
||||
const longRelatedResource =
|
||||
'storage-pool-with-a-very-long-description-that-keeps-going-beyond-the-handoff-limit-for-operators';
|
||||
const handoff = buildPatrolAssessmentAssistantHandoff({
|
||||
assessment: {
|
||||
title: 'Issues detected',
|
||||
},
|
||||
supportingEvidence: {
|
||||
recentChanges: [
|
||||
{
|
||||
id: 'change-related',
|
||||
observedAt: '2026-05-06T12:08:00Z',
|
||||
resourceId: 'vm-100',
|
||||
kind: 'metric_anomaly',
|
||||
sourceType: 'heuristic',
|
||||
sourceAdapter: 'proxmox_adapter',
|
||||
confidence: 'high',
|
||||
reason: 'CPU pressure increased after storage activity',
|
||||
relatedResources: [
|
||||
'backup-job',
|
||||
'cache-node',
|
||||
longRelatedResource,
|
||||
'db-primary',
|
||||
'db-replica',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
activeFindings: [],
|
||||
});
|
||||
|
||||
const relatedEvidence = handoff.context.briefing?.evidence?.find((line) =>
|
||||
line.includes('related resources'),
|
||||
);
|
||||
|
||||
expect(relatedEvidence).toContain('related resources backup-job');
|
||||
expect(relatedEvidence).toContain('and 1 more');
|
||||
expect(relatedEvidence).not.toContain(longRelatedResource);
|
||||
expect(relatedEvidence).not.toContain('db-replica');
|
||||
expect(handoff.context.handoffContext).toContain('related resources backup-job');
|
||||
expect(handoff.context.handoffContext).toContain('and 1 more');
|
||||
expect(handoff.context.handoffContext).not.toContain(longRelatedResource);
|
||||
expect(handoff.context.handoffContext).not.toContain('db-replica');
|
||||
});
|
||||
|
||||
it('builds a model-only Assistant handoff for the current Patrol assessment', () => {
|
||||
const handoff = buildPatrolAssessmentAssistantHandoff({
|
||||
assessment: {
|
||||
|
|
@ -326,6 +371,10 @@ describe('patrolInvestigationContextModel', () => {
|
|||
expect(handoff.context.handoffContext).toContain(
|
||||
'Recent Change 1: Metric anomaly: CPU spike after backup job',
|
||||
);
|
||||
expect(handoff.context.handoffContext).toContain('related resources backup-job');
|
||||
expect(handoff.context.briefing?.evidence).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining('related resources backup-job')]),
|
||||
);
|
||||
expect(handoff.context.handoffContext).toContain(
|
||||
'Recent Change 2: Command executed: execution event recorded',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -354,6 +354,8 @@ const MAX_ASSESSMENT_RESOURCES = 8;
|
|||
const MAX_ASSESSMENT_HANDOFF_ACTIONS = 4;
|
||||
const MAX_PATROL_RUN_HANDOFF_RESOURCES = 8;
|
||||
const MAX_PATROL_BRIEFING_SUGGESTED_PROMPTS = 3;
|
||||
const MAX_ASSESSMENT_RELATED_RESOURCE_LABELS = 4;
|
||||
const MAX_ASSESSMENT_RELATED_RESOURCE_LABEL_LENGTH = 80;
|
||||
const SAME_STATE_CHANGED_FIELD_LABELS: Record<string, string> = {
|
||||
'docker.command': 'Docker command',
|
||||
'docker.updateStatus': 'Docker image status',
|
||||
|
|
@ -2065,6 +2067,7 @@ function formatAssessmentRecentChangeEvidence(change: ResourceChange): string |
|
|||
return [
|
||||
summary,
|
||||
resource ? `resource ${resource}` : undefined,
|
||||
formatAssessmentRecentChangeRelatedResources(change),
|
||||
observedAt ? `observed ${observedAt}` : undefined,
|
||||
]
|
||||
.filter(isNonEmptyString)
|
||||
|
|
@ -2085,10 +2088,6 @@ function formatAssessmentCorrelationEvidence(correlation: ResourceCorrelation):
|
|||
}
|
||||
|
||||
function formatAssessmentRecentChangeContextLine(change: ResourceChange, index: number): string {
|
||||
const relatedResources = (change.relatedResources ?? [])
|
||||
.map(normalizeText)
|
||||
.filter(isNonEmptyString)
|
||||
.slice(0, 4);
|
||||
const parts = [
|
||||
formatAssessmentRecentChangeSummary(change),
|
||||
normalizeText(change.id) ? `change ${normalizeText(change.id)}` : undefined,
|
||||
|
|
@ -2105,12 +2104,43 @@ function formatAssessmentRecentChangeContextLine(change: ResourceChange, index:
|
|||
? `${formatIdentifierLabel(change.confidence)?.toLowerCase()} confidence`
|
||||
: undefined,
|
||||
normalizeText(change.actor) ? `actor ${truncateContextText(change.actor, 80)}` : undefined,
|
||||
relatedResources.length > 0 ? `related ${relatedResources.join(', ')}` : undefined,
|
||||
formatAssessmentRecentChangeRelatedResources(change),
|
||||
].filter(isNonEmptyString);
|
||||
|
||||
return `Recent Change ${index}: ${parts.join('; ')}`;
|
||||
}
|
||||
|
||||
function formatAssessmentRecentChangeRelatedResources(
|
||||
change: ResourceChange,
|
||||
): string | undefined {
|
||||
const labels: string[] = [];
|
||||
for (const relatedResource of change.relatedResources ?? []) {
|
||||
const label = truncateContextText(
|
||||
relatedResource,
|
||||
MAX_ASSESSMENT_RELATED_RESOURCE_LABEL_LENGTH,
|
||||
);
|
||||
if (label && !labels.includes(label)) {
|
||||
labels.push(label);
|
||||
}
|
||||
}
|
||||
if (labels.length === 0) return undefined;
|
||||
|
||||
const visibleLabels = labels.slice(0, MAX_ASSESSMENT_RELATED_RESOURCE_LABELS);
|
||||
const omittedCount = labels.length - visibleLabels.length;
|
||||
return `related resources ${formatAssessmentRelatedResourceList(visibleLabels, omittedCount)}`;
|
||||
}
|
||||
|
||||
function formatAssessmentRelatedResourceList(labels: string[], omittedCount: number): string {
|
||||
if (labels.length === 1) {
|
||||
return omittedCount > 0 ? `${labels[0]}, and ${omittedCount} more` : labels[0];
|
||||
}
|
||||
if (labels.length === 2 && omittedCount === 0) {
|
||||
return `${labels[0]} and ${labels[1]}`;
|
||||
}
|
||||
const visibleList = labels.join(', ');
|
||||
return omittedCount > 0 ? `${visibleList}, and ${omittedCount} more` : visibleList;
|
||||
}
|
||||
|
||||
function formatAssessmentCorrelationContextLine(
|
||||
correlation: ResourceCorrelation,
|
||||
index: number,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue