fix(webhooks): unify session-options factory across desktop/telegram/slack#28
Merged
Merged
Conversation
…slack Telegram/Slack `publish` URLs were resolving to `https://anton.computer/...` instead of the deployment's `ANTON_HOST` (e.g. `itsomg.antoncomputer.in`). Root cause was webhook sessions never receiving `domain` — and the deeper issue that the webhook code path was a separate session-options builder that had drifted from `AgentServer.buildSessionOptions(...)`. Tracing the divergence surfaced several silently-dropped fields on every Pi SDK session (desktop included): `onActivateWorkflow`, `onSharedState`, `workflowId/Key`, `thinkingLevel`. Changes: - getPublicHost() helper in @anton/agent-config; 9 process.env reads collapsed to one greppable consumer. - Unified SessionOptions interface in @anton/agent-core, used by both createSession and resumeSession; previously-dropped fields wired into ToolCallbacks / Session ctor. - AgentServer.buildSessionOptions now returns SessionOptions explicitly; webhook closure delegates to it instead of carrying its own shape. - AgentServer.buildHarnessSessionContext extracted; harness (Codex/Claude Code) sessions derive shared wiring (domain, project handlers, resolveProviderToken) from the same factory. - Pi SDK Session.getSystemPrompt now calls buildCurrentContextLayer instead of inlining a duplicate; "Public hostname" line surfaced so the model never hallucinates a domain when constructing URLs from ~/.anton/published/. - check-session-options drift guard runs as `pnpm --filter @anton/agent-server check:session-options`, with compile-time exhaustiveness + runtime source scan over 27 fields. - Webhook closure clears onSubAgentEvent (desktop-AI-channel handler has no place on Telegram/Slack). - getOrCreateSession reconciles resumed sessions with the binding /model override so the choice survives a server restart. Verification: - 77/77 cross-surface checks pass (check:harness) - 27/27 drift-guard fields verified (check:session-options) - @anton/agent-core, @anton/agent-server build clean Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
OmGuptaIND
added a commit
that referenced
this pull request
May 5, 2026
### Fixes - docx rendering and fileupload flow - issues ### Other - Fix universal upload progress (#31) - Polish markdown table typography - Structure file artifacts (#29) - fix(routines): add missing .conv-back styles so back buttons render inline (#27) - fix(webhooks): unify session-options factory across desktop/telegram/slack (#28) - observability: add per-turn telemetry to harness sessions (#26)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Investigation triggered by a Telegram bug where the bot returned
https://anton.computer/a/<slug>instead of the deployment'sANTON_HOST(e.g.itsomg.antoncomputer.in). Tracing the divergence revealed that the webhook session-options builder had drifted fromAgentServer.buildSessionOptions(...)— and that the underlyingcreateSessionopts type silently dropped several fields on every Pi SDK session, desktop included.This PR closes the drift class, ships a CI guard so it can't recur, and fixes the immediate Telegram URL bug along the way.
What was broken on Telegram/Slack (now fixed)
domain(publish URL)/a/<slug>https://<host>/a/<slug>resolveProviderTokenweb_search/web_researchreturned "not configured"onActivateWorkflowonSharedState,workflowId/KeyonDeliverResultagentInstructions/agentMemorythinkingLevelliveConnectors/modelafter server restartWhat was also broken on desktop Pi SDK sessions (silent latent bug)
createSession's opts type omittedonActivateWorkflow,onSharedState,workflowId/Key, andthinkingLevel.buildSessionOptionsreturned them, but TypeScript's excess-property check is silent on object variables, so they were silently dropped. The harness path (Codex/Claude Code) worked because it reads fromharnessSessionContextsdirectly — only Pi SDK was affected. This PR fixes the wiring as a side-effect of unifying the type.Architectural changes (the structural fix)
getPublicHost()helper in@anton/agent-config— 9process.env.ANTON_HOSTreads → 1 greppable consumer.SessionOptionsinterface in@anton/agent-core—createSessionandresumeSessionnow accept the exact same shape; previously-dropped fields wired intoToolCallbacks/Sessionctor.AgentServer.buildSessionOptionsdeclares explicit: SessionOptionsreturn type. Webhook closure delegates straight to it instead of carrying its own (drifty) shape.AgentServer.buildHarnessSessionContextextracted — harness sessions derive shared wiring (domain, project handlers, resolveProviderToken) from the same factory.buildCurrentContextLayerinprompt-layers.tsis now the single source of truth for the "Current Context" block. Pi SDKSession.getSystemPrompt()no longer inlines a duplicate. Adding a field there propagates to desktop, Telegram, Slack, and every harness CLI automatically.check-session-optionsdrift guard — compile-time exhaustiveness viasatisfies readonly (keyof SessionOptions)[]+ runtime source scan. Adding aSessionOptionsfield without wiring it through every consumer is now a CI failure.Side-fixes spotted along the way
onSubAgentEvent(the desktop AI-channel handler has no place on Telegram/Slack and risked leaking events into a desktop client sharing the same sessionId)./modelchoice survives server restart (post-resume reconciliation: if resolved binding override differs from the persisted provider/model,session.switchModel(...)is called).activate_workflow(matches the docstring's intent — harness wasn't enforcing it).onDeliverResult(was previously dropped).File map
packages/agent-config/src/config.tsgetPublicHost()packages/agent-core/src/index.tsSessionOptionspackages/agent-core/src/prompt-layers.tsbuildCurrentContextLayerpackages/agent-core/src/session.tsSessionOptionstype, wired fieldspackages/agent-server/package.jsoncheck:session-optionsscriptpackages/agent-server/src/server.tspackages/agent-server/src/webhooks/agent-runner.tsWebhookSessionOptions = SessionOptions, post-resume reconciliationpackages/agent-server/src/__fixtures__/check-session-options.ts8 files, +706 / −196.
Test plan
pnpm --filter @anton/agent-core buildcleanpnpm --filter @anton/agent-server buildcleanpnpm --filter @anton/agent-core check:harness— 77/77 cross-surface checks passpnpm --filter @anton/agent-server check:session-options— 27/27 drift-guard fields verifiedonActivateWorkflow: opts?.onActivateWorkflowincreateSessioncauses the script to exit non-zero with the exact field name flagged.ANTON_HOST=itsomg.antoncomputer.in: the Telegram bot'spublishURL should now point athttps://itsomg.antoncomputer.in/a/<slug>, and the model recalling a previously-published artifact from~/.anton/published/should reference the same host (notanton.computer)./model openrouter/...on Telegram, restart the server, send another message — should still use the override.web_searchandweb_researchon Telegram (previously returned "not configured").🤖 Generated with Claude Code