feat(observer)!: require roark_integration_id for call attribution#12
feat(observer)!: require roark_integration_id for call attribution#12munkhorgil wants to merge 3 commits into
Conversation
|
Claude finished @munkhorgil's task in 3m 5s —— View job Code Review
Code Review Summary
Key findings🟡 README configuration reference table is incompleteThe | `roark_integration_id` | `str \| None` | `None` | Roark integration this deployment belongs to. Copied from the Roark dashboard when you create a Pipecat integration. Defaults to `ROARK_INTEGRATION_ID` env var; constructor arg takes precedence. Omit to fall back to the project's self-hosted integration. |🔵
|
| self._agent_name = agent_name | ||
| self._agent_prompt = agent_prompt | ||
| self._pipecat_call_id = pipecat_call_id or str(uuid.uuid4()) | ||
| self._roark_integration_id = roark_integration_id or os.environ.get("ROARK_INTEGRATION_ID") |
There was a problem hiding this comment.
The or operator means passing roark_integration_id="" (empty string) silently falls through to the env var rather than disabling the feature. This is almost certainly the right behavior (an empty-string integration ID is meaningless), but it differs from the semantics of a strict None-check. For transparency, the docstring could add a note like: "An empty string is treated the same as None."
If you ever wanted explicit None-only semantics:
self._roark_integration_id = (
roark_integration_id if roark_integration_id is not None
else os.environ.get("ROARK_INTEGRATION_ID")
)As-is, the or pattern is idiomatic and consistent with agentName/agentPrompt elsewhere — flagging for awareness only.
Adds a keyword-only `roark_integration_id` to `RoarkObserver`, defaulting from the `ROARK_INTEGRATION_ID` env var (self-hosted) / `pcc secrets` (Pipecat Cloud); the constructor arg wins when both are present. When set it ships as `roarkIntegrationId` on both the `call-started` and `call-ended` webhook bodies so app-roark-analytics can attribute each call to a specific Roark Pipecat integration. Fully backward compatible — when unset the field is omitted and the server falls back to the project's self-hosted integration. The observer stays transport-agnostic; the id is the only new field. Bumps version to 0.1.5 and documents ROARK_INTEGRATION_ID in the README setup / running-modes sections, .env.example, and the example bot. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
a854b05 to
f7c107d
Compare
The Roark integration id is now mandatory: RoarkObserver raises a ValueError at construction if neither roark_integration_id= nor the ROARK_INTEGRATION_ID environment variable supplies one. roarkIntegrationId is consequently sent unconditionally on both the call-started and call-ended webhook bodies (no longer omitted), so every call is attributed to a specific Roark Pipecat integration rather than falling back to the project's self-hosted integration. BREAKING CHANGE: existing deployments must set ROARK_INTEGRATION_ID (self-hosted env var / pcc secrets on Pipecat Cloud) before upgrading. Docs (README, .env.example, example bot) and the CHANGELOG updated to describe the requirement; tests now supply the id suite-wide via an autouse fixture and assert construction raises when it is absent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@claude Review again |
|
Claude finished @munkhorgil's task in 2m 4s —— View job Code Review
Code Review Summary
Findings🔴 README
|
…v docs - README: add roark_integration_id row to the Configuration reference table. - examples/bot.py: list ROARK_INTEGRATION_ID in the module docstring env vars (both the .env list and the pcc secrets example). - CHANGELOG: fix the [Unreleased] compare link (v0.1.3 -> v0.1.4) and add the missing [0.1.4] link. - observer.py: docstring note that an empty-string roark_integration_id is treated the same as None (falls through to the env var). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@claude Review again |
|
Claude finished @munkhorgil's task in 2m 21s —— View job Code Review
|
| Category | Score | Notes |
|---|---|---|
| Code Quality | 5/5 | Clean, minimal, idiomatic implementation |
| Security | 5/5 | No sensitive data in logs; standard env-var pattern |
| Performance | 5/5 | Trivial string field, zero overhead |
| Testing | 5/5 | All four key scenarios covered thoroughly |
| Documentation | 5/5 | All previous omissions now resolved |
| Overall | 5/5 | Ready to merge |
Previous review findings — all resolved ✅
| Finding | Status |
|---|---|
🔴 README Configuration reference table missing roark_integration_id |
Fixed — row added after pipecat_call_id |
🟡 CHANGELOG [Unreleased] link pointed at v0.1.3 |
Fixed — updated to v0.1.4...HEAD; [0.1.4] link added |
🟡 examples/bot.py docstring missing ROARK_INTEGRATION_ID |
Fixed — added under the Roark: env var section and in the pcc secrets set example |
🔵 "" vs None semantics undocumented |
Fixed — docstring now explicitly states "an empty string is treated the same as None" |
What's done well ✅
ValueErrormessage is production-quality — specific, actionable, tells the user exactly where to get the value.- Both payload sites updated consistently —
call-startedandcall-endedboth carryroarkIntegrationIdunconditionally; both log lines include it too. Easy to grep in production. - Constructor arg wins over env var — explicit > implicit, correctly implemented with
orfallback chain. - Test suite is solid — autouse fixture keeps noise out of individual tests; four scenarios (constructor arg, env var, precedence, missing) all verified;
raising=Falseguard handles clean CI environments correctly. _types.pytype annotation —roarkIntegrationId: str(notstr | None) on both payloads, accurately reflecting the runtime guarantee..env.example— clear comment, empty-value placeholder is the right pattern.- CHANGELOG BREAKING section — includes the migration instruction (
ROARK_INTEGRATION_IDmust be set before upgrading).
Informational notes (no action needed)
uv.lockversion jump (0.1.3→0.1.5): the lock file had a pre-existing version lag relative topyproject.toml(0.1.4). The update to0.1.5brings them in sync — not a bug._types.pywithtotal=False:roarkIntegrationId: stris technically optional in the TypedDict type, though the constructor guarantees it's always present at runtime. This is consistent with the existing pattern for other always-set fields — no change needed.- Explicit
os.environ.get("ROARK_INTEGRATION_ID")inexamples/bot.py: the observer would read the env var automatically anyway, but the explicit form is good documentation — makes the env-var connection visible to someone reading the example.
The implementation is correct, tests are comprehensive, and all documentation is complete. This PR is ready to merge.
|
We have decided to extend api key with integration id rather than pass it via package here. |

