@sentry/junior 0.268.0 → 0.270.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +2 -9
  2. package/dist/{adapter-04AcD2SO.js → adapter-BQNTKVTF.js} +3 -49
  3. package/dist/{admin-DIU1QyG3.js → admin-CKVEoXa4.js} +1 -1
  4. package/dist/{agent-runner-CAYfFmU7.js → agent-runner-MSQSMFkq.js} +4538 -3251
  5. package/dist/api/schema.d.ts +2 -3
  6. package/dist/api/schema.js +7 -7
  7. package/dist/api.d.ts +3 -1
  8. package/dist/api.js +190 -301
  9. package/dist/{app-z6Uuyq3j.d.ts → app-Bz8t4P8p.d.ts} +9 -3
  10. package/dist/app.d.ts +1 -1
  11. package/dist/app.js +129 -209
  12. package/dist/{automation-CmeFBSEh.js → automation-Dwh_xcqM.js} +74 -74
  13. package/dist/{briefs-DQbV2jNr.js → briefs-DNFzFFVx.js} +5 -5
  14. package/dist/{catalog-runtime-BD9GSpc6.js → catalog-runtime-Bdym_wKy.js} +1 -1
  15. package/dist/cli/chat.js +16 -26
  16. package/dist/cli/check.js +3 -3
  17. package/dist/cli/main.js +5 -3
  18. package/dist/cli/plugins.js +4 -4
  19. package/dist/cli/snapshot-create.js +4 -4
  20. package/dist/cli/upgrade.d.ts +1 -1
  21. package/dist/cli/upgrade.js +3 -3
  22. package/dist/{client-C1yDYjoS.js → client-B2MjENki.js} +31 -16
  23. package/dist/{config-DrTeF80T.js → config-Dm3pWRqY.js} +3 -3
  24. package/dist/{connections-D46f8vvi.js → connections-0BBhiD-p.js} +10 -10
  25. package/dist/{conversation-DSo310Ps.js → conversation-AhOVzN_k.js} +11 -86
  26. package/dist/{conversation-privacy-CxlOCiUo.js → conversation-privacy-C1pJ89rs.js} +1 -1
  27. package/dist/{credential-sync-sm9fegLY.js → credential-sync-BRiWYs6_.js} +15 -14
  28. package/dist/{credentialed-lukuD-cc.js → credentialed-BeBaJMZ_.js} +565 -83
  29. package/dist/{store-xMuuXRE0.d.ts → db-BYOuu6v2.d.ts} +4 -0
  30. package/dist/{executor-4vhvsMZJ.js → executor-BB6eJkD4.js} +6 -6
  31. package/dist/instrumentation.js +2 -2
  32. package/dist/{interruption-marker-CkncDT8d.js → interruption-marker-CdblrIQK.js} +1 -1
  33. package/dist/{job-queue-In9QKz-I.js → job-queue-DiaXoSDg.js} +2 -2
  34. package/dist/{list-BkgnXEEB.js → list-BTDRxkOg.js} +331 -662
  35. package/dist/locks-D-0h111u.js +48 -0
  36. package/dist/{logging-DLSpkSSr.js → logging-C6EdT6PP.js} +1 -1
  37. package/dist/{history-C84mlAwO.js → media-U6Tuz6Mi.js} +84 -2
  38. package/dist/{message-BObyg59s.js → message-DsjiWRVg.js} +4 -4
  39. package/dist/{model-profile-Bg8EoCKD.js → model-profile-B998sjVd.js} +9 -2
  40. package/dist/nitro.d.ts +1 -1
  41. package/dist/nitro.js +5 -3
  42. package/dist/{oauth-callback-server-B-WbSdoH.js → oauth-callback-server-CjFFVGqa.js} +2 -2
  43. package/dist/{prompt-BW9jFsqZ.js → prompt-BPSdXYXV.js} +1 -1
  44. package/dist/{registry-BgecKva0.js → registry-CndmkP2P.js} +1 -1
  45. package/dist/reporting-schema-CZREhYc-.js +104 -0
  46. package/dist/{web-message-id-DlHNANtd.js → reporting-window-DRCi1Ls_.js} +139 -7
  47. package/dist/{resolve-Cpa4Bu1O.js → resolve-BkAA1wH7.js} +3 -3
  48. package/dist/{result-D3TSmZZ8.js → result-9TJTpuYP.js} +30 -11
  49. package/dist/{runner-DS5OKhEp.js → runner-BmKLSyJm.js} +12 -11
  50. package/dist/{sandbox-egress-signals-CnDjY5rx.js → sandbox-egress-signals-CjLaogMo.js} +1 -1
  51. package/dist/{schema-0050HFnB.js → schema-DNLJ_MzW.js} +36 -20
  52. package/dist/{schema-ZngqcOWM.d.ts → schema-WayPSHFu.d.ts} +149 -12
  53. package/dist/{service-account-CKV2WTY7.js → service-account-D6e9cVmH.js} +4 -3
  54. package/dist/{service-account-DGjnDw9y.js → service-account-DlhYl-Mu.js} +3 -3
  55. package/dist/{session-stop-Dam1EI7B.js → session-stop-MZRgYqYH.js} +24 -16
  56. package/dist/{skills-CfAnfImD.js → skills-BggTR_ue.js} +2 -2
  57. package/dist/{spawn-cmq9p4Ly.js → spawn-DmtlcAT_.js} +2 -2
  58. package/dist/{store-zPEoJPBB.js → store-BeWGgaMA.js} +3 -3
  59. package/dist/{store-C5PN02QO.js → store-Byarin7b.js} +4 -4
  60. package/dist/{task-queue-_mf28dSu.js → task-queue-Dt1_ZoI_.js} +3 -3
  61. package/dist/task-runner-DyKqAPpm.js +269 -0
  62. package/dist/{thread-state-BbbPh0Sn.js → thread-state-BHBLMvgb.js} +5 -5
  63. package/dist/{turn-failure-response-BKKmnMB5.js → turn-failure-response-DWXy_0oJ.js} +9 -9
  64. package/dist/{turn-lifecycle-oP0kVeGz.js → turn-lifecycle-AiXkVqCB.js} +1 -1
  65. package/dist/{tasks-SB9z-VTU.js → turn-session-routing-B9KLBhaT.js} +939 -120
  66. package/dist/{validation--JsAGLwc.js → validation-BW60Vtx_.js} +1 -1
  67. package/dist/{version-jHwJp4hC.js → version-CivPYmkH.js} +1 -1
  68. package/dist/version.js +1 -1
  69. package/dist/{viewer-CpXTGlep.js → viewer-BTgAfdUg.js} +216 -27
  70. package/dist/{work-3N-GHY9m.js → work-Bjm52fHo.js} +17 -36
  71. package/dist/{worker-CCdbcItd.js → worker-CMbgtHLu.js} +15 -7
  72. package/migrations/0069_system_identity.sql +25 -0
  73. package/migrations/0070_review_item_foreign_keys.sql +5 -0
  74. package/migrations/AGENTS.md +17 -0
  75. package/migrations/meta/0069_snapshot.json +3979 -0
  76. package/migrations/meta/0070_snapshot.json +3997 -0
  77. package/migrations/meta/_journal.json +15 -1
  78. package/package.json +5 -4
  79. package/dist/db-BU4LQD8s.d.ts +0 -6
  80. package/dist/history-BgI33Kie.d.ts +0 -78
  81. package/dist/reporting-window-DVCD_10C.js +0 -227
  82. package/dist/task-runner-DMI2prDO.js +0 -1073
  83. package/migrations/README.md +0 -30
