Skip to content

eventHistorian posts summary on conversation stopped#154

Merged
jencompgeek merged 9 commits into
mainfrom
jh/slack-summary-notif
Jun 10, 2026
Merged

eventHistorian posts summary on conversation stopped#154
jencompgeek merged 9 commits into
mainfrom
jh/slack-summary-notif

Conversation

@jencompgeek

@jencompgeek jencompgeek commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

What is in this PR?

The goal of this PR is for the eventHistorian to post an event summary at the end of an event (e.g. to Slack if configured for a Slack channel). It adds infra necessary to notify agents of conversation events, determining if they have permission to read a particular conversation, either through a read grant to that specific conversation, the topic containing the conversation, or an 'allPublicTopics' grant. Agent types whose folder contains a file called capabilities.ts will have their read and write grants automatically loaded into the agent instances on create/update.

eventHistorian is updated to post the summary generated for a conversation to the historian channel on receipt of any ConversationStoppedEvent within its scope (either app public topics or the topicIds configured in its agentConfig).

Changes in the codebase

  • feat: add authorization layer with agent capabilities
  • feat: add mechanism to dispatch conversation events to agents with access
  • feat: send conversation stopped event to agents on conversation stop
  • feat: load capabilities function from agent folder if exists
  • feat: eventHistorian posts summary on conversation stopped
  • feat: add allPublicTopics agent capabilities grant

Documentation and automated testing

Did you:

  • document any breaking changes in your commit messages?
  • document your changes as comments in the code? Use TSDoc format where appropriate.
  • update the README and docs to be clear and easy to use for end users and developers?
  • add and/or update automated tests?
  • update team documentation of any new or changed environment variables?

Testing this PR

  • Hook eventHistorian to a private test Slack channel by creating the appropriate conversation (see Create Historian Slack Conversation in our Hoppscotch for preconfigured request. Just substitute the slackChannelwith the channel ID). RemovetopicIdsto test the defaultallPublicTopics` case.
  • Create an event under a public topic and generate some transcript
  • Stop the event (manually through Hoppscotch Stop conversation endpoint. Events typically auto-stop 30 minutes after endTime, but this is easiest shortcut for testing)
  • Verify a summary is posted to your Slack channel
  • Create and stop another conversation in a private topic and verify that the summary is NOT posted to the Slack channel and all fails gracefully
  • Could delete and recreate the Historian Slack Conversation with specific topicIds specified in properties and verify this also works

Additional information

introduces auth/access.ts and per-agent capabilities.ts; grants are resolved from agentConfig on
save
…cess

add agentDispatcher that checks read access and dispatches events to authorized agents in Agenda job
assume single folder per agent and load capabilities.ts as agentType.capabilities if present
@jencompgeek jencompgeek changed the title Jh/slack summary notif eventHistorian posts summary on conversation stopped Jun 10, 2026
@jencompgeek jencompgeek marked this pull request as ready for review June 10, 2026 11:13
await doc.save()

const topicId = doc.topic?._id?.toString() ?? doc.topic?.toString()
const topicIsPrivate = doc.topic?.private ?? false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heads up, I think there's a way for private-topic summaries to leak here. We pull topicIsPrivate off doc.topic.private, but if topic came back as just an ID (not populated with the full topic doc), then .private is undefined and we fall back to false. That makes the topic look public, and any agent with the allPublicTopics grant will get the summary even though the event was private.

Two options that would fix this:

  • Make sure topic is populated (or do a quick Topic.findById(...).select('private').lean()) before reading .private.
  • Default to true if we can't tell. Better to skip a legit dispatch than to leak a private one.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Will default to private.

Comment thread src/jobs/handlers/conversationEvent.ts Outdated
logger.debug(`conversationEvent handler ${agent._id} - event type: ${event.type}`)
const responses = await agent.onConversationEvent(event)
for (const response of responses) {
AgentResponseZodSchema.parse(response)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if AgentResponseZodSchema.parse throws on response #2, responses #3 and beyond never get posted because the whole loop bails into the outer catch. Could we swap to safeParse and just log+skip the bad one? That way one malformed message doesn't take down the rest of the batch.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep! I'll make the same fix to the agent handler as well.

@cbj0hns0n cbj0hns0n left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left two suggestions. Tested and it works great, thanks!

@jencompgeek jencompgeek force-pushed the jh/slack-summary-notif branch from e064f21 to f804d9d Compare June 10, 2026 21:04
@jencompgeek jencompgeek merged commit 8fa5f21 into main Jun 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants