fix(athena): address 11 audit findings (H2,H3,H5,M1-M4,M8-M11)

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
ismeth
2026-03-01 16:48:12 +01:00
committed by YeonGyu-Kim
parent a13cc7b877
commit 7d2749cfe1
21 changed files with 610 additions and 213 deletions
@@ -140,13 +140,13 @@ describe("hasCouncilResponseTag", () => {
})
})
describe("#given assistant message contains the response tag", () => {
describe("#given assistant message contains a complete council response", () => {
it("#then should return true", () => {
//#given
const messages = [
{
info: { role: "assistant" },
parts: [{ type: "text", text: "My analysis </COUNCIL_MEMBER_RESPONSE>" }],
parts: [{ type: "text", text: "<COUNCIL_MEMBER_RESPONSE>This is a comprehensive analysis of the council member findings. The investigation reveals multiple significant patterns across the entire codebase that require careful refactoring.</COUNCIL_MEMBER_RESPONSE>" }],
},
]
@@ -170,7 +170,7 @@ describe("hasCouncilResponseTag", () => {
},
{
info: { role: "assistant" },
parts: [{ type: "text", text: "final answer </COUNCIL_MEMBER_RESPONSE>" }],
parts: [{ type: "text", text: "<COUNCIL_MEMBER_RESPONSE>This is a comprehensive analysis of the council member findings. The investigation reveals multiple significant patterns across the entire codebase that require careful refactoring.</COUNCIL_MEMBER_RESPONSE>" }],
},
]
@@ -6,12 +6,11 @@ import {
createInternalAgentTextPart,
} from "../../shared"
import { setSessionTools } from "../../shared/session-tools-store"
import { extractCouncilResponse } from "../../tools/council-archive/council-response-extractor"
import { COUNCIL_MEMBER_KEY_PREFIX } from "../../agents/builtin-agents/council-member-agents"
type OpencodeClient = PluginInput["client"]
const COUNCIL_RESPONSE_TAG = "</COUNCIL_MEMBER_RESPONSE>"
const CONTINUATION_PROMPT =
"You have not yet produced your final <COUNCIL_MEMBER_RESPONSE>. Continue your analysis and wrap your findings in <COUNCIL_MEMBER_RESPONSE> tags. If you are waiting for background tasks, use background_wait to block until they complete, then produce your response."
@@ -28,17 +27,18 @@ export function resetCouncilNudgeCount(taskId: string): void {
}
export function hasCouncilResponseTag(sessionMessages: Array<{ info?: { role?: string }; parts?: Array<{ type?: string; text?: string }> }>): boolean {
for (let i = sessionMessages.length - 1; i >= 0; i--) {
const msg = sessionMessages[i]
const assistantTexts: string[] = []
for (const msg of sessionMessages) {
if (msg.info?.role !== "assistant") continue
const parts = msg.parts ?? []
for (const part of parts) {
if (part.type === "text" && part.text?.includes(COUNCIL_RESPONSE_TAG)) {
return true
for (const part of msg.parts ?? []) {
if (part.type === "text" && part.text) {
assistantTexts.push(part.text)
}
}
}
return false
if (assistantTexts.length === 0) return false
const extraction = extractCouncilResponse(assistantTexts.join("\n"))
return extraction.has_response && extraction.response_complete
}
export function sendCouncilContinuationNudge(
@@ -13,13 +13,13 @@ function createMockClient(
}
describe("sessionHasCouncilResponse", () => {
describe("#given assistant message with closing council tag", () => {
describe("#given assistant message with complete council response", () => {
it("#when tag is in text part #then should return true", async () => {
//#given
const client = createMockClient([
{
info: { role: "assistant" },
parts: [{ type: "text", text: "Some response</COUNCIL_MEMBER_RESPONSE>" }],
parts: [{ type: "text", text: "<COUNCIL_MEMBER_RESPONSE>This is a comprehensive analysis of the council member findings. The investigation reveals multiple significant patterns across the entire codebase that require careful refactoring.</COUNCIL_MEMBER_RESPONSE>" }],
},
])
@@ -102,7 +102,7 @@ describe("sessionHasCouncilResponse", () => {
})
})
describe("#given assistant message with tag buried in longer text", () => {
describe("#given assistant message with complete council response in longer text", () => {
it("#when tag appears mid-text #then should return true", async () => {
//#given
const client = createMockClient([
@@ -111,7 +111,7 @@ describe("sessionHasCouncilResponse", () => {
parts: [
{
type: "text",
text: "Here is my analysis of the situation.\n\nLong content here.\n\n</COUNCIL_MEMBER_RESPONSE>\n\nMore text after.",
text: "Here is my analysis. <COUNCIL_MEMBER_RESPONSE>This is a comprehensive analysis of the council member findings. The investigation reveals multiple significant patterns across the entire codebase that require careful refactoring.</COUNCIL_MEMBER_RESPONSE> More text after.",
},
],
},
@@ -1,10 +1,9 @@
import type { PluginInput } from "@opencode-ai/plugin"
import { log, normalizeSDKResponse } from "../../shared"
import { hasCouncilResponseTag } from "./council-continuation-enforcer"
type OpencodeClient = PluginInput["client"]
const COUNCIL_RESPONSE_TAG = "</COUNCIL_MEMBER_RESPONSE>"
export async function sessionHasCouncilResponse(
client: OpencodeClient,
sessionID: string,
@@ -20,18 +19,7 @@ export async function sessionHasCouncilResponse(
{ preferResponseOnMissingData: true },
)
for (let i = messages.length - 1; i >= 0; i--) {
const msg = messages[i]
if (msg.info?.role !== "assistant") continue
const parts = msg.parts ?? []
for (const part of parts) {
if (part.type === "text" && part.text?.includes(COUNCIL_RESPONSE_TAG)) {
return true
}
}
}
return false
return hasCouncilResponseTag(messages)
} catch (error) {
log("[council-response-checker] Error checking session for response tag:", {
sessionID,