@@ -0,0 +1,48 @@
1
+ import { setTimeout } from "node:timers/promises";
2
+ // src/chat/state/locks.ts
3
+ const ACTIVE_LOCK_TTL_MS = 9e4;
4
+ const MUTATION_LOCK_TTL_MS = 1e4;
5
+ /**
6
+ * Acquire a lock for long-running work that the queued state adapter should
7
+ * keep alive while the owning invocation is still making progress.
8
+ */
9
+ async function acquireActiveLock(state, threadId) {
10
+ return await state.acquireLock(threadId, ACTIVE_LOCK_TTL_MS);
11
+ }
12
+ /**
13
+ * Run work under one lock, optionally waiting for the current owner.
14
+ * `keepAlive` is for multi-store mutations that must retain ownership until all
15
+ * side effects finish; callers should still fence each blind write.
16
+ */
17
+ async function withLock(state, key, run, options = {}) {
18
+ const ttlMs = options.ttlMs ?? 9e4;
19
+ const startedAtMs = Date.now();
20
+ let lock;
21
+ while (true) {
22
+ lock = await state.acquireLock(key, ttlMs);
23
+ if (lock) break;
24
+ if (Date.now() - startedAtMs >= (options.waitMs ?? 0)) return { acquired: false };
25
+ await setTimeout(options.retryMs ?? 25, void 0, { ref: false });
26
+ }
27
+ const heartbeat = options.keepAlive ? setInterval(() => void state.extendLock(lock, ttlMs).catch(() => void 0), Math.max(1, Math.floor(ttlMs / 3))) : void 0;
28
+ heartbeat?.unref();
29
+ try {
30
+ return {
31
+ acquired: true,
32
+ value: await run(lock)
33
+ };
34
+ } finally {
35
+ if (heartbeat) clearInterval(heartbeat);
36
+ await state.releaseLock(lock);
37
+ }
38
+ }
39
+ /**
40
+ * Prove lock ownership immediately before a blind write.
41
+ *
42
+ * Whole-record mutations must stop if their lock expired rather than overwrite
43
+ * state committed by a newer owner.
44
+ */
45
+ async function fenceLock(state, lock, ttlMs = MUTATION_LOCK_TTL_MS) {
46
+ if (!await state.extendLock(lock, ttlMs)) throw new Error(`Lock ownership was lost before write for ${lock.threadId}`);
47
+ }
48
+ export { withLock as a, fenceLock as i, MUTATION_LOCK_TTL_MS as n, acquireActiveLock as r, ACTIVE_LOCK_TTL_MS as t };
@@ -1,5 +1,5 @@
1
1
  import { _ as withScope, d as setTag, f as setUser, h as startSpan, i as getActiveSpan, l as logger, n as captureMessage, p as spanToJSON, s as getTraceData, t as captureException } from "./sentry-MDkYAVPV.js";
2
- import { t as JUNIOR_VERSION } from "./version-jHwJp4hC.js";
2
+ import { t as JUNIOR_VERSION } from "./version-CivPYmkH.js";
3
3
  import path from "node:path";
4
4
  import { styleText } from "node:util";
5
5
  import { ConfigError, configureSync, getConfig, getLogger } from "@logtape/logtape";
@@ -1,4 +1,4 @@
1
- import { l as TURN_REASONING_LEVELS, s as modelProfileSchema } from "./model-profile-Bg8EoCKD.js";
1
+ import { c as modelProfileSchema, u as TURN_REASONING_LEVELS } from "./model-profile-B998sjVd.js";
2
2
  import { z } from "zod";
3
3
  import { actorSchema } from "@sentry/junior-plugin-api";
4
4
  // src/usage-schema.ts
@@ -522,4 +522,86 @@ const newConversationEventSchema = z.object({
522
522
  idempotencyKey: z.string().min(1).optional(),
523
523
  createdAtMs: z.number().finite()
524
524
  }).strict();
