@sentry/junior-plugin-api 0.124.1 → 0.125.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.
package/README.md CHANGED
@@ -44,9 +44,17 @@ reports, and other typed hook surfaces exported by this package.
44
44
  database, logging, and only the host capabilities required by that hook.
45
45
  - Prompt hooks return bounded structured prompt messages rather than mutate the
46
46
  core prompt.
47
+ - User prompt hooks for durable turns may emit registered structured events
48
+ through `ctx.events` for auxiliary work completed while building context.
47
49
  - Tool hooks return model-visible schemas aligned with their executor inputs.
48
50
  - Host-owned structured model and embedding calls do not expose provider
49
- credentials to plugins.
51
+ credentials to plugins. Both return a best-effort provider cost estimate when
52
+ one is available.
53
+ - Operational report and authenticated API hooks may aggregate `costUsd` from
54
+ their own registered conversation events through `ctx.eventStats`. Core
55
+ binds the plugin namespace and owns access to the conversation event log.
56
+ Event `costUsd` is additive operation cost and must not duplicate cost
57
+ already recorded in the conversation's agent model usage.
50
58
  - Authenticated API route apps receive one verified viewer in their request
51
59
  context. The registration hook exposes actor resolution for plugins whose
52
60
  viewer-owned data spans platform identities.
@@ -76,8 +84,9 @@ routing, response validation, rendering, confirmation, and query state.
76
84
  - Conversation-bound background tasks may emit registered structured events
77
85
  through `ctx.events`. Define each version with `defineConversationEvent()`;
78
86
  the host supplies the plugin namespace, conversation, turn, ordering, and
79
- timestamps. Event definitions return bounded transcript presentation data,
80
- while Junior owns browser rendering.
87
+ timestamps without treating background work as new conversation activity.
88
+ Event definitions return bounded transcript presentation data, while Junior
89
+ owns browser rendering.
81
90
  - `ctx.agent.dispatch` creates durable agent work with an explicit actor,
82
91
  destination, source, metadata, and idempotency identity.
83
92
  - Delegated credential subjects declare the narrow action that authorized them.
@@ -90,11 +99,14 @@ routing, response validation, rendering, confirmation, and query state.
90
99
 
91
100
  Register plugin-owned event definitions through `conversationEvents`. A
92
101
  definition owns one local name, version, content schema, and `renderEvent()`
93
- projection. The active plugin context supplies the namespace, so plugins cannot
94
- emit native events or impersonate another plugin. The `junior` plugin name is
95
- reserved for host-owned native events. Stored events remain durable when a
96
- plugin is removed, but normal transcript projection skips definitions that are
97
- not currently registered.
102
+ projection. A renderer may return `undefined` when an event should remain
103
+ durable without producing a transcript row. The active plugin context supplies
104
+ the namespace, so plugins cannot emit native events or impersonate another
105
+ plugin. The `junior` plugin name is reserved for host-owned native events.
106
+ Versions of the same event name share one operation idempotency identity,
107
+ so keep previous definitions registered when evolving an event. Stored events
108
+ remain durable when a plugin is removed, but normal transcript projection skips
109
+ definitions that are not currently registered.
98
110
 
99
111
  ## Database
100
112
 
package/dist/context.d.ts CHANGED
@@ -38,6 +38,8 @@ export interface PluginModel {
38
38
  schema: TSchema;
39
39
  system?: string;
40
40
  }): Promise<{
41
+ /** Best-effort estimated provider cost for this completion. */
42
+ costUsd?: number;
41
43
  object: z.infer<TSchema>;
42
44
  }>;
43
45
  }
