@sentry/junior-plugin-api 0.127.0 → 0.128.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
@@ -55,12 +55,14 @@ reports, and other typed hook surfaces exported by this package.
55
55
  binds the plugin namespace and owns access to the conversation event log.
56
56
  Event `costUsd` is additive operation cost and must not duplicate cost
57
57
  already recorded in the conversation's agent model usage.
58
- - Authenticated API route apps receive one verified viewer in their request
59
- context. The registration hook exposes actor resolution for plugins whose
60
- viewer-owned data spans platform identities.
61
- - User page readers receive the signed-in email plus runtime-owned actors linked
62
- to that user. Plugins return bounded data and do not mount their own page
63
- routes or browser code.
58
+ - Tool hooks may lazily resolve the active actor's canonical identity and linked
59
+ user through `ctx.users.resolveActor()`.
60
+ - Authenticated API route hooks receive `ctx.users.resolve(email)` for lazy
61
+ canonical user resolution. Routes that do not need personal ownership do not
62
+ query identity storage.
63
+ - User page readers receive the canonical viewer `User` with linked identities.
64
+ Plugins return bounded data and do not mount their own page routes or browser
65
+ code.
64
66
 
65
67
  ## User Pages
66
68
 
@@ -72,7 +74,7 @@ Set `navigation: "primary"` for a top-level dashboard navigation item. The
72
74
  default `profile` placement keeps account-oriented pages in the signed-in user
73
75
  menu. Junior always renders core System navigation after plugin pages.
74
76
  Records may expose bounded `DELETE` actions inside their own authenticated
75
- plugin API namespace. Core owns discovery, authentication, actor resolution,
77
+ plugin API namespace. Core owns discovery, authentication, user resolution,
76
78
  routing, response validation, rendering, confirmation, and query state.
77
79
 
78
80
  ## Durable Work
package/dist/context.d.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  import { z } from "zod";
2
2
  import type { ZodTypeAny } from "zod";
3
- import { destinationSchema, localActorSchema, platformSchema, actorSchema, slackActorSchema, systemActorSchema, sourceSchema } from "./schemas";
3
+ import { destinationSchema, identitySchema, localActorSchema, platformSchema, actorSchema, slackActorSchema, systemActorSchema, sourceSchema, userSchema } from "./schemas";
4
4
  /** Runtime platform name without source or destination coordinates. */
5
5
  export type Platform = z.output<typeof platformSchema>;
6
6
  export type Actor = z.output<typeof actorSchema>;
7
7
  export type SlackActor = z.output<typeof slackActorSchema>;
8
8
  export type LocalActor = z.output<typeof localActorSchema>;
9
9
  export type SystemActor = z.output<typeof systemActorSchema>;
10
+ export type Identity = z.output<typeof identitySchema>;
11
+ export type User = z.output<typeof userSchema>;
10
12
  export type Source = z.output<typeof sourceSchema>;