525
- export { conversationTurnFailureReasonSchema as a, newConversationEventSchema as c, contextProvenance as d, instructionActors as f, usageSchema as h, conversationTurnFailureCodeSchema as i, encodeHistoryPayload as l, sameActorIdentity as m, agentHistoryItemSchema as n, decodeStoredConversationEvent as o, instructionProvenanceFor as p, conversationEventDataSchema as r, historyReplacementSchema as s, KNOWN_CONVERSATION_EVENT_TYPES as t, agentInstructionProvenance as u };
525
+ // src/chat/attachments/media.ts
526
+ const INPUT_IMAGE_TYPES = [
527
+ "image/png",
528
+ "image/jpeg",
529
+ "image/gif",
530
+ "image/webp"
531
+ ];
532
+ /** Leading bytes of each accepted image type. `null` matches any byte. */
533
+ const IMAGE_SIGNATURES = [
534
+ {
535
+ mediaType: "image/png",
536
+ bytes: [
537
+ 137,
538
+ 80,
539
+ 78,
540
+ 71,
541
+ 13,
542
+ 10,
543
+ 26,
544
+ 10
545
+ ]
546
+ },
547
+ {
548
+ mediaType: "image/jpeg",
549
+ bytes: [
550
+ 255,
551
+ 216,
552
+ 255
553
+ ]
554
+ },
555
+ {
556
+ mediaType: "image/gif",
557
+ bytes: [
558
+ 71,
559
+ 73,
560
+ 70,
561
+ 56,
562
+ 55,
563
+ 97
564
+ ]
565
+ },
566
+ {
567
+ mediaType: "image/gif",
568
+ bytes: [
569
+ 71,
570
+ 73,
571
+ 70,
572
+ 56,
573
+ 57,
574
+ 97
575
+ ]
576
+ },
577
+ {
578
+ mediaType: "image/webp",
579
+ bytes: [
580
+ 82,
581
+ 73,
582
+ 70,
583
+ 70,
584
+ null,
585
+ null,
586
+ null,
587
+ null,
588
+ 87,
589
+ 69,
590
+ 66,
591
+ 80
592
+ ]
593
+ }
594
+ ];
595
+ /**
596
+ * Detect an accepted image type from file bytes. Use this instead of a file
597
+ * name or declared content type, which can be wrong.
598
+ */
599
+ function detectImageMediaType(data) {
600
+ return IMAGE_SIGNATURES.find(({ bytes }) => data.length >= bytes.length && bytes.every((byte, index) => byte === null || data[index] === byte))?.mediaType;
601
+ }
602
+ /** Report whether a media type is a raster image accepted by vision models. */
603
+ function isVisionImageMediaType(mediaType) {
604
+ const normalized = mediaType.split(";", 1)[0]?.trim().toLowerCase();
605
+ return normalized ? INPUT_IMAGE_TYPES.some((type) => type === normalized) : false;
606
+ }
607
+ export { sameActorIdentity as _, agentHistoryItemSchema as a, conversationTurnFailureReasonSchema as c, newConversationEventSchema as d, encodeHistoryPayload as f, instructionProvenanceFor as g, instructionActors as h, KNOWN_CONVERSATION_EVENT_TYPES as i, decodeStoredConversationEvent as l, contextProvenance as m, detectImageMediaType as n, conversationEventDataSchema as o, agentInstructionProvenance as p, isVisionImageMediaType as r, conversationTurnFailureCodeSchema as s, INPUT_IMAGE_TYPES as t, historyReplacementSchema as u, usageSchema as v };
@@ -1,8 +1,8 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-nwUcYXjP.js";
2
- import { Bt as actorFromRun, Vt as toolInvocationDestination } from "./agent-runner-CAYfFmU7.js";
3
- import { P as PARENT_AGENT_TARGET, i as createAgentInvocationForMessage, j as AgentMessageTargetError, o as findChildAgentConversationId, s as getActiveAgentInvocationForConversation } from "./store-C5PN02QO.js";
4
- import { n as enqueueAgentMessageToParent } from "./result-D3TSmZZ8.js";
5
- import { r as enqueueAgentInvocation } from "./work-3N-GHY9m.js";
2
+ import { At as actorFromRun, jt as toolInvocationDestination } from "./agent-runner-MSQSMFkq.js";
3
+ import { P as PARENT_AGENT_TARGET, i as createAgentInvocationForMessage, j as AgentMessageTargetError, o as findChildAgentConversationId, s as getActiveAgentInvocationForConversation } from "./store-Byarin7b.js";
4
+ import { r as enqueueAgentMessageToParent } from "./result-9TJTpuYP.js";
5
+ import { r as enqueueAgentInvocation } from "./work-Bjm52fHo.js";
6
6
  // src/chat/agent-invocations/message.ts
7
7
  var message_exports = /* @__PURE__ */ __exportAll({ bindMessageAgent: () => bindMessageAgent });
8
8
  /**
@@ -36,13 +36,20 @@ function formatModelProfile(profile, description) {
36
36
  function formatModelProfiles(profiles, profileNames) {
37
37
  return profileNames.map((profile) => `- ${formatModelProfile(profile, profiles[profile]?.description)}`).join("\n");
38
38
  }
39
- /** Identify durable profile bindings that the current host cannot resolve. */
39
+ /** Identify a profile name that the current host does not configure. */
40
40
  var ModelProfileNotConfiguredError = class extends Error {
41
41
  constructor(profile) {
42
42
  super(`Model profile "${profile}" is not configured`);
43
43
  this.name = "ModelProfileNotConfiguredError";
44
44
  }
45
45
  };
46
+ /**
47
+ * Resolve a durable profile binding against the configured profiles.
48
+ * A binding to a profile that the host removed uses the default profile.
49
+ */
50
+ function boundProfile(config, profile) {
51
+ return Object.hasOwn(config.profiles, profile) ? profile : config.defaultProfile;
52
+ }
46
53
  /** Resolve a model id from a configured profile. */
