Skip to content

feat(sharing): per-agent custom instructions for public & channel chats (#1205)#1337

Open
dolho wants to merge 2 commits into
devfrom
feature/1205-public-channel-prompt
Open

feat(sharing): per-agent custom instructions for public & channel chats (#1205)#1337
dolho wants to merge 2 commits into
devfrom
feature/1205-public-channel-prompt

Conversation

@dolho

@dolho dolho commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a per-agent Additional instructions field on the Sharing tab that injects a custom system-prompt fragment into public-facing conversations only — public links, channel chats (Slack/Telegram/WhatsApp), and x402 paid chat. Owners can tailor persona, scope limits, disclaimers, or guardrails for outside audiences without touching how the agent behaves in their own authenticated chats, scheduled work, or agent-to-agent calls. The text-surface counterpart of the existing voice_system_prompt.

Implementation (mirrors voice_system_prompt end-to-end)

Behavior guarantees

  • Strict no-op when unset — zero behavior change for existing agents.
  • A DB lookup failure degrades to the memory block alone — never blocks a chat.
  • Composes correctly with MEM-001 per-user memory (folded into the same caller_prompt).
  • Group chats: applied (group channels are public-facing) — per the AC default.

Acceptance criteria

  • New per-agent field editable from the Sharing tab, save/clear + char limit
  • Appended for public links, channel router, x402 paid chat
  • NOT applied to authenticated chat/session, schedules, loops, a2a
  • Composes with MEM-001 memory block in caller_prompt
  • Owner-only GET/PUT mirroring the voice-prompt pattern
  • Empty/unset is a strict no-op
  • Group-chat behavior explicit (applies to groups)

Testing

30 passed — new test_public_channel_prompt.py (db get/set/clear/isolation on SQLite + Postgres; helper composition: 4 combos + db-error degradation) plus the schema-parity and migrations suites green.

Related to #1205

🤖 Generated with Claude Code

@dolho dolho requested a review from vybe June 24, 2026 11:20

@vybe vybe 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.

Validated via /validate-prtwo blockers (the prompt-injection framing, public/channel/x402 wiring, and tests look solid otherwise):

1. Missing Postgres/Alembic migration (Invariant #3). Adds agent_ownership.public_channel_system_prompt via a SQLite migration (_migrate_agent_ownership_public_channel_prompt) + schema.py/tables.py, but no Alembic revision under src/backend/migrations/versions/. PG deployments won't get the column. (schema-parity only guards the SQLite track — same gap as #1339.)

2. Conflicts with dev after #1317. #1317 restructured SharingPanel.vue (moved operator management to the new Access tab, reframed around Identity Proof / access policy). This PR was built on the old layout, so the SharingPanel.vue / routers/sharing.py conflicts need a rebase onto the redesigned component.

— posted via /validate-pr

@github-actions

Copy link
Copy Markdown

⚠️ Nightly unit-suite check skipped — merge conflict against dev.

Resolve by running git merge dev locally and pushing the result. The next nightly run will re-test once the conflict is gone.

dolho and others added 2 commits June 25, 2026 17:36
…ts (#1205)

Owners can attach extra system-prompt instructions that apply to public-facing
conversations ONLY — public links, channel chats (Slack/Telegram/WhatsApp), and
x402 paid chat — without changing the agent's behavior in their own
authenticated chats, scheduled runs, loops, or agent-to-agent calls. The
text-surface counterpart of voice_system_prompt.

- schema/migration: agent_ownership.public_channel_system_prompt TEXT (schema.py
  + tables.py Core object + versioned migration, Invariant #3)
- db: get/set_public_channel_system_prompt (set strips, empty clears) + facade
  delegation
- models: PublicChannelPrompt / PublicChannelPromptUpdate (4000-char cap)
- api: owner-only GET/PUT /api/agents/{name}/public-prompt (sharing.py),
  mirroring the voice-prompt endpoints
- injection: platform_prompt_service.build_public_channel_caller_prompt folds the
  fragment with the MEM-001 memory block (public fragment first); wired into the
  three public-facing sites — message_router (channels), public.py (sync+async),
  paid.py (x402). Authenticated chat / schedules / loops / a2a never call it, so
  the scope exclusion holds by construction. Unset = strict no-op; a DB error
  degrades to the memory block (never blocks a chat)
- ui: Additional Instructions textarea (save/clear, char counter) in
  SharingPanel.vue via two agents-store methods
- tests: db get/set/clear/isolation + helper composition (4 combos + db-error
  degradation), SQLite + Postgres; schema-parity + migrations suites green
- docs: requirements section 44, architecture endpoint + column

Related to #1205

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…em_prompt (#1205)

The PR predates Alembic adoption (#1183) and shipped only the SQLite migration.
Add the paired Postgres revision (0005, chained after 0004_agent_ownership_voice_name)
so the dual-track migration invariant holds — ADD COLUMN IF NOT EXISTS, no-op when
0001_baseline already created the column.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dolho dolho force-pushed the feature/1205-public-channel-prompt branch from fadcb90 to a8565ad Compare June 25, 2026 14:37
@dolho

dolho commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto dev + Alembic fix + review

Fix (rebase): resolved 8 conflicts. All backend ones were the same additive collision — dev's voice_name (#28) vs this PR's public_channel_system_prompt (#1205) at the same spots:

  • schema.py/tables.py/database.py/migrations.py (list): unioned (both columns/methods/entries).
  • migrations.py (function) + db/agents.py (getter/setter): git had interleaved the two functions/methods into one tangled flow — reconstructed both as complete separate units.
  • routers/sharing.py: merged imports (no dup from models) + kept both /access (Client/Viewer User Role (AUTH-002) #17) and /public-prompt GET+PUT (Per-agent custom instructions for public & channel chats (Sharing tab) #1205).
  • SharingPanel.vue: dropped the re-inherited Team Sharing section (Client/Viewer User Role (AUTH-002) #17 moved it to AccessPanel; its shareWithUser/shareEmail no longer exist), kept the new Additional Instructions section.
  • architecture.md: kept both endpoint rows + both DDL lines.

Added missing Alembic revision (fix): the PR predates Alembic adoption (#1183) and shipped SQLite-only — PG-broken (Invariant #9). Added 0005_agent_ownership_public_channel_prompt (chained after 0004_voice_name, ADD COLUMN IF NOT EXISTS).

Review — looks good:

  • Injection boundary is correct: build_public_channel_caller_prompt is wired only into public.py (links), paid.py (x402), message_router.py (channels) — not authenticated chat, loops, schedules, or a2a. ✅ Matches the documented "outside audiences only" intent.
  • Owner-only endpoints, 4000-char cap, empty clears the value.

Verified: py_compile (all backend conflict files), SharingPanel.vue compiles, schema-parity + test_public_channel_prompt.py: 13 passed. Now MERGEABLE.

⚠️ Two coordination flags

  1. SharingPanel vs the reframe (same as feat(sharing): external client roster on the Sharing tab (trinity-enterprise#20) #1335): the Additional Instructions section sits on the pre-reframe Sharing tab. My open feat(ui): reframe Sharing tab to external-client sharing via channels #1347 (Unified Executions Dashboard (EXEC-022) #18) / feat(ui): move channel config into dialogs + VoIP surface (#19) #1348 (MCP Execution Query Tools (MCP-007) #19) rewrite SharingPanel.vue — this will re-conflict. Recommend stacking after Unified Executions Dashboard (EXEC-022) #18/MCP Execution Query Tools (MCP-007) #19.
  2. Alembic 0005 collision: feat(loops): loop-level wall-clock deadline (max_duration_seconds) (#1156) #1182 (loop max_duration) also adds a 0005 off 0004_voice_name. Whichever of feat(loops): loop-level wall-clock deadline (max_duration_seconds) (#1156) #1182/feat(sharing): per-agent custom instructions for public & channel chats (#1205) #1337 merges second must bump to 0006.

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