Google Chat#
How to let your team ask the Osprey agent questions from a Google Chat space, and get answers, plots, and files back in the same conversation.
Before you start
A project whose build profile has a
dispatch:block — see Event Dispatch.Docker or Podman, for the container path.
A Google Cloud project in which you can create a chat app, a service account, and a message queue.
Overview#
The bridge turns a Google Chat conversation into a way of talking to the agent. Someone mentions the chat app in a space, Google puts that message on a queue, the bridge picks it up and hands the question to the event dispatch pipeline, and the answer is posted back in the same conversation thread.
It is a reader of a queue, not a server. Google never calls it; it asks Google for waiting messages, making only outbound calls.
Like every bridge, it remembers each question and conversation. What is particular to Google Chat is that there is no reading position to keep: a message the bridge has not finished with stays on the queue, so anything sent while the bridge was down is waiting when it comes back.
Enable It in a Profile#
Add a gchat_bridge: block to your build profile. The only setting is which
dispatcher trigger the bridge fires — that trigger decides what the agent is
allowed to do with a chat question — and the block is only meaningful next to a
dispatch: block:
gchat_bridge:
trigger: gchat-question # default; must exist in your triggers file
dispatch:
triggers: my_triggers.yml # the file that trigger must be declared in
worker_count: 1
env:
required:
- GCHAT_SA_KEY
- GCHAT_SUBSCRIPTION
- GCHAT_APP_ID
The queue, the service-account key and the bucket for files are not profile
settings. Which queue this deployment reads, which key file it signs in with,
and which storage bucket files are published through all differ per deployment —
and the key is a secret that must never be baked into a build. Listing them
under env.required documents them in .env.example; fill the values into
the profile’s .env, which is where a secret survives a rebuild. The
build derives the project’s .env from it (created mode 0600, readable
only by you).
Two mistakes are caught at build time rather than at runtime: declaring the
bridge without a dispatch: block, and naming a trigger your triggers file
does not declare. Both fail the build with a message naming the problem.
Runtime settings#
These are the ones you create and set yourself.
Variable |
Meaning |
|---|---|
|
Path to the service-account key file the bridge signs in with. The file must exist at that path on the deployment host; it is mounted read-only into the container at the same path, so one value names it on both sides. |
|
The full name of the queue subscription to read, in the form
|
|
The chat app’s own user id, e.g. |
|
Optional. The Cloud Storage bucket that plots and files are published to, and the project that owns it. Without a bucket the agent still answers, text only. Read Who Can Ask, and What Is Shared before setting one. |
Warning
One bridge per queue. Deploy exactly one bridge against a given subscription. Google hands each message to only one of a subscription’s readers, so a second deployment pointed at the same subscription — a staging stack, a container someone forgot to remove, another facility reusing the name — does not get its own copy of every message. It silently splits them: each bridge answers only the messages it happened to receive, the other questions look to your team like they were ignored, and nothing anywhere logs an error. Give every deployment its own subscription.
Settings that are filled in for you, or safe to leave alone
Variable |
Meaning |
|---|---|
|
The trigger to fire. Comes from the profile block above. |
|
Shared secrets for talking to the dispatcher and the worker.
|
|
Where the dispatcher and worker are — the bridge collects answers and files from the worker directly. Filled in for you when they run in the same stack; when they run elsewhere you must set them, and the bridge refuses to start without them. |
|
How long the worker may spend on one run. Comes from your project configuration, so raising it raises it for both halves at once. |
|
How long the bridge waits for an answer before giving up on it. Defaults to 30 seconds more than the worker’s own limit, and may never be less than that limit — the bridge refuses to start if it is. |
|
Seconds between checks on an answer in progress (default 2). |
|
Seconds between sweeps of the queue of questions that could not be handed off yet (default 60). |
|
How long a failed hand-off is held before it is retried, so a brief outage has time to clear (default 20 minutes). |
|
Age at which a question that still cannot be handed off is abandoned (default 48 hours). |
|
Hard ceiling on how long anything may sit in that queue, whatever its state (default 7 days). |
|
Set to |
|
Where to file an issue when a question is finally given up on. Leave unset if you have no such host: nothing is filed and nothing is checked. |
|
A release label shown with each acknowledgement, so a conversation shows which version answered. Omitted when unset. |
|
Where the bridge keeps what it remembers. Both default to files under
|
|
Timezone, taken from your project configuration so timestamps match the rest of the stack. |
Bring It Up#
1. Create the chat app and the identity it speaks as. In your Google Cloud
project, create a Chat app for the agent — its display name is what your team
sees replying, so make it obvious (for example OSPREY agent). Create a
service account for it, download a key file for that account, and note the app’s
own user id (the users/… value).
2. Give this deployment its own queue. Configure the chat app to publish its events to a topic, and create one subscription on that topic for this deployment — not one shared with any other. Allow the service account to read that subscription. See the warning above for what a shared subscription does.
3. Add the app to the spaces it should serve. It only sees conversations it has been added to. Add it to each space you want served; people can also message it directly without any setup.
4. Optional: create a bucket for plots and files. Allow the service account to write to it. Anything the agent publishes there has to be readable without signing in — see Who Can Ask, and What Is Shared before you decide to do this at all. Skip this step and the agent answers text only.
5. Fill in the environment file. Set the values from the table above in the
profile’s .env (the build derives the project’s .env from it):
GCHAT_SA_KEY=/etc/osprey/gchat-service-account.json
GCHAT_SUBSCRIPTION=projects/my-gcp-project/subscriptions/osprey-chat-events
GCHAT_APP_ID=users/1234567890
GCS_BUCKET=my-osprey-chat-artifacts # optional; enables plots and files
GCS_PROJECT=my-gcp-project # optional; the bucket's project
6. Bring the stack up. The bridge is registered in deployed_services, so
it starts with everything else:
osprey up # add --dev to bake in a local osprey checkout
Then mention the app in one of its spaces and ask it something. If nothing happens, check the service’s logs first: a missing credential stops the bridge at startup with the missing variable named. A wrong app id is the quieter failure — the bridge runs happily and ignores every message, because nothing it sees looks like a mention of itself.
Important
The bridge keeps what it remembers — which questions it has answered and the
recent conversation — in a named volume mounted at /data. Do not remove
that volume. Without it, a restart in the middle of a question can answer it
twice or drop it, and conversations lose their thread of context.