47
54
  function modelIdForProfile(config, profile) {
48
55
  return profileConfig(config, profile).modelId;
@@ -57,4 +64,4 @@ function profileConfig(config, profile) {
57
64
  if (!profileConfig) throw new ModelProfileNotConfiguredError(profile);
58
65
  return profileConfig;
59
66
  }
60
- export { formatModelProfiles as a, profileConfig as c, formatModelProfile as i, TURN_REASONING_LEVELS as l, ModelProfileNotConfiguredError as n, modelIdForProfile as o, defaultModelId as r, modelProfileSchema as s, DEFAULT_MODEL_PROFILES as t, parseTurnReasoningLevel as u };
67
+ export { formatModelProfile as a, modelProfileSchema as c, parseTurnReasoningLevel as d, defaultModelId as i, profileConfig as l, ModelProfileNotConfiguredError as n, formatModelProfiles as o, boundProfile as r, modelIdForProfile as s, DEFAULT_MODEL_PROFILES as t, TURN_REASONING_LEVELS as u };
package/dist/nitro.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as JuniorDashboardOptions } from "./app-z6Uuyq3j.js";
1
+ import { i as JuniorDashboardOptions } from "./app-Bz8t4P8p.js";
2
2
  import { n as JuniorPluginSet } from "./plugins-B_0Cr0MO.js";
3
3
  import { withSentryConfig as withSentryConfig$1 } from "@sentry/nitro";
4
4
  type SentryNitroConfig = Parameters<typeof withSentryConfig$1>[0];
package/dist/nitro.js CHANGED
@@ -1,8 +1,8 @@
1
- import { A as JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, D as JUNIOR_CONVERSATION_WORK_CALLBACK_ROUTE, F as getDeploymentServiceVersion, M as JUNIOR_RETENTION_ROUTE, N as JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE, O as JUNIOR_HEARTBEAT_CRON_SCHEDULE, j as JUNIOR_RETENTION_CRON_SCHEDULE, k as JUNIOR_HEARTBEAT_ROUTE } from "./logging-DLSpkSSr.js";
1
+ import { A as JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, D as JUNIOR_CONVERSATION_WORK_CALLBACK_ROUTE, F as getDeploymentServiceVersion, M as JUNIOR_RETENTION_ROUTE, N as JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE, O as JUNIOR_HEARTBEAT_CRON_SCHEDULE, j as JUNIOR_RETENTION_CRON_SCHEDULE, k as JUNIOR_HEARTBEAT_ROUTE } from "./logging-C6EdT6PP.js";
2
2
  import { d as resolvePackageDir, t as discoverInstalledPluginPackageContent, u as isValidPackageName } from "./package-discovery-DJBompdd.js";
3
- import { o as resolveConversationWorkQueueTopic, t as WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC } from "./job-queue-In9QKz-I.js";
3
+ import { o as resolveConversationWorkQueueTopic, t as WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC } from "./job-queue-DiaXoSDg.js";
4
4
  import { a as pluginRuntimeRegistrationsFromPluginSet, r as pluginCatalogConfigFromPluginSet } from "./plugins-DOm9Y6qI.js";
5
- import { t as PLUGIN_TASK_QUEUE_TOPIC } from "./task-queue-_mf28dSu.js";
5
+ import { t as PLUGIN_TASK_QUEUE_TOPIC } from "./task-queue-Dt1_ZoI_.js";
6
6
  import { n as loadPluginSetFromModule, r as resolvePluginModule } from "./plugin-module-Cf5gVPWP.js";
7
7
  import path from "node:path";
8
8
  import { cpSync, existsSync, mkdirSync, readdirSync, statSync } from "node:fs";
@@ -198,6 +198,7 @@ function withSentryConfig(config, options = {}) {
198
198
  }
199
199
  const DEFAULT_FUNCTION_MAX_DURATION_SECONDS = 300;
200
200
  const VERCEL_QUEUE_TRIGGER_TYPE = "queue/v2beta";
201
+ const CODEMODE_TRACE_DEPS = ["@earendil-works/pi-codemode*", "quickjs-wasi*"];
201
202
  function isPluginModuleReference(value) {
202
203
  return typeof value === "string" || Boolean(value && "module" in value);
203
204
  }
