Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
fcb1fb0
fix(respond): complete requester identity from session record in resu…
sentry-junior[bot] Jun 5, 2026
27663f9
fix(respond): complete requester identity from session record in resu…
sentry-junior[bot] Jun 5, 2026
03a536c
fix(user): reconstruct requester identity at continuation endpoints
sentry-junior[bot] Jun 5, 2026
7cfcb3f
fix(user): use stored session requester directly in continuation endp…
sentry-junior[bot] Jun 5, 2026
191103a
fix(user): drop userId comparison from resolveSlackResumeRequester
sentry-junior[bot] Jun 5, 2026
3fdaee7
fix(user): make resolveSlackResumeRequester synchronous with no live …
sentry-junior[bot] Jun 5, 2026
074911f
fix(user): type resolveSlackResumeRequester with AgentTurnRequester
sentry-junior[bot] Jun 5, 2026
ecc3908
fix(user): stored is the single source — drop separate userId param
sentry-junior[bot] Jun 5, 2026
1343a1c
fix(user): one direct path — no fallbacks in resolveSlackResumeRequester
sentry-junior[bot] Jun 5, 2026
6f0c64c
fix(user): inline identity remap at continuation endpoints
sentry-junior[bot] Jun 5, 2026
454af7b
test: seed session records with requester identity in continuation tests
sentry-junior[bot] Jun 6, 2026
b6355ee
feat(session-log): store requester identity in canonical session log
sentry-junior[bot] Jun 6, 2026
747dc1f
refactor(turn-session): hard break — requester identity from session …
sentry-junior[bot] Jun 6, 2026
fc422d4
fix(slack): Process pending work before continuations
dcramer Jun 9, 2026
cd4ca32
fix(slack): Remove stale session log import
dcramer Jun 9, 2026
b7ea1da
fix(slack): Preserve requester on empty session commits
dcramer Jun 9, 2026
e7c0b7b
fix(slack): Keep requester through compaction resets
dcramer Jun 9, 2026
435a08f
fix(junior): Complete conversation continuation cleanup
dcramer Jun 9, 2026
7b6ffcd
fix(junior): Preserve active continuation on Slack skips
dcramer Jun 9, 2026
38172f2
fix(junior): Ack stale conversation queue messages
dcramer Jun 9, 2026
3e6f890
ref(junior): Centralize requester modeling
dcramer Jun 9, 2026
e14894e
fix(junior): Scope requester identity to Slack workspace
dcramer Jun 9, 2026
f388e69
fix(junior): Migrate awaiting continuation work
dcramer Jun 9, 2026
e971ab2
test(junior): Update Slack requester expectation
dcramer Jun 9, 2026
0716abe
ref(junior): Remove redundant requester aliases
dcramer Jun 9, 2026
2ced1f2
fix(junior): Preserve steered turn transcript scope
dcramer Jun 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Co-Authored-By: (agent model name) <email>
- `policies/context-bound-systems.md` (explicit actor/destination/context propagation across runtime boundaries)
- `policies/evals.md` (evals as behavior integration tests and rubric authoring boundaries)
- `policies/frontend-components.md` (Tailwind colocation and component-owned frontend styling)
- `policies/interface-design.md` (naming, module paths, and minimal interface boundaries)
- `policies/interface-design.md` (domain naming, module paths, and minimal interface boundaries)
- `policies/policy-template.md` (template for adding new policy docs)
- `policies/runtime-boundary-schemas.md` (strict runtime schemas and inferred types for boundary contracts)
- `policies/test-adapters.md` (Django-inspired shared test adapters, outboxes, and isolation rules)
Expand All @@ -87,7 +87,7 @@ Co-Authored-By: (agent model name) <email>
- Do not leak third-party SDK types across chat subsystem boundaries when a small local interface will do; keep vendor SDKs inside infrastructure modules.
- Service modules must depend on small injected ports for Slack behavior, not import Slack infrastructure directly.
- Slack modules must not import runtime modules.
- `runtime/` orchestrates turns and turn-scoped formatting, `services/` do domain work (reply policy, delivery planning, channel intent, attachment validation), `state/` persists by concern, `ingress/` only parses, classifies, and routes source events.
- `runtime/` orchestrates agent runs and response-scoped formatting, `services/` do domain work (reply policy, delivery planning, channel intent, attachment validation), `state/` persists by concern, `ingress/` only parses, classifies, and routes source events.
- **Feature-based colocation**: group files by domain feature, not by technical role. Within a module, create subdirectories for each feature domain (e.g., `tools/slack/`, `tools/web/`, `tools/sandbox/`, `tools/skill/`). Shared contracts and cross-cutting utilities live at the module root. Only extract to a shared location when 2+ features need the same code.
- Do not use barrel `index.ts` re-exports inside feature subdirectories — import directly from the source file. A module-root `index.ts` is acceptable as a composition root that wires features together.
- Queue and worker paths must depend on injected runtime interfaces or factories, not import the production singleton from `@/chat/app/production`.
Expand All @@ -114,7 +114,7 @@ Co-Authored-By: (agent model name) <email>
- `specs/data-redaction-policy.md` (conversation privacy classification and raw payload redaction policy)
- `specs/chat-architecture.md` (chat composition, service, and test-seam architecture contract)
- `specs/task-execution.md` (durable conversation mailbox, queue wake-up, lease, and heartbeat execution contract)
- `specs/agent-turn-handling.md` (agent user-message response policy: reply/silence, tool use, Slack side effects, resumed turns, and completion)
- `specs/agent-turn-handling.md` (agent user-message response policy: reply/silence, tool use, Slack side effects, resumed runs, and completion)
- `specs/slack-agent-delivery.md` (Slack entry surfaces, reply delivery, continuation, files, images, and resume behavior contract)
- `specs/slack-outbound-contract.md` (Slack outbound boundary, message/file/reaction safety rules, and markdown-to-`mrkdwn` ownership)
- `specs/identity.md` (current actor, system actor, requester, author, creator, credential subject, service principal, and display identity contract)
Expand All @@ -127,7 +127,7 @@ Co-Authored-By: (agent model name) <email>
- `specs/plugin-heartbeat.md` (plugin heartbeat and tool hook contract)
- `specs/plugin-dispatch.md` (durable plugin agent dispatch contract)
- `specs/harness-agent.md` (agent loop and output contract)
- `specs/agent-session-resumability.md` (multi-slice turn resumability and timeout recovery contract)
- `specs/agent-session-resumability.md` (multi-slice agent-run resumability and timeout recovery contract)
- `specs/agent-execution.md` (agent execution rubric and completion gates)
- `specs/instrumentation.md` (logging/tracing spec index)
- `specs/plugin.md` (plugin architecture for self-contained provider integrations)
Expand Down
8 changes: 4 additions & 4 deletions TELEMETRY.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ fields=timestamp,level,event.name,span_id,gen_ai.conversation.id,error.type,exce
sort=timestamp
```

Recent failed or timed-out turns.
Recent failed or timed-out agent runs.

```text
dataset=logs query='event.name:agent_turn_timeout OR event.name:agent_turn_failed OR event.name:agent_turn_provider_error'
Expand Down Expand Up @@ -163,15 +163,15 @@ A turn parked for auth, resumed late, or failed after callback.

