Conversation
Add the provider-neutral Brief schema, snapshot projection, bounded structured generator, deterministic evidence checks, and Markdown renderer. Add briefs pull and run commands for complete dashboard snapshots and reproducible local generation, with prompt and model overrides and turn-by-turn output. Document the workflow and cover projection, caps, search text, and URL filtering with unit tests.
Resolve the default Brief model from the app's fast-model configuration when a run starts, while keeping explicit CLI model overrides independent. Accept model citations that match deterministic code change or resource evidence, count them as kept, and document and test both rules.
Cap user and assistant entries, reserve the prompt budget for them first, and use remaining space for the newest tool results while preserving transcript order. Report omitted entry counts in the model input and cover message retention, tool priority, truncation, ordering, and the total input cap.
Build the durable record from bounded conversation input and scale model output to the record size. Add attribution, runtime-marker, URL, and merge-claim guards while preserving deterministic evidence links.\n\nRevise the prompt and Markdown report so local tuning exposes the record and every guard result.
Use the configured default model for Brief generation and add stated, confirmed, and assumed decision kinds with deterministic consistency checks.\n\nResolve snapshot authors across the full event history, separate resource events from human messages, and expose the event count in the deterministic record. Update rendering, prompt guidance, docs, and focused coverage.
Only flag unsupported merge claims when the conversation has linked evidence to validate. Compare cited URLs against HTML-unescaped transcript text and keep decoded normalized URLs. Leave unresolved snapshot actors unnamed so they cannot enter the participant or attribution record.
Add append-only Brief storage, SQL input projection, and a core post-Turn task that uses the configured default structured model. Record generation cost in a namespaced conversation event and keep task retries idempotent by Turn. Preserve public Briefs after transcript expiry and delete non-public Briefs when purge scrubs private metadata. Share one reporting-event entry mapper between snapshot and SQL inputs, and document the Brief term and lifecycle.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
HazAT
added this pull request to stack #1807
September 9, 2026 11:28
Use schema-valid local Conversation ids for the root and child task cases. Commit each Turn's complete Pi history before appending reporting events so the second Turn follows the durable agent-history branch while retaining a real tool result.
Reject late private Brief writes in the locked storage transaction and keep leftover private Brief rows eligible for purge. Skip covered out-of-order Turns before model generation, restore idempotent update events on retries, require complete normalized URL evidence tokens, and render core Brief events outside the plugin catalog.
Treat an already-purged non-public Conversation as an expected task skip before Brief input construction or model generation. Keep the storage transaction check as the race-safe final invariant.
Keep core Brief task registration disabled unless createApp explicitly enables it. Enable the task for the example app and local chat, while leaving stored event rendering unconditional. Restore plugin task tests to plugin-only expectations and cover Brief scheduling from the opted-in Brief task scenario.
Keep the Nitro scaffold aligned with the example app, which now opts into Brief generation.
Merge the Brief and generator input schemas into schema.ts, drop the config indirection, and let callers bind the model into the completion function so the CLI and the runtime send the same request. Keep a closing bracket that a cited URL opened, so a Wikipedia-style link is stored intact instead of truncated.
# Conflicts: # packages/junior/src/chat/briefs/README.md # packages/junior/src/chat/briefs/generate.ts # packages/junior/src/chat/briefs/snapshot.ts # packages/junior/tests/unit/briefs/generate.test.ts
Drop the unused store readers, flatten the SQL input adapter into input.ts, and let the task call the model client with the same request as `junior briefs run` so the tuned temperature applies in production. Share the Brief test fixture instead of an inline copy.
HazAT
marked this pull request as ready for review
September 9, 2026 19:34
Never upgrade a decision kind: a human named on an assumed decision loses the name instead of becoming a confirmation, and an unknown name keeps the kind. Match Slack <url|label> links by their URL, try a stray /https suffix only as an alternate match, and store the form that matched. Bound replay evidence to what existed at the replayed event. Load app config only when a run needs the default model so `briefs pull` works with a token alone, and route `briefs` through the shared CLI dispatcher.
…3-storage # Conflicts: # packages/junior/src/chat/briefs/snapshot.ts
The event read and the sequence boundary were independent queries, so a Turn completing between them produced a Brief stamped with a sequence it never read, and the next task skipped that Turn as already covered. The task now passes its terminal sequence into the input adapter.
Co-Authored-By: Daniel Griesser <dgriesser@sentry.io>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 6bd3f18. Configure here.
| db, | ||
| run.conversationId, | ||
| run.runId, | ||
| ); |
There was a problem hiding this comment.
Public purge races fail the task
Medium Severity
The task lets a purged public Conversation continue so a stored Brief can re-emit its event, but when no Brief exists yet it still requires the turn_completed row. Purge has already deleted that event, so readTurnCompletedSeq throws and retries keep failing.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 6bd3f18. Configure here.
matejminar
approved these changes
Sep 10, 2026
HazAT
added a commit
that referenced
this pull request
Sep 10, 2026
First of a four-PR stack that gives Junior **conversation briefs**: one durable, versioned, evidence-backed record per Conversation that survives transcript expiry and can be indexed and searched. Background: #1784 and the "work items" discussion; a Brief is the structured intent + outcome + evidence unit those ideas build on. Stack: **#1805** generator and tuning loop → #1806 storage and post-turn generation → #1808 search, tool, and API → #1810 dashboard and cost report. ## Why When a transcript expires, nothing durable says what was asked, what was decided, which PR came out of it, and which decisions are still open. A Brief keeps exactly that: a model-generated summary with source-checked links. ## What - `packages/junior/src/chat/briefs/`: the Brief shape and a pure `generateBrief` over a provider-neutral `BriefInput`. - A deterministic **record** (participants, message and turn counts, duration, location, code changes) built from the input, not the model. - Summary, intent, outcome with status, **decisions classified as stated, confirmed, or assumed by Junior**, open decisions with an owner, durable facts, keywords. - **Evidence links are deterministic**: code changes and `resource_link` annotations come from trusted input; a model-cited URL is kept only when it matches a complete normalized URL token in the transcript, the previous Brief, or that evidence. Dropped URLs, dropped attributions, runtime-marker items, and unsupported "merged" claims are reported in an evidence-check footer. - Bounded prompt input: messages first, newest tool results fill the rest, sentence-boundary truncation, depth scaled to the conversation. - `junior briefs pull <id…> --base-url … --token … --out …` saves a self-contained snapshot of any public conversation through the dashboard API with a personal token. - `junior briefs run <snapshot…> [--model] [--prompt] [--turn-by-turn] [--out]` replays generation locally and writes `<id>.brief.json` and a readable `<id>.brief.md`. - The default model is the app's configured default model. It was chosen after hand-tuning on 50 public production conversations: it separates decisions from findings far better than the fast model at roughly two cents more per large brief. The prompt lives in `chat/briefs/prompt.ts`. ## Verification - `pnpm --filter @sentry/junior exec vitest run tests/unit/briefs` - `pnpm typecheck`, `pnpm --filter @sentry/junior lint`, `pnpm file-length:check`, `pnpm test-architecture:check`, `pnpm docs:check` - Four rounds of real-model runs over the 50-conversation sample set, read by hand; sample briefs are not committed (public repo).
HazAT
added a commit
that referenced
this pull request
Sep 10, 2026
Stacked on #1806. Milestone 4 of conversation briefs: make briefs findable. ## What - `ConversationBriefSearchStore`: full-text search over the latest brief version per conversation, with `query`, `status`, time range, channel, and annotation-key filters. Scope is either the current Slack workspace's public conversations or all public conversations (web). Purged public conversations are included on purpose; that is what a brief is for. Private, child, and other-tenant conversations are excluded. - `searchConversationBriefs`: a deferred, read-only agent tool registered for every public conversation. Results carry status, summary, highlighted excerpt, up to five evidence links, and a dashboard link. Its description steers the model to use it before message search for "what did we decide" and "which PR" questions. - The tool is provider-neutral. Slack channel resolution, the channel filter parameter, and permalink enrichment live in a small port under `chat/slack/tools/` that is injected only when Slack context exists, per `policies/provider-boundaries.md`. The dashboard link builder, which only builds core dashboard URLs, moves from `chat/slack/` to `chat/dashboard-link.ts`. - Detail API: `brief` (latest version, content, updated time) on `GET /api/conversations/:id`, behind the same privacy gate as annotations. - Feed search: `q` now matches brief text via full-text search in addition to the title substring. ## Verification - New `tests/component/briefs/conversation-brief-search.test.ts` and `tests/integration/search-conversation-briefs-tool.test.ts`; extended detail, list, and tool-registration tests. - `pnpm typecheck`, `pnpm --filter @sentry/junior lint`, `tool-annotations:check`, `tool-error-classification:check`, `pnpm file-length:check`, `pnpm test-architecture:check`. --------- Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
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.