@@ -274,6 +275,7 @@ function juniorNitro(options = {}) {
274
275
  const cwd = path.resolve(options.cwd ?? nitro.options.rootDir ?? process.cwd());
275
276
  const functionMaxDurationSeconds = configureVercelDeployment(nitro, options);
276
277
  applyRolldownTreeshakeWorkaround(nitro);
278
+ nitro.options.traceDeps = [...nitro.options.traceDeps ?? [], ...CODEMODE_TRACE_DEPS];
277
279
  const pluginSource = options.plugins;
278
280
  const pluginModule = isPluginModuleReference(pluginSource) ? resolvePluginModule(cwd, pluginSource) : void 0;
279
281
  const directPluginSet = isPluginSet(pluginSource) ? pluginSource : void 0;
@@ -1,5 +1,5 @@
1
- import { n as createUserTokenStore } from "./credentialed-lukuD-cc.js";
2
- import { a as GET, n as syncLocalOAuthCredential, r as GET$1 } from "./credential-sync-sm9fegLY.js";
1
+ import { n as createUserTokenStore } from "./credentialed-BeBaJMZ_.js";
2
+ import { a as GET, n as syncLocalOAuthCredential, r as GET$1 } from "./credential-sync-BRiWYs6_.js";
3
3
  import { createServer } from "node:http";
4
4
  // src/chat/local/oauth-callback-server.ts
5
5
  const LOCAL_OAUTH_TIMEOUT_MS = 6e5;
@@ -1,4 +1,4 @@
1
- import { Q as parseBriefInput, X as briefOutcomeStatusSchema, Z as conversationBriefSchema } from "./conversation-DSo310Ps.js";
1
+ import { J as conversationBriefSchema, Y as parseBriefInput, q as briefOutcomeStatusSchema } from "./conversation-AhOVzN_k.js";
2
2
  import { z } from "zod";
3
3
  // src/chat/briefs/generate.ts
4
4
  const MAX_INPUT_CHARS = 6e4;
@@ -1,4 +1,4 @@
1
- import { b as setSpanAttributes, h as logWarn, m as logInfo } from "./logging-DLSpkSSr.js";
1
+ import { b as setSpanAttributes, h as logWarn, m as logInfo } from "./logging-C6EdT6PP.js";
2
2
  import { o as isUserActor, s as parseActorUserId } from "./actor-CP9K2Idu.js";
3
3
  import { n as normalizePluginPackageNames, o as pluginRoots, t as discoverInstalledPluginPackageContent } from "./package-discovery-DJBompdd.js";
4
4
  import path from "node:path";
@@ -0,0 +1,104 @@
1
+ import { z } from "zod";
2
+ // src/reporting-schema.ts
3
+ const healthReportSchema = z.object({
4
+ status: z.literal("ok"),
5
+ service: z.string(),
6
+ timestamp: z.string()
7
+ }).strict();
8
+ const pluginSchema = z.object({
9
+ configKeys: z.array(z.string()),
10
+ description: z.string(),
11
+ displayName: z.string(),
12
+ name: z.string()
13
+ }).strict();
14
+ const pluginsSchema = z.array(pluginSchema);
15
+ const skillReportSchema = z.object({
16
+ name: z.string(),
17
+ pluginProvider: z.string().optional()
18
+ }).strict();
19
+ const skillReportsSchema = z.array(skillReportSchema);
20
+ const pluginPackageContentItemReportSchema = z.object({
21
+ dir: z.string(),
22
+ hasMigrationsDir: z.boolean(),
23
+ hasSkillsDir: z.boolean(),
24
+ packageName: z.string()
25
+ }).strict();
26
+ const pluginPackageContentReportSchema = z.object({
27
+ packageNames: z.array(z.string()),
28
+ packages: z.array(pluginPackageContentItemReportSchema),
29
+ manifestRoots: z.array(z.string()),
30
+ skillRoots: z.array(z.string()),
31
+ tracingIncludes: z.array(z.string())
32
+ }).strict();
33
+ const runtimeInfoReportSchema = z.object({
34
+ cwd: z.string(),
35
+ homeDir: z.string(),
36
+ descriptionText: z.string().optional(),
37
+ providers: z.array(z.string()),
38
+ skills: z.array(skillReportSchema),
39
+ packagedContent: pluginPackageContentReportSchema
40
+ }).strict();
41
+ const pluginOperationalToneSchema = z.enum([
42
+ "danger",
43
+ "good",
44
+ "neutral",
45
+ "warning"
46
+ ]);
47
+ const pluginOperationalMetricSchema = z.object({
48
+ label: z.string(),
49
+ tone: pluginOperationalToneSchema.optional(),
50
+ value: z.string()
51
+ }).strict();
52
+ const pluginOperationalFieldSchema = z.object({
53
+ key: z.string(),
54
+ label: z.string()
55
+ }).strict();
56
+ const pluginOperationalRecordSchema = z.object({
57
+ id: z.string(),
58
+ tone: pluginOperationalToneSchema.optional(),
59
+ values: z.record(z.string(), z.string())
60
+ }).strict();
61
+ const pluginOperationalRecordSetSchema = z.object({
62
+ fields: z.array(pluginOperationalFieldSchema).optional(),
63
+ emptyText: z.string().optional(),
64
+ records: z.array(pluginOperationalRecordSchema).optional(),
65
+ title: z.string()
66
+ }).strict();
67
+ const pluginOperationalBarChartWidgetSchema = z.object({
68
+ categories: z.array(z.object({
69
+ id: z.string().min(1),
70
+ label: z.string().min(1),
71
+ values: z.record(z.string(), z.number().finite())
72
+ }).strict()).max(100),
73
+ description: z.string().optional(),
74
+ emptyText: z.string().optional(),
75
+ id: z.string().min(1),
76
+ series: z.array(z.object({
77
+ format: z.literal("usd").optional(),
78
+ key: z.string().min(1),
79
+ label: z.string().min(1),
80
+ tone: pluginOperationalToneSchema.optional()
81
+ }).strict()).min(1).max(8),
82
+ timeRangeDays: z.array(z.union([
83
+ z.literal(1),
84
+ z.literal(7),
85
+ z.literal(30),
86
+ z.literal(90)
87
+ ])).min(1).max(4).optional(),
88
+ title: z.string().min(1),
89
+ type: z.literal("bar_chart")
90
+ }).strict();
91
+ const pluginOperationalReportSchema = z.object({
92
+ generatedAt: z.string().optional(),
93
+ metrics: z.array(pluginOperationalMetricSchema).optional(),
94
+ recordSets: z.array(pluginOperationalRecordSetSchema).optional(),
95
+ title: z.string().optional(),
96
+ pluginName: z.string(),
97
+ widgets: z.array(pluginOperationalBarChartWidgetSchema).max(12).optional()
98
+ }).strict();
99
+ const pluginOperationalReportFeedSchema = z.object({
100
+ generatedAt: z.string(),
101
+ reports: z.array(pluginOperationalReportSchema),
102
+ source: z.literal("plugins")
103
+ }).strict();
104
+ export { pluginPackageContentReportSchema as a, runtimeInfoReportSchema as c, pluginPackageContentItemReportSchema as i, skillReportSchema as l, pluginOperationalReportFeedSchema as n, pluginSchema as o, pluginOperationalReportSchema as r, pluginsSchema as s, healthReportSchema as t, skillReportsSchema as u };
@@ -6,6 +6,15 @@ const USER_CUSTOMIZATION_MAX_CHARS = 1e3;
6
6
  const userCustomizationTextSchema = z.string().trim().max(USER_CUSTOMIZATION_MAX_CHARS);
7
7
  /** Request and response body for the viewer's customization. */
8
8
  const userCustomizationSchema = z.object({ customization: userCustomizationTextSchema }).strict();
9
+ // src/chat/conversations/web-message-id.ts
10
+ /**
11
+ * Build the retry-stable Message id shared by web ingress and browser sends.
12
+ * Keep the existing hash and prefix so retries still address stored Messages.
13
+ */
14
+ async function webMessageId(args) {
15
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(`${args.conversationId}\u0000${args.idempotencyKey}`));
16
+ return `api-msg:${Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, 24)}`;
17
+ }
9
18
  // src/chat/tools/runtime/user-input-request.ts
10
19
  const USER_INPUT_LIMITS = {
11
20
  maxButtonOptions: 5,
@@ -65,6 +74,15 @@ const userInputRequestSchema = z.object({
65
74
  }
66
75
  });
