@sentry/junior 0.109.0 → 0.111.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-FHHVLNPA.js → agent-hooks-QQ2IWKOP.js} +12 -13
- package/dist/api/conversations/access.d.ts +9 -0
- package/dist/api/conversations/aggregate.d.ts +12 -1
- package/dist/api/conversations/archive.d.ts +3 -5
- package/dist/api/conversations/detail.d.ts +156 -7
- package/dist/api/conversations/events.d.ts +1 -1
- package/dist/api/conversations/list.d.ts +57 -6
- package/dist/api/conversations/projection.d.ts +6 -7
- package/dist/api/conversations/reporting.d.ts +10 -4
- package/dist/api/conversations/routes.d.ts +2 -1
- package/dist/api/conversations/shared.d.ts +1 -1
- package/dist/api/conversations/stats.d.ts +37 -6
- package/dist/api/conversations/stats.query.d.ts +1 -1
- package/dist/api/conversations/usage.d.ts +9 -0
- package/dist/api/http.d.ts +7 -0
- package/dist/api/locations/detail.d.ts +102 -6
- package/dist/api/locations/list.d.ts +43 -5
- package/dist/api/locations/query.d.ts +4 -2
- package/dist/api/locations/routes.d.ts +2 -1
- package/dist/api/people/list.d.ts +28 -6
- package/dist/api/people/list.query.d.ts +1 -1
- package/dist/api/people/profile.d.ts +96 -7
- package/dist/api/people/profile.query.d.ts +4 -2
- package/dist/api/people/routes.d.ts +2 -1
- package/dist/api/people/shared.d.ts +1219 -2
- package/dist/api/route.d.ts +18 -4
- package/dist/api/schema/common.d.ts +6 -0
- package/dist/api/{conversations/schema.d.ts → schema/conversation.d.ts} +31 -3
- package/dist/api/{locations/schema.d.ts → schema/location.d.ts} +5 -0
- package/dist/api/{people/schema.d.ts → schema/person.d.ts} +37 -45
- package/dist/api/schema.d.ts +8 -22
- package/dist/api/schema.js +10 -2
- package/dist/api.d.ts +5 -1
- package/dist/api.js +767 -384
- package/dist/app.js +591 -447
- package/dist/build/virtual-config.d.ts +2 -0
- package/dist/catalog-runtime-D22W6QEJ.js +16 -0
- package/dist/chat/agent/request.d.ts +3 -6
- package/dist/chat/agent/resume.d.ts +11 -12
- package/dist/chat/agent/sandbox.d.ts +36 -11
- package/dist/chat/agent/tools.d.ts +5 -8
- package/dist/chat/config.d.ts +8 -1
- package/dist/chat/conversations/history.d.ts +3 -0
- package/dist/chat/conversations/sql/privacy.d.ts +3 -15
- package/dist/chat/pi/messages.d.ts +2 -2
- package/dist/chat/pi/sdk.d.ts +1 -1
- package/dist/chat/pi/sql-model-usage.d.ts +4 -1
- package/dist/chat/plugins/agent-hooks.d.ts +2 -2
- package/dist/chat/runtime/agent-continue-runner.d.ts +7 -3
- package/dist/chat/runtime/slack-runtime.d.ts +1 -2
- package/dist/chat/runtime/thread-state.d.ts +3 -7
- package/dist/chat/runtime/turn-preparation.d.ts +2 -2
- package/dist/chat/sandbox/command-result.d.ts +91 -0
- package/dist/chat/sandbox/errors.d.ts +3 -1
- package/dist/chat/sandbox/ref.d.ts +5 -0
- package/dist/chat/sandbox/sandbox.d.ts +19 -46
- package/dist/chat/sandbox/session.d.ts +16 -20
- package/dist/chat/sandbox/skill-sync.d.ts +2 -2
- package/dist/chat/sandbox/workspace.d.ts +14 -12
- package/dist/chat/services/auth-pause.d.ts +4 -0
- package/dist/chat/services/context-compaction.d.ts +1 -0
- package/dist/chat/services/turn-result.d.ts +3 -4
- package/dist/chat/task-execution/queue-signing.d.ts +10 -8
- package/dist/chat/task-execution/queue.d.ts +9 -7
- package/dist/chat/task-execution/slack-work.d.ts +9 -7
- package/dist/chat/task-execution/state.d.ts +75 -22
- package/dist/chat/task-execution/store.d.ts +34 -3
- package/dist/chat/task-execution/worker.d.ts +0 -1
- package/dist/chat/tool-support/normalize-result.d.ts +2 -2
- package/dist/chat/tool-support/pi-tool-adapter.d.ts +2 -2
- package/dist/chat/tool-support/structured-result.d.ts +1 -2
- package/dist/chat/tools/sandbox/file-uploads.d.ts +1 -1
- package/dist/chat/{runtime → tools/sandbox}/generated-artifacts.d.ts +3 -3
- package/dist/chat/tools/types.d.ts +1 -1
- package/dist/chat/tools/web/fetch-content.d.ts +5 -0
- package/dist/chat/tools/web/image-generate.d.ts +2 -1
- package/dist/chat/tools/web/search.d.ts +1 -1
- package/dist/{chunk-CEA3A3UA.js → chunk-2ZTTXTSZ.js} +24 -1
- package/dist/{chunk-IVVGFRQQ.js → chunk-42WRQLJ6.js} +10 -38
- package/dist/{chunk-O3JMSZLI.js → chunk-6Y5L4BOM.js} +3 -5
- package/dist/{chunk-HO5NT6OE.js → chunk-B45FPP2A.js} +306 -31
- package/dist/{chunk-WHMOBKT7.js → chunk-BTRNMS6A.js} +2 -2
- package/dist/{chunk-PLB7MRCQ.js → chunk-C4MZ3GP5.js} +1 -1
- package/dist/{chunk-HHVY4SMP.js → chunk-FPK7XY3F.js} +98 -92
- package/dist/{chunk-RGX4V75M.js → chunk-IFAHK54X.js} +3 -3
- package/dist/{chunk-ISMWX44P.js → chunk-J7APPQIJ.js} +2 -2
- package/dist/{chunk-TMBRFULF.js → chunk-JQFJO5WH.js} +7 -1
- package/dist/{chunk-FWJRXN4F.js → chunk-L6JPKANW.js} +3 -139
- package/dist/{chunk-7Q6WCISF.js → chunk-MIAKQNYX.js} +43 -31
- package/dist/chunk-MPVES2IC.js +44 -0
- package/dist/{chunk-JNAVF45E.js → chunk-NQLWOTY4.js} +47 -19
- package/dist/{chunk-IXKSQGIO.js → chunk-OOLU34J4.js} +8860 -9137
- package/dist/{chunk-OUHNWH46.js → chunk-PYKKM4MM.js} +1 -1
- package/dist/{chunk-MXW4GL53.js → chunk-PZELBSHC.js} +8 -9
- package/dist/{chunk-QY636HZU.js → chunk-QQIVLZW4.js} +96 -17
- package/dist/{chunk-72OMGPDS.js → chunk-SL3ZKNLQ.js} +19 -18
- package/dist/{chunk-3SXUV423.js → chunk-WSRBFHPX.js} +1 -1
- package/dist/{chunk-TT6GMXNA.js → chunk-XQAYFRWT.js} +2 -2
- package/dist/{chunk-MGUMR35T.js → chunk-Z2W4SJZ7.js} +1 -1
- package/dist/{chunk-OCD3OZRK.js → chunk-Z4G3WCP3.js} +1 -1
- package/dist/{chunk-FENLIFJD.js → chunk-ZRZ4SVWG.js} +69 -10
- package/dist/cli/chat.js +23 -24
- package/dist/cli/check.js +8 -8
- package/dist/cli/plugins.js +15 -16
- package/dist/cli/snapshot-warmup.js +11 -11
- package/dist/cli/upgrade.js +9 -9
- package/dist/db/schema/conversations.d.ts +17 -0
- package/dist/db/schema.d.ts +17 -0
- package/dist/{db-V3NU72O2.js → db-WXQOQESG.js} +8 -9
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +15 -10
- package/dist/reporting-schema.d.ts +46 -0
- package/dist/{runner-JYBCQBLK.js → runner-4QY4XH4B.js} +23 -33
- package/dist/{skills-U6MDAST7.js → skills-P5MU4EBX.js} +8 -8
- package/dist/{validation-72N3JVRU.js → validation-PQF5OP6T.js} +8 -8
- package/dist/version.js +1 -1
- package/migrations/0007_thick_sugar_man.sql +23 -0
- package/migrations/meta/0007_snapshot.json +1013 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +6 -6
- package/dist/catalog-runtime-DMGJSLV2.js +0 -16
- package/dist/chunk-OB42YVAE.js +0 -16
- package/dist/chunk-SYAQIR5Z.js +0 -53
|
@@ -1,60 +1,33 @@
|
|
|
1
1
|
import { type LogContext } from "@/chat/logging";
|
|
2
|
-
import { type SandboxEgressAuthRequiredSignal, type SandboxEgressPermissionDeniedSignal } from "@/chat/sandbox/egress/session";
|
|
3
2
|
import type { SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress/tracing";
|
|
4
3
|
import type { CredentialContext } from "@/chat/credentials/context";
|
|
5
|
-
import type {
|
|
6
|
-
import type {
|
|
4
|
+
import type { SandboxRef } from "@/chat/sandbox/ref";
|
|
5
|
+
import type { SandboxWorkspace } from "@/chat/sandbox/workspace";
|
|
7
6
|
import type { SkillMetadata } from "@/chat/skills";
|
|
8
|
-
interface
|
|
7
|
+
export interface SandboxToolCall {
|
|
9
8
|
toolName: string;
|
|
10
9
|
input: unknown;
|
|
11
10
|
signal?: AbortSignal;
|
|
12
11
|
}
|
|
13
|
-
export interface
|
|
14
|
-
|
|
12
|
+
export interface SandboxTools {
|
|
13
|
+
supports(toolName: string): boolean;
|
|
14
|
+
execute(params: SandboxToolCall): Promise<unknown>;
|
|
15
15
|
}
|
|
16
|
-
export interface
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
exit_code: number;
|
|
21
|
-
signal: null;
|
|
22
|
-
timed_out: boolean;
|
|
23
|
-
aborted?: boolean;
|
|
24
|
-
stdout: string;
|
|
25
|
-
stderr: string;
|
|
26
|
-
stdout_truncated: boolean;
|
|
27
|
-
stderr_truncated: boolean;
|
|
28
|
-
auth_required?: SandboxEgressAuthRequiredSignal;
|
|
29
|
-
permission_denied?: SandboxEgressPermissionDeniedSignal;
|
|
16
|
+
export interface SandboxAccess {
|
|
17
|
+
readonly tools: SandboxTools;
|
|
18
|
+
readonly workspace: SandboxWorkspace;
|
|
19
|
+
sandboxRef(): SandboxRef | undefined;
|
|
30
20
|
}
|
|
31
|
-
export interface
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
export interface SandboxExecutor {
|
|
36
|
-
configureSkills(skills: SkillMetadata[]): void;
|
|
37
|
-
configureReferenceFiles(files: string[]): void;
|
|
38
|
-
getSandboxId(): string | undefined;
|
|
39
|
-
getDependencyProfileHash(): string | undefined;
|
|
40
|
-
canExecute(toolName: string): boolean;
|
|
41
|
-
createSandbox(): Promise<SandboxInstance>;
|
|
42
|
-
execute<T>(params: SandboxExecutionInput): Promise<SandboxExecutionEnvelope<T>>;
|
|
43
|
-
dispose(): Promise<void>;
|
|
44
|
-
}
|
|
45
|
-
/** Create one sandbox-backed tool executor facade for the current turn. */
|
|
46
|
-
export declare function createSandboxExecutor(options?: {
|
|
47
|
-
sandboxId?: string;
|
|
48
|
-
sandboxDependencyProfileHash?: string;
|
|
21
|
+
export interface SandboxOptions {
|
|
22
|
+
sandboxRef?: SandboxRef;
|
|
23
|
+
skills: SkillMetadata[];
|
|
24
|
+
referenceFiles: string[];
|
|
49
25
|
timeoutMs?: number;
|
|
50
26
|
traceContext?: LogContext;
|
|
51
27
|
tracePropagation?: SandboxEgressTracePropagationConfig;
|
|
52
28
|
credentialEgress?: CredentialContext;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}>;
|
|
59
|
-
}): SandboxExecutor;
|
|
60
|
-
export {};
|
|
29
|
+
prepare?: (workspace: SandboxWorkspace) => void | Promise<void>;
|
|
30
|
+
onSandboxRefChanged?: (sandboxRef: SandboxRef) => void | Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/** Create lazy run-scoped access to a conversation's durable sandbox. */
|
|
33
|
+
export declare function createSandbox(options: SandboxOptions): SandboxAccess;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { type NetworkPolicy } from "@vercel/sandbox";
|
|
2
2
|
import { type LogContext, type TracePropagationHeaders } from "@/chat/logging";
|
|
3
|
-
import { type SandboxFileSystem, type
|
|
3
|
+
import { type SandboxFileSystem, type SandboxSession } from "@/chat/sandbox/workspace";
|
|
4
4
|
import type { SkillMetadata } from "@/chat/skills";
|
|
5
|
+
import type { SandboxRef } from "@/chat/sandbox/ref";
|
|
5
6
|
interface SandboxToolExecutors {
|
|
7
|
+
sessionId: string;
|
|
6
8
|
bash: (input: {
|
|
7
9
|
command: string;
|
|
8
10
|
env?: Record<string, string>;
|
|
@@ -30,29 +32,23 @@ interface SandboxToolExecutors {
|
|
|
30
32
|
}>;
|
|
31
33
|
fs: SandboxFileSystem;
|
|
32
34
|
}
|
|
33
|
-
interface
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
getSandboxEgressId(): string | undefined;
|
|
38
|
-
getDependencyProfileHash(): string | undefined;
|
|
39
|
-
createSandbox(): Promise<SandboxInstance>;
|
|
40
|
-
ensureToolExecutors(): Promise<SandboxToolExecutors>;
|
|
35
|
+
interface SandboxRuntime {
|
|
36
|
+
sandboxRef(): SandboxRef | undefined;
|
|
37
|
+
acquire(): Promise<SandboxSession>;
|
|
38
|
+
tools(): Promise<SandboxToolExecutors>;
|
|
41
39
|
refreshNetworkPolicy(traceHeaders?: TracePropagationHeaders): Promise<void>;
|
|
42
|
-
dispose(): Promise<void>;
|
|
43
40
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
interface SandboxRuntimeOptions {
|
|
42
|
+
sandboxRef?: SandboxRef;
|
|
43
|
+
skills: SkillMetadata[];
|
|
44
|
+
referenceFiles: string[];
|
|
48
45
|
timeoutMs?: number;
|
|
49
46
|
traceContext?: LogContext;
|
|
50
47
|
commandEnv?: () => Promise<Record<string, string>>;
|
|
51
48
|
createNetworkPolicy?: (egressId: string, traceHeaders?: TracePropagationHeaders) => NetworkPolicy | undefined;
|
|
52
|
-
onSandboxPrepare?: (sandbox:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}): SandboxSessionManager;
|
|
49
|
+
onSandboxPrepare?: (sandbox: SandboxSession) => void | Promise<void>;
|
|
50
|
+
onSandboxRefChanged?: (sandboxRef: SandboxRef) => void | Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
/** Own sandbox acquisition, preparation, and session-scoped tool caching. */
|
|
53
|
+
export declare function createSandboxRuntime(options: SandboxRuntimeOptions): SandboxRuntime;
|
|
58
54
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SandboxSession } from "@/chat/sandbox/workspace";
|
|
2
2
|
import type { SkillMetadata } from "@/chat/skills";
|
|
3
3
|
/** Resolve a virtual sandbox skill path back to the host filesystem when no sandbox exists yet. */
|
|
4
4
|
export declare function resolveHostSkillPath(availableSkills: SkillMetadata[], sandboxPath: string): string | null;
|
|
@@ -8,7 +8,7 @@ export declare function resolveHostDataPath(referenceFiles: string[], sandboxPat
|
|
|
8
8
|
export declare function isHostFileMissingError(error: unknown): boolean;
|
|
9
9
|
/** Copy the current skill set and reference files into a sandbox. */
|
|
10
10
|
export declare function syncSkillsToSandbox(params: {
|
|
11
|
-
sandbox:
|
|
11
|
+
sandbox: SandboxSession;
|
|
12
12
|
skills: SkillMetadata[];
|
|
13
13
|
referenceFiles?: string[];
|
|
14
14
|
withSpan: <T>(name: string, op: string, attributes: Record<string, unknown>, callback: () => Promise<T>) => Promise<T>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type NetworkPolicy, type Sandbox as VercelSandbox } from "@vercel/sandbox";
|
|
2
2
|
export interface SandboxCommandResult {
|
|
3
3
|
exitCode: number;
|
|
4
|
-
stderr
|
|
5
|
-
stdout
|
|
4
|
+
stderr: string;
|
|
5
|
+
stdout: string;
|
|
6
6
|
}
|
|
7
7
|
export interface SandboxCommandInput {
|
|
8
8
|
args?: string[];
|
|
@@ -31,10 +31,15 @@ export interface SandboxWorkspace {
|
|
|
31
31
|
path: string;
|
|
32
32
|
}): Promise<Buffer | null | undefined>;
|
|
33
33
|
runCommand(input: SandboxCommandInput): Promise<SandboxCommandResult>;
|
|
34
|
+
writeFiles(files: Array<{
|
|
35
|
+
content: string | Uint8Array;
|
|
36
|
+
mode?: number;
|
|
37
|
+
path: string;
|
|
38
|
+
}>): Promise<void>;
|
|
34
39
|
}
|
|
35
|
-
export interface
|
|
40
|
+
export interface SandboxSession extends SandboxWorkspace {
|
|
36
41
|
readonly sandboxId: string;
|
|
37
|
-
readonly
|
|
42
|
+
readonly sessionId: string;
|
|
38
43
|
readonly fs: SandboxFileSystem;
|
|
39
44
|
extendTimeout(duration: number): Promise<void>;
|
|
40
45
|
mkDir(path: string): Promise<void>;
|
|
@@ -45,11 +50,8 @@ export interface SandboxInstance extends SandboxWorkspace {
|
|
|
45
50
|
update(params: {
|
|
46
51
|
networkPolicy?: NetworkPolicy;
|
|
47
52
|
}): Promise<void>;
|
|
48
|
-
writeFiles(files: Array<{
|
|
49
|
-
content: string | Uint8Array;
|
|
50
|
-
mode?: number;
|
|
51
|
-
path: string;
|
|
52
|
-
}>): Promise<void>;
|
|
53
53
|
}
|
|
54
|
-
/**
|
|
55
|
-
export declare function
|
|
54
|
+
/** Pin Junior's sandbox contract to one Vercel session without SDK replay. */
|
|
55
|
+
export declare function createSandboxSession(sandbox: VercelSandbox, options?: {
|
|
56
|
+
onUnavailable?: (sessionId: string) => void;
|
|
57
|
+
}): SandboxSession;
|
|
@@ -12,6 +12,10 @@ export declare class AuthorizationPauseError extends Error {
|
|
|
12
12
|
readonly providerDisplayName: string;
|
|
13
13
|
constructor(kind: AuthorizationPauseKind, provider: string, providerDisplayName: string, disposition: AuthorizationPauseDisposition);
|
|
14
14
|
}
|
|
15
|
+
/** Error indicating an authorization pause could not be made durable. */
|
|
16
|
+
export declare class AuthPausePersistenceError extends Error {
|
|
17
|
+
constructor(conversationId: string, turnId: string, cause?: unknown);
|
|
18
|
+
}
|
|
15
19
|
/** Error indicating this turn cannot start an external authorization flow. */
|
|
16
20
|
export declare class AuthorizationFlowDisabledError extends Error {
|
|
17
21
|
readonly kind: AuthorizationPauseKind;
|
|
@@ -3,6 +3,7 @@ import type { PiMessage } from "@/chat/pi/messages";
|
|
|
3
3
|
import type { TurnRoute } from "@/chat/services/turn-router";
|
|
4
4
|
import type { AgentTurnUsage } from "@/chat/usage";
|
|
5
5
|
import type { ThreadArtifactsState } from "@/chat/state/artifacts";
|
|
6
|
+
import type { SandboxRef } from "@/chat/sandbox/ref";
|
|
6
7
|
import { extractAssistantText } from "@/chat/pi/transcript";
|
|
7
8
|
export interface AgentTurnDiagnostics {
|
|
8
9
|
assistantMessageCount: number;
|
|
@@ -23,8 +24,7 @@ export interface AgentRunResult {
|
|
|
23
24
|
/** Sanitized terminal text for diagnostics and failure fallback, not success delivery. */
|
|
24
25
|
text: string;
|
|
25
26
|
artifactStatePatch?: Partial<ThreadArtifactsState>;
|
|
26
|
-
|
|
27
|
-
sandboxDependencyProfileHash?: string;
|
|
27
|
+
sandboxRef?: SandboxRef;
|
|
28
28
|
piMessages?: PiMessage[];
|
|
29
29
|
diagnostics: AgentTurnDiagnostics;
|
|
30
30
|
}
|
|
@@ -33,8 +33,7 @@ export interface TurnResultInput {
|
|
|
33
33
|
userInput: string;
|
|
34
34
|
artifactStatePatch: Partial<ThreadArtifactsState>;
|
|
35
35
|
toolCalls: string[];
|
|
36
|
-
|
|
37
|
-
sandboxDependencyProfileHash?: string;
|
|
36
|
+
sandboxRef?: SandboxRef;
|
|
38
37
|
piMessages?: PiMessage[];
|
|
39
38
|
durationMs?: number;
|
|
40
39
|
generatedFileCount: number;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type ConversationQueueMessage } from "./queue";
|
|
3
3
|
export declare const CONVERSATION_WORK_QUEUE_SIGNATURE_MAX_SKEW_MS: number;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
declare const signedConversationQueueMessageSchema: z.ZodObject<{
|
|
5
|
+
conversationId: z.ZodString;
|
|
6
|
+
signature: z.ZodString;
|
|
7
|
+
signatureVersion: z.ZodLiteral<"v2">;
|
|
8
|
+
signedAtMs: z.ZodNumber;
|
|
9
|
+
}, z.core.$strict>;
|
|
10
|
+
type SignedConversationQueueMessage = z.output<typeof signedConversationQueueMessageSchema>;
|
|
9
11
|
export type ConversationQueueMessageVerificationResult = {
|
|
10
12
|
message: ConversationQueueMessage;
|
|
11
13
|
status: "verified";
|
|
@@ -18,7 +20,7 @@ export type ConversationQueueMessageVerificationResult = {
|
|
|
18
20
|
};
|
|
19
21
|
/** Sign a conversation queue payload before it crosses the public callback route. */
|
|
20
22
|
export declare function signConversationQueueMessage(message: ConversationQueueMessage, nowMs?: number): SignedConversationQueueMessage;
|
|
21
|
-
/** Explain whether a queue payload is verified, rejected, or
|
|
23
|
+
/** Explain whether a queue payload is verified, rejected, or unavailable. */
|
|
22
24
|
export declare function verifyConversationQueueMessage(value: unknown, nowMs?: number): ConversationQueueMessageVerificationResult;
|
|
23
25
|
/** Verify a signed conversation queue payload from the Vercel Queue callback. */
|
|
24
26
|
export declare function verifySignedConversationQueueMessage(value: unknown, nowMs?: number): ConversationQueueMessage | undefined;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Validate the conversation work hint sent through Vercel Queue. */
|
|
3
|
+
export declare const conversationQueueMessageSchema: z.ZodObject<{
|
|
4
|
+
conversationId: z.ZodString;
|
|
5
|
+
}, z.core.$strict>;
|
|
6
|
+
/** Conversation work hint accepted by the queue callback and worker. */
|
|
7
|
+
export type ConversationQueueMessage = z.output<typeof conversationQueueMessageSchema>;
|
|
8
|
+
export type ConversationQueueMessageRejectReason = "expired" | "invalid_record" | "malformed" | "signature_mismatch";
|
|
7
9
|
export declare class ConversationQueueMessageRejectedError extends Error {
|
|
8
10
|
conversationId?: string;
|
|
9
11
|
reason: ConversationQueueMessageRejectReason;
|
|
@@ -11,7 +13,7 @@ export declare class ConversationQueueMessageRejectedError extends Error {
|
|
|
11
13
|
conversationId?: string;
|
|
12
14
|
});
|
|
13
15
|
}
|
|
14
|
-
/** Return whether
|
|
16
|
+
/** Return whether an error means the queue message was permanently rejected. */
|
|
15
17
|
export declare function isConversationQueueMessageRejectedError(error: unknown): error is ConversationQueueMessageRejectedError;
|
|
16
18
|
export interface ConversationQueueSendOptions {
|
|
17
19
|
delayMs?: number;
|
|
@@ -22,8 +22,8 @@ declare const slackConversationMessageMetadataSchema: z.ZodUnion<readonly [z.Zod
|
|
|
22
22
|
_type: z.ZodLiteral<"chat:Message">;
|
|
23
23
|
attachments: z.ZodArray<z.ZodObject<{
|
|
24
24
|
type: z.ZodEnum<{
|
|
25
|
-
image: "image";
|
|
26
25
|
file: "file";
|
|
26
|
+
image: "image";
|
|
27
27
|
audio: "audio";
|
|
28
28
|
video: "video";
|
|
29
29
|
}>;
|
|
@@ -72,16 +72,16 @@ declare const slackConversationMessageMetadataSchema: z.ZodUnion<readonly [z.Zod
|
|
|
72
72
|
channelId: z.ZodString;
|
|
73
73
|
channelVisibility: z.ZodOptional<z.ZodEnum<{
|
|
74
74
|
unknown: "unknown";
|
|
75
|
-
private: "private";
|
|
76
75
|
external: "external";
|
|
76
|
+
private: "private";
|
|
77
77
|
workspace: "workspace";
|
|
78
78
|
}>>;
|
|
79
79
|
currentMessage: z.ZodOptional<z.ZodObject<{
|
|
80
80
|
_type: z.ZodLiteral<"chat:Message">;
|
|
81
81
|
attachments: z.ZodArray<z.ZodObject<{
|
|
82
82
|
type: z.ZodEnum<{
|
|
83
|
-
image: "image";
|
|
84
83
|
file: "file";
|
|
84
|
+
image: "image";
|
|
85
85
|
audio: "audio";
|
|
86
86
|
video: "video";
|
|
87
87
|
}>;
|
|
@@ -132,8 +132,8 @@ declare const slackConversationMessageMetadataSchema: z.ZodUnion<readonly [z.Zod
|
|
|
132
132
|
_type: z.ZodLiteral<"chat:Message">;
|
|
133
133
|
attachments: z.ZodArray<z.ZodObject<{
|
|
134
134
|
type: z.ZodEnum<{
|
|
135
|
-
image: "image";
|
|
136
135
|
file: "file";
|
|
136
|
+
image: "image";
|
|
137
137
|
audio: "audio";
|
|
138
138
|
video: "video";
|
|
139
139
|
}>;
|
|
@@ -182,16 +182,16 @@ declare const slackConversationMessageMetadataSchema: z.ZodUnion<readonly [z.Zod
|
|
|
182
182
|
channelId: z.ZodString;
|
|
183
183
|
channelVisibility: z.ZodOptional<z.ZodEnum<{
|
|
184
184
|
unknown: "unknown";
|
|
185
|
-
private: "private";
|
|
186
185
|
external: "external";
|
|
186
|
+
private: "private";
|
|
187
187
|
workspace: "workspace";
|
|
188
188
|
}>>;
|
|
189
189
|
currentMessage: z.ZodOptional<z.ZodObject<{
|
|
190
190
|
_type: z.ZodLiteral<"chat:Message">;
|
|
191
191
|
attachments: z.ZodArray<z.ZodObject<{
|
|
192
192
|
type: z.ZodEnum<{
|
|
193
|
-
image: "image";
|
|
194
193
|
file: "file";
|
|
194
|
+
image: "image";
|
|
195
195
|
audio: "audio";
|
|
196
196
|
video: "video";
|
|
197
197
|
}>;
|
|
@@ -272,7 +272,9 @@ interface SlackResourceEventInboundInput {
|
|
|
272
272
|
export interface CreateSlackConversationWorkerOptions {
|
|
273
273
|
getSlackAdapter: () => SlackAdapter;
|
|
274
274
|
lookupSlackUser?: (teamId: string, userId: string) => Promise<SlackActorProfile | null | undefined>;
|
|
275
|
-
resumeAwaitingContinuation: (conversationId: string
|
|
275
|
+
resumeAwaitingContinuation: (conversationId: string, options: {
|
|
276
|
+
shouldYield: () => boolean;
|
|
277
|
+
}) => Promise<boolean>;
|
|
276
278
|
conversationStore?: ConversationStore;
|
|
277
279
|
runtime: SlackInboxTurnRuntime;
|
|
278
280
|
state?: StateAdapter;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { StateAdapter } from "chat";
|
|
2
|
-
import type
|
|
2
|
+
import { type Destination } from "@sentry/junior-plugin-api";
|
|
3
|
+
import { z } from "zod";
|
|
3
4
|
import { type StoredSlackActor } from "@/chat/actor";
|
|
4
5
|
declare class InvalidConversationRecordError extends Error {
|
|
5
6
|
constructor(conversationId: string);
|
|
@@ -12,25 +13,67 @@ export declare const CONVERSATION_WORK_LEASE_TTL_MS = 90000;
|
|
|
12
13
|
export declare const CONVERSATION_WORK_CHECK_IN_INTERVAL_MS = 15000;
|
|
13
14
|
export declare const CONVERSATION_WORK_STALE_ENQUEUE_MS = 60000;
|
|
14
15
|
export declare const CONVERSATION_WORK_MAX_DELIVERY_ATTEMPTS = 5;
|
|
15
|
-
|
|
16
|
+
declare const inboundMessageSourceSchema: z.ZodEnum<{
|
|
17
|
+
slack: "slack";
|
|
18
|
+
plugin: "plugin";
|
|
19
|
+
api: "api";
|
|
20
|
+
local: "local";
|
|
21
|
+
internal: "internal";
|
|
22
|
+
resource_event: "resource_event";
|
|
23
|
+
scheduler: "scheduler";
|
|
24
|
+
}>;
|
|
25
|
+
export type Source = z.output<typeof inboundMessageSourceSchema>;
|
|
16
26
|
export type ExecutionStatus = "awaiting_resume" | "failed" | "idle" | "pending" | "running";
|
|
17
|
-
|
|
18
|
-
attachments
|
|
19
|
-
authorId
|
|
20
|
-
metadata
|
|
21
|
-
text:
|
|
22
|
-
}
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
declare const agentInputSchema: z.ZodObject<{
|
|
28
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
29
|
+
authorId: z.ZodOptional<z.ZodString>;
|
|
30
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
31
|
+
text: z.ZodString;
|
|
32
|
+
}, z.core.$strict>;
|
|
33
|
+
export type AgentInput = z.output<typeof agentInputSchema>;
|
|
34
|
+
/** Durable delivery modes for pending inbound mailbox work. */
|
|
35
|
+
export declare const inboundMessageDeliverySchema: z.ZodEnum<{
|
|
36
|
+
defer: "defer";
|
|
37
|
+
interrupt: "interrupt";
|
|
38
|
+
}>;
|
|
39
|
+
export type InboundMessageDelivery = z.output<typeof inboundMessageDeliverySchema>;
|
|
40
|
+
/** Canonical durable mailbox entry owned by task execution. */
|
|
41
|
+
export declare const inboundMessageSchema: z.ZodObject<{
|
|
42
|
+
attemptCount: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
conversationId: z.ZodString;
|
|
44
|
+
createdAtMs: z.ZodNumber;
|
|
45
|
+
delivery: z.ZodEnum<{
|
|
46
|
+
defer: "defer";
|
|
47
|
+
interrupt: "interrupt";
|
|
48
|
+
}>;
|
|
49
|
+
destination: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
50
|
+
platform: z.ZodLiteral<"slack">;
|
|
51
|
+
teamId: z.ZodString;
|
|
52
|
+
channelId: z.ZodString;
|
|
53
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
54
|
+
platform: z.ZodLiteral<"local">;
|
|
55
|
+
conversationId: z.ZodString;
|
|
56
|
+
}, z.core.$strict>], "platform">;
|
|
57
|
+
inboundMessageId: z.ZodString;
|
|
58
|
+
injectedAtMs: z.ZodOptional<z.ZodNumber>;
|
|
59
|
+
input: z.ZodObject<{
|
|
60
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
61
|
+
authorId: z.ZodOptional<z.ZodString>;
|
|
62
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
63
|
+
text: z.ZodString;
|
|
64
|
+
}, z.core.$strict>;
|
|
65
|
+
receivedAtMs: z.ZodNumber;
|
|
66
|
+
source: z.ZodEnum<{
|
|
67
|
+
slack: "slack";
|
|
68
|
+
plugin: "plugin";
|
|
69
|
+
api: "api";
|
|
70
|
+
local: "local";
|
|
71
|
+
internal: "internal";
|
|
72
|
+
resource_event: "resource_event";
|
|
73
|
+
scheduler: "scheduler";
|
|
74
|
+
}>;
|
|
75
|
+
}, z.core.$strict>;
|
|
76
|
+
export type InboundMessage = z.output<typeof inboundMessageSchema>;
|
|
34
77
|
export interface Lease {
|
|
35
78
|
acquiredAtMs: number;
|
|
36
79
|
expiresAtMs: number;
|
|
@@ -56,7 +99,7 @@ export interface Conversation {
|
|
|
56
99
|
execution: ConversationExecution;
|
|
57
100
|
lastActivityAtMs: number;
|
|
58
101
|
actor?: StoredSlackActor;
|
|
59
|
-
schemaVersion:
|
|
102
|
+
schemaVersion: 2;
|
|
60
103
|
source?: Source;
|
|
61
104
|
title?: string;
|
|
62
105
|
updatedAtMs: number;
|
|
@@ -182,7 +225,7 @@ export declare function checkInConversationWork(args: {
|
|
|
182
225
|
state?: StateAdapter;
|
|
183
226
|
}): Promise<boolean>;
|
|
184
227
|
/**
|
|
185
|
-
*
|
|
228
|
+
* Resolve pending mailbox entries after the caller accepts responsibility.
|
|
186
229
|
*
|
|
187
230
|
* Returning ids acknowledges only that subset; returning nothing acknowledges
|
|
188
231
|
* every pending entry passed to the handler.
|
|
@@ -193,7 +236,10 @@ export declare function drainConversationMailbox(args: {
|
|
|
193
236
|
leaseToken: string;
|
|
194
237
|
nowMs?: number;
|
|
195
238
|
state?: StateAdapter;
|
|
196
|
-
}): Promise<
|
|
239
|
+
}): Promise<{
|
|
240
|
+
changed: boolean;
|
|
241
|
+
messages: InboundMessage[];
|
|
242
|
+
}>;
|
|
197
243
|
/** Acknowledge leased mailbox entries after the handler accepts responsibility. */
|
|
198
244
|
export declare function ackMessages(args: {
|
|
199
245
|
conversationId: string;
|
|
@@ -210,6 +256,13 @@ export declare function requestConversationContinuation(args: {
|
|
|
210
256
|
nowMs?: number;
|
|
211
257
|
state?: StateAdapter;
|
|
212
258
|
}): Promise<boolean>;
|
|
259
|
+
/** Begin a requested turn resume under the worker's existing lease. */
|
|
260
|
+
export declare function beginConversationResume(args: {
|
|
261
|
+
conversationId: string;
|
|
262
|
+
leaseToken: string;
|
|
263
|
+
nowMs?: number;
|
|
264
|
+
state?: StateAdapter;
|
|
265
|
+
}): Promise<boolean>;
|
|
213
266
|
/** Release the durable execution lease without changing completion state. */
|
|
214
267
|
export declare function releaseConversationWork(args: {
|
|
215
268
|
conversationId: string;
|
|
@@ -2,13 +2,13 @@ import type { StateAdapter } from "chat";
|
|
|
2
2
|
import type { ConversationStore } from "@/chat/conversations/store";
|
|
3
3
|
import type { ConversationWorkQueue } from "./queue";
|
|
4
4
|
import * as workState from "./state";
|
|
5
|
-
export { CONVERSATION_ACTIVE_INDEX_KEY, CONVERSATION_BY_ACTIVITY_INDEX_KEY, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS, CONVERSATION_WORK_LEASE_TTL_MS, CONVERSATION_WORK_MAX_DELIVERY_ATTEMPTS, CONVERSATION_WORK_STALE_ENQUEUE_MS, isFinalAttempt, isInvalidConversationRecordError, type AgentInput, type AttemptFailure, 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";
|
|
5
|
+
export { CONVERSATION_ACTIVE_INDEX_KEY, CONVERSATION_BY_ACTIVITY_INDEX_KEY, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS, CONVERSATION_WORK_LEASE_TTL_MS, CONVERSATION_WORK_MAX_DELIVERY_ATTEMPTS, CONVERSATION_WORK_STALE_ENQUEUE_MS, isFinalAttempt, isInvalidConversationRecordError, type AgentInput, type AttemptFailure, type AppendAndEnqueueInboundMessageResult, type AppendInboundMessageResult, type Conversation, type ConversationExecution, type ConversationWorkLease, type ConversationWorkState, type ExecutionStatus, type InboundMessage, type InboundMessageDelivery, 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
7
|
export type EnsureConversationWakeResult = {
|
|
8
8
|
queueMessageId?: string;
|
|
9
9
|
status: "enqueued";
|
|
10
10
|
} | {
|
|
11
|
-
status: "already_enqueued" | "no_work";
|
|
11
|
+
status: "already_enqueued" | "lease_active" | "no_work";
|
|
12
12
|
};
|
|
13
13
|
/** Return a persisted conversation record, if one exists. */
|
|
14
14
|
export declare function getConversation(args: {
|
|
@@ -94,7 +94,30 @@ export declare function checkInConversationWork(args: {
|
|
|
94
94
|
export declare function drainConversationMailbox(args: Parameters<typeof workState.drainConversationMailbox>[0] & {
|
|
95
95
|
conversationStore?: ConversationStore;
|
|
96
96
|
state?: StateAdapter;
|
|
97
|
-
}): Promise<
|
|
97
|
+
}): Promise<{
|
|
98
|
+
conversationId: string;
|
|
99
|
+
createdAtMs: number;
|
|
100
|
+
delivery: "defer" | "interrupt";
|
|
101
|
+
destination: {
|
|
102
|
+
platform: "slack";
|
|
103
|
+
teamId: string;
|
|
104
|
+
channelId: string;
|
|
105
|
+
} | {
|
|
106
|
+
platform: "local";
|
|
107
|
+
conversationId: string;
|
|
108
|
+
};
|
|
109
|
+
inboundMessageId: string;
|
|
110
|
+
input: {
|
|
111
|
+
text: string;
|
|
112
|
+
attachments?: unknown[] | undefined;
|
|
113
|
+
authorId?: string | undefined;
|
|
114
|
+
metadata?: Record<string, unknown> | undefined;
|
|
115
|
+
};
|
|
116
|
+
receivedAtMs: number;
|
|
117
|
+
source: "slack" | "plugin" | "api" | "local" | "internal" | "resource_event" | "scheduler";
|
|
118
|
+
attemptCount?: number | undefined;
|
|
119
|
+
injectedAtMs?: number | undefined;
|
|
120
|
+
}[]>;
|
|
98
121
|
/** Acknowledge leased mailbox entries after the handler accepts responsibility. */
|
|
99
122
|
export declare function ackMessages(args: {
|
|
100
123
|
conversationId: string;
|
|
@@ -113,6 +136,14 @@ export declare function requestConversationContinuation(args: {
|
|
|
113
136
|
nowMs?: number;
|
|
114
137
|
state?: StateAdapter;
|
|
115
138
|
}): Promise<boolean>;
|
|
139
|
+
/** Begin a requested turn resume without releasing the current lease. */
|
|
140
|
+
export declare function beginConversationResume(args: {
|
|
141
|
+
conversationId: string;
|
|
142
|
+
leaseToken: string;
|
|
143
|
+
conversationStore?: ConversationStore;
|
|
144
|
+
nowMs?: number;
|
|
145
|
+
state?: StateAdapter;
|
|
146
|
+
}): Promise<boolean>;
|
|
116
147
|
/** Release the durable execution lease without changing completion state. */
|
|
117
148
|
export declare function releaseConversationWork(args: {
|
|
118
149
|
conversationId: string;
|
|
@@ -4,7 +4,6 @@ import type { ConversationStore } from "@/chat/conversations/store";
|
|
|
4
4
|
import { type ConversationQueueMessage, type ConversationWorkQueue } from "./queue";
|
|
5
5
|
import { type InboundMessage } from "./store";
|
|
6
6
|
export declare const CONVERSATION_WORK_DEFER_DELAY_MS = 15000;
|
|
7
|
-
export declare const CONVERSATION_WORK_SOFT_YIELD_AFTER_MS = 240000;
|
|
8
7
|
export interface ConversationWorkerContext {
|
|
9
8
|
attempt: InboxAttempt;
|
|
10
9
|
checkIn(): Promise<boolean>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ImageContent, TextContent } from "@earendil-works/pi-ai";
|
|
2
|
-
/**
|
|
3
|
-
export declare function normalizeToolResult(result: unknown,
|
|
2
|
+
/** Normalize raw tool output into Pi content and structured details. */
|
|
3
|
+
export declare function normalizeToolResult(result: unknown, options?: {
|
|
4
4
|
requireStructuredResult?: boolean;
|
|
5
5
|
toolName?: string;
|
|
6
6
|
}): {
|
|
@@ -3,10 +3,10 @@ import { type ConversationPrivacy } from "@/chat/conversation-privacy";
|
|
|
3
3
|
import { type LogContext } from "@/chat/logging";
|
|
4
4
|
import type { PluginAuthOrchestration } from "@/chat/services/plugin-auth-orchestration";
|
|
5
5
|
import type { AssistantStatusSpec } from "@/chat/slack/assistant-thread/status";
|
|
6
|
-
import type {
|
|
6
|
+
import type { SandboxTools } from "@/chat/sandbox/sandbox";
|
|
7
7
|
import type { SkillSandbox } from "@/chat/sandbox/skill-sandbox";
|
|
8
8
|
import type { AnyToolDefinition } from "@/chat/tools/definition";
|
|
9
9
|
import type { ToolExecutionReport } from "@/chat/tool-support/tool-execution-report";
|
|
10
10
|
import type { PluginHookRunner } from "@/chat/plugins/agent-hooks";
|
|
11
11
|
/** Wrap tool definitions into Pi Agent tool objects with logging, validation, and sandbox execution. */
|
|
12
|
-
export declare function createPiAgentTools(tools: Record<string, AnyToolDefinition>, sandbox: SkillSandbox, spanContext: LogContext, onStatus?: (status: AssistantStatusSpec) => void | Promise<void>,
|
|
12
|
+
export declare function createPiAgentTools(tools: Record<string, AnyToolDefinition>, sandbox: SkillSandbox, spanContext: LogContext, onStatus?: (status: AssistantStatusSpec) => void | Promise<void>, sandboxTools?: SandboxTools, pluginAuthOrchestration?: PluginAuthOrchestration, onToolCall?: (toolCallId: string, toolName: string, params: Record<string, unknown>) => void | Promise<void>, agentHooks?: PluginHookRunner, conversationPrivacy?: ConversationPrivacy, onToolResult?: (report: ToolExecutionReport) => void | Promise<void>): AgentTool[];
|
|
@@ -61,7 +61,7 @@ export interface JuniorToolResultEnvelope<TDetails extends JuniorToolResult = Ju
|
|
|
61
61
|
}
|
|
62
62
|
/** Bind continuation metadata to the exposed runtime tool name. */
|
|
63
63
|
export declare function injectContinuationToolName(details: JuniorToolResult, toolName: string): JuniorToolResult | JuniorToolResultWithBoundContinuation;
|
|
64
|
-
interface JuniorTextToolResultEnvelope<TDetails extends JuniorToolResult = JuniorToolResult> {
|
|
64
|
+
export interface JuniorTextToolResultEnvelope<TDetails extends JuniorToolResult = JuniorToolResult> {
|
|
65
65
|
content: [TextContent];
|
|
66
66
|
details: TDetails;
|
|
67
67
|
}
|
|
@@ -70,4 +70,3 @@ export declare function makeStructuredToolResult<TDetails extends JuniorToolResu
|
|
|
70
70
|
export declare function makeStructuredToolResult<TDetails extends JuniorToolResult>(details: TDetails, options: {
|
|
71
71
|
content: Array<TextContent | ImageContent>;
|
|
72
72
|
}): JuniorToolResultEnvelope<TDetails>;
|
|
73
|
-
export {};
|
|
@@ -48,5 +48,5 @@ export declare function sandboxArtifactPath(filename: string): string;
|
|
|
48
48
|
/** Infer upload MIME type from an explicit value or filename extension. */
|
|
49
49
|
export declare function inferMimeType(filename: string, explicitMimeType?: string): string;
|
|
50
50
|
/** Read and validate one sandbox file for Slack/file reply upload. */
|
|
51
|
-
export declare function readSandboxFileUpload(
|
|
51
|
+
export declare function readSandboxFileUpload(workspace: SandboxWorkspace, input: SandboxFileMaterializationInput): Promise<SandboxFileUpload>;
|
|
52
52
|
export {};
|