Stacked on #1805. Milestone 3 of conversation briefs: production wiring of storage and generation. No user-visible surface yet; search, API, and dashboard follow in #1808 and #1810.
What
createApp({ briefs: { enabled: true } }), mirroring experimental features. It is off by default because it costs one default-model call per completed Turn; the example app, thejunior initscaffold, andjunior chatenable it. Integration tests stay off unless they opt in, so no test turn ever reaches the model gateway.junior_conversation_briefs: append-only versions, one per completed Turn (conversation_id, versionPK; uniqueconversation_id, turn_id;through_seq; GIN index onsearch_textfor feat(briefs): search briefs from the agent, API, and feed #1808).briefs.updateBrieftask delivered through the existing plugin task queue after Slack, web, and local Turns with a user instruction. It builds its input from durable SQL events through the same event-to-entry mapping the CLI snapshot adapter uses, runs the tuned generator with the configured default model, and stores the next version under a per-conversation lock.briefs/brief_updatedstructured conversation event with version, model id, item counts, and model cost. Cost rolls into the conversation auxiliary-cost breakdown under thebriefsnamespace and renders in conversation history.TERMINOLOGY.mdgains Brief; the module README documents storage, versioning, purge, and the privacy gate later readers must apply.Verification
tests/component/briefs/conversation-brief-task.test.ts(new), the extended purge scenario intests/component/conversations/retention.test.ts, the plugin task scheduling and event rendering tests: 84 tests pass against Postgres.tests/unit/cli/init-cli.test.tskeeps the scaffold aligned with the example app.pnpm typecheck,pnpm --filter @sentry/junior lint,pnpm migration-metadata:check,pnpm file-length:check,pnpm test-architecture:check.