* Load max-tool-denials guard events from Copilot SDK session events.jsonl files. * @returns {Array<{denialCount: number, threshold: number, reason: string, recentToolCalls: Array , timestamp: string}>}
()
| 1382 | * @returns {Array<{denialCount: number, threshold: number, reason: string, recentToolCalls: Array<string>, timestamp: string}>} |
| 1383 | */ |
| 1384 | function loadToolDenialsExceededEvents() { |
| 1385 | try { |
| 1386 | if (!fs.existsSync(COPILOT_SESSION_STATE_DIR)) { |
| 1387 | return []; |
| 1388 | } |
| 1389 | |
| 1390 | const events = []; |
| 1391 | const sessionDirs = fs.readdirSync(COPILOT_SESSION_STATE_DIR, { withFileTypes: true }); |
| 1392 | for (const entry of sessionDirs) { |
| 1393 | if (!entry.isDirectory()) continue; |
| 1394 | const eventsPath = path.join(COPILOT_SESSION_STATE_DIR, entry.name, "events.jsonl"); |
| 1395 | if (!fs.existsSync(eventsPath)) continue; |
| 1396 | const content = fs.readFileSync(eventsPath, "utf8"); |
| 1397 | const lines = content.split("\n"); |
| 1398 | /** @type {Array<string>} */ |
| 1399 | const recentToolCalls = []; |
| 1400 | for (const rawLine of lines) { |
| 1401 | const line = rawLine.trim(); |
| 1402 | if (!line) continue; |
| 1403 | try { |
| 1404 | const parsed = JSON.parse(line); |
| 1405 | if (parsed.type === "tool.execution_start" && parsed.data && typeof parsed.data === "object") { |
| 1406 | const toolName = typeof parsed.data.toolName === "string" ? parsed.data.toolName.trim() : ""; |
| 1407 | if (toolName) { |
| 1408 | const mcpServerName = typeof parsed.data.mcpServerName === "string" ? parsed.data.mcpServerName.trim() : ""; |
| 1409 | recentToolCalls.push(formatRecentToolCall(toolName, mcpServerName, parsed.data)); |
| 1410 | if (recentToolCalls.length > 5) recentToolCalls.shift(); |
| 1411 | } |
| 1412 | continue; |
| 1413 | } |
| 1414 | if (parsed.type !== "guard.tool_denials_exceeded" || !parsed.data || typeof parsed.data !== "object") { |
| 1415 | continue; |
| 1416 | } |
| 1417 | const denialCount = Number.parseInt(String(parsed.data.denialCount), 10); |
| 1418 | const threshold = Number.parseInt(String(parsed.data.threshold), 10); |
| 1419 | if (!Number.isFinite(denialCount) || !Number.isFinite(threshold)) { |
| 1420 | continue; |
| 1421 | } |
| 1422 | events.push({ |
| 1423 | denialCount, |
| 1424 | threshold, |
| 1425 | reason: typeof parsed.data.reason === "string" ? parsed.data.reason.trim() : "", |
| 1426 | recentToolCalls: recentToolCalls.slice(), |
| 1427 | timestamp: typeof parsed.timestamp === "string" ? parsed.timestamp : "", |
| 1428 | }); |
| 1429 | } catch { |
| 1430 | // Skip malformed lines |
| 1431 | } |
| 1432 | } |
| 1433 | } |
| 1434 | return events; |
| 1435 | } catch (error) { |
| 1436 | core.warning(`Failed to load tool-denials-exceeded events: ${getErrorMessage(error)}`); |
| 1437 | return []; |
| 1438 | } |
| 1439 | } |
| 1440 | |
| 1441 | /** |
no test coverage detected