Summary
Adds a required
roark_integration_idtoRoarkObserverso app-roark-analytics can attribute each call to a specific Roark Pipecat integration (self-hosted vs Pipecat Cloud).Customers copy the id from the Roark dashboard when they create a Pipecat integration and set it as
ROARK_INTEGRATION_ID(env var self-hosted,pcc secrets seton Pipecat Cloud), or passroark_integration_id=directly.Warning
Breaking change.
RoarkObservernow raises aValueErrorat construction if no integration id is resolvable (neitherroark_integration_id=norROARK_INTEGRATION_ID). Existing deployments must setROARK_INTEGRATION_IDbefore upgrading.Changes
observer.py— keyword-onlyroark_integration_id: str | None = None, resolved fromos.environ["ROARK_INTEGRATION_ID"]when not passed (constructor arg wins). RaisesValueErrorif the resolved value is empty. Documented in the constructor docstring (incl. aRaises:section).observer.pypayload builders —roarkIntegrationIdis now set unconditionally on bothCallStartedPayloadandCallEndedPayload(guaranteed present), and logged on the existinglog.infolines._types.py—roarkIntegrationId: stron both payloads (comment updated to "required").examples/bot.py+.env.example—roark_integration_id=os.environ.get("ROARK_INTEGRATION_ID"); docs note it is required.README.md— Configure + running-modes sections documentROARK_INTEGRATION_IDas required, with the startup-ValueErrorbehavior.CHANGELOG.md—Addedentry for the field + a BREAKINGChangednote.0.1.5.The observer stays transport-agnostic — no transport or deployment detection; the integration id is the only new field.
Testing
uv run pytest -q→ 33 passeduv run ruff check src tests examples→ cleanuv run mypy src→ no issues🤖 Generated with Claude Code