@sentry/junior 0.81.0 → 0.83.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/dist/{agent-hooks-ZGTDOXQY.js → agent-hooks-EEWWWIS2.js} +5 -5
- package/dist/api-reference.d.ts +1 -1
- package/dist/app.d.ts +1 -1
- package/dist/app.js +3763 -4132
- package/dist/chat/agent-dispatch/runner.d.ts +1 -1
- package/dist/chat/app/services.d.ts +1 -1
- package/dist/chat/conversations/store.d.ts +1 -1
- package/dist/chat/egress/credentialed.d.ts +57 -0
- package/dist/chat/egress/plugin.d.ts +24 -0
- package/dist/chat/plugins/agent-hooks.d.ts +3 -3
- package/dist/chat/plugins/credential-hooks.d.ts +2 -0
- package/dist/chat/resource-events/ingest.d.ts +23 -0
- package/dist/chat/resource-events/notification.d.ts +20 -0
- package/dist/chat/resource-events/store.d.ts +79 -0
- package/dist/chat/respond.d.ts +1 -1
- package/dist/chat/sandbox/{egress-credentials.d.ts → egress/credentials.d.ts} +28 -5
- package/dist/chat/sandbox/egress/policy.d.ts +32 -0
- package/dist/chat/sandbox/egress/proxy.d.ts +35 -0
- package/dist/chat/sandbox/{egress-session.d.ts → egress/session.d.ts} +41 -11
- package/dist/chat/sandbox/sandbox.d.ts +2 -2
- package/dist/chat/services/pending-auth.d.ts +5 -0
- package/dist/chat/slack/client.d.ts +2 -0
- package/dist/chat/task-execution/slack-work.d.ts +22 -0
- package/dist/chat/task-execution/state.d.ts +7 -1
- package/dist/chat/task-execution/store.d.ts +30 -8
- package/dist/chat/tools/resource-events.d.ts +19 -0
- package/dist/chat/tools/types.d.ts +2 -1
- package/dist/{chunk-Y3YUOEAZ.js → chunk-5C3RY6IZ.js} +20 -11
- package/dist/{chunk-IOBSRZK5.js → chunk-AK7T7XRQ.js} +1 -1
- package/dist/{chunk-LX5GBMEP.js → chunk-BFQ7IUTE.js} +1 -1
- package/dist/{chunk-YA2JCC7G.js → chunk-GK5CITCY.js} +4 -2
- package/dist/{chunk-4XHCVBXH.js → chunk-KZLRUQAA.js} +77 -12
- package/dist/{chunk-BOMLWLTF.js → chunk-LK53AHO5.js} +1759 -175
- package/dist/{chunk-2AJ4TEKE.js → chunk-ORRLK22J.js} +24 -2
- package/dist/{chunk-PQ2U2AO3.js → chunk-QVMLDCVR.js} +10 -2
- package/dist/{chunk-RV5RYIJW.js → chunk-UXPG6ZIN.js} +28 -0
- package/dist/cli/chat.js +4 -4
- package/dist/cli/env.js +7 -1
- package/dist/cli/init.js +1 -0
- package/dist/cli/main.js +1 -1
- package/dist/cli/plugins.js +3 -3
- package/dist/cli/upgrade.js +3 -3
- package/dist/{db-GQJKBX5W.js → db-TRIVS6BW.js} +2 -2
- package/dist/handlers/agent-dispatch.d.ts +1 -1
- package/dist/handlers/github-webhook/check-suite.d.ts +3 -0
- package/dist/handlers/github-webhook/pull-request-review.d.ts +3 -0
- package/dist/handlers/github-webhook/pull-request.d.ts +3 -0
- package/dist/handlers/github-webhook/resource.d.ts +10 -0
- package/dist/handlers/github-webhook.d.ts +15 -0
- package/dist/handlers/sandbox-egress-proxy.d.ts +2 -2
- package/dist/nitro.js +2 -2
- package/dist/reporting/conversations.d.ts +2 -2
- package/dist/reporting.d.ts +2 -2
- package/dist/reporting.js +16 -22
- package/dist/{runner-LNBN7BIN.js → runner-KS4XDMHF.js} +5 -5
- package/package.json +6 -5
- package/dist/chat/sandbox/egress-policy.d.ts +0 -15
- package/dist/chat/sandbox/egress-proxy.d.ts +0 -19
- /package/dist/chat/sandbox/{egress-oidc.d.ts → egress/oidc.d.ts} +0 -0
- /package/dist/chat/sandbox/{egress-schemas.d.ts → egress/schemas.d.ts} +0 -0
- /package/dist/chat/sandbox/{egress-tracing.d.ts → egress/tracing.d.ts} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { generateAssistantReply as generateAssistantReplyImpl } from "@/chat/respond";
|
|
2
|
-
import type { SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress
|
|
2
|
+
import type { SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress/tracing";
|
|
3
3
|
import { scheduleSessionCompletedPluginTasks } from "@/chat/plugins/task-runner";
|
|
4
4
|
import { scheduleDispatchCallback } from "./signing";
|
|
5
5
|
import type { DispatchCallback } from "./types";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { generateAssistantReply as generateAssistantReplyImpl } from "@/chat/respond";
|
|
2
|
-
import type { SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress
|
|
2
|
+
import type { SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress/tracing";
|
|
3
3
|
import { type ConversationMemoryDeps, type ConversationMemoryService } from "@/chat/services/conversation-memory";
|
|
4
4
|
import { type ContextCompactor, type ContextCompactorDeps } from "@/chat/services/context-compaction";
|
|
5
5
|
import { type SubscribedReplyPolicy, type SubscribedReplyPolicyDeps } from "@/chat/services/subscribed-reply-policy";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Destination } from "@sentry/junior-plugin-api";
|
|
2
2
|
import type { StoredSlackRequester } from "@/chat/requester";
|
|
3
|
-
export type ConversationSource = "api" | "internal" | "local" | "plugin" | "scheduler" | "slack";
|
|
3
|
+
export type ConversationSource = "api" | "internal" | "local" | "plugin" | "resource_event" | "scheduler" | "slack";
|
|
4
4
|
export type ConversationStatus = "awaiting_resume" | "failed" | "idle" | "pending" | "running";
|
|
5
5
|
export interface ConversationExecution {
|
|
6
6
|
lastCheckpointAtMs?: number;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type SandboxEgressGrantSelection } from "@/chat/sandbox/egress/credentials";
|
|
2
|
+
import { type SandboxEgressCredentialContext, type SandboxEgressCredentialLease } from "@/chat/sandbox/egress/session";
|
|
3
|
+
import { type SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress/tracing";
|
|
4
|
+
/**
|
|
5
|
+
* Intercepts the already-authenticated provider request before live forwarding.
|
|
6
|
+
*
|
|
7
|
+
* Tests use this to inspect the exact upstream request after grant selection
|
|
8
|
+
* and credential header injection, without weakening the proxy verification
|
|
9
|
+
* path that runs before this hook is reached.
|
|
10
|
+
*/
|
|
11
|
+
export type CredentialedEgressHttpInterceptor = (input: {
|
|
12
|
+
provider: string;
|
|
13
|
+
request: Request;
|
|
14
|
+
upstreamUrl: URL;
|
|
15
|
+
}) => Promise<Response | undefined>;
|
|
16
|
+
/** Runtime dependencies for the credentialed provider forwarding step. */
|
|
17
|
+
export interface CredentialedEgressDeps {
|
|
18
|
+
clearCredentialLease?: (provider: string, grantName: string, credentialContext: SandboxEgressCredentialContext) => Promise<void>;
|
|
19
|
+
fetch?: typeof fetch;
|
|
20
|
+
issueCredentialLease?: (provider: string, selection: SandboxEgressGrantSelection, credentialContext: SandboxEgressCredentialContext) => Promise<SandboxEgressCredentialLease>;
|
|
21
|
+
interceptHttp?: CredentialedEgressHttpInterceptor;
|
|
22
|
+
recordAuthRequired?: (input: {
|
|
23
|
+
authorization?: SandboxEgressCredentialLease["authorization"];
|
|
24
|
+
credentialContext: SandboxEgressCredentialContext;
|
|
25
|
+
grant: SandboxEgressCredentialLease["grant"];
|
|
26
|
+
kind?: "auth_required" | "unavailable";
|
|
27
|
+
message: string;
|
|
28
|
+
provider: string;
|
|
29
|
+
}) => Promise<void>;
|
|
30
|
+
recordPermissionDenied?: (input: {
|
|
31
|
+
credentialContext: SandboxEgressCredentialContext;
|
|
32
|
+
lease: SandboxEgressCredentialLease;
|
|
33
|
+
message: string;
|
|
34
|
+
provider: string;
|
|
35
|
+
upstream: Response;
|
|
36
|
+
upstreamUrl: URL;
|
|
37
|
+
}) => Promise<void>;
|
|
38
|
+
tracePropagation?: SandboxEgressTracePropagationConfig;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Forward one verified sandbox egress request with host-managed credentials.
|
|
42
|
+
*
|
|
43
|
+
* The caller must already have authenticated the sandbox VM, checked the signed
|
|
44
|
+
* credential context, and resolved the provider for `upstreamUrl`. This function
|
|
45
|
+
* then selects the read/write grant, issues or reuses a short-lived credential
|
|
46
|
+
* lease, applies its header transforms, and maps provider auth failures into
|
|
47
|
+
* command-level signals instead of throwing raw upstream details at the agent.
|
|
48
|
+
*/
|
|
49
|
+
export declare function executeCredentialedEgressRequest(input: {
|
|
50
|
+
activeEgressId: string;
|
|
51
|
+
credentialContext: SandboxEgressCredentialContext;
|
|
52
|
+
deps: CredentialedEgressDeps;
|
|
53
|
+
operation?: string;
|
|
54
|
+
provider: string;
|
|
55
|
+
request: Request;
|
|
56
|
+
upstreamUrl: URL;
|
|
57
|
+
}): Promise<Response>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PluginAuthorization, PluginEgress } from "@sentry/junior-plugin-api";
|
|
2
|
+
import type { CredentialContext } from "@/chat/credentials/context";
|
|
3
|
+
interface PluginEgressAuth {
|
|
4
|
+
handleAuthRequired(input: {
|
|
5
|
+
authorization?: PluginAuthorization;
|
|
6
|
+
grant: {
|
|
7
|
+
access: "read" | "write";
|
|
8
|
+
name: string;
|
|
9
|
+
reason?: string;
|
|
10
|
+
requirements?: string[];
|
|
11
|
+
};
|
|
12
|
+
kind: "auth_required" | "unavailable";
|
|
13
|
+
message: string;
|
|
14
|
+
provider: string;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
interface PluginEgressDeps {
|
|
18
|
+
credentialContext?: CredentialContext;
|
|
19
|
+
fetch?: typeof fetch;
|
|
20
|
+
pluginAuth: PluginEgressAuth;
|
|
21
|
+
}
|
|
22
|
+
/** Create host-owned provider egress for plugin runtime tools. */
|
|
23
|
+
export declare function createPluginEgress(deps: PluginEgressDeps): PluginEgress;
|
|
24
|
+
export {};
|
|
@@ -19,7 +19,7 @@ export interface ToolHookResult {
|
|
|
19
19
|
export interface PluginRouteRegistration extends PluginRoute {
|
|
20
20
|
pluginName: string;
|
|
21
21
|
}
|
|
22
|
-
export interface
|
|
22
|
+
export interface PluginApiRouteRegistration {
|
|
23
23
|
app: PluginRouteApp;
|
|
24
24
|
pluginName: string;
|
|
25
25
|
}
|
|
@@ -43,8 +43,8 @@ export declare function getPluginUserPromptContributions(args: {
|
|
|
43
43
|
export declare function getPluginTools(context: ToolRuntimeContext): Record<string, ToolDefinition<any>>;
|
|
44
44
|
/** Collect route handlers exposed by plugins for app-level mounting. */
|
|
45
45
|
export declare function getPluginRoutes(): PluginRouteRegistration[];
|
|
46
|
-
/** Collect
|
|
47
|
-
export declare function
|
|
46
|
+
/** Collect authenticated product API route apps exposed by plugins. */
|
|
47
|
+
export declare function getPluginApiRoutes(): PluginApiRouteRegistration[];
|
|
48
48
|
/** Resolve the first plugin conversation URL for finalized Slack footers. */
|
|
49
49
|
export declare function getPluginSlackConversationLink(conversationId: string): SlackConversationLink | undefined;
|
|
50
50
|
/** Collect read-only operational summaries exposed by plugins. */
|
|
@@ -3,6 +3,7 @@ import type { StoredTokens, UserTokenStore } from "@/chat/credentials/user-token
|
|
|
3
3
|
export interface EgressGrantInput {
|
|
4
4
|
bodyText?: string;
|
|
5
5
|
method: string;
|
|
6
|
+
operation?: string;
|
|
6
7
|
provider: string;
|
|
7
8
|
upstreamUrl: URL;
|
|
8
9
|
}
|
|
@@ -11,6 +12,7 @@ export declare function selectPluginGrant(input: EgressGrantInput): Promise<Plug
|
|
|
11
12
|
export interface EgressResponseInput {
|
|
12
13
|
grant: PluginGrant;
|
|
13
14
|
method: string;
|
|
15
|
+
operation?: string;
|
|
14
16
|
provider: string;
|
|
15
17
|
response: {
|
|
16
18
|
headers: Headers;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { StateAdapter } from "chat";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import type { ConversationWorkQueue } from "@/chat/task-execution/queue";
|
|
4
|
+
declare const ingestResourceEventInputSchema: z.ZodObject<{
|
|
5
|
+
eventKey: z.ZodString;
|
|
6
|
+
eventType: z.ZodString;
|
|
7
|
+
occurredAtMs: z.ZodNumber;
|
|
8
|
+
provider: z.ZodString;
|
|
9
|
+
resourceRef: z.ZodString;
|
|
10
|
+
terminal: z.ZodOptional<z.ZodBoolean>;
|
|
11
|
+
trustedSummary: z.ZodString;
|
|
12
|
+
untrustedText: z.ZodOptional<z.ZodString>;
|
|
13
|
+
}, z.core.$strict>;
|
|
14
|
+
export type IngestResourceEventInput = z.output<typeof ingestResourceEventInputSchema>;
|
|
15
|
+
/** Match a normalized provider event and enqueue notifications into conversations. */
|
|
16
|
+
export declare function ingestResourceEvent(input: unknown, options: {
|
|
17
|
+
nowMs?: number;
|
|
18
|
+
queue: ConversationWorkQueue;
|
|
19
|
+
state?: StateAdapter;
|
|
20
|
+
}): Promise<{
|
|
21
|
+
enqueued: number;
|
|
22
|
+
}>;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ConversationWorkQueue } from "@/chat/task-execution/queue";
|
|
2
|
+
import { appendAndEnqueueInboundMessage } from "@/chat/task-execution/store";
|
|
3
|
+
import type { ResourceEventSubscription } from "@/chat/resource-events/store";
|
|
4
|
+
export interface ResourceEventNotification {
|
|
5
|
+
eventKey: string;
|
|
6
|
+
eventType: string;
|
|
7
|
+
occurredAtMs: number;
|
|
8
|
+
provider: string;
|
|
9
|
+
resourceRef: string;
|
|
10
|
+
terminal?: boolean;
|
|
11
|
+
trustedSummary: string;
|
|
12
|
+
untrustedText?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Enqueue a resource event as normal conversation mailbox input. */
|
|
15
|
+
export declare function enqueueResourceEventNotification(args: {
|
|
16
|
+
event: ResourceEventNotification;
|
|
17
|
+
queue: ConversationWorkQueue;
|
|
18
|
+
subscription: ResourceEventSubscription;
|
|
19
|
+
state?: Parameters<typeof appendAndEnqueueInboundMessage>[0]["state"];
|
|
20
|
+
}): Promise<Awaited<ReturnType<typeof appendAndEnqueueInboundMessage>>>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { StateAdapter } from "chat";
|
|
2
|
+
import { type Destination } from "@sentry/junior-plugin-api";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
declare const subscriptionSchema: z.ZodObject<{
|
|
5
|
+
conversationId: z.ZodString;
|
|
6
|
+
createdAtMs: z.ZodNumber;
|
|
7
|
+
destination: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
8
|
+
platform: z.ZodLiteral<"slack">;
|
|
9
|
+
teamId: z.ZodString;
|
|
10
|
+
channelId: z.ZodString;
|
|
11
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
12
|
+
platform: z.ZodLiteral<"local">;
|
|
13
|
+
conversationId: z.ZodString;
|
|
14
|
+
}, z.core.$strict>], "platform">;
|
|
15
|
+
events: z.ZodArray<z.ZodString>;
|
|
16
|
+
expiresAtMs: z.ZodNumber;
|
|
17
|
+
id: z.ZodString;
|
|
18
|
+
intent: z.ZodString;
|
|
19
|
+
label: z.ZodString;
|
|
20
|
+
provider: z.ZodString;
|
|
21
|
+
resourceRef: z.ZodString;
|
|
22
|
+
resourceType: z.ZodString;
|
|
23
|
+
status: z.ZodEnum<{
|
|
24
|
+
completed: "completed";
|
|
25
|
+
active: "active";
|
|
26
|
+
cancelled: "cancelled";
|
|
27
|
+
}>;
|
|
28
|
+
updatedAtMs: z.ZodNumber;
|
|
29
|
+
}, z.core.$strict>;
|
|
30
|
+
export type ResourceEventSubscription = z.output<typeof subscriptionSchema>;
|
|
31
|
+
export interface CreateResourceEventSubscriptionInput {
|
|
32
|
+
conversationId: string;
|
|
33
|
+
destination: Destination;
|
|
34
|
+
events: string[];
|
|
35
|
+
expiresAtMs: number;
|
|
36
|
+
intent: string;
|
|
37
|
+
label: string;
|
|
38
|
+
provider: string;
|
|
39
|
+
resourceRef: string;
|
|
40
|
+
resourceType: string;
|
|
41
|
+
}
|
|
42
|
+
/** Create or replace the active subscription for one conversation/resource/event set. */
|
|
43
|
+
export declare function createResourceEventSubscription(input: CreateResourceEventSubscriptionInput, options?: {
|
|
44
|
+
nowMs?: number;
|
|
45
|
+
state?: StateAdapter;
|
|
46
|
+
}): Promise<ResourceEventSubscription>;
|
|
47
|
+
/** List active subscriptions bound to one conversation. */
|
|
48
|
+
export declare function listResourceEventSubscriptions(input: {
|
|
49
|
+
conversationId: string;
|
|
50
|
+
nowMs?: number;
|
|
51
|
+
state?: StateAdapter;
|
|
52
|
+
}): Promise<ResourceEventSubscription[]>;
|
|
53
|
+
/** Cancel a current-conversation subscription and remove it from match indexes. */
|
|
54
|
+
export declare function cancelResourceEventSubscription(input: {
|
|
55
|
+
conversationId: string;
|
|
56
|
+
id: string;
|
|
57
|
+
nowMs?: number;
|
|
58
|
+
state?: StateAdapter;
|
|
59
|
+
}): Promise<ResourceEventSubscription | undefined>;
|
|
60
|
+
/** Find active subscriptions interested in a normalized provider event. */
|
|
61
|
+
export declare function findMatchingResourceEventSubscriptions(input: {
|
|
62
|
+
eventType: string;
|
|
63
|
+
nowMs?: number;
|
|
64
|
+
provider: string;
|
|
65
|
+
resourceRef: string;
|
|
66
|
+
state?: StateAdapter;
|
|
67
|
+
}): Promise<ResourceEventSubscription[]>;
|
|
68
|
+
/** Recheck and deliver a matched subscription while holding its status lock. */
|
|
69
|
+
export declare function deliverResourceEventSubscription(input: {
|
|
70
|
+
deliver: (subscription: ResourceEventSubscription) => Promise<boolean>;
|
|
71
|
+
eventType: string;
|
|
72
|
+
nowMs?: number;
|
|
73
|
+
provider: string;
|
|
74
|
+
resourceRef: string;
|
|
75
|
+
state?: StateAdapter;
|
|
76
|
+
subscription: ResourceEventSubscription;
|
|
77
|
+
terminal?: boolean;
|
|
78
|
+
}): Promise<boolean>;
|
|
79
|
+
export {};
|
package/dist/chat/respond.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { ConversationPendingAuthState } from "@/chat/state/conversation";
|
|
|
5
5
|
import type { ImageGenerateToolDeps, WebFetchToolDeps, WebSearchToolDeps } from "@/chat/tools/types";
|
|
6
6
|
import type { PiMessage } from "@/chat/pi/messages";
|
|
7
7
|
import { type SandboxAcquiredState } from "@/chat/sandbox/sandbox";
|
|
8
|
-
import type { SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress
|
|
8
|
+
import type { SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress/tracing";
|
|
9
9
|
import type { AssistantStatusSpec } from "@/chat/slack/assistant-thread/status";
|
|
10
10
|
import type { SlackConversationContext } from "@/chat/slack/conversation-context";
|
|
11
11
|
import { type ToolExecutionReport } from "@/chat/tools/agent-tools";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PluginAuthorization, PluginGrant } from "@sentry/junior-plugin-api";
|
|
2
|
-
import { type SandboxEgressCredentialContext, type SandboxEgressCredentialLease } from "@/chat/sandbox/egress
|
|
2
|
+
import { type SandboxEgressCredentialContext, type SandboxEgressCredentialLease } from "@/chat/sandbox/egress/session";
|
|
3
|
+
/** Describes whether grant selection came from plugin hooks or the broker default. */
|
|
3
4
|
export type SandboxEgressGrantSelection = {
|
|
4
5
|
grant: PluginGrant;
|
|
5
6
|
source: "plugin";
|
|
@@ -8,7 +9,12 @@ export type SandboxEgressGrantSelection = {
|
|
|
8
9
|
source: "broker";
|
|
9
10
|
};
|
|
10
11
|
export type SandboxEgressCredentialErrorKind = "auth_required" | "unavailable";
|
|
11
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Signals that egress selected a grant but could not issue credential headers.
|
|
14
|
+
*
|
|
15
|
+
* Callers convert this into command-level auth-required state so the agent can
|
|
16
|
+
* request authorization without exposing provider-specific lease internals.
|
|
17
|
+
*/
|
|
12
18
|
export declare class SandboxEgressCredentialError extends Error {
|
|
13
19
|
readonly authorization?: PluginAuthorization;
|
|
14
20
|
readonly grant: PluginGrant;
|
|
@@ -22,16 +28,33 @@ export declare class SandboxEgressCredentialError extends Error {
|
|
|
22
28
|
provider: string;
|
|
23
29
|
});
|
|
24
30
|
}
|
|
25
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Select the grant needed for one outbound request.
|
|
33
|
+
*
|
|
34
|
+
* GitHub GraphQL and other plugin-owned APIs may need body-aware grant choices;
|
|
35
|
+
* providers without hooks use a simple read/write default based on HTTP method.
|
|
36
|
+
*/
|
|
26
37
|
export declare function selectSandboxEgressGrant(input: {
|
|
27
38
|
bodyText?: string;
|
|
28
39
|
method: string;
|
|
40
|
+
operation?: string;
|
|
29
41
|
provider: string;
|
|
30
42
|
upstreamUrl: URL;
|
|
31
43
|
}): Promise<SandboxEgressGrantSelection>;
|
|
32
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the authorization flow attached to a broker-selected egress grant.
|
|
46
|
+
*
|
|
47
|
+
* Plugin-selected grants can return their own authorization metadata when
|
|
48
|
+
* issuing credentials; broker defaults use the provider OAuth config.
|
|
49
|
+
*/
|
|
33
50
|
export declare function authorizationForSandboxEgressGrant(provider: string, selection: SandboxEgressGrantSelection): PluginAuthorization | undefined;
|
|
34
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Return cached or newly issued credential header transforms for a selected grant.
|
|
53
|
+
*
|
|
54
|
+
* Leases are cached per actor/context/grant, validated against provider-owned
|
|
55
|
+
* domains, and reused only while both the provider lease and sandbox context are
|
|
56
|
+
* still valid.
|
|
57
|
+
*/
|
|
35
58
|
export declare function sandboxEgressCredentialLease(provider: string, selection: SandboxEgressGrantSelection, context: SandboxEgressCredentialContext): Promise<SandboxEgressCredentialLease>;
|
|
36
59
|
/** Return whether a credential lease can modify requests to the target host. */
|
|
37
60
|
export declare function hasSandboxEgressLeaseTransformForHost(lease: SandboxEgressCredentialLease, host: string): boolean;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { NetworkPolicy } from "@vercel/sandbox";
|
|
2
|
+
import type { TracePropagationHeaders } from "@/chat/logging";
|
|
3
|
+
import { type SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress/tracing";
|
|
4
|
+
/** Return whether an outbound host is covered by a provider domain rule. */
|
|
5
|
+
export declare function matchesSandboxEgressDomain(host: string, domain: string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the plugin provider responsible for an outbound sandbox host.
|
|
8
|
+
*
|
|
9
|
+
* Only plugin-declared provider domains are eligible for credentialed sandbox
|
|
10
|
+
* egress. Hosts without a matching provider are blocked by the proxy even if a
|
|
11
|
+
* malformed or stale network policy tried to forward them.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveSandboxEgressProviderForHost(host: string): string | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Build the policy that forwards provider domains through the egress proxy.
|
|
16
|
+
*
|
|
17
|
+
* The signed credential token is embedded in the forward URL so the proxy can
|
|
18
|
+
* bind each forwarded request back to the actor and sandbox VM that created the
|
|
19
|
+
* command. The sandbox receives placeholder env vars, not provider credentials.
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildSandboxEgressNetworkPolicy(input?: {
|
|
22
|
+
credentialToken?: string;
|
|
23
|
+
traceConfig?: SandboxEgressTracePropagationConfig;
|
|
24
|
+
traceHeaders?: TracePropagationHeaders;
|
|
25
|
+
}): NetworkPolicy;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve non-secret command environment values for registered sandbox providers.
|
|
28
|
+
*
|
|
29
|
+
* Credential env vars are placeholders that tell tools which auth variable name
|
|
30
|
+
* exists; real credential headers are issued lazily by host egress.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveSandboxCommandEnvironment(): Promise<Record<string, string>>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type CredentialedEgressHttpInterceptor } from "@/chat/egress/credentialed";
|
|
2
|
+
import { type SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress/tracing";
|
|
3
|
+
import type { JWTPayload } from "jose";
|
|
4
|
+
/**
|
|
5
|
+
* Intercepts a verified sandbox HTTP request before live provider forwarding.
|
|
6
|
+
*
|
|
7
|
+
* The hook runs after OIDC, forwarded URL validation, provider ownership, and
|
|
8
|
+
* credential-context checks have succeeded.
|
|
9
|
+
*/
|
|
10
|
+
export type SandboxEgressHttpInterceptor = CredentialedEgressHttpInterceptor;
|
|
11
|
+
/** Runtime dependencies for the sandbox egress proxy boundary. */
|
|
12
|
+
interface ProxyDeps {
|
|
13
|
+
fetch?: typeof fetch;
|
|
14
|
+
interceptHttp?: SandboxEgressHttpInterceptor;
|
|
15
|
+
tracePropagation?: SandboxEgressTracePropagationConfig;
|
|
16
|
+
verifyOidc?: (token: string) => Promise<JWTPayload>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Return whether a request carries the forwarding headers expected from Vercel.
|
|
20
|
+
*
|
|
21
|
+
* This is only a cheap classifier for routing into the proxy handler. Real
|
|
22
|
+
* authentication happens in `proxySandboxEgressRequest` by verifying the OIDC
|
|
23
|
+
* token and signed Junior credential context.
|
|
24
|
+
*/
|
|
25
|
+
export declare function isSandboxEgressForwardedRequest(request: Request): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Handle one forwarded sandbox egress request.
|
|
28
|
+
*
|
|
29
|
+
* This is the public proxy boundary: it rejects unauthenticated VM requests,
|
|
30
|
+
* rejects forwarded URLs outside plugin-owned provider domains, rejects signed
|
|
31
|
+
* credential contexts that do not match the active VM id, and only then asks
|
|
32
|
+
* `execute.ts` to issue credentials and contact the upstream provider.
|
|
33
|
+
*/
|
|
34
|
+
export declare function proxySandboxEgressRequest(request: Request, deps?: ProxyDeps): Promise<Response>;
|
|
35
|
+
export {};
|
|
@@ -1,30 +1,60 @@
|
|
|
1
1
|
import type { CredentialContext } from "@/chat/credentials/context";
|
|
2
|
-
import { type SandboxEgressAuthRequiredSignal, type SandboxEgressCredentialContext, type SandboxEgressCredentialLease, type SandboxEgressPermissionDeniedSignal } from "@/chat/sandbox/egress
|
|
2
|
+
import { type SandboxEgressAuthRequiredSignal, type SandboxEgressCredentialContext, type SandboxEgressCredentialLease, type SandboxEgressPermissionDeniedSignal } from "@/chat/sandbox/egress/schemas";
|
|
3
3
|
export declare const SANDBOX_EGRESS_PROXY_PATH = "/api/internal/sandbox-egress";
|
|
4
4
|
export type { SandboxEgressAuthRequiredSignal, SandboxEgressCredentialContext, SandboxEgressCredentialLease, SandboxEgressPermissionDeniedSignal, };
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Create the signed Junior credential context embedded in the proxy URL.
|
|
7
|
+
*
|
|
8
|
+
* The token binds requester credentials to a specific sandbox egress id and a
|
|
9
|
+
* short expiry. Vercel OIDC proves which VM sent a request; this token proves
|
|
10
|
+
* which Junior actor and credential context that VM is allowed to use.
|
|
11
|
+
*/
|
|
6
12
|
export declare function createSandboxEgressCredentialToken(input: {
|
|
7
13
|
credentials: CredentialContext;
|
|
8
14
|
egressId: string;
|
|
9
15
|
ttlMs?: number;
|
|
10
16
|
}): string;
|
|
11
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Verify the signed Junior credential context from the proxy URL.
|
|
19
|
+
*
|
|
20
|
+
* Returning `undefined` means the token is missing, expired, malformed, or not
|
|
21
|
+
* signed with the current `JUNIOR_SECRET`.
|
|
22
|
+
*/
|
|
12
23
|
export declare function parseSandboxEgressCredentialToken(token: string | undefined): SandboxEgressCredentialContext | undefined;
|
|
13
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Cache credential header transforms for one actor, VM, context token, and grant.
|
|
26
|
+
*
|
|
27
|
+
* The cache TTL is capped by both the provider lease expiry and the signed
|
|
28
|
+
* context expiry so a stale sandbox URL cannot keep using old credentials.
|
|
29
|
+
*/
|
|
14
30
|
export declare function setSandboxEgressCredentialLease(context: SandboxEgressCredentialContext, lease: SandboxEgressCredentialLease): Promise<void>;
|
|
15
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Load cached credential header transforms for the exact actor/context/grant.
|
|
33
|
+
*/
|
|
16
34
|
export declare function getSandboxEgressCredentialLease(provider: string, grantName: string, context: SandboxEgressCredentialContext): Promise<SandboxEgressCredentialLease | undefined>;
|
|
17
|
-
/** Clear a cached
|
|
35
|
+
/** Clear a cached lease after the upstream provider rejects its auth headers. */
|
|
18
36
|
export declare function clearSandboxEgressCredentialLease(provider: string, grantName: string, context: SandboxEgressCredentialContext): Promise<void>;
|
|
19
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* Record that credential issuance needs user authorization for this command.
|
|
39
|
+
*
|
|
40
|
+
* The command runner consumes this after the sandbox tool finishes so the agent
|
|
41
|
+
* can present a normal authorization-required response instead of a raw proxy
|
|
42
|
+
* failure.
|
|
43
|
+
*/
|
|
20
44
|
export declare function setSandboxEgressAuthRequiredSignal(context: SandboxEgressCredentialContext, signal: Omit<SandboxEgressAuthRequiredSignal, "createdAtMs" | "kind"> & {
|
|
21
45
|
kind?: SandboxEgressAuthRequiredSignal["kind"];
|
|
22
46
|
}): Promise<void>;
|
|
23
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Record that the provider rejected an issued credential with permission denial.
|
|
49
|
+
*/
|
|
24
50
|
export declare function setSandboxEgressPermissionDeniedSignal(context: SandboxEgressCredentialContext, signal: Omit<SandboxEgressPermissionDeniedSignal, "createdAtMs">): Promise<void>;
|
|
25
|
-
/** Remove
|
|
51
|
+
/** Remove pending auth/permission signals before or after a sandbox command. */
|
|
26
52
|
export declare function clearSandboxEgressSignals(egressId: string | undefined): Promise<void>;
|
|
27
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Consume the auth signal produced during a sandbox command, preferring writes.
|
|
55
|
+
*/
|
|
28
56
|
export declare function consumeSandboxEgressAuthRequiredSignal(egressId: string | undefined): Promise<SandboxEgressAuthRequiredSignal | undefined>;
|
|
29
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Consume the permission signal produced during a sandbox command, preferring writes.
|
|
59
|
+
*/
|
|
30
60
|
export declare function consumeSandboxEgressPermissionDeniedSignal(egressId: string | undefined): Promise<SandboxEgressPermissionDeniedSignal | undefined>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type LogContext } from "@/chat/logging";
|
|
2
|
-
import { type SandboxEgressAuthRequiredSignal, type SandboxEgressPermissionDeniedSignal } from "@/chat/sandbox/egress
|
|
3
|
-
import type { SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress
|
|
2
|
+
import { type SandboxEgressAuthRequiredSignal, type SandboxEgressPermissionDeniedSignal } from "@/chat/sandbox/egress/session";
|
|
3
|
+
import type { SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress/tracing";
|
|
4
4
|
import type { CredentialContext } from "@/chat/credentials/context";
|
|
5
5
|
import type { PluginHookRunner } from "@/chat/plugins/agent-hooks";
|
|
6
6
|
import type { SandboxInstance } from "@/chat/sandbox/workspace";
|
|
@@ -28,4 +28,9 @@ export declare function applyPendingAuthUpdate(args: {
|
|
|
28
28
|
conversationId: string | undefined;
|
|
29
29
|
nextPendingAuth: ConversationPendingAuthState;
|
|
30
30
|
}): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Decide whether an auth callback still belongs to the latest real human
|
|
33
|
+
* request, ignoring bot-authored and passive bystander rows while treating
|
|
34
|
+
* failed human turns and opt-outs as newer freshness blockers.
|
|
35
|
+
*/
|
|
31
36
|
export declare function isPendingAuthLatestRequest(conversation: ThreadConversationState, pendingAuth: ConversationPendingAuthState): boolean;
|
|
@@ -28,6 +28,8 @@ export declare class SlackActionError extends Error {
|
|
|
28
28
|
interface SlackRetryContext {
|
|
29
29
|
action?: string;
|
|
30
30
|
attributes?: Record<string, string | number | boolean>;
|
|
31
|
+
/** Extra attributes forwarded onto the per-attempt Sentry span. */
|
|
32
|
+
spanAttributes?: Record<string, string | number | boolean>;
|
|
31
33
|
}
|
|
32
34
|
/** Extract a header value by case-insensitive name from a raw headers object. */
|
|
33
35
|
export declare function getHeaderString(headers: unknown, name: string): string | undefined;
|
|
@@ -15,6 +15,25 @@ export interface SlackConversationMessageMetadata {
|
|
|
15
15
|
route: SlackConversationRoute;
|
|
16
16
|
thread: SerializedThread;
|
|
17
17
|
}
|
|
18
|
+
interface SlackResourceEventInboundInput {
|
|
19
|
+
event: {
|
|
20
|
+
eventKey: string;
|
|
21
|
+
eventType: string;
|
|
22
|
+
occurredAtMs: number;
|
|
23
|
+
provider: string;
|
|
24
|
+
resourceRef: string;
|
|
25
|
+
};
|
|
26
|
+
subscription: {
|
|
27
|
+
conversationId: string;
|
|
28
|
+
destination: {
|
|
29
|
+
channelId: string;
|
|
30
|
+
platform: "slack";
|
|
31
|
+
teamId: string;
|
|
32
|
+
};
|
|
33
|
+
id: string;
|
|
34
|
+
};
|
|
35
|
+
text: string;
|
|
36
|
+
}
|
|
18
37
|
export interface CreateSlackConversationWorkerOptions {
|
|
19
38
|
getSlackAdapter: () => SlackAdapter;
|
|
20
39
|
lookupSlackUser?: (teamId: string, userId: string) => Promise<SlackRequesterProfile | null | undefined>;
|
|
@@ -23,6 +42,8 @@ export interface CreateSlackConversationWorkerOptions {
|
|
|
23
42
|
runtime: Pick<SlackTurnRuntime<unknown>, "handleNewMention" | "handleSubscribedMessage">;
|
|
24
43
|
state?: StateAdapter;
|
|
25
44
|
}
|
|
45
|
+
/** Create a Slack mailbox record for a subscribed resource-event notification. */
|
|
46
|
+
export declare function createSlackResourceEventInboundMessage(input: SlackResourceEventInboundInput): InboundMessage;
|
|
26
47
|
/** Build the worker run function for queued Slack conversation work. */
|
|
27
48
|
export declare function createSlackConversationWorker(options: CreateSlackConversationWorkerOptions): (context: ConversationWorkerContext) => Promise<ConversationWorkerResult>;
|
|
28
49
|
/** Serialize a Slack message into the generic durable conversation mailbox. */
|
|
@@ -34,3 +55,4 @@ export declare function buildSlackInboundMessage(args: {
|
|
|
34
55
|
route: SlackConversationRoute;
|
|
35
56
|
thread: ThreadImpl;
|
|
36
57
|
}): InboundMessage;
|
|
58
|
+
export {};
|
|
@@ -6,7 +6,7 @@ export declare const CONVERSATION_ACTIVE_INDEX_KEY = "junior:conversation:active
|
|
|
6
6
|
export declare const CONVERSATION_WORK_LEASE_TTL_MS = 90000;
|
|
7
7
|
export declare const CONVERSATION_WORK_CHECK_IN_INTERVAL_MS = 15000;
|
|
8
8
|
export declare const CONVERSATION_WORK_STALE_ENQUEUE_MS = 60000;
|
|
9
|
-
export type Source = "api" | "internal" | "local" | "plugin" | "scheduler" | "slack";
|
|
9
|
+
export type Source = "api" | "internal" | "local" | "plugin" | "resource_event" | "scheduler" | "slack";
|
|
10
10
|
export type ExecutionStatus = "awaiting_resume" | "failed" | "idle" | "pending" | "running";
|
|
11
11
|
export interface AgentInput {
|
|
12
12
|
attachments?: unknown[];
|
|
@@ -153,6 +153,12 @@ export declare function markConversationWorkEnqueued(args: {
|
|
|
153
153
|
nowMs?: number;
|
|
154
154
|
state?: StateAdapter;
|
|
155
155
|
}): Promise<void>;
|
|
156
|
+
/** Clear a wake marker after its queue delivery finds no runnable work. */
|
|
157
|
+
export declare function clearConsumedConversationWake(args: {
|
|
158
|
+
conversationId: string;
|
|
159
|
+
nowMs?: number;
|
|
160
|
+
state?: StateAdapter;
|
|
161
|
+
}): Promise<boolean>;
|
|
156
162
|
/** Try to acquire the durable execution lease for one conversation. */
|
|
157
163
|
export declare function startConversationWork(args: {
|
|
158
164
|
conversationId: string;
|
|
@@ -4,6 +4,12 @@ import type { ConversationWorkQueue } from "./queue";
|
|
|
4
4
|
import * as workState from "./state";
|
|
5
5
|
export { CONVERSATION_ACTIVE_INDEX_KEY, CONVERSATION_BY_ACTIVITY_INDEX_KEY, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS, CONVERSATION_WORK_LEASE_TTL_MS, CONVERSATION_WORK_STALE_ENQUEUE_MS, type AgentInput, type AppendAndEnqueueInboundMessageResult, type AppendInboundMessageResult, type Conversation, type ConversationExecution, type ConversationWorkLease, type ConversationWorkState, type ExecutionStatus, type InboundMessage, type Lease, type RequestConversationWorkResult, type Source, type StartConversationWorkAcquired, type StartConversationWorkActive, type StartConversationWorkNoWork, type StartConversationWorkResult, } from "@/chat/task-execution/state";
|
|
6
6
|
import type { AppendAndEnqueueInboundMessageResult, Conversation, InboundMessage } from "@/chat/task-execution/state";
|
|
7
|
+
export type EnsureConversationWakeResult = {
|
|
8
|
+
queueMessageId?: string;
|
|
9
|
+
status: "enqueued";
|
|
10
|
+
} | {
|
|
11
|
+
status: "already_enqueued" | "no_work";
|
|
12
|
+
};
|
|
7
13
|
/** Return a persisted conversation record, if one exists. */
|
|
8
14
|
export declare function getConversation(args: {
|
|
9
15
|
conversationId: string;
|
|
@@ -18,6 +24,22 @@ export declare function getConversationWorkState(args: {
|
|
|
18
24
|
export declare function countPendingConversationMessages(conversation: Conversation): number;
|
|
19
25
|
/** Return whether a conversation has pending or resumable execution work. */
|
|
20
26
|
export declare function hasRunnableConversationWork(conversation: Conversation): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Ensure runnable conversation work has one accepted queue wake-up nudge.
|
|
29
|
+
*
|
|
30
|
+
* Ordinary wakes coalesce on a recent accepted marker. Replacement is only for
|
|
31
|
+
* consumed or known-stale deliveries where another queue nudge must exist.
|
|
32
|
+
*/
|
|
33
|
+
export declare function ensureConversationWake(args: {
|
|
34
|
+
conversationId: string;
|
|
35
|
+
conversationStore?: ConversationStore;
|
|
36
|
+
delayMs?: number;
|
|
37
|
+
idempotencyKey: string;
|
|
38
|
+
nowMs?: number;
|
|
39
|
+
queue: ConversationWorkQueue;
|
|
40
|
+
replaceExistingWake?: true;
|
|
41
|
+
state?: StateAdapter;
|
|
42
|
+
}): Promise<EnsureConversationWakeResult>;
|
|
21
43
|
/** Persist one inbound message idempotently in its conversation mailbox. */
|
|
22
44
|
export declare function appendInboundMessage(args: {
|
|
23
45
|
message: InboundMessage;
|
|
@@ -25,7 +47,7 @@ export declare function appendInboundMessage(args: {
|
|
|
25
47
|
nowMs?: number;
|
|
26
48
|
state?: StateAdapter;
|
|
27
49
|
}): Promise<workState.AppendInboundMessageResult>;
|
|
28
|
-
/** Persist inbound work and
|
|
50
|
+
/** Persist inbound work and ensure a worker wake-up. */
|
|
29
51
|
export declare function appendAndEnqueueInboundMessage(args: {
|
|
30
52
|
message: InboundMessage;
|
|
31
53
|
conversationStore?: ConversationStore;
|
|
@@ -33,6 +55,13 @@ export declare function appendAndEnqueueInboundMessage(args: {
|
|
|
33
55
|
queue: ConversationWorkQueue;
|
|
34
56
|
state?: StateAdapter;
|
|
35
57
|
}): Promise<AppendAndEnqueueInboundMessageResult>;
|
|
58
|
+
/** Clear an accepted wake marker after its delivery finds no runnable work. */
|
|
59
|
+
export declare function clearConsumedConversationWake(args: {
|
|
60
|
+
conversationId: string;
|
|
61
|
+
conversationStore?: ConversationStore;
|
|
62
|
+
nowMs?: number;
|
|
63
|
+
state?: StateAdapter;
|
|
64
|
+
}): Promise<boolean>;
|
|
36
65
|
/** Mark a conversation runnable when there is no new mailbox message. */
|
|
37
66
|
export declare function requestConversationWork(args: {
|
|
38
67
|
conversationId: string;
|
|
@@ -46,13 +75,6 @@ export declare function recordConversationActivity(args: Parameters<Conversation
|
|
|
46
75
|
conversationStore?: ConversationStore;
|
|
47
76
|
state?: StateAdapter;
|
|
48
77
|
}): Promise<void>;
|
|
49
|
-
/** Record that a wake-up nudge was accepted for the conversation. */
|
|
50
|
-
export declare function markConversationWorkEnqueued(args: {
|
|
51
|
-
conversationId: string;
|
|
52
|
-
conversationStore?: ConversationStore;
|
|
53
|
-
nowMs?: number;
|
|
54
|
-
state?: StateAdapter;
|
|
55
|
-
}): Promise<void>;
|
|
56
78
|
/** Try to acquire the durable execution lease for one conversation. */
|
|
57
79
|
export declare function startConversationWork(args: {
|
|
58
80
|
conversationId: string;
|