67
76
  /**
77
+ * Label and help text of the free-text input that every form adds after the
78
+ * fields. The text goes with the picked answers and does not replace them, so
79
+ * every surface says that in the same words.
80
+ */
81
+ const USER_INPUT_NOTE = {
82
+ label: "Anything else?",
83
+ description: "Optional. This note is sent together with your answers above."
84
+ };
85
+ /**
68
86
  * Return the single choice field of a request that a surface can show as
69
87
  * one row of buttons, where one click is the whole answer.
70
88
  */
@@ -120,13 +138,127 @@ function formatUserInputAnswer(request, answer) {
120
138
  if (normalized.other) lines.push(answerLine(`Other: ${normalized.other}`));
121
139
  return lines.join("\n");
122
140
  }
123
- // src/chat/conversations/web-message-id.ts
141
+ // src/api/reporting-window.ts
142
+ /** Shared UTC day/hour/six-hour windows for dashboard activity series. */
143
+ const HOUR_MS = 36e5;
144
+ const SIX_HOUR_MS = 6 * HOUR_MS;
145
+ const DAY_MS = 24 * HOUR_MS;
146
+ /** Start of the UTC calendar day containing `valueMs`. */
147
+ function startOfUtcDay(valueMs) {
148
+ const date = new Date(valueMs);
149
+ date.setUTCHours(0, 0, 0, 0);
150
+ return date;
151
+ }
152
+ /** Start of the UTC hour containing `valueMs`. */
153
+ function startOfUtcHour(valueMs) {
154
+ const date = new Date(valueMs);
155
+ date.setUTCMinutes(0, 0, 0);
156
+ return date;
157
+ }
158
+ /** Start of the UTC 6-hour bucket containing `valueMs` (00/06/12/18). */
159
+ function startOfUtcSixHour(valueMs) {
160
+ const date = startOfUtcHour(valueMs);
161
+ date.setUTCHours(Math.floor(date.getUTCHours() / 6) * 6, 0, 0, 0);
162
+ return date;
163
+ }
164
+ /** UTC day key `YYYY-MM-DD`. */
165
+ function utcDayKey(value) {
166
+ return (typeof value === "number" ? new Date(value) : value).toISOString().slice(0, 10);
167
+ }
168
+ /** UTC hour key `YYYY-MM-DDTHH`. */
169
+ function utcHourKey(value) {
170
+ return (typeof value === "number" ? new Date(value) : value).toISOString().slice(0, 13);
171
+ }
172
+ /** UTC 6-hour bucket key `YYYY-MM-DDTHH` at 00/06/12/18. */
173
+ function utcSixHourKey(value) {
174
+ return utcHourKey(startOfUtcSixHour(typeof value === "number" ? value : value.getTime()));
175
+ }
176
+ /** Inclusive trailing UTC day window ending on today's UTC day. */
177
+ function trailingUtcDayWindow(nowMs, dayCount) {
178
+ const end = startOfUtcDay(nowMs);
179
+ const start = new Date(end);
180
+ start.setUTCDate(start.getUTCDate() - (dayCount - 1));
181
+ return {
182
+ end,
183
+ start
184
+ };
185
+ }
186
+ /** Inclusive trailing UTC hour window ending on the current UTC hour. */
187
+ function trailingUtcHourWindow(nowMs, hourCount = 24) {
188
+ const end = startOfUtcHour(nowMs);
189
+ return {
190
+ end,
191
+ start: /* @__PURE__ */ new Date(end.getTime() - (hourCount - 1) * HOUR_MS)
192
+ };
193
+ }
194
+ /** Inclusive trailing UTC 6-hour window ending on the current 6h bucket. */
195
+ function trailingUtcSixHourWindow(nowMs, bucketCount = 28) {
196
+ const end = startOfUtcSixHour(nowMs);
197
+ return {
198
+ end,
199
+ start: /* @__PURE__ */ new Date(end.getTime() - (bucketCount - 1) * SIX_HOUR_MS)
200
+ };
201
+ }
202
+ /** Fill a fixed UTC day window from a sparse map. */
203
+ function fillUtcDays(args) {
204
+ const { end, start } = trailingUtcDayWindow(args.nowMs, args.count);
205
+ const items = [];
206
+ for (const cursor = new Date(start); cursor.getTime() <= end.getTime(); cursor.setUTCDate(cursor.getUTCDate() + 1)) {
207
+ const date = utcDayKey(cursor);
208
+ items.push(args.rows.get(date) ?? args.empty(date));
209
+ }
210
+ return items;
211
+ }
212
+ /** Fill a fixed UTC hour window from a sparse map. */
213
+ function fillUtcHours(args) {
214
+ const hourCount = args.count ?? 24;
215
+ const { end, start } = trailingUtcHourWindow(args.nowMs, hourCount);
216
+ const items = [];
217
+ for (const cursor = new Date(start); cursor.getTime() <= end.getTime(); cursor.setTime(cursor.getTime() + HOUR_MS)) {
218
+ const date = utcHourKey(cursor);
219
+ items.push(args.rows.get(date) ?? args.empty(date));
220
+ }
221
+ return items;
222
+ }
223
+ /** Fill a fixed UTC 6-hour window from a map of known rows. */
224
+ function fillUtcSixHours(args) {
225
+ const bucketCount = args.count ?? 28;
226
+ const { end, start } = trailingUtcSixHourWindow(args.nowMs, bucketCount);
227
+ const items = [];
228
+ for (const cursor = new Date(start); cursor.getTime() <= end.getTime(); cursor.setTime(cursor.getTime() + SIX_HOUR_MS)) {
229
+ const date = utcSixHourKey(cursor);
230
+ items.push(args.rows.get(date) ?? args.empty(date));
231
+ }
232
+ return items;
233
+ }
124
234
  /**
125
- * Build the retry-stable Message id shared by web ingress and browser sends.
126
- * Keep the existing hash and prefix so retries still address stored Messages.
235
+ * Sum hour rows into trailing 6-hour buckets.
236
+ * Adds number fields. Keeps other fields from the first row in the bucket.
237
+ * Sets `date` to the 6-hour bucket key.
127
238
  */