@@ -46,6 +48,8 @@ export interface PluginEmbedder {
46
48
  embedTexts(input: {
47
49
  texts: string[];
48
50
  }): Promise<{
51
+ /** Best-effort estimated provider cost for this embedding call. */
52
+ costUsd?: number;
49
53
  dimensions: number;
50
54
  model: string;
51
55
  provider: string;
@@ -39,12 +39,12 @@ export interface PluginConversationEventValue {
39
39
  readonly data: Record<string, unknown>;
40
40
  readonly definition: PluginConversationEventDefinition;
41
41
  }
42
- /** Registered schema and transcript presentation for one plugin event version. */
42
+ /** Registered schema and optional transcript presentation for one event version. */
43
43
  export interface PluginConversationEventDefinition {
44
44
  readonly eventName: string;
45
45
  readonly version: number;
46
46
  parse(data: unknown): Record<string, unknown>;
47
- renderEvent(data: Record<string, unknown>): ConversationEventPresentation;
47
+ renderEvent(data: Record<string, unknown>): ConversationEventPresentation | undefined;
48
48
  }
49
49
  /** Typed factory returned while authoring one plugin conversation event. */
50
50
  export interface DefinedConversationEvent<TInput> extends PluginConversationEventDefinition {
@@ -55,9 +55,21 @@ export declare function defineConversationEvent<TSchema extends z.ZodType<Record
55
55
  name: string;
56
56
  version: number;
57
57
  schema: TSchema;
58
- renderEvent(event: z.output<TSchema>): z.input<typeof conversationEventPresentationSchema>;
58
+ renderEvent(event: z.output<TSchema>): z.input<typeof conversationEventPresentationSchema> | undefined;
59
59
  }): DefinedConversationEvent<z.input<TSchema>>;
60
60
  /** Conversation-bound event writer supplied by Junior core. */
61
61
  export interface PluginConversationEvents {
62
62
  emit(event: PluginConversationEventValue): Promise<void>;
63
63
  }
64
+ export interface PluginConversationEventCostDay {
65
+ costUsd: number;
66
+ date: string;
67
+ events: number;
68
+ }
69
+ /** Read aggregate costs for events owned by the current plugin namespace. */
70
+ export interface PluginConversationEventStats {
71
+ costsByDay(input: {
72
+ days: 7 | 30 | 90;
73
+ eventName: string;
74
+ }): Promise<PluginConversationEventCostDay[]>;
75
+ }
package/dist/index.js CHANGED
@@ -64,9 +64,8 @@ function defineConversationEvent(definition) {
64
64
  },
65
65
  renderEvent(data) {
66
66
  const parsed = definition.schema.parse(data);
67
- return conversationEventPresentationSchema.parse(
68
- definition.renderEvent(parsed)
69
- );
67
+ const presentation = definition.renderEvent(parsed);
68
+ return presentation === void 0 ? void 0 : conversationEventPresentationSchema.parse(presentation);
70
69
  }
71
70
  });
72
71
  return eventDefinition;
@@ -4,6 +4,7 @@ import type { Dispatch, DispatchOptions, DispatchResult } from "./dispatch";
4
4
  import type { PluginReadState, PluginState } from "./state";
5
5
  import type { ResourceEventPublisher } from "./resource-events";
6
6
  import type { PluginConversationAnnotations } from "./annotations";
7
+ import type { PluginConversationEventStats } from "./conversation-events";
7
8
  export interface HeartbeatHookContext extends PluginContext {
8
9
  agent: {
9
10
  dispatch(options: DispatchOptions): Promise<DispatchResult>;
@@ -37,6 +38,7 @@ export interface PluginOperationalRecordSet {
37
38
  title: string;
38
39
  }
39
40
  export interface PluginOperationalChartSeries {
41
+ format?: "usd";
40
42
  key: string;
41
43
  label: string;
42
44
  tone?: PluginOperationalTone;
@@ -67,6 +69,7 @@ export interface PluginOperationalReport extends PluginOperationalReportContent
67
69
  pluginName: string;
68
70
  }
69
71
  export interface OperationalReportHookContext extends PluginContext {
72
+ eventStats: PluginConversationEventStats;
70
73
  nowMs: number;
71
74
  state: PluginReadState;
72
75
  }
@@ -89,6 +92,7 @@ export interface RouteRegistrationHookContext extends PluginContext {
89
92
  resourceEvents: ResourceEventPublisher;
90
93
  }
91
94
  export interface ApiRouteRegistrationHookContext extends PluginContext {
95
+ eventStats: PluginConversationEventStats;
92
96
  viewer: {
93
97
  /** Resolve every runtime actor linked to one authenticated viewer email. */
94
98
  actors(email: string): Promise<Array<LocalActor | SlackActor>>;
package/dist/prompt.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import type { Destination, Platform, PluginContext, PluginEmbedder, PluginModel, Actor, Source } from "./context";
3
3
  import type { PluginState } from "./state";
4
+ import type { PluginConversationEvents } from "./conversation-events";
4
5
  export declare const promptMessageSchema: z.ZodObject<{
5
6
  text: z.ZodString;
6
7
  }, z.core.$strict>;
@@ -36,6 +37,8 @@ export type UserPromptContext = Pick<PluginContext, "db" | "log" | "plugin"> & {
36
37
  conversationId?: string;
37
38
  destination: Destination;
38
39
  embedder: PluginEmbedder;
40
+ /** Conversation-bound event writer when the prompt belongs to a durable turn. */
41
+ events?: PluginConversationEvents;
39
42
  model: PluginModel;
40
43
  actor?: Actor;
41
44
  source: Source;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-plugin-api",
3
- "version": "0.124.1",
3
+ "version": "0.125.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
package/src/context.ts CHANGED
@@ -44,12 +44,18 @@ export interface PluginModel {
44
44
  prompt: string;
45
45
  schema: TSchema;
46
46
  system?: string;
47
- }): Promise<{ object: z.infer<TSchema> }>;
47
+ }): Promise<{
48
+ /** Best-effort estimated provider cost for this completion. */
49
+ costUsd?: number;
50
+ object: z.infer<TSchema>;
51
+ }>;
48
52
  }
49
53
 
50
54
  export interface PluginEmbedder {
51
55
  /** Embed plugin-owned text for derived retrieval without exposing provider credentials. */
52
56
  embedTexts(input: { texts: string[] }): Promise<{
57
+ /** Best-effort estimated provider cost for this embedding call. */
58
+ costUsd?: number;
53
59
  dimensions: number;
54
60
  model: string;
55
61
  provider: string;
@@ -48,12 +48,14 @@ export interface PluginConversationEventValue {
48
48
  readonly definition: PluginConversationEventDefinition;
49
49
  }
50
50
 
51
- /** Registered schema and transcript presentation for one plugin event version. */
51
+ /** Registered schema and optional transcript presentation for one event version. */
52
52
  export interface PluginConversationEventDefinition {
53
53
  readonly eventName: string;
54
54
  readonly version: number;
55
55
  parse(data: unknown): Record<string, unknown>;
56
- renderEvent(data: Record<string, unknown>): ConversationEventPresentation;
56
+ renderEvent(
57
+ data: Record<string, unknown>,
58
+ ): ConversationEventPresentation | undefined;
57
59
  }
58
60
 
59
61
  /** Typed factory returned while authoring one plugin conversation event. */
@@ -72,7 +74,7 @@ export function defineConversationEvent<
72
74
  schema: TSchema;
73
75
  renderEvent(
74
76
  event: z.output<TSchema>,
75
- ): z.input<typeof conversationEventPresentationSchema>;
77
+ ): z.input<typeof conversationEventPresentationSchema> | undefined;
76
78
  }): DefinedConversationEvent<z.input<TSchema>> {
77
79
  const identity = z
78
80
  .object({
@@ -96,9 +98,10 @@ export function defineConversationEvent<
96
98
  },
97
99
  renderEvent(data: Record<string, unknown>) {
98
100
  const parsed = definition.schema.parse(data);
99
- return conversationEventPresentationSchema.parse(
100
- definition.renderEvent(parsed),
101
- );
101
+ const presentation = definition.renderEvent(parsed);
102
+ return presentation === undefined
103
+ ? undefined
104
+ : conversationEventPresentationSchema.parse(presentation);
102
105
  },
103
106
  });