11
13
  export type SlackSource = Extract<Source, {
12
14
  platform: "slack";
package/dist/index.js CHANGED
@@ -154,6 +154,20 @@ var actorSchema = z3.discriminatedUnion("platform", [
154
154
  localActorSchema,
155
155
  systemActorSchema
156
156
  ]);
157
+ var identitySchema = z3.object({
158
+ displayName: nonBlankStringSchema.optional(),
159
+ handle: nonBlankStringSchema.optional(),
160
+ id: exactNonBlankStringSchema,
161
+ provider: exactNonBlankStringSchema,
162
+ providerSubjectId: exactNonBlankStringSchema,
163
+ providerTenantId: exactNonBlankStringSchema.optional()
164
+ }).strict();
165
+ var userSchema = z3.object({
166
+ displayName: nonBlankStringSchema.optional(),
167
+ email: nonBlankStringSchema.max(320),
168
+ id: exactNonBlankStringSchema,
169
+ identities: z3.array(identitySchema).max(100)
170
+ }).strict();
157
171
  var dispatchMetadataSchema = z3.record(z3.string(), z3.string()).superRefine((metadata, ctx) => {
158
172
  const entries = Object.entries(metadata);
159
173
  if (entries.length > 20) {
@@ -429,19 +443,10 @@ var pluginToolContinuationSchema = z7.object({
429
443
  arguments: z7.record(z7.string(), z7.unknown()),
430
444
  reason: z7.string().min(1).optional()
431
445
  }).strict();
432
- var pluginToolErrorSchema = z7.object({
433
- kind: z7.string().min(1),
434
- message: z7.string().min(1),
435
- retryable: z7.boolean().optional()
436
- }).strict();
437
- var pluginToolResultSchema = z7.object({
438
- ok: z7.boolean(),
439
- status: z7.enum(["success", "error"]),
446
+ var pluginToolOutputSchema = z7.object({
440
447
  target: z7.string().min(1).optional(),
441
- data: z7.unknown().optional(),
442
448
  truncated: z7.boolean().optional(),
443
- continuation: pluginToolContinuationSchema.optional(),
444
- error: z7.union([pluginToolErrorSchema, z7.string()]).optional()
449
+ continuation: pluginToolContinuationSchema.optional()
445
450
  }).passthrough();
446
451
  var toolApprovalModeSchema = z7.enum(["auto", "review", "approve"]);
447
452
  var REQUIRED_TOOL_ANNOTATION_KEYS = [
@@ -455,7 +460,7 @@ function missingToolAnnotationKeys(annotations) {
455
460
  (key) => typeof annotations?.[key] !== "boolean"
456
461
  );
457
462
  }
458
- function isPluginToolResultEnvelope(value) {
463
+ function isPluginToolOutputEnvelope(value) {
459
464
  return value !== null && typeof value === "object" && Array.isArray(value.content) && "details" in value;
460
465
  }
461
466
  function formatZodPath(path) {
@@ -511,15 +516,13 @@ function createZodTool(definition, helperName) {
511
516
  input,
512
517
  options
513
518
  );
514
- if (isPluginToolResultEnvelope(result)) {
519
+ if (isPluginToolOutputEnvelope(result)) {
515
520
  return {
516
521
  content: z7.array(pluginToolContentSchema).parse(result.content),
517
- details: outputSchema.parse(
518
- pluginToolResultSchema.parse(result.details)
519
- )
522
+ details: outputSchema.parse(result.details)
520
523
  };
521
524
  }
522
- return outputSchema.parse(pluginToolResultSchema.parse(result));
525
+ return outputSchema.parse(result);
523
526
  }
524
527
  } : {}
525
528
  };
@@ -801,6 +804,7 @@ export {
801
804
  destinationVisibilitySchema,
802
805
  dispatchOptionsSchema,
803
806
  getSourceKey,
807
+ identitySchema,
804
808
  isPrivateSource,
805
809
  isSlackDestination,
806
810
  localActorSchema,
@@ -826,8 +830,7 @@ export {
826
830
  pluginStoredTokensSchema,
827
831
  pluginToolContentSchema,
828
832
  pluginToolContinuationSchema,
829
- pluginToolErrorSchema,
830
- pluginToolResultSchema,
833
+ pluginToolOutputSchema,
831
834
  pluginUserPageContentSchema,
832
835
  pluginUserPageInputSchema,
833
836
  pluginUserPageLinkSchema,
@@ -848,5 +851,6 @@ export {
848
851
  subscribableResourceSchema,
849
852
  systemActorSchema,
850
853
  toolApprovalModeSchema,
854
+ userSchema,
851
855
  zodTool
852
856
  };
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import type { LocalActor, PluginContext, SlackActor } from "./context";
2
+ import type { PluginContext, User } from "./context";
3
3
  import type { Dispatch, DispatchOptions, DispatchResult } from "./dispatch";
4
4
  import type { PluginReadState, PluginState } from "./state";
5
5
  import type { ResourceEventPublisher } from "./resource-events";
@@ -93,9 +93,9 @@ export interface RouteRegistrationHookContext extends PluginContext {
93
93
  }
94
94
  export interface ApiRouteRegistrationHookContext extends PluginContext {
95
95
  eventStats: PluginConversationEventStats;
96
- viewer: {
97
- /** Resolve every runtime actor linked to one authenticated viewer email. */
98
- actors(email: string): Promise<Array<LocalActor | SlackActor>>;
96
+ users: {
97
+ /** Resolve or create the canonical user for one verified email. */
98
+ resolve(email: string): Promise<User | undefined>;
99
99
  };
100
100
  }
101
101
  /** Per-request context Junior passes to authenticated plugin product API routes. */
package/dist/schemas.d.ts CHANGED
@@ -117,6 +117,29 @@ export declare const actorSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
117
117
  platform: z.ZodLiteral<"system">;
118
118
  name: z.ZodString;
119
119
  }, z.core.$strict>], "platform">;
120
+ /** Core-owned provider account linked to a user when verified. */
121
+ export declare const identitySchema: z.ZodObject<{
122
+ displayName: z.ZodOptional<z.ZodString>;
123
+ handle: z.ZodOptional<z.ZodString>;
124
+ id: z.ZodString;
125
+ provider: z.ZodString;
126
+ providerSubjectId: z.ZodString;
127
+ providerTenantId: z.ZodOptional<z.ZodString>;
128
+ }, z.core.$strict>;
129
+ /** Core-owned person with every linked provider identity. */
130
+ export declare const userSchema: z.ZodObject<{
131
+ displayName: z.ZodOptional<z.ZodString>;
132
+ email: z.ZodString;
133
+ id: z.ZodString;
134
+ identities: z.ZodArray<z.ZodObject<{
135
+ displayName: z.ZodOptional<z.ZodString>;
136
+ handle: z.ZodOptional<z.ZodString>;
137
+ id: z.ZodString;
138
+ provider: z.ZodString;
139
+ providerSubjectId: z.ZodString;
140
+ providerTenantId: z.ZodOptional<z.ZodString>;
141
+ }, z.core.$strict>>;
142
+ }, z.core.$strict>;
120
143
  /** Compact destination-visible context explaining what produced a reply. */
121
144
  export declare const replyAttributionSchema: z.ZodObject<{
122
145
  label: z.ZodPipe<z.ZodString, z.ZodString>;
package/dist/tools.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import type { PluginContext, LocalInvocationContext, PluginEmbedder, PluginModel, Actor, SlackInvocationContext } from "./context";
1
+ import type { PluginContext, LocalInvocationContext, PluginEmbedder, Identity, PluginModel, Actor, SlackInvocationContext, User } from "./context";
2
2
  import type { PluginCredentialSubject } from "./credentials";
3
3
  import type { PluginAnnotations } from "./annotations";
4
4
  import type { SlackConversationLink } from "./operations";
5
5
  import type { PluginState } from "./state";
6
- import { z, type ZodType, type ZodTypeAny } from "zod";
6
+ import { z, type ZodTypeAny } from "zod";
7
7
  export interface PluginEnv {
8
8
  get(key: string): string | undefined;
9
9
  set(key: string, value: string): void;
@@ -63,8 +63,8 @@ export declare const pluginToolContentSchema: z.ZodDiscriminatedUnion<[z.ZodObje
63
63
  }, z.core.$strict>], "type">;
64
64
  /** Model-visible content returned by a plugin tool. */
65
65
  export type PluginToolContent = z.output<typeof pluginToolContentSchema>;
66
- /** Standard tool result envelope with separate model content and runtime details. */
67
- export interface PluginToolResultEnvelope<TDetails = PluginToolResult> {
66
+ /** Pi-native projection with model-facing content and canonical runtime details. */
67
+ export interface PluginToolOutputEnvelope<TDetails = unknown> {
68
68
  content: PluginToolContent[];
69
69
  details: TDetails;
70
70
  }
@@ -159,31 +159,16 @@ export declare const pluginToolContinuationSchema: z.ZodObject<{
159
159
  arguments: z.ZodRecord<z.ZodString, z.ZodUnknown>;
160
160
  reason: z.ZodOptional<z.ZodString>;
161
161
  }, z.core.$strict>;
162
- export declare const pluginToolErrorSchema: z.ZodObject<{
163
- kind: z.ZodString;
164
- message: z.ZodString;
165
- retryable: z.ZodOptional<z.ZodBoolean>;
166
- }, z.core.$strict>;
167
- export declare const pluginToolResultSchema: z.ZodObject<{
168
- ok: z.ZodBoolean;
169
- status: z.ZodEnum<{
170
- error: "error";
171
- success: "success";
172
- }>;
162
+ /** Shared optional fields for canonical plugin tool outputs. */
163
+ export declare const pluginToolOutputSchema: z.ZodObject<{
173
164
  target: z.ZodOptional<z.ZodString>;
174
- data: z.ZodOptional<z.ZodUnknown>;
175
165
  truncated: z.ZodOptional<z.ZodBoolean>;
176
166
  continuation: z.ZodOptional<z.ZodObject<{
177
167
  arguments: z.ZodRecord<z.ZodString, z.ZodUnknown>;
178
168
  reason: z.ZodOptional<z.ZodString>;
179
169
  }, z.core.$strict>>;
180
- error: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
181
- kind: z.ZodString;
182
- message: z.ZodString;
183
- retryable: z.ZodOptional<z.ZodBoolean>;
184
- }, z.core.$strict>, z.ZodString]>>;
185
170
  }, z.core.$loose>;
186
- export type PluginToolResult = z.output<typeof pluginToolResultSchema>;
171
+ export type PluginToolOutput = z.output<typeof pluginToolOutputSchema>;
187
172
  export type PluginToolExecute<TInput = unknown, TOutput = unknown> = {
188
173
  bivarianceHack(input: TInput, options: PluginToolExecuteOptions): Promise<TOutput> | TOutput;
189
174
  }["bivarianceHack"];
@@ -262,17 +247,17 @@ export interface PluginToolDefinition<TInput = unknown, TOutput = unknown, TExec
262
247
  promptSnippet?: string;
263
248
  execute?: PluginToolExecute<TInput, TExecuteOutput>;
264
249
  }
265
- type ZodPluginToolDefinition<TInputSchema extends ZodTypeAny, TOutputSchema extends ZodType<PluginToolResult>, TExecuteResult extends z.input<TOutputSchema> | PluginToolResultEnvelope<z.input<TOutputSchema>>> = Omit<PluginToolDefinition<z.output<TInputSchema>, z.output<TOutputSchema>>, "inputSchema" | "outputSchema" | "prepareArguments" | "execute"> & {
250
+ type ZodPluginToolDefinition<TInputSchema extends ZodTypeAny, TOutputSchema extends ZodTypeAny, TExecuteResult extends z.input<TOutputSchema> | PluginToolOutputEnvelope<z.input<TOutputSchema>>> = Omit<PluginToolDefinition<z.output<TInputSchema>, z.output<TOutputSchema>>, "inputSchema" | "outputSchema" | "prepareArguments" | "execute"> & {
266
251
  inputSchema: TInputSchema;
267
252
  outputSchema: TOutputSchema;
268
253
  prepareArguments?: (args: unknown) => z.input<TInputSchema>;
269
254
  execute?: (input: z.output<TInputSchema>, options: PluginToolExecuteOptions) => Promise<TExecuteResult> | TExecuteResult;
270
255
  };
271
- type ParsedPluginToolExecuteResult<TOutputSchema extends ZodTypeAny, TResult> = TResult extends PluginToolResultEnvelope<unknown> ? PluginToolResultEnvelope<z.output<TOutputSchema>> : z.output<TOutputSchema>;
256
+ type ParsedPluginToolExecuteResult<TOutputSchema extends ZodTypeAny, TResult> = TResult extends PluginToolOutputEnvelope<unknown> ? PluginToolOutputEnvelope<z.output<TOutputSchema>> : z.output<TOutputSchema>;
272
257
  /** Define a plugin tool with Zod input parsing and validated structured results. */
273
- export declare function zodTool<TInputSchema extends ZodTypeAny, TOutputSchema extends ZodType<PluginToolResult>, TExecuteResult extends z.input<TOutputSchema> | PluginToolResultEnvelope<z.input<TOutputSchema>>>(definition: ZodPluginToolDefinition<TInputSchema, TOutputSchema, TExecuteResult>): PluginToolDefinition<z.output<TInputSchema>, z.output<TOutputSchema>, ParsedPluginToolExecuteResult<TOutputSchema, TExecuteResult>>;
258
+ export declare function zodTool<TInputSchema extends ZodTypeAny, TOutputSchema extends ZodTypeAny, TExecuteResult extends z.input<TOutputSchema> | PluginToolOutputEnvelope<z.input<TOutputSchema>>>(definition: ZodPluginToolDefinition<TInputSchema, TOutputSchema, TExecuteResult>): PluginToolDefinition<z.output<TInputSchema>, z.output<TOutputSchema>, ParsedPluginToolExecuteResult<TOutputSchema, TExecuteResult>>;
274
259
  /** Define a plugin tool with Zod input parsing and the structured result contract. */
275
- export declare function definePluginTool<TInputSchema extends ZodTypeAny, TOutputSchema extends ZodType<PluginToolResult>, TExecuteResult extends z.input<TOutputSchema> | PluginToolResultEnvelope<z.input<TOutputSchema>>>(definition: ZodPluginToolDefinition<TInputSchema, TOutputSchema, TExecuteResult>): PluginToolDefinition<z.output<TInputSchema>, z.output<TOutputSchema>, ParsedPluginToolExecuteResult<TOutputSchema, TExecuteResult>>;
260
+ export declare function definePluginTool<TInputSchema extends ZodTypeAny, TOutputSchema extends ZodTypeAny, TExecuteResult extends z.input<TOutputSchema> | PluginToolOutputEnvelope<z.input<TOutputSchema>>>(definition: ZodPluginToolDefinition<TInputSchema, TOutputSchema, TExecuteResult>): PluginToolDefinition<z.output<TInputSchema>, z.output<TOutputSchema>, ParsedPluginToolExecuteResult<TOutputSchema, TExecuteResult>>;
276
261
  export interface SlackToolRegistrationHookContext {
277
262
  /**
278
263
  * Capabilities of the source Slack conversation exposed to this plugin.
@@ -289,6 +274,10 @@ export interface SlackToolRegistrationHookContext {
289
274
  allowedWhen: "private-direct-conversation";
290
275
  }>;
291
276
  }
277
+ export interface PluginResourceEventToolContext {
278
+ /** Whether this invocation can create a working resource-event subscription. */
279
+ canSubscribe: boolean;
280
+ }
292
281
  interface BaseToolRegistrationHookContext extends PluginContext {
293
282
  /**
294
283
  * Opaque Junior conversation/session identity for this turn.
@@ -302,7 +291,15 @@ interface BaseToolRegistrationHookContext extends PluginContext {
302
291
  egress: PluginEgress;
303
292
  mcp?: PluginMcp;
304
293
  model: PluginModel;
294
+ resourceEvents: PluginResourceEventToolContext;
305
295
  state: PluginState;
296
+ users: {
297
+ /** Resolve the current actor's stored identity and linked user. */
298
+ resolveActor(): Promise<{
299
+ identity: Identity;
300
+ user?: User;
301
+ } | undefined>;
302
+ };
306
303
  userText?: string;
307
304
  }
308
305
  interface SlackToolRegistrationContext extends BaseToolRegistrationHookContext, SlackInvocationContext {
@@ -5,7 +5,7 @@
5
5
  * routing, response validation, and browser rendering.
6
6
  */
7
7
  import { z } from "zod";
8
- import type { LocalActor, PluginContext, SlackActor } from "./context";
8
+ import type { PluginContext, User } from "./context";
9
9
  /** Bounded list content returned by a plugin-owned user page. */
10
10
  export declare const pluginUserPageContentSchema: z.ZodObject<{
11
11
  emptyText: z.ZodOptional<z.ZodString>;
@@ -76,14 +76,9 @@ export declare const pluginUserPageInputSchema: z.ZodObject<{
76
76
  query: z.ZodOptional<z.ZodString>;
77
77
  }, z.core.$strict>;
78
78
  export type PluginUserPageInput = z.output<typeof pluginUserPageInputSchema>;
79
- /** Runtime-owned actor shapes that may belong to an authenticated viewer. */
80
- export type PluginUserPageActor = SlackActor | LocalActor;
81
79
  /** Trusted host context supplied while reading one plugin user page. */
82
80
  export interface PluginUserPageContext extends PluginContext {
83
- viewer: {
84
- actors: PluginUserPageActor[];
85
- email: string;
86
- };
81
+ viewer: User;
87
82
  }
88
83
  /** Navigation metadata and reader for one core-rendered plugin user page. */
89
84
  export interface PluginUserPageDefinition {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-plugin-api",
3
- "version": "0.127.0",
3
+ "version": "0.128.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
package/src/context.ts CHANGED
@@ -2,12 +2,14 @@ import { z } from "zod";
2
2
  import type { ZodTypeAny } from "zod";
3
3
  import {
4
4
  destinationSchema,
5
+ identitySchema,
5
6
  localActorSchema,
6
7
  platformSchema,
7
8
  actorSchema,
8
9
  slackActorSchema,
9
10
  systemActorSchema,
10
11
  sourceSchema,
12
+ userSchema,
11
13
  } from "./schemas";
12
14
 
13
15
  /** Runtime platform name without source or destination coordinates. */
@@ -16,6 +18,8 @@ export type Actor = z.output<typeof actorSchema>;
16
18
  export type SlackActor = z.output<typeof slackActorSchema>;
17
19
  export type LocalActor = z.output<typeof localActorSchema>;
18
20
  export type SystemActor = z.output<typeof systemActorSchema>;
21
+ export type Identity = z.output<typeof identitySchema>;
22
+ export type User = z.output<typeof userSchema>;
19
23
  export type Source = z.output<typeof sourceSchema>;
20
24
  export type SlackSource = Extract<Source, { platform: "slack" }>;
21
25
  export type LocalSource = Extract<Source, { platform: "local" }>;
package/src/operations.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import type { LocalActor, PluginContext, SlackActor } from "./context";
2
+ import type { PluginContext, User } from "./context";
3
3
  import type { Dispatch, DispatchOptions, DispatchResult } from "./dispatch";
4
4
  import { nonBlankStringSchema } from "./schemas";
5
5
  import type { PluginReadState, PluginState } from "./state";
@@ -124,9 +124,9 @@ export interface RouteRegistrationHookContext extends PluginContext {
124
124
 
125
125
  export interface ApiRouteRegistrationHookContext extends PluginContext {
126
126
  eventStats: PluginConversationEventStats;
127
- viewer: {
128
- /** Resolve every runtime actor linked to one authenticated viewer email. */
129
- actors(email: string): Promise<Array<LocalActor | SlackActor>>;
127
+ users: {
128
+ /** Resolve or create the canonical user for one verified email. */
129
+ resolve(email: string): Promise<User | undefined>;
130
130
  };
131
131
  }
132
132
 
package/src/schemas.ts CHANGED
@@ -136,6 +136,28 @@ export const actorSchema = z.discriminatedUnion("platform", [
136
136
  systemActorSchema,
137
137
  ]);
138
138
 
139
+ /** Core-owned provider account linked to a user when verified. */
140
+ export const identitySchema = z
141
+ .object({
142
+ displayName: nonBlankStringSchema.optional(),
143
+ handle: nonBlankStringSchema.optional(),
144
+ id: exactNonBlankStringSchema,
145
+ provider: exactNonBlankStringSchema,
146
+ providerSubjectId: exactNonBlankStringSchema,
147
+ providerTenantId: exactNonBlankStringSchema.optional(),
148
+ })
149
+ .strict();
150
+
151
+ /** Core-owned person with every linked provider identity. */
152
+ export const userSchema = z
153
+ .object({
154
+ displayName: nonBlankStringSchema.optional(),
155
+ email: nonBlankStringSchema.max(320),
156
+ id: exactNonBlankStringSchema,
157
+ identities: z.array(identitySchema).max(100),
158
+ })
159
+ .strict();
160
+
139
161
  const dispatchMetadataSchema = z
140
162
  .record(z.string(), z.string())
141
163
  .superRefine((metadata, ctx) => {
package/src/tools.ts CHANGED
@@ -2,15 +2,17 @@ import type {
2
2
  PluginContext,
3
3
  LocalInvocationContext,
4
4
  PluginEmbedder,
5
+ Identity,
5
6
  PluginModel,
6
7
  Actor,
7
8
  SlackInvocationContext,
9
+ User,
8
10
  } from "./context";
9
11
  import type { PluginCredentialSubject } from "./credentials";
10
12
  import type { PluginAnnotations } from "./annotations";
11
13
  import type { SlackConversationLink } from "./operations";
12
14
  import type { PluginState } from "./state";
13
- import { z, type ZodType, type ZodTypeAny } from "zod";
15
+ import { z, type ZodTypeAny } from "zod";
14
16
 
15
17
  export interface PluginEnv {
16
18
  get(key: string): string | undefined;
@@ -81,8 +83,8 @@ export const pluginToolContentSchema = z.discriminatedUnion("type", [
81
83
  /** Model-visible content returned by a plugin tool. */
82
84
  export type PluginToolContent = z.output<typeof pluginToolContentSchema>;
83
85
 
84
- /** Standard tool result envelope with separate model content and runtime details. */
85
- export interface PluginToolResultEnvelope<TDetails = PluginToolResult> {
86
+ /** Pi-native projection with model-facing content and canonical runtime details. */
87
+ export interface PluginToolOutputEnvelope<TDetails = unknown> {
86
88
  content: PluginToolContent[];
87
89
  details: TDetails;
88
90
  }
@@ -194,27 +196,16 @@ export const pluginToolContinuationSchema = z
194
196
  })
195
197
  .strict();
196
198
 
197
- export const pluginToolErrorSchema = z
199
+ /** Shared optional fields for canonical plugin tool outputs. */
200
+ export const pluginToolOutputSchema = z
198
201
  .object({
199
- kind: z.string().min(1),
200
- message: z.string().min(1),
201
- retryable: z.boolean().optional(),
202
- })
203
- .strict();
204
-
205
- export const pluginToolResultSchema = z
206
- .object({
207
- ok: z.boolean(),
208
- status: z.enum(["success", "error"]),
209
202
  target: z.string().min(1).optional(),
210
- data: z.unknown().optional(),
211
203
  truncated: z.boolean().optional(),
212
204
  continuation: pluginToolContinuationSchema.optional(),
213
- error: z.union([pluginToolErrorSchema, z.string()]).optional(),
214
205
  })
215
206
  .passthrough();
216
207
 
217
- export type PluginToolResult = z.output<typeof pluginToolResultSchema>;
208
+ export type PluginToolOutput = z.output<typeof pluginToolOutputSchema>;
218
209
 
219
210
  export type PluginToolExecute<TInput = unknown, TOutput = unknown> = {
220
211
  bivarianceHack(
@@ -320,10 +311,10 @@ export interface PluginToolDefinition<
320
311
 
321
312
  type ZodPluginToolDefinition<
322
313
  TInputSchema extends ZodTypeAny,
323
- TOutputSchema extends ZodType<PluginToolResult>,
314
+ TOutputSchema extends ZodTypeAny,
324
315
  TExecuteResult extends
325
316
  | z.input<TOutputSchema>
326
- | PluginToolResultEnvelope<z.input<TOutputSchema>>,
317
+ | PluginToolOutputEnvelope<z.input<TOutputSchema>>,
327
318
  > = Omit<
328
319
  PluginToolDefinition<z.output<TInputSchema>, z.output<TOutputSchema>>,
329
320
  "inputSchema" | "outputSchema" | "prepareArguments" | "execute"
@@ -338,13 +329,13 @@ type ZodPluginToolDefinition<
338
329
  };
339
330
 
340
331
  type ParsedPluginToolExecuteResult<TOutputSchema extends ZodTypeAny, TResult> =
341
- TResult extends PluginToolResultEnvelope<unknown>
342
- ? PluginToolResultEnvelope<z.output<TOutputSchema>>
332
+ TResult extends PluginToolOutputEnvelope<unknown>
333
+ ? PluginToolOutputEnvelope<z.output<TOutputSchema>>
343
334
  : z.output<TOutputSchema>;
344
335
 
345
- function isPluginToolResultEnvelope(
336
+ function isPluginToolOutputEnvelope(
346
337
  value: unknown,
347
- ): value is PluginToolResultEnvelope<unknown> {
338
+ ): value is PluginToolOutputEnvelope<unknown> {
348
339
  return (
349
340
  value !== null &&
350
341
  typeof value === "object" &&
@@ -380,10 +371,10 @@ function parsePluginToolInput<TInputSchema extends ZodTypeAny>(
380
371
 
381
372
  function createZodTool<
382
373
  TInputSchema extends ZodTypeAny,
383
- TOutputSchema extends ZodType<PluginToolResult>,
374
+ TOutputSchema extends ZodTypeAny,
384
375
  TExecuteResult extends
385
376
  | z.input<TOutputSchema>
386
- | PluginToolResultEnvelope<z.input<TOutputSchema>>,
377
+ | PluginToolOutputEnvelope<z.input<TOutputSchema>>,
387
378
  >(
388
379
  definition: ZodPluginToolDefinition<
389
380
  TInputSchema,
@@ -434,15 +425,13 @@ function createZodTool<
434
425
  input as z.output<TInputSchema>,
435
426
  options,
436
427
  );
437
- if (isPluginToolResultEnvelope(result)) {
428
+ if (isPluginToolOutputEnvelope(result)) {
438
429
  return {
439
430
  content: z.array(pluginToolContentSchema).parse(result.content),
440
- details: outputSchema.parse(
441
- pluginToolResultSchema.parse(result.details),
442
- ),
431
+ details: outputSchema.parse(result.details),
443
432
  };
444
433
  }
445
- return outputSchema.parse(pluginToolResultSchema.parse(result));
434
+ return outputSchema.parse(result);
446
435
  },
447
436
  }
448
437
  : {}),
@@ -456,10 +445,10 @@ function createZodTool<
456
445
  /** Define a plugin tool with Zod input parsing and validated structured results. */
457
446
  export function zodTool<
458
447
  TInputSchema extends ZodTypeAny,
459
- TOutputSchema extends ZodType<PluginToolResult>,
448
+ TOutputSchema extends ZodTypeAny,
460
449
  TExecuteResult extends
461
450
  | z.input<TOutputSchema>
462
- | PluginToolResultEnvelope<z.input<TOutputSchema>>,
451
+ | PluginToolOutputEnvelope<z.input<TOutputSchema>>,
463
452
  >(
464
453
  definition: ZodPluginToolDefinition<
465
454
  TInputSchema,
@@ -477,10 +466,10 @@ export function zodTool<
477
466
  /** Define a plugin tool with Zod input parsing and the structured result contract. */
478
467
  export function definePluginTool<
479
468
  TInputSchema extends ZodTypeAny,
480
- TOutputSchema extends ZodType<PluginToolResult>,
469
+ TOutputSchema extends ZodTypeAny,
481
470
  TExecuteResult extends
482
471
  | z.input<TOutputSchema>
483
- | PluginToolResultEnvelope<z.input<TOutputSchema>>,
472
+ | PluginToolOutputEnvelope<z.input<TOutputSchema>>,
484
473
  >(
485
474
  definition: ZodPluginToolDefinition<
486
475
  TInputSchema,
@@ -513,6 +502,11 @@ export interface SlackToolRegistrationHookContext {
513
502
  >;
514
503
  }
515
504
 
505
+ export interface PluginResourceEventToolContext {
506
+ /** Whether this invocation can create a working resource-event subscription. */
507
+ canSubscribe: boolean;
508
+ }
509
+
516
510
  interface BaseToolRegistrationHookContext extends PluginContext {
517
511
  /**
518
512
  * Opaque Junior conversation/session identity for this turn.
@@ -526,7 +520,12 @@ interface BaseToolRegistrationHookContext extends PluginContext {
526
520
  egress: PluginEgress;
527
521
  mcp?: PluginMcp;
528
522
  model: PluginModel;
523
+ resourceEvents: PluginResourceEventToolContext;
529
524
  state: PluginState;
525
+ users: {
526
+ /** Resolve the current actor's stored identity and linked user. */
527
+ resolveActor(): Promise<{ identity: Identity; user?: User } | undefined>;
528
+ };
530
529
  userText?: string;
531
530
  }
532
531
 
package/src/user-pages.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * routing, response validation, and browser rendering.
6
6
  */
7
7
  import { z } from "zod";
8
- import type { LocalActor, PluginContext, SlackActor } from "./context";
8
+ import type { PluginContext, User } from "./context";
9
9
  import { nonBlankStringSchema } from "./schemas";
10
10
 
11
11
  const userPageIdSchema = nonBlankStringSchema
@@ -98,15 +98,9 @@ export const pluginUserPageInputSchema = z
98
98
 
99
99
  export type PluginUserPageInput = z.output<typeof pluginUserPageInputSchema>;
100
100
 
101
- /** Runtime-owned actor shapes that may belong to an authenticated viewer. */
102
- export type PluginUserPageActor = SlackActor | LocalActor;
103
-
104
101
  /** Trusted host context supplied while reading one plugin user page. */
105
102
  export interface PluginUserPageContext extends PluginContext {
106
- viewer: {
107
- actors: PluginUserPageActor[];
108
- email: string;
109
- };
103
+ viewer: User;
110
104
  }
111
105
 
112
106
  /** Navigation metadata and reader for one core-rendered plugin user page. */