128
- async function webMessageId(args) {
129
- const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(`${args.conversationId}\u0000${args.idempotencyKey}`));
130
- return `api-msg:${Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, 24)}`;
239
+ function sumUtcHoursIntoSixHours(args) {
240
+ const bucketCount = args.count ?? 28;
241
+ const bySix = /* @__PURE__ */ new Map();
242
+ for (const hour of args.hours) {
243
+ const key = utcSixHourKey(Date.parse(`${hour.date}:00:00.000Z`));
244
+ const next = {
245
+ ...bySix.get(key) ?? args.empty(key),
246
+ date: key
247
+ };
248
+ for (const [field, value] of Object.entries(hour)) {
249
+ if (field === "date") continue;
250
+ if (typeof value === "number") {
251
+ const prior = next[field];
252
+ next[field] = (typeof prior === "number" ? prior : 0) + value;
253
+ }
254
+ }
255
+ bySix.set(key, next);
256
+ }
257
+ return fillUtcSixHours({
258
+ count: bucketCount,
259
+ empty: args.empty,
260
+ nowMs: args.nowMs,
261
+ rows: bySix
262
+ });
131
263
  }
132
- export { isEmptyUserInputAnswer as a, USER_CUSTOMIZATION_MAX_CHARS as c, formatUserInputAnswer as i, userCustomizationSchema as l, USER_INPUT_LIMITS as n, normalizeUserInputAnswer as o, buttonUserInputField as r, userInputRequestSchema as s, webMessageId as t, userCustomizationTextSchema as u };
264
+ export { userCustomizationTextSchema as C, userCustomizationSchema as S, isEmptyUserInputAnswer as _, fillUtcSixHours as a, webMessageId as b, trailingUtcDayWindow as c, utcDayKey as d, utcHourKey as f, formatUserInputAnswer as g, buttonUserInputField as h, fillUtcHours as i, trailingUtcHourWindow as l, USER_INPUT_NOTE as m, HOUR_MS as n, startOfUtcHour as o, USER_INPUT_LIMITS as p, fillUtcDays as r, sumUtcHoursIntoSixHours as s, DAY_MS as t, trailingUtcSixHourWindow as u, normalizeUserInputAnswer as v, USER_CUSTOMIZATION_MAX_CHARS as x, userInputRequestSchema as y };
@@ -1,6 +1,6 @@
1
- import { E as withSpan, b as setSpanAttributes } from "./logging-DLSpkSSr.js";
2
- import { Cn as runNonInteractiveCommand, F as getSandboxProvider, N as isStale, j as create, kn as SANDBOX_WORKSPACE_ROOT, un as sleep, wn as SANDBOX_COMMAND_PATH } from "./credentialed-lukuD-cc.js";
3
- import { i as getStateAdapter } from "./adapter-04AcD2SO.js";
1
+ import { E as withSpan, b as setSpanAttributes } from "./logging-C6EdT6PP.js";
2
+ import { Kn as runNonInteractiveCommand, Nn as sleep, Qn as SANDBOX_WORKSPACE_ROOT, it as isStale, nt as create, ot as getSandboxProvider, qn as SANDBOX_COMMAND_PATH } from "./credentialed-BeBaJMZ_.js";
3
+ import { r as getStateAdapter } from "./adapter-BQNTKVTF.js";
4
4
  import { z } from "zod";
5
5
  // src/chat/sandbox/resources.ts
6
6
  let configuredResources;
@@ -1,13 +1,14 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-nwUcYXjP.js";
2
- import { Xt as listTurnSummaries, Yt as getTurnRecord } from "./tasks-SB9z-VTU.js";
2
+ import { On as getTurnRecord, kn as listTurnSummaries } from "./turn-session-routing-B9KLBhaT.js";
3
3
  import { t as createActor } from "./actor-CP9K2Idu.js";
4
- import { f as credentialContextForActor } from "./registry-BgecKva0.js";
5
- import { At as listUnreportedSiblingAgents } from "./agent-runner-CAYfFmU7.js";
6
- import { a as EVENT_SYSTEM_ACTOR, i as EVENT_MESSAGE_AUTHOR, o as isEventConversationMessage } from "./prompt-BW9jFsqZ.js";
7
- import { C as markAgentInvocationParentMailboxAppended, _ as getLatestAgentInvocationForConversation, a as createAgentInvocationFromLatest, c as getAgentInvocation, d as getAgentInvocationIdForResult, l as getAgentInvocationIdForEvents, p as getAgentInvocationResultMessageId, u as getAgentInvocationIdForMessage, y as isTerminalAgentInvocation } from "./store-C5PN02QO.js";
8
- import { a as EVENT_WAIT_MS, c as isEventMailboxMetadata, l as renderEventBatchText, u as timerWatchCredentialSubject } from "./session-stop-Dam1EI7B.js";
9
- import { r as appendAndEnqueueInboundMessage } from "./store-zPEoJPBB.js";
10
- import { r as enqueueAgentInvocation } from "./work-3N-GHY9m.js";
4
+ import { j as SYSTEM_IDENTITY_ID } from "./viewer-BTgAfdUg.js";
5
+ import { f as credentialContextForActor } from "./registry-CndmkP2P.js";
6
+ import { bt as listUnreportedSiblingAgents } from "./agent-runner-MSQSMFkq.js";
7
+ import { a as EVENT_SYSTEM_ACTOR, i as EVENT_MESSAGE_AUTHOR, o as isEventConversationMessage } from "./prompt-BPSdXYXV.js";
8
+ import { C as markAgentInvocationParentMailboxAppended, _ as getLatestAgentInvocationForConversation, a as createAgentInvocationFromLatest, c as getAgentInvocation, d as getAgentInvocationIdForResult, l as getAgentInvocationIdForEvents, p as getAgentInvocationResultMessageId, u as getAgentInvocationIdForMessage, y as isTerminalAgentInvocation } from "./store-Byarin7b.js";
9
+ import { a as EVENT_WAIT_MS, c as isEventMailboxMetadata, l as renderEventBatchText, u as timerWatchCredentialSubject } from "./session-stop-MZRgYqYH.js";
10
+ import { r as appendAndEnqueueInboundMessage } from "./store-BeWGgaMA.js";
11
+ import { i as resolveAgentInvocationId, r as enqueueAgentInvocation, t as createAgentInvocationWorker } from "./work-Bjm52fHo.js";
11
12
  import { z } from "zod";