Events: `credential_issue_failed`, `credential_issue_request`,
`credential_issue_success`, `mention_handler_auth_pause`,
`subscribed_message_handler_auth_pause`, `timeout_resume_handler_failed`,
`timeout_resume_lock_busy`, `oauth_callback_resume_complete`,
`subscribed_message_handler_auth_pause`, `agent_continue_schedule_failed`,
`agent_continue_lock_busy`, `oauth_callback_resume_complete`,
`mcp_oauth_callback_failed`

Spans: resumed `chat.turn`, `chat.reply`

Attributes: `app.credential.provider`, `app.credential.delivery`,
`app.ai.retryable_reason`, `app.ai.session_id`,
`app.ai.resume_checkpoint_version`
`app.ai.resume_session_version`

### Skills And Plugins

Expand Down
6 changes: 5 additions & 1 deletion packages/docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ export default defineConfig({
{ label: "GitHub Plugin", link: "/extend/github-plugin/" },
{ label: "Hex Plugin", link: "/extend/hex-plugin/" },
{ label: "Linear Plugin", link: "/extend/linear-plugin/" },
{ label: "Maintenance Plugin", link: "/extend/maintenance-plugin/" },
{
label: "Maintenance Plugin",
link: "/extend/maintenance-plugin/",
},
{ label: "Notion Plugin", link: "/extend/notion-plugin/" },
{ label: "Scheduler Plugin", link: "/extend/scheduler-plugin/" },
{ label: "Sentry Plugin", link: "/extend/sentry-plugin/" },
Expand Down Expand Up @@ -140,6 +143,7 @@ export default defineConfig({
label: "junior snapshot create",
link: "/cli/snapshot-create/",
},
{ label: "junior upgrade", link: "/cli/upgrade/" },
],
},
{
Expand Down
1 change: 1 addition & 0 deletions packages/docs/src/content/docs/cli/check.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ related:
- /extend/
- /cli/init/
- /cli/snapshot-create/
- /cli/upgrade/
---

`junior check` validates local app content, installed plugin package content, and Junior deployment config before build or deploy. It ignores legacy top-level `plugins/` and `skills/` directories, and it only runs app-file checks when the target already looks like a Junior app.
Expand Down
1 change: 1 addition & 0 deletions packages/docs/src/content/docs/cli/snapshot-create.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ related:
- /reference/config-and-env/
- /start-here/quickstart/
- /cli/check/
- /cli/upgrade/
- /operate/sandbox-snapshots/
- /operate/observability/
---
Expand Down
76 changes: 76 additions & 0 deletions packages/docs/src/content/docs/cli/upgrade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
title: "junior upgrade"
description: "Run one-shot Junior state upgrade migrations."
type: reference
summary: Move persisted Junior state forward after upgrading packages.
prerequisites:
- /start-here/quickstart/
related:
- /reference/config-and-env/
- /cli/check/
- /cli/snapshot-create/
---

Use `junior upgrade` after installing a Junior release that includes a one-shot state migration. The command mutates the configured state store, so run it from the same app environment that has `REDIS_URL` and `JUNIOR_STATE_KEY_PREFIX` configured for the deployment you are upgrading.

## Usage

Run it from a project that already has `@sentry/junior` installed:

```bash
pnpm exec junior upgrade
```

The command takes no extra arguments.

## What it does

`junior upgrade` runs registered migrations sequentially. The current migration moves legacy `junior:conversation-work:*` Redis state into the newer conversation record and index state used by the durable worker and dashboard feed.

The migration is idempotent: rerunning it skips records that were already moved and removes stale legacy index entries that no longer have a record.

## Vercel deploys

Run `junior upgrade` as an out-of-band production maintenance command, not as a permanent request-time path. Vercel build jobs can run the command when they have production `REDIS_URL` access, but build-time alone can leave a small cutover window where the old deployment writes more legacy state.

For production deploys that need this migration, use this order:

1. Load the same `REDIS_URL` and `JUNIOR_STATE_KEY_PREFIX` used by the production deployment.
2. Run `pnpm exec junior upgrade`.
3. Build and deploy the new release.
4. Run `pnpm exec junior upgrade` again after the deploy is serving traffic.

The second run is safe because the migration is idempotent, and it catches records written by the old deployment during the Vercel build or promotion window.

## Example output

Typical logs look like this:

```text
Running Junior upgrade migrations...
Running migration migrate-legacy-conversation-work-redis-state...
Finished migration migrate-legacy-conversation-work-redis-state: scanned=2 migrated=1 existing=0 missing=1
Junior upgrade complete.
```

## Failure behavior

If the configured state store is unavailable or a legacy record is malformed, the CLI exits non-zero and prints the underlying error:

```text
junior command failed: Legacy conversation work state is invalid for slack:C123:1712345.0001
```

Treat that as a deploy blocker for the affected environment. Check `REDIS_URL`, `JUNIOR_STATE_KEY_PREFIX`, and the reported legacy record before retrying.

## Verification

After running the command:

1. Confirm the final log line includes `Junior upgrade complete`.
2. Confirm the migration summary has the expected `scanned` and `migrated` counts.
3. Run `pnpm exec junior check` before building or deploying the app.

## Next step

Run [junior check](/cli/check/) after the upgrade, then continue with [junior snapshot create](/cli/snapshot-create/) if your plugins need sandbox dependencies.
8 changes: 4 additions & 4 deletions packages/docs/src/content/docs/concepts/execution-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ related:

1. Slack sends an event to `/api/webhooks/slack`.
2. Junior validates and routes the event.
3. Thread work is enqueued to `junior-thread-message`.
4. `/api/queue/callback` processes queued work.
5. Agent turn runs with configured tools, loaded skills, and capability gates.
3. Conversation work is enqueued to the durable conversation-work queue.
4. `/api/internal/agent/continue` processes queued conversation work.
5. The agent run continues with configured tools, loaded skills, and capability gates.
6. If sandbox traffic reaches a declared provider domain, the sandbox egress proxy lazily fetches requester-bound credentials and injects them at the host boundary.
7. If OAuth is required, Junior sends the link privately to the requesting user and resumes the blocked request after the callback.
8. Reply is posted back to the original Slack thread.
Expand All @@ -30,7 +30,7 @@ related:
## Core invariants

- Webhook ingress and queue callback are both required for production.
- Tool usage is turn-scoped; sandbox credential leases are requester-bound and minted lazily only after forwarded provider traffic needs them.
- Tool usage is agent-run scoped; sandbox credential leases are requester-bound and minted lazily only after forwarded provider traffic needs them.
- Registered plugin providers determine which provider credentials can be injected for matching provider domains.
- Failure states are logged and surfaced for operator recovery.

Expand Down
6 changes: 3 additions & 3 deletions packages/docs/src/content/docs/operate/dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,15 @@ The current dashboard API slices are:
| `/api/dashboard/runtime` | Runtime paths, providers, skills, and packages. |
| `/api/dashboard/plugins` | Loaded plugin list. |
| `/api/dashboard/skills` | Discovered skill list. |
| `/api/dashboard/sessions` | Recent conversation feed from turn-session checkpoints. |
| `/api/dashboard/sessions` | Recent conversation feed from the conversation activity index. |
| `/api/dashboard/conversation-stats` | Aggregate conversation stats, people/place leaderboards, and sampling metadata. |
| `/api/dashboard/plugin-reports` | Sanitized plugin operational summaries. |
| `/api/dashboard/conversations/:conversation` | Expiring conversation transcript; private conversations return redacted metadata only. |
| `/api/dashboard/config` | Safe dashboard config signals and feature readiness. |
| `/api/dashboard/me` | Signed-in dashboard identity. |

The dashboard UI is a React client using React Router for browser views and TanStack Query to poll dashboard APIs. `/` shows command-center health, aggregate conversation stats, and recent turn durations; `/conversations` shows conversation history; `/conversations/:conversation` shows the transcript and turn/tool-call detail for one conversation; `/plugins` shows loaded plugin inventory and plugin operational summaries. The dashboard does not wrap Slack webhooks, provider OAuth callbacks, sandbox egress, or `/api/internal/*`.
The conversation feed is a bounded metadata index with the same expiration policy as turn-session checkpoints. Conversation detail reads transcript data from the expiring checkpoint message store, so old transcripts disappear when checkpoint state expires. When `SENTRY_DSN` initializes the runtime and `SENTRY_ORG_SLUG` is set, conversation rows include a Sentry conversation link; when the runtime captures a trace ID, conversation detail shows it with the turn metadata.
The dashboard UI is a React client using React Router for browser views and TanStack Query to poll dashboard APIs. `/` shows command-center health, aggregate conversation stats, and recent run durations; `/conversations` shows conversation history; `/conversations/:conversation` shows the transcript and run/tool-call detail for one conversation; `/plugins` shows loaded plugin inventory and plugin operational summaries. The dashboard does not wrap Slack webhooks, provider OAuth callbacks, sandbox egress, or `/api/internal/*`.
The conversation feed is backed by the bounded conversation activity index. Conversation detail joins run metadata and transcript data from expiring session stores, so old transcripts disappear when session state expires. When `SENTRY_DSN` initializes the runtime and `SENTRY_ORG_SLUG` is set, conversation rows include a Sentry conversation link; when the runtime captures a trace ID, conversation detail shows it with the run metadata.
The conversation stats endpoint is separate from the recent feed and includes `sampleLimit`, `sampleSize`, and `truncated` fields so the UI can mark bounded aggregates.
Dashboard dates use `JUNIOR_TIMEZONE`, defaulting to `America/Los_Angeles`.

Expand Down
14 changes: 12 additions & 2 deletions packages/docs/src/content/docs/operate/observability.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ related:
## Key event signals

- `webhook_handler_failed`
- `queue_callback_failed`
- `conversation_work_failed`
- `conversation_work_recovery_failed`
- `agent_continue_schedule_failed`
- `agent_turn_failed`
- `agent_turn_timeout`
- `agent_tool_call_failed`
Expand Down Expand Up @@ -42,7 +44,15 @@ event.name:webhook_handler_failed
```

```text
event.name:queue_callback_failed OR event.name:queue_message_failed
event.name:conversation_work_failed OR event.name:conversation_work_recovery_failed
```

```text
event.name:conversation_work_pending_requeued OR event.name:conversation_work_lease_expired_requeued
```

```text
event.name:agent_continue_schedule_failed OR event.name:agent_continue_lock_busy
```

```text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ Question: are messages enqueued and processed successfully?

Check:

- `event.name:queue_callback_failed OR event.name:queue_message_failed`
- `event.name:queue_ingress_dedup_hit`
- `event.name:conversation_work_failed OR event.name:conversation_work_recovery_failed`
- `event.name:conversation_work_pending_requeued OR event.name:conversation_work_lease_expired_requeued`
- `event.name:agent_continue_schedule_failed OR event.name:agent_continue_lock_busy`
- `span.op:queue.process_message`

## Turn execution failures
Expand Down
5 changes: 4 additions & 1 deletion packages/docs/src/content/docs/reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ summary: Find the generated API entrypoints for app creation, Nitro wiring, Verc
prerequisites:
- /reference/handler-surface/
related:
- /operate/dashboard/
- /reference/config-and-env/
- /start-here/quickstart/
---
Expand All @@ -19,6 +20,7 @@ The API reference is generated from public package entry points.
- [Nitro wiring](/reference/api/functions/juniornitro/)
- [Vercel config helper](/reference/api/functions/juniorvercelconfig/)
- [Instrumentation](/reference/api/functions/initsentry/)
- [Reporting](/reference/api/functions/createjuniorreporting/)

## Suggested reading order

Expand All @@ -27,7 +29,8 @@ The API reference is generated from public package entry points.
3. Read `juniorNitro` options before changing plugin package bundling.
4. For plugin hooks, use `@sentry/junior-plugin-api` from a plugin
package and register the returned `JuniorPlugin` with `createApp()`.
5. Read instrumentation exports for telemetry setup.
5. Read reporting exports when building dashboard or operational views.
6. Read instrumentation exports for telemetry setup.

## Next step

Expand Down
24 changes: 24 additions & 0 deletions packages/docs/src/content/docs/reference/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,43 @@ title: "@sentry/junior"

## Interfaces

- [ConversationFeed](/reference/api/interfaces/conversationfeed/)
- [ConversationReport](/reference/api/interfaces/conversationreport/)
- [ConversationRunReport](/reference/api/interfaces/conversationrunreport/)
- [ConversationStatsItem](/reference/api/interfaces/conversationstatsitem/)
- [ConversationStatsReport](/reference/api/interfaces/conversationstatsreport/)
- [ConversationSummaryReport](/reference/api/interfaces/conversationsummaryreport/)
- [ConversationUsage](/reference/api/interfaces/conversationusage/)
- [HealthReport](/reference/api/interfaces/healthreport/)
- [JuniorAppOptions](/reference/api/interfaces/juniorappoptions/)
- [JuniorNitroOptions](/reference/api/interfaces/juniornitrooptions/)
- [JuniorPluginSet](/reference/api/interfaces/juniorpluginset/)
- [JuniorPluginSetOptions](/reference/api/interfaces/juniorpluginsetoptions/)
- [JuniorReporting](/reference/api/interfaces/juniorreporting/)
- [JuniorVercelConfigOptions](/reference/api/interfaces/juniorvercelconfigoptions/)
- [PluginOperationalReport](/reference/api/interfaces/pluginoperationalreport/)
- [PluginOperationalReportFeed](/reference/api/interfaces/pluginoperationalreportfeed/)
- [PluginPackageContentItemReport](/reference/api/interfaces/pluginpackagecontentitemreport/)
- [PluginPackageContentReport](/reference/api/interfaces/pluginpackagecontentreport/)
- [PluginReport](/reference/api/interfaces/pluginreport/)
- [RequesterIdentity](/reference/api/interfaces/requesteridentity/)
- [RuntimeInfoReport](/reference/api/interfaces/runtimeinforeport/)
- [SkillReport](/reference/api/interfaces/skillreport/)
- [TranscriptMessage](/reference/api/interfaces/transcriptmessage/)
- [TranscriptPart](/reference/api/interfaces/transcriptpart/)

## Type Aliases

- [ConversationReportStatus](/reference/api/type-aliases/conversationreportstatus/)
- [ConversationSurface](/reference/api/type-aliases/conversationsurface/)
- [JuniorPluginInput](/reference/api/type-aliases/juniorplugininput/)
- [TranscriptPartType](/reference/api/type-aliases/transcriptparttype/)
- [TranscriptRole](/reference/api/type-aliases/transcriptrole/)

## Functions

- [createApp](/reference/api/functions/createapp/)
- [createJuniorReporting](/reference/api/functions/createjuniorreporting/)
- [defineJuniorPlugins](/reference/api/functions/definejuniorplugins/)
- [initSentry](/reference/api/functions/initsentry/)
- [juniorNitro](/reference/api/functions/juniornitro/)
Expand Down
Loading
Loading