@sentry/junior 0.116.1 → 0.117.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-GUAAS3XH.js → agent-hooks-5IK4LPLP.js} +8 -8
- package/dist/api/conversations/detail.d.ts +7 -0
- package/dist/api/conversations/event-list.d.ts +7 -0
- package/dist/api/conversations/events.d.ts +1 -1
- package/dist/api/schema/conversation.d.ts +28 -0
- package/dist/api/schema.js +1 -1
- package/dist/api.js +25 -12
- package/dist/app.js +32 -30
- package/dist/{catalog-runtime-WMPC4J4U.js → catalog-runtime-MTUYW3AA.js} +5 -5
- package/dist/chat/agent/prompt.d.ts +2 -0
- package/dist/chat/agent/request.d.ts +2 -1
- package/dist/chat/agent/resume.d.ts +2 -0
- package/dist/chat/agent/tools.d.ts +1 -0
- package/dist/chat/conversations/history.d.ts +22 -1
- package/dist/chat/conversations/projection.d.ts +6 -0
- package/dist/chat/mcp/client.d.ts +4 -0
- package/dist/chat/mcp/errors.d.ts +22 -1
- package/dist/chat/oauth-response.d.ts +21 -0
- package/dist/chat/plugins/prompt.d.ts +9 -0
- package/dist/chat/plugins/types.d.ts +2 -21
- package/dist/chat/sandbox/snapshot/install.d.ts +6 -0
- package/dist/chat/sandbox/snapshot/profile.d.ts +14 -0
- package/dist/chat/sandbox/snapshot/resolve.d.ts +22 -0
- package/dist/chat/sandbox/snapshot/span.d.ts +2 -0
- package/dist/chat/services/context-compaction-marker.d.ts +1 -0
- package/dist/chat/services/turn-session-record.d.ts +2 -0
- package/dist/chat/state/turn-session.d.ts +2 -0
- package/dist/chat/tools/query-conversation-events.d.ts +1 -1
- package/dist/chat/tools/sandbox/view-image.d.ts +11 -0
- package/dist/chat/tools/types.d.ts +7 -0
- package/dist/{chunk-RYFAVWP3.js → chunk-27KWTFP6.js} +33 -12
- package/dist/{chunk-N3C4XCRE.js → chunk-3GE3F4LT.js} +1 -1
- package/dist/{chunk-XA3VLFPK.js → chunk-5O3JDQDG.js} +154 -20
- package/dist/{chunk-CGXLCMWI.js → chunk-6G45D3YG.js} +114 -10
- package/dist/{chunk-F3SWGSPG.js → chunk-72Z3HNTQ.js} +1 -1
- package/dist/{chunk-DLLW5ITL.js → chunk-AKG4TZNH.js} +2 -2
- package/dist/{chunk-TC4ZEM2D.js → chunk-BFIRIZPH.js} +9 -0
- package/dist/{chunk-OY2PQQ4P.js → chunk-CU7HTGNI.js} +1 -1
- package/dist/{chunk-CY7NXM32.js → chunk-DS27ZBSP.js} +4 -2
- package/dist/{chunk-VBMMMVVQ.js → chunk-FAWBONPC.js} +404 -443
- package/dist/{chunk-7CSVG54J.js → chunk-KU6ALEJC.js} +1 -1
- package/dist/{chunk-H35BDAUS.js → chunk-LN765Y4N.js} +6 -6
- package/dist/{chunk-KNCELO2M.js → chunk-LUMEBOWC.js} +1 -1
- package/dist/{chunk-GDAXWEIJ.js → chunk-NHZEUHKH.js} +514 -344
- package/dist/{chunk-ZYHLNTC2.js → chunk-STUI6NIL.js} +78 -16
- package/dist/{chunk-2YYPXQNQ.js → chunk-W5JEQQEA.js} +1 -1
- package/dist/{chunk-JPKGW6L6.js → chunk-WEK3V5RI.js} +73 -32
- package/dist/{chunk-WLT72MRP.js → chunk-WUNPRM76.js} +1 -1
- package/dist/{chunk-FAEALXEH.js → chunk-YRWJ3KEU.js} +2 -2
- package/dist/{chunk-BFYVIOTS.js → chunk-ZRQUQJUV.js} +12 -2
- package/dist/cli/chat.js +21 -21
- package/dist/cli/check.js +6 -6
- package/dist/cli/main.js +1 -1
- package/dist/cli/plugins.js +11 -11
- package/dist/cli/{snapshot-warmup.js → snapshot-create.js} +17 -19
- package/dist/cli/upgrade.js +5 -5
- package/dist/{db-FH4R5ZQ4.js → db-J2ITKS63.js} +5 -5
- package/dist/handlers/oauth-html.d.ts +4 -2
- package/dist/instrumentation.js +2 -2
- package/dist/nitro.js +2 -2
- package/dist/{oauth-callback-server-C2SSJ3FQ.js → oauth-callback-server-NQYKBT24.js} +15 -15
- package/dist/{runner-NAALFIXM.js → runner-53V5GIQM.js} +10 -10
- package/dist/{skills-UN2JXYYF.js → skills-BU3ZMLVB.js} +6 -6
- package/dist/{validation-EEF4ROHR.js → validation-74EIKKE6.js} +6 -6
- package/dist/version.js +1 -1
- package/package.json +5 -5
- package/dist/chat/sandbox/runtime-dependency-snapshots.d.ts +0 -20
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type OAuthProviderErrorPhase = "token_exchange" | "token_refresh";
|
|
2
|
+
export interface OAuthProviderErrorDetails {
|
|
3
|
+
phase: OAuthProviderErrorPhase;
|
|
4
|
+
provider: string;
|
|
5
|
+
resourceHost: string;
|
|
6
|
+
status?: number;
|
|
7
|
+
}
|
|
8
|
+
/** Safe failure at a generic OAuth provider boundary. */
|
|
9
|
+
export declare class OAuthProviderError extends Error {
|
|
10
|
+
readonly phase: OAuthProviderErrorPhase;
|
|
11
|
+
readonly provider: string;
|
|
12
|
+
readonly resourceHost: string;
|
|
13
|
+
readonly status?: number;
|
|
14
|
+
constructor(details: OAuthProviderErrorDetails);
|
|
15
|
+
}
|
|
16
|
+
/** Return safe generic OAuth provider fields for logs and spans. */
|
|
17
|
+
export declare function getOAuthProviderErrorAttributes(error: unknown): Record<string, string | number>;
|
|
18
|
+
/** Read only the bounded prefix needed to classify an OAuth error response. */
|
|
19
|
+
export declare function readBoundedOAuthErrorBody(response: Response): Promise<string>;
|
|
20
|
+
/** Preserve small OAuth error responses while bounding bodies before SDK parsing. */
|
|
21
|
+
export declare function fetchWithBoundedOAuthErrorBodies(fetchFn?: typeof fetch, onErrorResponseStatus?: (status: number) => void): typeof fetch;
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
/** Validated plugin context retained for the current turn. */
|
|
2
|
+
export interface PluginTurnContext {
|
|
3
|
+
content: Record<string, unknown>;
|
|
4
|
+
kind: string;
|
|
5
|
+
loadedAtMs: number;
|
|
6
|
+
pluginName: string;
|
|
7
|
+
version: number;
|
|
8
|
+
}
|
|
1
9
|
export interface PluginPromptContributionContext {
|
|
10
|
+
context?: PluginTurnContext;
|
|
2
11
|
id: string;
|
|
3
12
|
pluginName: string;
|
|
4
13
|
text: string;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { PluginRuntimeDependency, PluginRuntimePostinstallCommand } from "@sentry/junior-plugin-api";
|
|
1
2
|
import type { UserTokenStore } from "@/chat/credentials/user-token-store";
|
|
3
|
+
export type { PluginNpmRuntimeDependency, PluginRuntimeDependency, PluginRuntimePostinstallCommand, PluginSystemRuntimeDependency, PluginSystemRuntimeDependencyFromUrl, } from "@sentry/junior-plugin-api";
|
|
2
4
|
export interface PluginOAuthConfig {
|
|
3
5
|
clientIdEnv: string;
|
|
4
6
|
clientSecretEnv: string;
|
|
@@ -28,26 +30,6 @@ export interface OAuthBearerCredentials {
|
|
|
28
30
|
authTokenPlaceholder?: string;
|
|
29
31
|
}
|
|
30
32
|
export type PluginCredentials = OAuthBearerCredentials;
|
|
31
|
-
export interface PluginNpmRuntimeDependency {
|
|
32
|
-
type: "npm";
|
|
33
|
-
package: string;
|
|
34
|
-
version: string;
|
|
35
|
-
}
|
|
36
|
-
export interface PluginSystemRuntimeDependency {
|
|
37
|
-
type: "system";
|
|
38
|
-
package: string;
|
|
39
|
-
}
|
|
40
|
-
export interface PluginSystemRuntimeDependencyFromUrl {
|
|
41
|
-
type: "system";
|
|
42
|
-
url: string;
|
|
43
|
-
sha256: string;
|
|
44
|
-
}
|
|
45
|
-
export type PluginRuntimeDependency = PluginNpmRuntimeDependency | PluginSystemRuntimeDependency | PluginSystemRuntimeDependencyFromUrl;
|
|
46
|
-
export interface PluginRuntimePostinstallCommand {
|
|
47
|
-
cmd: string;
|
|
48
|
-
args?: string[];
|
|
49
|
-
sudo?: boolean;
|
|
50
|
-
}
|
|
51
33
|
export interface PluginMcpHttpConfig {
|
|
52
34
|
transport: "http";
|
|
53
35
|
url: string;
|
|
@@ -148,4 +130,3 @@ export interface InlinePluginManifestDefinition {
|
|
|
148
130
|
manifest: PluginManifest;
|
|
149
131
|
packageName?: string;
|
|
150
132
|
}
|
|
151
|
-
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PluginRuntimeDependency, PluginRuntimePostinstallCommand } from "@/chat/plugins/types";
|
|
2
|
+
import type { SandboxSession } from "@/chat/sandbox/workspace";
|
|
3
|
+
/** Install declared system and npm dependencies into a snapshot sandbox. */
|
|
4
|
+
export declare function dependencies(sandbox: SandboxSession, values: PluginRuntimeDependency[]): Promise<void>;
|
|
5
|
+
/** Run declared postinstall commands after dependency binaries are available. */
|
|
6
|
+
export declare function postinstall(sandbox: SandboxSession, commands: PluginRuntimePostinstallCommand[]): Promise<void>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PluginRuntimeDependency, PluginRuntimePostinstallCommand } from "@/chat/plugins/types";
|
|
2
|
+
export type Profile = {
|
|
3
|
+
hash: string;
|
|
4
|
+
dependencyCount: number;
|
|
5
|
+
floating: boolean;
|
|
6
|
+
dependencies: PluginRuntimeDependency[];
|
|
7
|
+
postinstall: PluginRuntimePostinstallCommand[];
|
|
8
|
+
};
|
|
9
|
+
/** Build the dependency profile that selects a reusable sandbox snapshot. */
|
|
10
|
+
export declare function create(runtime: string): Profile | null;
|
|
11
|
+
/** Return the current dependency profile hash without building its snapshot. */
|
|
12
|
+
export declare function hash(runtime: string): string | undefined;
|
|
13
|
+
/** Decide whether a cached snapshot has outlived a floating profile. */
|
|
14
|
+
export declare function isStale(profile: Profile, createdAtMs: number): boolean;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type ResolveOutcome = "no_profile" | "cache_hit" | "cache_hit_after_lock_wait" | "rebuilt" | "forced_rebuild";
|
|
2
|
+
export type RebuildReason = "cache_miss" | "floating_stale" | "force_rebuild" | "snapshot_missing";
|
|
3
|
+
/** Result of resolving the reusable snapshot for one dependency profile. */
|
|
4
|
+
export interface Snapshot {
|
|
5
|
+
snapshotId?: string;
|
|
6
|
+
profileHash?: string;
|
|
7
|
+
dependencyCount: number;
|
|
8
|
+
cacheHit: boolean;
|
|
9
|
+
resolveOutcome: ResolveOutcome;
|
|
10
|
+
rebuildReason?: RebuildReason;
|
|
11
|
+
}
|
|
12
|
+
export type ProgressPhase = "resolve_start" | "cache_hit" | "waiting_for_lock" | "building_snapshot" | "build_complete";
|
|
13
|
+
/** Resolve or build the reusable snapshot for the current dependency profile. */
|
|
14
|
+
export declare function resolve(params: {
|
|
15
|
+
runtime: string;
|
|
16
|
+
timeoutMs: number;
|
|
17
|
+
forceRebuild?: boolean;
|
|
18
|
+
staleSnapshotId?: string;
|
|
19
|
+
onProgress?: (phase: ProgressPhase) => void | Promise<void>;
|
|
20
|
+
}): Promise<Snapshot>;
|
|
21
|
+
/** Identify provider errors that mean a referenced snapshot no longer exists. */
|
|
22
|
+
export declare function isMissingError(error: unknown): boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PiMessage } from "@/chat/pi/messages";
|
|
2
2
|
export declare const COMPACTION_SUMMARY_PREFIX = "Context compaction summary for future Junior turns:";
|
|
3
|
+
export declare const ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX = "Active-turn context checkpoint. If no newer user instruction follows this checkpoint, continue the same unfinished task now using the authoritative instructions above and this summary as internal continuation state. If a newer user instruction follows, treat this checkpoint as prior context and follow that newer instruction. Do not reply with a plan or summary solely because this checkpoint appeared:";
|
|
3
4
|
export declare const MODEL_HANDOFF_SUMMARY_PREFIX = "Model handoff checkpoint. Continue the outstanding request now using this summary as the complete prior context:";
|
|
4
5
|
/** Return whether text is one of Junior's durable compacted-context markers. */
|
|
5
6
|
export declare function isCompactionSummaryText(text: string): boolean;
|
|
@@ -4,6 +4,7 @@ import type { Destination, Actor, Source } from "@sentry/junior-plugin-api";
|
|
|
4
4
|
import type { PiMessage } from "@/chat/pi/messages";
|
|
5
5
|
import type { ConversationMessageProvenance } from "@/chat/conversations/provenance";
|
|
6
6
|
import { type AgentTurnUsage } from "@/chat/usage";
|
|
7
|
+
import type { PluginTurnContext } from "@/chat/plugins/prompt";
|
|
7
8
|
export interface TurnSessionContext {
|
|
8
9
|
conversationId: string;
|
|
9
10
|
sessionId: string;
|
|
@@ -40,6 +41,7 @@ export declare function persistRunningSessionRecord(args: {
|
|
|
40
41
|
actor?: Actor;
|
|
41
42
|
reasoningLevel?: string;
|
|
42
43
|
surface?: AgentTurnSurface;
|
|
44
|
+
turnContexts?: PluginTurnContext[];
|
|
43
45
|
turnStartMessageIndex?: number;
|
|
44
46
|
}): Promise<boolean>;
|
|
45
47
|
/**
|
|
@@ -12,6 +12,7 @@ import { type Destination, type Source } from "@sentry/junior-plugin-api";
|
|
|
12
12
|
import { type PiMessage } from "@/chat/pi/messages";
|
|
13
13
|
import { type Actor } from "@/chat/actor";
|
|
14
14
|
import { type ConversationMessageProvenance } from "@/chat/conversations/provenance";
|
|
15
|
+
import type { PluginTurnContext } from "@/chat/plugins/prompt";
|
|
15
16
|
import { type AgentTurnUsage } from "@/chat/usage";
|
|
16
17
|
import type { ConversationPrivacy } from "@/chat/conversation-privacy";
|
|
17
18
|
import type { ConversationStore } from "@/chat/conversations/store";
|
|
@@ -95,6 +96,7 @@ export declare function upsertAgentTurnSessionRecord(args: {
|
|
|
95
96
|
errorMessage?: string;
|
|
96
97
|
resumedFromSliceId?: number;
|
|
97
98
|
traceId?: string;
|
|
99
|
+
turnContexts?: PluginTurnContext[];
|
|
98
100
|
turnStartMessageIndex?: number;
|
|
99
101
|
ttlMs?: number;
|
|
100
102
|
}): Promise<AgentTurnSessionRecord>;
|
|
@@ -9,7 +9,7 @@ export declare function createQueryConversationEventsTool(context: ToolRuntimeCo
|
|
|
9
9
|
after_seq?: number | null | undefined;
|
|
10
10
|
before_seq?: number | null | undefined;
|
|
11
11
|
limit?: number | null | undefined;
|
|
12
|
-
types?: ("message" | "handoff" | "user_message" | "assistant_message" | "tool_result" | "compaction" | "mcp_provider_connected" | "authorization_requested" | "authorization_completed" | "tool_execution_started" | "message_updated" | "message_handled" | "messages_summarized" | "turn_started" | "turn_routed" | "turn_completed" | "turn_failed" | "subagent_started" | "subagent_ended")[] | null | undefined;
|
|
12
|
+
types?: ("message" | "handoff" | "user_message" | "assistant_message" | "tool_result" | "compaction" | "mcp_provider_connected" | "authorization_requested" | "authorization_completed" | "tool_execution_started" | "message_updated" | "message_handled" | "messages_summarized" | "turn_started" | "turn_routed" | "turn_context" | "turn_completed" | "turn_failed" | "subagent_started" | "subagent_ended")[] | null | undefined;
|
|
13
13
|
};
|
|
14
14
|
execute?: ((input: unknown, options: import("./definition").ToolExecuteOptions) => {
|
|
15
15
|
[x: string]: unknown;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SandboxWorkspace } from "@/chat/sandbox/workspace";
|
|
2
|
+
import type { ViewImageToolDeps } from "@/chat/tools/types";
|
|
3
|
+
/** Create a tool that loads a sandbox image into the active model context. */
|
|
4
|
+
export declare function createViewImageTool(sandbox: SandboxWorkspace, supportsImageInput: () => boolean, deps?: ViewImageToolDeps): Omit<import("../definition").AnyToolDefinition, "inputSchema" | "outputSchema" | "prepareArguments" | "execute"> & {
|
|
5
|
+
inputSchema: import("../definition").JsonSchemaObject;
|
|
6
|
+
outputSchema?: undefined;
|
|
7
|
+
prepareArguments(args: unknown): {
|
|
8
|
+
path: string;
|
|
9
|
+
};
|
|
10
|
+
execute?: (input: unknown, options: import("../definition").ToolExecuteOptions) => Promise<import("@/chat/tool-support/zod-tool").ContentOnlyToolResult> | import("@/chat/tool-support/zod-tool").ContentOnlyToolResult;
|
|
11
|
+
};
|
|
@@ -34,6 +34,10 @@ export interface WebSearchToolDeps {
|
|
|
34
34
|
max_results?: number;
|
|
35
35
|
}) => Promise<JuniorToolResult> | JuniorToolResult;
|
|
36
36
|
}
|
|
37
|
+
/** Optional host image reader for deterministic tool execution without sandbox I/O. */
|
|
38
|
+
export interface ViewImageToolDeps {
|
|
39
|
+
readFile?: (path: string) => Promise<Buffer | null | undefined>;
|
|
40
|
+
}
|
|
37
41
|
export interface ToolHooks {
|
|
38
42
|
/**
|
|
39
43
|
* Materialize generated files and return sandbox paths that exist before the
|
|
@@ -44,6 +48,7 @@ export interface ToolHooks {
|
|
|
44
48
|
onSkillLoaded?: (skill: Skill) => void | LoadSkillMetadata | Promise<void | LoadSkillMetadata>;
|
|
45
49
|
toolOverrides?: {
|
|
46
50
|
imageGenerate?: ImageGenerateToolDeps;
|
|
51
|
+
viewImage?: ViewImageToolDeps;
|
|
47
52
|
webFetch?: WebFetchToolDeps;
|
|
48
53
|
webSearch?: WebSearchToolDeps;
|
|
49
54
|
};
|
|
@@ -70,6 +75,8 @@ interface BaseToolRuntimeContext {
|
|
|
70
75
|
egress: PluginEgress;
|
|
71
76
|
mcpToolManager?: McpToolManager;
|
|
72
77
|
workspace: SandboxWorkspace;
|
|
78
|
+
/** Report whether the model currently executing the turn accepts images. */
|
|
79
|
+
supportsImageInput?: () => boolean;
|
|
73
80
|
}
|
|
74
81
|
interface SlackToolRuntimeContext extends BaseToolRuntimeContext {
|
|
75
82
|
destination: SlackDestination;
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-MU6HHZEN.js";
|
|
5
5
|
import {
|
|
6
6
|
getStateAdapter
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KU6ALEJC.js";
|
|
8
8
|
import {
|
|
9
9
|
agentHistoryItemSchema,
|
|
10
10
|
contextProvenance,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
instructionProvenanceFor,
|
|
17
17
|
sanitizePostgresJson,
|
|
18
18
|
withConversationEventLock
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-ZRQUQJUV.js";
|
|
20
20
|
import {
|
|
21
21
|
sleep
|
|
22
22
|
} from "./chunk-4ZNGQH7C.js";
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
escapeXml,
|
|
26
26
|
resolveGatewayModel,
|
|
27
27
|
unwrapCurrentInstruction
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-DS27ZBSP.js";
|
|
29
29
|
import {
|
|
30
30
|
toStoredSlackActor
|
|
31
31
|
} from "./chunk-HZF5P5UN.js";
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
logException,
|
|
35
35
|
logWarn,
|
|
36
36
|
setSpanAttributes
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-72Z3HNTQ.js";
|
|
38
38
|
import {
|
|
39
39
|
isRecord,
|
|
40
40
|
toOptionalNumber,
|
|
@@ -412,16 +412,29 @@ async function commitMessagesLocked(args, executor) {
|
|
|
412
412
|
});
|
|
413
413
|
if (matchingPrefix === current.messages.length) {
|
|
414
414
|
const newMessages = nextLocalMessages.slice(matchingPrefix);
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
415
|
+
const turnContext = args.turnContext;
|
|
416
|
+
const turnContextEvents = turnContext?.contexts.map((context, index) => ({
|
|
417
|
+
idempotencyKey: `turn:${turnContext.turnId}:context:${context.pluginName}:${index}`,
|
|
418
|
+
createdAtMs: context.loadedAtMs,
|
|
419
|
+
data: {
|
|
420
|
+
type: "turn_context",
|
|
421
|
+
turnId: turnContext.turnId,
|
|
422
|
+
pluginName: context.pluginName,
|
|
423
|
+
kind: context.kind,
|
|
424
|
+
version: context.version,
|
|
425
|
+
content: context.content
|
|
426
|
+
}
|
|
427
|
+
})) ?? [];
|
|
428
|
+
await eventStore.append(args.conversationId, [
|
|
429
|
+
...newMessages.map((message, index) => ({
|
|
418
430
|
data: historyItemFromPiMessage(
|
|
419
431
|
message,
|
|
420
432
|
nextLocalProvenance[matchingPrefix + index]
|
|
421
433
|
),
|
|
422
434
|
createdAtMs: messageTimestamp(message)
|
|
423
|
-
}))
|
|
424
|
-
|
|
435
|
+
})),
|
|
436
|
+
...turnContextEvents
|
|
437
|
+
]);
|
|
425
438
|
} else {
|
|
426
439
|
throw new Error(
|
|
427
440
|
`Agent history for ${args.conversationId} changed before its committed boundary`
|
|
@@ -818,6 +831,7 @@ function materializeAgentTurnSessionRecord(stored, piProjection, turnStartMessag
|
|
|
818
831
|
function restoreRuntimeContext(messages, runtimeContext) {
|
|
819
832
|
if (!runtimeContext || runtimeContext.length === 0) return messages;
|
|
820
833
|
const restored = [...messages];
|
|
834
|
+
const unmatchedRuntimeContext = [];
|
|
821
835
|
for (const runtimeMessage of runtimeContext) {
|
|
822
836
|
const runtime = runtimeMessage;
|
|
823
837
|
const targetIndex = restored.findIndex((message) => {
|
|
@@ -825,7 +839,7 @@ function restoreRuntimeContext(messages, runtimeContext) {
|
|
|
825
839
|
return candidate.role === "user" && candidate.timestamp === runtime.timestamp;
|
|
826
840
|
});
|
|
827
841
|
if (targetIndex < 0) {
|
|
828
|
-
|
|
842
|
+
unmatchedRuntimeContext.push(runtimeMessage);
|
|
829
843
|
continue;
|
|
830
844
|
}
|
|
831
845
|
const target = restored[targetIndex];
|
|
@@ -837,7 +851,7 @@ function restoreRuntimeContext(messages, runtimeContext) {
|
|
|
837
851
|
]
|
|
838
852
|
};
|
|
839
853
|
}
|
|
840
|
-
return restored;
|
|
854
|
+
return [...unmatchedRuntimeContext, ...restored];
|
|
841
855
|
}
|
|
842
856
|
async function getStoredAgentTurnSessionRecord(conversationId, sessionId) {
|
|
843
857
|
const stateAdapter = getStateAdapter();
|
|
@@ -1022,7 +1036,13 @@ async function upsertAgentTurnSessionRecord(args) {
|
|
|
1022
1036
|
conversationId: args.conversationId,
|
|
1023
1037
|
messages: args.piMessages,
|
|
1024
1038
|
...instructionActor ? { newMessageProvenance: instructionProvenanceFor(instructionActor) } : {},
|
|
1025
|
-
...args.trailingMessageProvenance ? { trailingMessageProvenance: args.trailingMessageProvenance } : {}
|
|
1039
|
+
...args.trailingMessageProvenance ? { trailingMessageProvenance: args.trailingMessageProvenance } : {},
|
|
1040
|
+
...args.turnContexts && args.turnContexts.length > 0 ? {
|
|
1041
|
+
turnContext: {
|
|
1042
|
+
contexts: args.turnContexts,
|
|
1043
|
+
turnId: args.sessionId
|
|
1044
|
+
}
|
|
1045
|
+
} : {}
|
|
1026
1046
|
});
|
|
1027
1047
|
const durableTurnStartMessageIndex = args.turnStartMessageIndex === void 0 ? void 0 : stripRuntimeTurnContext(
|
|
1028
1048
|
args.piMessages.slice(0, args.turnStartMessageIndex)
|
|
@@ -1294,6 +1314,7 @@ async function persistRunningSessionRecord(args) {
|
|
|
1294
1314
|
...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
|
|
1295
1315
|
modelId: args.modelId,
|
|
1296
1316
|
...args.reasoningLevel ? { reasoningLevel: args.reasoningLevel } : {},
|
|
1317
|
+
...args.turnContexts ? { turnContexts: args.turnContexts } : {},
|
|
1297
1318
|
...args.actor ?? latestSessionRecord?.actor ? { actor: args.actor ?? latestSessionRecord?.actor } : {},
|
|
1298
1319
|
...getActiveTraceId() ?? latestSessionRecord?.traceId ? { traceId: getActiveTraceId() ?? latestSessionRecord?.traceId } : {},
|
|
1299
1320
|
...(args.turnStartMessageIndex ?? latestSessionRecord?.turnStartMessageIndex) !== void 0 ? {
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
logInfo,
|
|
6
6
|
logWarn,
|
|
7
7
|
setSpanAttributes
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-72Z3HNTQ.js";
|
|
9
9
|
import {
|
|
10
10
|
discoverInstalledPluginPackageContent,
|
|
11
11
|
normalizePluginPackageNames
|
|
@@ -1097,6 +1097,115 @@ function hasRequiredOAuthScope(storedScope, requiredScope) {
|
|
|
1097
1097
|
return required.every((scope) => stored.has(scope));
|
|
1098
1098
|
}
|
|
1099
1099
|
|
|
1100
|
+
// src/chat/oauth-response.ts
|
|
1101
|
+
var MAX_OAUTH_ERROR_BODY_BYTES = 16 * 1024;
|
|
1102
|
+
var MAX_OAUTH_ERROR_BODY_READS = MAX_OAUTH_ERROR_BODY_BYTES;
|
|
1103
|
+
var MAX_OAUTH_ERROR_BODY_READ_MS = 5e3;
|
|
1104
|
+
var OAUTH_ERROR_BODY_READ_TIMEOUT = /* @__PURE__ */ Symbol("oauth-error-body-read-timeout");
|
|
1105
|
+
async function readOAuthErrorBodyChunk(reader) {
|
|
1106
|
+
let timeout;
|
|
1107
|
+
const timeoutResult = new Promise(
|
|
1108
|
+
(resolve) => {
|
|
1109
|
+
timeout = setTimeout(
|
|
1110
|
+
resolve,
|
|
1111
|
+
MAX_OAUTH_ERROR_BODY_READ_MS,
|
|
1112
|
+
OAUTH_ERROR_BODY_READ_TIMEOUT
|
|
1113
|
+
);
|
|
1114
|
+
}
|
|
1115
|
+
);
|
|
1116
|
+
try {
|
|
1117
|
+
const result = await Promise.race([reader.read(), timeoutResult]);
|
|
1118
|
+
if (result === OAUTH_ERROR_BODY_READ_TIMEOUT) {
|
|
1119
|
+
await reader.cancel();
|
|
1120
|
+
throw new Error("OAuth error body read timed out");
|
|
1121
|
+
}
|
|
1122
|
+
return result;
|
|
1123
|
+
} finally {
|
|
1124
|
+
if (timeout) {
|
|
1125
|
+
clearTimeout(timeout);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
var OAuthProviderError = class extends Error {
|
|
1130
|
+
phase;
|
|
1131
|
+
provider;
|
|
1132
|
+
resourceHost;
|
|
1133
|
+
status;
|
|
1134
|
+
constructor(details) {
|
|
1135
|
+
super(`OAuth provider ${details.phase.replace("_", " ")} failed`);
|
|
1136
|
+
this.name = "OAuthProviderError";
|
|
1137
|
+
this.phase = details.phase;
|
|
1138
|
+
this.provider = details.provider;
|
|
1139
|
+
this.resourceHost = details.resourceHost;
|
|
1140
|
+
this.status = details.status;
|
|
1141
|
+
}
|
|
1142
|
+
};
|
|
1143
|
+
function getOAuthProviderErrorAttributes(error) {
|
|
1144
|
+
if (!(error instanceof OAuthProviderError)) {
|
|
1145
|
+
return {};
|
|
1146
|
+
}
|
|
1147
|
+
return {
|
|
1148
|
+
"app.credential.provider": error.provider,
|
|
1149
|
+
"app.oauth.error.phase": error.phase,
|
|
1150
|
+
"server.address": error.resourceHost,
|
|
1151
|
+
...error.status !== void 0 ? { "http.response.status_code": error.status } : {}
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
async function readBoundedOAuthErrorBody(response) {
|
|
1155
|
+
if (!response.body) {
|
|
1156
|
+
return "";
|
|
1157
|
+
}
|
|
1158
|
+
const reader = response.body.getReader();
|
|
1159
|
+
const decoder = new TextDecoder();
|
|
1160
|
+
let bytesRead = 0;
|
|
1161
|
+
let reads = 0;
|
|
1162
|
+
let text = "";
|
|
1163
|
+
try {
|
|
1164
|
+
while (bytesRead < MAX_OAUTH_ERROR_BODY_BYTES && reads < MAX_OAUTH_ERROR_BODY_READS) {
|
|
1165
|
+
reads += 1;
|
|
1166
|
+
const { done, value } = await readOAuthErrorBodyChunk(reader);
|
|
1167
|
+
if (done) {
|
|
1168
|
+
return text + decoder.decode();
|
|
1169
|
+
}
|
|
1170
|
+
const remaining = MAX_OAUTH_ERROR_BODY_BYTES - bytesRead;
|
|
1171
|
+
const chunk = value.subarray(0, remaining);
|
|
1172
|
+
bytesRead += chunk.byteLength;
|
|
1173
|
+
text += decoder.decode(chunk, { stream: true });
|
|
1174
|
+
if (chunk.byteLength < value.byteLength) {
|
|
1175
|
+
await reader.cancel();
|
|
1176
|
+
return text + decoder.decode();
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
await reader.cancel();
|
|
1180
|
+
return text + decoder.decode();
|
|
1181
|
+
} finally {
|
|
1182
|
+
reader.releaseLock();
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
function fetchWithBoundedOAuthErrorBodies(fetchFn = globalThis.fetch, onErrorResponseStatus) {
|
|
1186
|
+
return (async (input, init) => {
|
|
1187
|
+
const response = await fetchFn(input, init);
|
|
1188
|
+
if (response.ok) {
|
|
1189
|
+
return response;
|
|
1190
|
+
}
|
|
1191
|
+
onErrorResponseStatus?.(response.status);
|
|
1192
|
+
if (!response.body) {
|
|
1193
|
+
return response;
|
|
1194
|
+
}
|
|
1195
|
+
let body = "";
|
|
1196
|
+
try {
|
|
1197
|
+
body = await readBoundedOAuthErrorBody(response);
|
|
1198
|
+
} catch {
|
|
1199
|
+
await response.body.cancel().catch(() => void 0);
|
|
1200
|
+
}
|
|
1201
|
+
return new Response(body, {
|
|
1202
|
+
headers: response.headers,
|
|
1203
|
+
status: response.status,
|
|
1204
|
+
statusText: response.statusText
|
|
1205
|
+
});
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1100
1209
|
// src/chat/plugins/command-env.ts
|
|
1101
1210
|
var ENV_PLACEHOLDER_RE2 = /\$\{([A-Z_][A-Z0-9_]*)\}/g;
|
|
1102
1211
|
function resolveValue(manifest, value) {
|
|
@@ -1320,7 +1429,7 @@ function parseRefreshError(text) {
|
|
|
1320
1429
|
return void 0;
|
|
1321
1430
|
}
|
|
1322
1431
|
}
|
|
1323
|
-
async function refreshAccessToken(refreshToken, oauth, requestedScope) {
|
|
1432
|
+
async function refreshAccessToken(provider, refreshToken, oauth, requestedScope) {
|
|
1324
1433
|
const clientId = process.env[oauth.clientIdEnv]?.trim();
|
|
1325
1434
|
const clientSecret = process.env[oauth.clientSecretEnv]?.trim();
|
|
1326
1435
|
if (!clientId || !clientSecret) {
|
|
@@ -1338,28 +1447,49 @@ async function refreshAccessToken(refreshToken, oauth, requestedScope) {
|
|
|
1338
1447
|
tokenAuthMethod: oauth.tokenAuthMethod,
|
|
1339
1448
|
tokenExtraHeaders: oauth.tokenExtraHeaders
|
|
1340
1449
|
});
|
|
1341
|
-
const
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1450
|
+
const errorDetails = {
|
|
1451
|
+
phase: "token_refresh",
|
|
1452
|
+
provider,
|
|
1453
|
+
resourceHost: new URL(oauth.tokenEndpoint).hostname
|
|
1454
|
+
};
|
|
1455
|
+
let response;
|
|
1456
|
+
try {
|
|
1457
|
+
response = await fetch(oauth.tokenEndpoint, {
|
|
1458
|
+
method: "POST",
|
|
1459
|
+
headers: request.headers,
|
|
1460
|
+
body: request.body,
|
|
1461
|
+
signal: AbortSignal.timeout(TOKEN_REFRESH_TIMEOUT_MS)
|
|
1462
|
+
});
|
|
1463
|
+
} catch {
|
|
1464
|
+
throw new OAuthProviderError(errorDetails);
|
|
1465
|
+
}
|
|
1347
1466
|
if (!response.ok) {
|
|
1348
|
-
|
|
1467
|
+
let errorCode;
|
|
1468
|
+
try {
|
|
1469
|
+
errorCode = parseRefreshError(await readBoundedOAuthErrorBody(response));
|
|
1470
|
+
} catch {
|
|
1471
|
+
throw new OAuthProviderError({
|
|
1472
|
+
...errorDetails,
|
|
1473
|
+
status: response.status
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1349
1476
|
if (errorCode === "invalid_grant" || errorCode === "bad_refresh_token") {
|
|
1350
|
-
throw new OAuthRefreshRejectedError(
|
|
1351
|
-
`Token refresh rejected: ${errorCode}`
|
|
1352
|
-
);
|
|
1477
|
+
throw new OAuthRefreshRejectedError("Token refresh was rejected");
|
|
1353
1478
|
}
|
|
1354
|
-
throw new
|
|
1355
|
-
|
|
1356
|
-
|
|
1479
|
+
throw new OAuthProviderError({
|
|
1480
|
+
...errorDetails,
|
|
1481
|
+
status: response.status
|
|
1482
|
+
});
|
|
1483
|
+
}
|
|
1484
|
+
try {
|
|
1485
|
+
const data = await response.json();
|
|
1486
|
+
return parseOAuthTokenResponse(data, requestedScope, {
|
|
1487
|
+
treatEmptyScopeAsUnreported: oauth.treatEmptyScopeAsUnreported,
|
|
1488
|
+
refreshToken
|
|
1489
|
+
});
|
|
1490
|
+
} catch {
|
|
1491
|
+
throw new OAuthProviderError(errorDetails);
|
|
1357
1492
|
}
|
|
1358
|
-
const data = await response.json();
|
|
1359
|
-
return parseOAuthTokenResponse(data, requestedScope, {
|
|
1360
|
-
treatEmptyScopeAsUnreported: oauth.treatEmptyScopeAsUnreported,
|
|
1361
|
-
refreshToken
|
|
1362
|
-
});
|
|
1363
1493
|
}
|
|
1364
1494
|
function getLeaseExpiry(expiresAt) {
|
|
1365
1495
|
return expiresAt ? Math.min(expiresAt, Date.now() + MAX_LEASE_MS2) : Date.now() + MAX_LEASE_MS2;
|
|
@@ -1447,6 +1577,7 @@ function createOAuthBearerBroker(manifest, credentials, deps) {
|
|
|
1447
1577
|
);
|
|
1448
1578
|
}
|
|
1449
1579
|
const refreshed = await refreshAccessToken(
|
|
1580
|
+
provider,
|
|
1450
1581
|
latest.refreshToken,
|
|
1451
1582
|
oauth,
|
|
1452
1583
|
latest.scope ?? oauth.scope
|
|
@@ -1955,6 +2086,9 @@ export {
|
|
|
1955
2086
|
parseInlinePluginManifest,
|
|
1956
2087
|
CredentialUnavailableError,
|
|
1957
2088
|
hasRequiredOAuthScope,
|
|
2089
|
+
OAuthProviderError,
|
|
2090
|
+
getOAuthProviderErrorAttributes,
|
|
2091
|
+
fetchWithBoundedOAuthErrorBodies,
|
|
1958
2092
|
resolvePluginCommandEnv,
|
|
1959
2093
|
resolveAuthTokenPlaceholder,
|
|
1960
2094
|
buildOAuthTokenRequest,
|