12
13
  import { createEventSource, createLocalSource, createWebSource } from "@sentry/junior-plugin-api";
13
14
  // src/chat/conversations/web-mailbox.ts
@@ -167,9 +168,9 @@ async function resolveMailboxTurnWork(context) {
167
168
  }
168
169
  // src/chat/agent-invocations/result.ts
169
170
  var result_exports = /* @__PURE__ */ __exportAll({
171
+ createChildConversationWorker: () => createChildConversationWorker,
170
172
  enqueueAgentInvocationResult: () => enqueueAgentInvocationResult,
171
173
  enqueueAgentMessageToParent: () => enqueueAgentMessageToParent,
172
- startAgentInvocationsForChildInput: () => startAgentInvocationsForChildInput,
173
174
  withAgentInvocationResultActors: () => withAgentInvocationResultActors
174
175
  });
175
176
  const AGENT_INVOCATION_EVENT_NAMESPACE = "junior";
@@ -214,7 +215,7 @@ function trustedSummary(invocation, agent) {
214
215
  */
215
216
  const RESULT_NEXT_STEP = {
216
217
  completed: "Use this result to continue the work in this conversation. Do not repeat work that the child agent already did.",
217
- blocked: "The child agent did not finish its task because something is missing. If you can give it, send it to the child agent with messageAgent. If it needs user approval, your own text cannot give it: ask the user one focused question that names the exact action. After the user answers in this conversation, tell the child agent with messageAgent to try again. The runtime shows the user's own messages to the child's action review. Otherwise tell the user what is missing.",
218
+ blocked: "The child agent did not finish its task because something is missing. If you can give it, send it to the child agent with messageAgent. If only a person can give it, such as user approval, your own text cannot give it. Do not ask in plain text: add one action item with `addReviewItem` that names the exact action. Make its `dedupe_key` from the child conversation and the blocked action, so a repeat block updates the same item. After the user answers in this conversation, tell the child agent with messageAgent to try again. The runtime shows the user's own messages to the child's action review. Otherwise tell the user what is missing.",
218
219
  failed: "The child agent did not finish its task. If you still need this work, use messageAgent to ask the same child agent to try again, or tell the user what is blocked.",
219
220
  stopped: "The child agent was stopped before it finished. Do not start this work again unless the user asks."
220
221
  };
@@ -266,6 +267,7 @@ function buildResultInboundMessage(invocation, nowMs, openSiblings) {
266
267
  inboundMessageId: getAgentInvocationResultMessageId(invocation.invocationId),
267
268
  input: {
268
269
  authorId: resultAuthorId(invocation.actor),
270
+ authorIdentityId: SYSTEM_IDENTITY_ID,
269
271
  metadata,
270
272
  text: renderResultInput(invocation, summary, openSiblings)
271
273
  },
@@ -342,6 +344,7 @@ async function enqueueAgentMessageToParent(args) {
342
344
  inboundMessageId,
343
345
  input: {
344
346
  authorId: resultAuthorId(args.sender.actor),
347
+ authorIdentityId: SYSTEM_IDENTITY_ID,
345
348
  metadata,
346
349
  text: renderMessageInput(args.sender, summary, args.text)
347
350
  },
@@ -434,6 +437,22 @@ async function startAgentInvocationsForChildInput(context, options) {
434
437
  return { status: "completed" };
435
438
  }
436
439
  /**
440
+ * Build the worker for all work of a child Conversation. The caller selects
441
+ * it from the stored parent of the Conversation, never from a Turn Source. It
442
+ * starts agent invocations for child input, then runs the agent invocation
443
+ * that owns the work. Work that no agent invocation owns is an error.
444
+ */
445
+ function createChildConversationWorker(agentRunner, options) {
446
+ const invocationWorker = createAgentInvocationWorker(agentRunner, options);
447
+ return async (context) => {
448
+ const started = await startAgentInvocationsForChildInput(context, options);
449
+ if (started) return started;
450
+ const invocationId = await resolveAgentInvocationId(context);
451
+ if (!invocationId) throw new Error(`Child conversation ${context.conversationId} has no agent invocation for this work`);
452
+ return await invocationWorker(context, invocationId);
453
+ };
454
+ }
455
+ /**
437
456
  * Run each agent invocation result or message as the Actor that triggered the
438
457
  * child, user or system. This is on purpose: the result continues that
439
458
  * Actor's work. The Actor comes from SQL, not from mailbox metadata, so the
@@ -457,4 +476,4 @@ async function withAgentInvocationResultActors(work) {
457
476
  }))
458
477
  };
459
478
  }
460
- export { withAgentInvocationResultActors as a, resolveMailboxTurnWork as c, legacyWebMailboxMetadataSchema as d, startAgentInvocationsForChildInput as i, sourceFromTurnInput as l, enqueueAgentMessageToParent as n, getAuthPausedConversationTurnId as o, result_exports as r, getEventBatchDelayMs as s, enqueueAgentInvocationResult as t, turnInputFactsFromConversationMessage as u };
479
+ export { withAgentInvocationResultActors as a, resolveMailboxTurnWork as c, legacyWebMailboxMetadataSchema as d, result_exports as i, sourceFromTurnInput as l, enqueueAgentInvocationResult as n, getAuthPausedConversationTurnId as o, enqueueAgentMessageToParent as r, getEventBatchDelayMs as s, createChildConversationWorker as t, turnInputFactsFromConversationMessage as u };