104
107
  return eventDefinition;
@@ -108,3 +111,17 @@ export function defineConversationEvent<
108
111
  export interface PluginConversationEvents {
109
112
  emit(event: PluginConversationEventValue): Promise<void>;
110
113
  }
114
+
115
+ export interface PluginConversationEventCostDay {
116
+ costUsd: number;
117
+ date: string;
118
+ events: number;
119
+ }
120
+
121
+ /** Read aggregate costs for events owned by the current plugin namespace. */
122
+ export interface PluginConversationEventStats {
123
+ costsByDay(input: {
124
+ days: 7 | 30 | 90;
125
+ eventName: string;
126
+ }): Promise<PluginConversationEventCostDay[]>;
127
+ }
package/src/operations.ts CHANGED
@@ -5,6 +5,7 @@ import { nonBlankStringSchema } from "./schemas";
5
5
  import type { PluginReadState, PluginState } from "./state";
6
6
  import type { ResourceEventPublisher } from "./resource-events";
7
7
  import type { PluginConversationAnnotations } from "./annotations";
8
+ import type { PluginConversationEventStats } from "./conversation-events";
8
9
 
9
10
  export interface HeartbeatHookContext extends PluginContext {
10
11
  agent: {
@@ -46,6 +47,7 @@ export interface PluginOperationalRecordSet {
46
47
  }
47
48
 
48
49
  export interface PluginOperationalChartSeries {
50
+ format?: "usd";
49
51
  key: string;
50
52
  label: string;
51
53
  tone?: PluginOperationalTone;
@@ -81,6 +83,7 @@ export interface PluginOperationalReport extends PluginOperationalReportContent
81
83
  }
82
84
 
83
85
  export interface OperationalReportHookContext extends PluginContext {
86
+ eventStats: PluginConversationEventStats;
84
87
  nowMs: number;
85
88
  state: PluginReadState;
86
89
  }
@@ -120,6 +123,7 @@ export interface RouteRegistrationHookContext extends PluginContext {
120
123
  }
121
124
 
122
125
  export interface ApiRouteRegistrationHookContext extends PluginContext {
126
+ eventStats: PluginConversationEventStats;
123
127
  viewer: {
124
128
  /** Resolve every runtime actor linked to one authenticated viewer email. */
125
129
  actors(email: string): Promise<Array<LocalActor | SlackActor>>;
package/src/prompt.ts CHANGED
@@ -9,6 +9,7 @@ import type {
9
9
  Source,
10
10
  } from "./context";
11
11
  import type { PluginState } from "./state";
12
+ import type { PluginConversationEvents } from "./conversation-events";
12
13
 
13
14
  const promptContextKindSchema = z
14
15
  .string()
@@ -80,6 +81,8 @@ export type UserPromptContext = Pick<PluginContext, "db" | "log" | "plugin"> & {
80
81
  conversationId?: string;
81
82
  destination: Destination;
82
83
  embedder: PluginEmbedder;
84
+ /** Conversation-bound event writer when the prompt belongs to a durable turn. */
85
+ events?: PluginConversationEvents;
83
86
  model: PluginModel;
84
87
  actor?: Actor;
85
88
  source: Source;