Repository navigation
feat(inference): opt-in failureNotices — tell the room when a turn produced nothing #178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| - Opt-in `failureNotices`: when a turn fails outright (provider error, | ||
| refusal, over-budget), post a short automatic notice to the agent's locus on | ||
| the first failure of a streak and every 5th after, so people can tell a | ||
| dead turn from a quiet one. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11531,6 +11531,7 @@ export class AgentFramework { | |
|
|
||
| const streak = (this.refusalStreak.get(agentName) ?? 0) + 1; | ||
| this.refusalStreak.set(agentName, streak); | ||
| this.postFailureNotice(agentName, streak, `the model declined to respond (safety category: ${category})`); | ||
|
|
||
| this.logFailure({ | ||
| agent: agentName, | ||
|
|
@@ -11591,6 +11592,30 @@ export class AgentFramework { | |
| this.opsAlert(kind, agentName, message, { data }); | ||
| } | ||
|
|
||
| /** | ||
| * AgentConfig.failureNotices: tell the ROOM when a turn produced nothing. | ||
| * The chronicle marker already tells the resident; without this, people | ||
| * see only silence and can't tell a dead turn from a quiet one. Posted on | ||
| * the first failure of a streak and every 5th after, so a stuck loop can't | ||
| * flood the channel. Best-effort: a notice that can't be delivered is | ||
| * dropped (the stderr/failures.log records remain). | ||
| */ | ||
| private postFailureNotice(agentName: string, streak: number, what: string): void { | ||
| const agent = this.agents.get(agentName); | ||
| if (!agent?.failureNotices || !this.channelRegistry) return; | ||
| if (streak !== 1 && streak % 5 !== 0) return; | ||
| const locus = this.channelRegistry.resolveLocus(agentName) ?? null; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/framework.ts
Line: 11607
Comment:
**Notice can reach wrong room** When a heartbeat turn starts, its speaking room is pinned. If an unrelated message changes the default channel before that turn fails, this fresh lookup can send the failure notice and its reason to the other room rather than the failed turn’s room.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Comment on lines
+11605
to
+11607
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/framework.ts
Line: 11605-11607
Comment:
**Background notice bypasses explicit routing** A subconscious agent inherits `failureNotices: true` from its primary agent, but its speech must use an explicit destination. When a background turn fails without one, this lookup can fall back to the last incoming channel and post an unsolicited notice there.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly. |
||
| if (!locus) return; | ||
| const oneLine = what.replace(/\s+/g, ' ').trim(); | ||
| const reason = oneLine.length > 160 ? `${oneLine.slice(0, 157)}…` : oneLine; | ||
| const text = | ||
| `⚠️ [automatic notice] ${agentName}'s reply failed to generate` + | ||
| `${streak > 1 ? ` (${streak} in a row)` : ''}: ${reason}. ` + | ||
| 'Nothing was lost from the conversation; it will see this and your messages on its next turn.'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/framework.ts
Line: 11614
Comment:
**Notice promises removed messages** On a refusal with auto-rewind enabled, the notice posts before the rewind can remove the latest incoming human message. The next turn then sees a marker describing withheld content, not the message itself. Telling participants the agent will see their messages may discourage them from resending input it no longer has.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly. |
||
| void this.channelRegistry.routeSpeech(agentName, text, locus) | ||
| .catch((err) => console.error(`[inference-failed] failure notice not delivered for ${agentName}:`, err)); | ||
|
Comment on lines
+11615
to
+11616
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/framework.ts
Line: 11615-11616
Comment:
**Failed notice creates false marker** An undeliverable notice normally makes `routeSpeech` resolve to `null`, so this catch does not handle it. The ordinary speech-failure callback then records a `[discord-send-failed]` marker saying the agent’s previous reply was saved to its archive, although the failed notice was not an archived reply. This gives the agent an inaccurate account of what was sent.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly. |
||
| } | ||
|
|
||
| private noteInferenceExhausted( | ||
| agentName: string, | ||
| reason: string, | ||
|
|
@@ -11603,6 +11628,7 @@ export class AgentFramework { | |
|
|
||
| // (1) Durable stderr line — works in headless/daemon mode with no client. | ||
| console.error(`[inference-failed] agent=${agentName} consecutive=${streak}: ${reason}`); | ||
| this.postFailureNotice(agentName, streak, reason); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/framework.ts
Line: 11631
Comment:
**Notice overlooks delivered narration** A tool-using turn can publish narration during one round and encounter a provider error in a later round. This notice still says the reply failed to generate, although the room received part of it. That wording can mislead participants about what they have already seen.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly. |
||
|
|
||
| // (1b) Machine-greppable durable record, independent of journald/unit log | ||
| // redirects: logs/failures.log under the host's working directory. This is | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prompt To Fix With AI