Repository navigation
feat(typing): show typing in disabled prose-routing mode #233
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
02edb4e
336c7cf
41c846b
1c2d353
7166b0b
37fc06a
575f314
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,21 @@ | ||
| - Agents with `proseRouting: 'disabled'` now show the typing indicator during | ||
| a turn, on the channel the trigger came from, the same as explicit mode. A | ||
| batched gate wake names no `channelId`, so its `wakeChannelId` is used | ||
| instead. Before, disabled-mode turns showed no indicator at all, so a | ||
| resident that answers only through send tools looked idle while it worked. | ||
| Never on a tuned-out channel: the agent turned its attention off there, yet | ||
| an ambient push or a gate wake can still name the channel. Silent wakes | ||
| (`suppressProse`, such as a silent heartbeat) still show none. Explicit and | ||
| locus modes pick their typing channel as before. | ||
| - Entering tune-out on a channel now stops a typing indicator already running | ||
| there. Before, its 7 s refresh continued until the turn ended. A | ||
| disabled-mode turn does not restart it; an explicit or locus turn can still | ||
| restart it at stream start or on a retry, as before. | ||
| - With conversation routing, a disabled-mode gate wake shows typing only | ||
| where the channel's messages reach the agent: a fork on its home channel, | ||
| any other agent never on a fork-bound channel. | ||
| - A silent request batched with ordinary ones no longer picks the turn's | ||
| channel or wake provenance; the ordinary requests decide, in every | ||
| prose-routing mode. A batch of only silent requests is unchanged. | ||
| - A typing `stop` now honors the server's `channels.typing` grant, like the | ||
| start: a server without the grant no longer receives an unpaired stop. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1291,9 +1291,7 @@ export class ChannelRegistry { | |
| // global-clear branch's semantics, and keeps defensive stopTyping(ch) | ||
| // calls from spamming stops at a server that never saw a start. | ||
| const entry = this.findChannelEntry(channelId); | ||
| if (entry && this.sendTypingFn) { | ||
| this.sendTypingFn(entry.serverId, channelId, this.typingMetadata.get(channelId), 'stop'); | ||
| } | ||
| if (entry) this.sendTypingStop(entry.serverId, channelId); | ||
| } | ||
| this.typingMetadata.delete(channelId); | ||
| } else { | ||
|
|
@@ -1303,11 +1301,9 @@ export class ChannelRegistry { | |
| clearInterval(interval); | ||
| } | ||
| this.typingIntervals.clear(); | ||
| if (this.sendTypingFn) { | ||
| for (const id of channels) { | ||
| const entry = this.findChannelEntry(id); | ||
| if (entry) this.sendTypingFn(entry.serverId, id, this.typingMetadata.get(id), 'stop'); | ||
| } | ||
| for (const id of channels) { | ||
| const entry = this.findChannelEntry(id); | ||
| if (entry) this.sendTypingStop(entry.serverId, id); | ||
| } | ||
| this.typingMetadata.clear(); | ||
| } | ||
|
|
@@ -1988,6 +1984,9 @@ export class ChannelRegistry { | |
| source, | ||
| timestamp: new Date().toISOString(), | ||
| }); | ||
| // A tuned-out channel shows no attendance: stop a typing run already | ||
| // going there, or its 7s refresh would continue until the turn ends. | ||
| this.stopTyping(channelId); | ||
|
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.
Knowledge Base Used: MCPL transport and server registration Prompt To Fix With AIThis is a comment left during a code review.
Path: src/mcpl/channel-registry.ts
Line: 1877
Comment:
**Tune-out sends ungranted typing** `startTyping` installs a timer even when the server lacks the `channels.typing` grant and the initial notification is skipped. If tune-out then stops that timer, `stopTyping` sends a stop notification without checking the grant, so the server receives an unpaired typing notification it was not authorized to receive.
**Knowledge Base Used:** [MCPL transport and server registration](https://app.greptile.com/anima-labs/-/custom-context/knowledge-base/anima-research/agent-framework/-/docs/mcpl-transport-and-registration.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Contributor
Author
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. Valid, and it applied to the existing turn-end stop too. Fixed in 7166b0b at the shared point: both |
||
| } | ||
|
|
||
| /** | ||
|
|
@@ -2271,6 +2270,16 @@ export class ChannelRegistry { | |
| // Private: Typing notification | ||
| // ========================================================================== | ||
|
|
||
| /** | ||
| * Send a typing 'stop'. The same §14.1 grant gate as the start: a timer can | ||
| * exist for a server whose start was skipped for lack of `channels.typing`, | ||
| * and it must not receive an unpaired stop either. | ||
| */ | ||
| private sendTypingStop(serverId: string, channelId: string): void { | ||
| if (!CapabilityGrant.of(this.serverRegistry.getServer(serverId)).has('channels.typing')) return; | ||
| this.sendTypingFn?.(serverId, channelId, this.typingMetadata.get(channelId), 'stop'); | ||
| } | ||
|
|
||
| /** | ||
| * Send a typing notification for a channel. | ||
| * | ||
|
|
||
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.
Knowledge Base Used: MCPL transport and server registration
Prompt To Fix With AI
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.
Valid, but this predates the PR, and fixing only the check would make it disagree with the send:
startTypingresolves the channel through the same first-matchfindChannelEntry, so with duplicate ids the indicator already went to the first server before this change. As it stands, the tune-out check and the send always use the same server. Listed under "Not covered" in the description; resolving the owning server from the trigger's source would need to change both the check andstartTyping.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.
That’s a fair distinction. Since
disabledTypingChannelandstartTypingboth resolve duplicate IDs through the same first-match lookup, this PR does not introduce a new mismatch between the tune-out check and the indicator destination. Correct ownership would require changing both paths and knowing the wake’s source server, so this is appropriately documented as pre-existing scope rather than an actionable finding here. I’m withdrawing the comment.Tip: You can customize Greptile's behavior for this repo with
.greptile/rules.mdand.greptile/config.json.