-
Notifications
You must be signed in to change notification settings - Fork 52.3k
feat(mattermost): add ambient session ingestion mode #26901
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
61870f6
5ee2aa8
78cfc55
c8c8926
786cf1b
3f1b621
40213b4
13ede5b
45434cf
36a9f9c
5c4c04f
06a0b8a
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,55 @@ | ||
| name: Build & Push CR Custom Image | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - feature/mattermost-ambient-session-ingestion | ||
| paths: | ||
| - '**/*.py' | ||
| - 'pyproject.toml' | ||
| - 'uv.lock' | ||
| - 'Dockerfile' | ||
| - 'docker/**' | ||
| - '.github/workflows/build-cr-image.yml' | ||
|
|
||
| permissions: | ||
| contents: read | ||
| packages: write | ||
|
|
||
| concurrency: | ||
| group: cr-docker-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| env: | ||
| IMAGE: ghcr.io/coding-reality/hermes-agent | ||
|
|
||
| jobs: | ||
| build-push: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 45 | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 | ||
|
|
||
| - name: Log in to GHCR | ||
| uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3 | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Build and push | ||
| uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 | ||
| with: | ||
| context: . | ||
| file: Dockerfile | ||
| push: true | ||
| platforms: linux/amd64 | ||
| tags: | | ||
| ${{ env.IMAGE }}:latest | ||
| ${{ env.IMAGE }}:${{ github.sha }} | ||
| cache-from: type=gha,scope=cr-hermes-amd64 | ||
| cache-to: type=gha,mode=max,scope=cr-hermes-amd64 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -966,6 +966,12 @@ class MessageEvent: | |
| # completion notifications) that must bypass user authorization checks. | ||
| internal: bool = False | ||
|
|
||
| # When False, the message is ingested into session history but does NOT | ||
| # trigger an LLM response. Used by ambient/silent-ingestion channels | ||
| # (e.g. MATTERMOST_AMBIENT_CHANNELS) where Hermes should accumulate | ||
| # context passively and only respond when explicitly triggered. | ||
| trigger_llm: bool = True | ||
|
|
||
| # Timestamps | ||
| timestamp: datetime = field(default_factory=datetime.now) | ||
|
|
||
|
|
@@ -2816,10 +2822,48 @@ async def handle_message(self, event: MessageEvent) -> None: | |
| This method returns quickly by spawning background tasks. | ||
| This allows new messages to be processed even while an agent is running, | ||
| enabling interruption support. | ||
|
|
||
| When ``event.trigger_llm`` is False (ambient/silent-ingestion mode) the | ||
| message is appended to the session transcript so it becomes part of the | ||
| conversational context, but no LLM response is generated. | ||
| """ | ||
| if not self._message_handler: | ||
| return | ||
|
|
||
| # Ambient ingestion: store to session history without invoking the LLM. | ||
| if not event.trigger_llm: | ||
|
Collaborator
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. This returns before the GatewayRunner handler, which performs the normal authorization/pairing gate. An unapproved participant can therefore write |
||
| if self._session_store is not None: | ||
| try: | ||
| session_entry = self._session_store.get_or_create_session(event.source) | ||
|
Collaborator
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. This derives the transcript from the individual sender's |
||
| # Prefix the message with sender attribution so the agent | ||
| # has full context when it is eventually triggered. | ||
| sender = ( | ||
| event.source.user_name | ||
| or event.source.user_id | ||
| or "unknown" | ||
| ) if event.source else "unknown" | ||
| attributed_content = f"[{sender}]: {event.text}" | ||
| self._session_store.append_to_transcript( | ||
| session_entry.session_id, | ||
| { | ||
| "role": "user", | ||
| "content": attributed_content, | ||
| "ambient": True, | ||
| "sender_id": event.source.user_id if event.source else None, | ||
| "sender_name": event.source.user_name if event.source else None, | ||
| }, | ||
| ) | ||
| logger.debug( | ||
| "Ambient ingestion: stored message from %s to session %s (no LLM invocation)", | ||
| sender, | ||
| session_entry.session_id, | ||
| ) | ||
| except Exception as exc: | ||
| logger.warning("Ambient ingestion: failed to store message: %s", exc) | ||
| else: | ||
| logger.debug("Ambient ingestion: session_store not available, message discarded") | ||
| return | ||
|
|
||
| coerce_plaintext_gateway_command(event) | ||
|
|
||
| session_key = build_session_key( | ||
|
|
||
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.
Remove this branch-specific publishing workflow from the feature PR. It is unrelated to Mattermost ingestion and grants package-publishing capability for an external Coding-Reality image.