@sentry/junior 0.32.0 → 0.34.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/app.js +190 -127
- package/dist/{chunk-3M7ZD6FF.js → chunk-HZIJ4BSE.js} +60 -55
- package/dist/{chunk-EHXMTKBA.js → chunk-LAD5O3RX.js} +1 -1
- package/dist/{chunk-XARRBRQV.js → chunk-QZRPUFO6.js} +202 -62
- package/dist/cli/check.js +2 -2
- package/dist/cli/snapshot-warmup.js +2 -2
- package/package.json +1 -1
package/dist/app.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
findSkillByName,
|
|
4
4
|
loadSkillsByName,
|
|
5
5
|
parseSkillInvocation
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-LAD5O3RX.js";
|
|
7
7
|
import {
|
|
8
8
|
GEN_AI_PROVIDER_NAME,
|
|
9
9
|
MISSING_GATEWAY_CREDENTIALS_ERROR,
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
runNonInteractiveCommand,
|
|
31
31
|
sandboxSkillDir,
|
|
32
32
|
sandboxSkillFile
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-HZIJ4BSE.js";
|
|
34
34
|
import {
|
|
35
35
|
CredentialUnavailableError,
|
|
36
36
|
buildOAuthTokenRequest,
|
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
logException,
|
|
54
54
|
logInfo,
|
|
55
55
|
logWarn,
|
|
56
|
+
mergeHeaderTransforms,
|
|
56
57
|
parseOAuthTokenResponse,
|
|
57
58
|
resolveAuthTokenPlaceholder,
|
|
58
59
|
resolveErrorReference,
|
|
@@ -64,7 +65,7 @@ import {
|
|
|
64
65
|
toOptionalString,
|
|
65
66
|
withContext,
|
|
66
67
|
withSpan
|
|
67
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-QZRPUFO6.js";
|
|
68
69
|
import "./chunk-Z3YD6NHK.js";
|
|
69
70
|
import {
|
|
70
71
|
discoverInstalledPluginPackageContent,
|
|
@@ -1131,7 +1132,6 @@ async function postSlackMessage(input) {
|
|
|
1131
1132
|
() => getSlackClient().chat.postMessage({
|
|
1132
1133
|
channel: channelId,
|
|
1133
1134
|
text,
|
|
1134
|
-
mrkdwn: true,
|
|
1135
1135
|
...input.blocks?.length ? {
|
|
1136
1136
|
blocks: input.blocks
|
|
1137
1137
|
} : {},
|
|
@@ -3134,11 +3134,11 @@ function buildBehaviorSection() {
|
|
|
3134
3134
|
].join("\n\n");
|
|
3135
3135
|
}
|
|
3136
3136
|
function buildOutputSection() {
|
|
3137
|
-
const openTag = `<output format="slack-
|
|
3137
|
+
const openTag = `<output format="slack-markdown" max_inline_chars="${slackOutputPolicy.maxInlineChars}" max_inline_lines="${slackOutputPolicy.maxInlineLines}">`;
|
|
3138
3138
|
return [
|
|
3139
3139
|
openTag,
|
|
3140
3140
|
"- Start with the answer or result, not internal process narration.",
|
|
3141
|
-
"- Use Slack-
|
|
3141
|
+
"- Use Slack-flavored Markdown: **bold** section labels, `code`, [text](url) links, bullet lists, and fenced code blocks. No tables. When the answer primarily lists several URLs, show each URL bare instead of as a labeled link.",
|
|
3142
3142
|
"- Keep replies brief and scannable; use bullets or short code blocks when helpful, and one compact thread reply when it fits.",
|
|
3143
3143
|
"- When a research or document-style answer would benefit from continuation, multiple sections, or future reference value, create a Slack canvas and keep the thread reply to one or two short sentences plus the link; do not recap the canvas contents.",
|
|
3144
3144
|
"- Unless a successful Slack side-effect tool intentionally satisfied the request by itself, end every turn with a final user-facing markdown response.",
|
|
@@ -3367,7 +3367,7 @@ var SkillCapabilityRuntime = class {
|
|
|
3367
3367
|
throw new Error("Credential enablement requires requester context");
|
|
3368
3368
|
}
|
|
3369
3369
|
const plugin = getPluginDefinition(provider);
|
|
3370
|
-
if (!plugin?.manifest.credentials) {
|
|
3370
|
+
if (!plugin?.manifest.credentials && !plugin?.manifest.apiHeaders) {
|
|
3371
3371
|
return void 0;
|
|
3372
3372
|
}
|
|
3373
3373
|
const existing = this.enabledByProvider.get(provider);
|
|
@@ -3499,19 +3499,22 @@ var TestCredentialBroker = class {
|
|
|
3499
3499
|
async issue(input) {
|
|
3500
3500
|
const token = process.env.EVAL_TEST_CREDENTIAL_TOKEN?.trim() || "eval-test-token";
|
|
3501
3501
|
const expiresAt = new Date(Date.now() + 5 * 60 * 1e3).toISOString();
|
|
3502
|
+
const env = this.config.envKey && this.config.placeholder ? { [this.config.envKey]: this.config.placeholder } : {};
|
|
3503
|
+
const tokenTransforms = this.config.domains?.map((domain) => ({
|
|
3504
|
+
domain,
|
|
3505
|
+
headers: {
|
|
3506
|
+
...this.config.apiHeaders ?? {},
|
|
3507
|
+
Authorization: `Bearer ${token}`
|
|
3508
|
+
}
|
|
3509
|
+
})) ?? [];
|
|
3502
3510
|
return {
|
|
3503
3511
|
id: randomUUID2(),
|
|
3504
3512
|
provider: this.config.provider,
|
|
3505
|
-
env
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
headers: {
|
|
3511
|
-
...this.config.apiHeaders ?? {},
|
|
3512
|
-
Authorization: `Bearer ${token}`
|
|
3513
|
-
}
|
|
3514
|
-
})),
|
|
3513
|
+
env,
|
|
3514
|
+
headerTransforms: mergeHeaderTransforms([
|
|
3515
|
+
...this.config.headerTransforms?.() ?? [],
|
|
3516
|
+
...tokenTransforms
|
|
3517
|
+
]),
|
|
3515
3518
|
expiresAt,
|
|
3516
3519
|
metadata: {
|
|
3517
3520
|
reason: input.reason
|
|
@@ -3521,24 +3524,50 @@ var TestCredentialBroker = class {
|
|
|
3521
3524
|
};
|
|
3522
3525
|
|
|
3523
3526
|
// src/chat/capabilities/factory.ts
|
|
3527
|
+
var ENV_PLACEHOLDER_RE = /\$\{([A-Z_][A-Z0-9_]*)\}/g;
|
|
3524
3528
|
function createUserTokenStore() {
|
|
3525
3529
|
return new StateAdapterTokenStore(getStateAdapter());
|
|
3526
3530
|
}
|
|
3531
|
+
function resolveTestApiHeaderTransforms(manifest) {
|
|
3532
|
+
const { apiDomains, apiHeaders } = manifest;
|
|
3533
|
+
if (!apiDomains || !apiHeaders) {
|
|
3534
|
+
return [];
|
|
3535
|
+
}
|
|
3536
|
+
const headers = Object.fromEntries(
|
|
3537
|
+
Object.entries(apiHeaders).map(([key, value]) => [
|
|
3538
|
+
key,
|
|
3539
|
+
value.replace(ENV_PLACEHOLDER_RE, (_match, name) => {
|
|
3540
|
+
return `eval-test-${String(name).toLowerCase().replaceAll("_", "-")}`;
|
|
3541
|
+
})
|
|
3542
|
+
])
|
|
3543
|
+
);
|
|
3544
|
+
return apiDomains.map((domain) => ({ domain, headers }));
|
|
3545
|
+
}
|
|
3527
3546
|
function createSkillCapabilityRuntime(options = {}) {
|
|
3528
3547
|
logCapabilityCatalogLoadedOnce();
|
|
3529
3548
|
const useTestBroker = process.env.EVAL_ENABLE_TEST_CREDENTIALS === "1";
|
|
3530
3549
|
const userTokenStore = createUserTokenStore();
|
|
3531
3550
|
const brokersByProvider = {};
|
|
3532
3551
|
for (const plugin of getPluginProviders()) {
|
|
3533
|
-
const { credentials, name } = plugin.manifest;
|
|
3552
|
+
const { apiHeaders, credentials, name } = plugin.manifest;
|
|
3553
|
+
if (!credentials && !apiHeaders) {
|
|
3554
|
+
continue;
|
|
3555
|
+
}
|
|
3534
3556
|
if (!credentials) {
|
|
3557
|
+
brokersByProvider[name] = useTestBroker ? new TestCredentialBroker({
|
|
3558
|
+
provider: name,
|
|
3559
|
+
headerTransforms: () => resolveTestApiHeaderTransforms(plugin.manifest)
|
|
3560
|
+
}) : createPluginBroker(name, { userTokenStore });
|
|
3535
3561
|
continue;
|
|
3536
3562
|
}
|
|
3537
3563
|
const placeholder = resolveAuthTokenPlaceholder(credentials);
|
|
3538
3564
|
brokersByProvider[name] = useTestBroker ? new TestCredentialBroker({
|
|
3539
3565
|
provider: name,
|
|
3540
3566
|
domains: credentials.apiDomains,
|
|
3541
|
-
apiHeaders: credentials.apiHeaders,
|
|
3567
|
+
...credentials.apiHeaders ? { apiHeaders: credentials.apiHeaders } : {},
|
|
3568
|
+
...apiHeaders ? {
|
|
3569
|
+
headerTransforms: () => resolveTestApiHeaderTransforms(plugin.manifest)
|
|
3570
|
+
} : {},
|
|
3542
3571
|
envKey: credentials.authTokenEnv,
|
|
3543
3572
|
placeholder
|
|
3544
3573
|
}) : createPluginBroker(name, { userTokenStore });
|
|
@@ -4109,7 +4138,6 @@ var PluginMcpClient = class {
|
|
|
4109
4138
|
setSpanAttributes({
|
|
4110
4139
|
"mcp.method.name": MCP_TOOLS_CALL_METHOD,
|
|
4111
4140
|
"gen_ai.operation.name": "execute_tool",
|
|
4112
|
-
"gen_ai.tool.name": name,
|
|
4113
4141
|
...this.transport?.sessionId ? { "mcp.session.id": this.transport.sessionId } : {},
|
|
4114
4142
|
...this.transport?.protocolVersion ? { "mcp.protocol.version": this.transport.protocolVersion } : {},
|
|
4115
4143
|
...getMcpNetworkAttributes(url)
|
|
@@ -4459,7 +4487,6 @@ var McpToolManager = class {
|
|
|
4459
4487
|
execute: async (args) => {
|
|
4460
4488
|
const resolvedArgs = typeof args === "object" && args !== null ? args : {};
|
|
4461
4489
|
const baseAttributes = {
|
|
4462
|
-
"gen_ai.tool.name": tool2.name,
|
|
4463
4490
|
"mcp.method.name": "tools/call"
|
|
4464
4491
|
};
|
|
4465
4492
|
setSpanAttributes(baseAttributes);
|
|
@@ -8753,12 +8780,6 @@ function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor
|
|
|
8753
8780
|
execute: async (toolCallId, params) => {
|
|
8754
8781
|
const normalizedToolCallId = typeof toolCallId === "string" && toolCallId.length > 0 ? toolCallId : void 0;
|
|
8755
8782
|
const toolArgumentsAttribute = serializeGenAiAttribute(params);
|
|
8756
|
-
const traceToolContext = {
|
|
8757
|
-
...spanContext,
|
|
8758
|
-
conversationId: spanContext.conversationId,
|
|
8759
|
-
turnId: spanContext.turnId,
|
|
8760
|
-
agentId: spanContext.agentId
|
|
8761
|
-
};
|
|
8762
8783
|
if (toolName === "reportProgress") {
|
|
8763
8784
|
const status = buildReportedProgressStatus(params);
|
|
8764
8785
|
if (status) {
|
|
@@ -8813,9 +8834,8 @@ function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor
|
|
|
8813
8834
|
details: normalized.details
|
|
8814
8835
|
});
|
|
8815
8836
|
}
|
|
8816
|
-
const
|
|
8817
|
-
|
|
8818
|
-
);
|
|
8837
|
+
const resultAttributeValue = normalized.details && typeof normalized.details === "object" && "rawResult" in normalized.details && normalized.details.rawResult !== void 0 ? normalized.details.rawResult : normalized.details;
|
|
8838
|
+
const toolResultAttribute = serializeGenAiAttribute(resultAttributeValue);
|
|
8819
8839
|
if (toolResultAttribute) {
|
|
8820
8840
|
setSpanAttributes({
|
|
8821
8841
|
"gen_ai.tool.call.result": toolResultAttribute
|
|
@@ -8831,7 +8851,7 @@ function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor
|
|
|
8831
8851
|
toolName,
|
|
8832
8852
|
normalizedToolCallId,
|
|
8833
8853
|
shouldTrace,
|
|
8834
|
-
|
|
8854
|
+
spanContext
|
|
8835
8855
|
);
|
|
8836
8856
|
}
|
|
8837
8857
|
},
|
|
@@ -9889,13 +9909,17 @@ function commandTargetsProvider(provider, command, details) {
|
|
|
9889
9909
|
}
|
|
9890
9910
|
const plugin = getPluginDefinition(provider);
|
|
9891
9911
|
const candidates = /* @__PURE__ */ new Set([provider.toLowerCase()]);
|
|
9892
|
-
const
|
|
9912
|
+
const manifest = plugin?.manifest;
|
|
9913
|
+
const credentials = manifest?.credentials;
|
|
9893
9914
|
if (credentials) {
|
|
9894
9915
|
candidates.add(credentials.authTokenEnv.toLowerCase());
|
|
9895
9916
|
for (const domain of credentials.apiDomains) {
|
|
9896
9917
|
candidates.add(domain.toLowerCase());
|
|
9897
9918
|
}
|
|
9898
9919
|
}
|
|
9920
|
+
for (const domain of manifest?.apiDomains ?? []) {
|
|
9921
|
+
candidates.add(domain.toLowerCase());
|
|
9922
|
+
}
|
|
9899
9923
|
const combinedText = `${normalizedCommand}
|
|
9900
9924
|
${details.stdout?.toLowerCase() ?? ""}
|
|
9901
9925
|
${details.stderr?.toLowerCase() ?? ""}`;
|
|
@@ -11230,25 +11254,25 @@ function buildSlackReplyFooter(args) {
|
|
|
11230
11254
|
return items.length > 0 ? { items } : void 0;
|
|
11231
11255
|
}
|
|
11232
11256
|
function buildSlackReplyBlocks(text, footer) {
|
|
11233
|
-
if (!text.trim()
|
|
11257
|
+
if (!text.trim()) {
|
|
11234
11258
|
return void 0;
|
|
11235
11259
|
}
|
|
11236
|
-
|
|
11237
|
-
{
|
|
11238
|
-
type: "section",
|
|
11239
|
-
text: {
|
|
11240
|
-
type: "mrkdwn",
|
|
11241
|
-
text
|
|
11242
|
-
}
|
|
11243
|
-
},
|
|
11260
|
+
const blocks = [
|
|
11244
11261
|
{
|
|
11262
|
+
type: "markdown",
|
|
11263
|
+
text
|
|
11264
|
+
}
|
|
11265
|
+
];
|
|
11266
|
+
if (footer?.items.length) {
|
|
11267
|
+
blocks.push({
|
|
11245
11268
|
type: "context",
|
|
11246
11269
|
elements: footer.items.map((item) => ({
|
|
11247
11270
|
type: "mrkdwn",
|
|
11248
11271
|
text: `*${escapeSlackMrkdwn(item.label)}:* ${escapeSlackMrkdwn(item.value)}`
|
|
11249
11272
|
}))
|
|
11250
|
-
}
|
|
11251
|
-
|
|
11273
|
+
});
|
|
11274
|
+
}
|
|
11275
|
+
return blocks;
|
|
11252
11276
|
}
|
|
11253
11277
|
|
|
11254
11278
|
// src/chat/slack/reply.ts
|
|
@@ -11372,11 +11396,13 @@ async function postSlackApiReplyPosts(args) {
|
|
|
11372
11396
|
let messageTs;
|
|
11373
11397
|
try {
|
|
11374
11398
|
if (post.text.trim().length > 0) {
|
|
11399
|
+
const footer = index === lastTextPostIndex ? args.footer : void 0;
|
|
11400
|
+
const blocks = buildSlackReplyBlocks(post.text, footer);
|
|
11375
11401
|
const response = await postSlackMessage({
|
|
11376
11402
|
channelId: args.channelId,
|
|
11377
11403
|
threadTs: args.threadTs,
|
|
11378
11404
|
text: post.text,
|
|
11379
|
-
...
|
|
11405
|
+
...blocks ? { blocks } : {}
|
|
11380
11406
|
});
|
|
11381
11407
|
messageTs = response.ts;
|
|
11382
11408
|
lastPostedMessageTs = response.ts;
|
|
@@ -13484,6 +13510,7 @@ function buildFailureMessage(reference) {
|
|
|
13484
13510
|
}
|
|
13485
13511
|
function buildLogContext(deps, args) {
|
|
13486
13512
|
return {
|
|
13513
|
+
conversationId: args.threadId ?? args.runId,
|
|
13487
13514
|
slackThreadId: args.threadId,
|
|
13488
13515
|
slackUserId: args.requesterId,
|
|
13489
13516
|
slackUserName: args.requesterUserName,
|
|
@@ -13608,78 +13635,6 @@ function createSlackTurnRuntime(deps) {
|
|
|
13608
13635
|
const threadId = deps.getThreadId(thread, message);
|
|
13609
13636
|
const channelId = deps.getChannelId(thread, message);
|
|
13610
13637
|
const runId = deps.getRunId(thread, message);
|
|
13611
|
-
const rawUserText = message.text;
|
|
13612
|
-
const userText = deps.stripLeadingBotMention(rawUserText, {
|
|
13613
|
-
stripLeadingSlackMentionToken: Boolean(message.isMention)
|
|
13614
|
-
});
|
|
13615
|
-
const context = {
|
|
13616
|
-
threadId,
|
|
13617
|
-
requesterId: message.author.userId,
|
|
13618
|
-
channelId,
|
|
13619
|
-
runId
|
|
13620
|
-
};
|
|
13621
|
-
const preflightDecision = getSubscribedReplyPreflightDecision({
|
|
13622
|
-
botUserName: deps.assistantUserName,
|
|
13623
|
-
rawText: rawUserText,
|
|
13624
|
-
text: userText,
|
|
13625
|
-
isExplicitMention: Boolean(message.isMention)
|
|
13626
|
-
});
|
|
13627
|
-
if (preflightDecision && !preflightDecision.shouldReply) {
|
|
13628
|
-
const reason = preflightDecision.reasonDetail ? `${preflightDecision.reason}:${preflightDecision.reasonDetail}` : preflightDecision.reason;
|
|
13629
|
-
await skipSubscribedMessage({
|
|
13630
|
-
thread,
|
|
13631
|
-
message,
|
|
13632
|
-
decision: { shouldReply: false, reason },
|
|
13633
|
-
context,
|
|
13634
|
-
userText
|
|
13635
|
-
});
|
|
13636
|
-
return;
|
|
13637
|
-
}
|
|
13638
|
-
const preparedState = await deps.prepareTurnState({
|
|
13639
|
-
thread,
|
|
13640
|
-
message,
|
|
13641
|
-
userText,
|
|
13642
|
-
explicitMention: Boolean(message.isMention),
|
|
13643
|
-
context
|
|
13644
|
-
});
|
|
13645
|
-
await deps.persistPreparedState({
|
|
13646
|
-
thread,
|
|
13647
|
-
preparedState
|
|
13648
|
-
});
|
|
13649
|
-
const decision = await deps.decideSubscribedReply({
|
|
13650
|
-
rawText: rawUserText,
|
|
13651
|
-
text: userText,
|
|
13652
|
-
conversationContext: deps.getPreparedConversationContext(preparedState),
|
|
13653
|
-
hasAttachments: message.attachments.length > 0,
|
|
13654
|
-
isExplicitMention: Boolean(message.isMention),
|
|
13655
|
-
context
|
|
13656
|
-
});
|
|
13657
|
-
if (await maybeHandleThreadOptOutDecision({
|
|
13658
|
-
thread,
|
|
13659
|
-
decision,
|
|
13660
|
-
beforeFirstResponsePost: hooks?.beforeFirstResponsePost
|
|
13661
|
-
})) {
|
|
13662
|
-
await skipSubscribedMessage({
|
|
13663
|
-
thread,
|
|
13664
|
-
message,
|
|
13665
|
-
decision,
|
|
13666
|
-
context,
|
|
13667
|
-
preparedState,
|
|
13668
|
-
userText
|
|
13669
|
-
});
|
|
13670
|
-
return;
|
|
13671
|
-
}
|
|
13672
|
-
if (!decision.shouldReply) {
|
|
13673
|
-
await skipSubscribedMessage({
|
|
13674
|
-
thread,
|
|
13675
|
-
message,
|
|
13676
|
-
decision,
|
|
13677
|
-
context,
|
|
13678
|
-
preparedState,
|
|
13679
|
-
userText
|
|
13680
|
-
});
|
|
13681
|
-
return;
|
|
13682
|
-
}
|
|
13683
13638
|
await deps.withSpan(
|
|
13684
13639
|
"chat.turn",
|
|
13685
13640
|
"chat.turn",
|
|
@@ -13691,6 +13646,78 @@ function createSlackTurnRuntime(deps) {
|
|
|
13691
13646
|
runId
|
|
13692
13647
|
}),
|
|
13693
13648
|
async () => {
|
|
13649
|
+
const rawUserText = message.text;
|
|
13650
|
+
const userText = deps.stripLeadingBotMention(rawUserText, {
|
|
13651
|
+
stripLeadingSlackMentionToken: Boolean(message.isMention)
|
|
13652
|
+
});
|
|
13653
|
+
const context = {
|
|
13654
|
+
threadId,
|
|
13655
|
+
requesterId: message.author.userId,
|
|
13656
|
+
channelId,
|
|
13657
|
+
runId
|
|
13658
|
+
};
|
|
13659
|
+
const preflightDecision = getSubscribedReplyPreflightDecision({
|
|
13660
|
+
botUserName: deps.assistantUserName,
|
|
13661
|
+
rawText: rawUserText,
|
|
13662
|
+
text: userText,
|
|
13663
|
+
isExplicitMention: Boolean(message.isMention)
|
|
13664
|
+
});
|
|
13665
|
+
if (preflightDecision && !preflightDecision.shouldReply) {
|
|
13666
|
+
const reason = preflightDecision.reasonDetail ? `${preflightDecision.reason}:${preflightDecision.reasonDetail}` : preflightDecision.reason;
|
|
13667
|
+
await skipSubscribedMessage({
|
|
13668
|
+
thread,
|
|
13669
|
+
message,
|
|
13670
|
+
decision: { shouldReply: false, reason },
|
|
13671
|
+
context,
|
|
13672
|
+
userText
|
|
13673
|
+
});
|
|
13674
|
+
return;
|
|
13675
|
+
}
|
|
13676
|
+
const preparedState = await deps.prepareTurnState({
|
|
13677
|
+
thread,
|
|
13678
|
+
message,
|
|
13679
|
+
userText,
|
|
13680
|
+
explicitMention: Boolean(message.isMention),
|
|
13681
|
+
context
|
|
13682
|
+
});
|
|
13683
|
+
await deps.persistPreparedState({
|
|
13684
|
+
thread,
|
|
13685
|
+
preparedState
|
|
13686
|
+
});
|
|
13687
|
+
const decision = await deps.decideSubscribedReply({
|
|
13688
|
+
rawText: rawUserText,
|
|
13689
|
+
text: userText,
|
|
13690
|
+
conversationContext: deps.getPreparedConversationContext(preparedState),
|
|
13691
|
+
hasAttachments: message.attachments.length > 0,
|
|
13692
|
+
isExplicitMention: Boolean(message.isMention),
|
|
13693
|
+
context
|
|
13694
|
+
});
|
|
13695
|
+
if (await maybeHandleThreadOptOutDecision({
|
|
13696
|
+
thread,
|
|
13697
|
+
decision,
|
|
13698
|
+
beforeFirstResponsePost: hooks?.beforeFirstResponsePost
|
|
13699
|
+
})) {
|
|
13700
|
+
await skipSubscribedMessage({
|
|
13701
|
+
thread,
|
|
13702
|
+
message,
|
|
13703
|
+
decision,
|
|
13704
|
+
context,
|
|
13705
|
+
preparedState,
|
|
13706
|
+
userText
|
|
13707
|
+
});
|
|
13708
|
+
return;
|
|
13709
|
+
}
|
|
13710
|
+
if (!decision.shouldReply) {
|
|
13711
|
+
await skipSubscribedMessage({
|
|
13712
|
+
thread,
|
|
13713
|
+
message,
|
|
13714
|
+
decision,
|
|
13715
|
+
context,
|
|
13716
|
+
preparedState,
|
|
13717
|
+
userText
|
|
13718
|
+
});
|
|
13719
|
+
return;
|
|
13720
|
+
}
|
|
13694
13721
|
await deps.replyToThread(thread, message, {
|
|
13695
13722
|
explicitMention: Boolean(message.isMention),
|
|
13696
13723
|
preparedState,
|
|
@@ -15317,6 +15344,24 @@ function nonEmptyString(value) {
|
|
|
15317
15344
|
return trimmed || void 0;
|
|
15318
15345
|
}
|
|
15319
15346
|
|
|
15347
|
+
// src/chat/ingress/workspace-membership.ts
|
|
15348
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
15349
|
+
var workspaceTeamIdStorage = new AsyncLocalStorage();
|
|
15350
|
+
function runWithWorkspaceTeamId(teamId, fn) {
|
|
15351
|
+
if (!teamId) return fn();
|
|
15352
|
+
return workspaceTeamIdStorage.run(teamId, fn);
|
|
15353
|
+
}
|
|
15354
|
+
function isExternalSlackUser(raw) {
|
|
15355
|
+
if (!raw) return false;
|
|
15356
|
+
const workspaceTeamId = workspaceTeamIdStorage.getStore();
|
|
15357
|
+
if (!workspaceTeamId) return false;
|
|
15358
|
+
const userTeam = typeof raw.user_team === "string" ? raw.user_team : void 0;
|
|
15359
|
+
if (userTeam) return userTeam !== workspaceTeamId;
|
|
15360
|
+
const sourceTeam = typeof raw.source_team === "string" ? raw.source_team : void 0;
|
|
15361
|
+
if (sourceTeam) return sourceTeam !== workspaceTeamId;
|
|
15362
|
+
return false;
|
|
15363
|
+
}
|
|
15364
|
+
|
|
15320
15365
|
// src/chat/ingress/junior-chat.ts
|
|
15321
15366
|
function enqueueBackgroundTask(options, task) {
|
|
15322
15367
|
if (!options?.waitUntil) {
|
|
@@ -15355,6 +15400,9 @@ var JuniorChat = class extends Chat {
|
|
|
15355
15400
|
(async () => {
|
|
15356
15401
|
try {
|
|
15357
15402
|
const message = await messageOrFactory();
|
|
15403
|
+
if (isExternalSlackUser(message.raw)) {
|
|
15404
|
+
return;
|
|
15405
|
+
}
|
|
15358
15406
|
const normalized = normalizeIncomingSlackThreadId(
|
|
15359
15407
|
threadId,
|
|
15360
15408
|
message
|
|
@@ -15373,6 +15421,9 @@ var JuniorChat = class extends Chat {
|
|
|
15373
15421
|
);
|
|
15374
15422
|
return;
|
|
15375
15423
|
}
|
|
15424
|
+
if (isExternalSlackUser(messageOrFactory.raw)) {
|
|
15425
|
+
return;
|
|
15426
|
+
}
|
|
15376
15427
|
enqueueBackgroundTask(
|
|
15377
15428
|
options,
|
|
15378
15429
|
(async () => {
|
|
@@ -15824,12 +15875,16 @@ function extractMessageChangedMention(body, botUserId, adapter) {
|
|
|
15824
15875
|
const userId = event.message.user ?? "unknown";
|
|
15825
15876
|
const threadId = `slack:${channelId}:${threadTs}`;
|
|
15826
15877
|
const teamId = typeof body.team_id === "string" ? body.team_id : void 0;
|
|
15878
|
+
const userTeam = typeof event.message.user_team === "string" ? event.message.user_team : void 0;
|
|
15879
|
+
const sourceTeam = typeof event.message.source_team === "string" ? event.message.source_team : void 0;
|
|
15827
15880
|
const raw = {
|
|
15828
15881
|
channel: channelId,
|
|
15829
15882
|
ts: messageTs,
|
|
15830
15883
|
thread_ts: threadTs,
|
|
15831
15884
|
user: userId,
|
|
15832
|
-
...teamId ? { team_id: teamId } : {}
|
|
15885
|
+
...teamId ? { team_id: teamId } : {},
|
|
15886
|
+
...userTeam ? { user_team: userTeam } : {},
|
|
15887
|
+
...sourceTeam ? { source_team: sourceTeam } : {}
|
|
15833
15888
|
};
|
|
15834
15889
|
const message = new Message({
|
|
15835
15890
|
id: getEditedMentionMessageId(messageTs),
|
|
@@ -15931,6 +15986,7 @@ async function handlePlatformWebhook(request, platform, waitUntil, bot = getProd
|
|
|
15931
15986
|
return new Response(`Unknown platform: ${platform}`, { status: 404 });
|
|
15932
15987
|
}
|
|
15933
15988
|
let rebuiltRequest = request;
|
|
15989
|
+
let slackWorkspaceTeamId;
|
|
15934
15990
|
if (platform === "slack") {
|
|
15935
15991
|
const rawBody = await request.text();
|
|
15936
15992
|
let parsedBody;
|
|
@@ -15939,15 +15995,19 @@ async function handlePlatformWebhook(request, platform, waitUntil, bot = getProd
|
|
|
15939
15995
|
} catch {
|
|
15940
15996
|
parsedBody = void 0;
|
|
15941
15997
|
}
|
|
15998
|
+
slackWorkspaceTeamId = getSlackPayloadTeamId(parsedBody);
|
|
15942
15999
|
if (parsedBody && isMessageChangedEnvelope(parsedBody)) {
|
|
15943
16000
|
try {
|
|
15944
|
-
await
|
|
15945
|
-
|
|
15946
|
-
|
|
15947
|
-
|
|
15948
|
-
|
|
15949
|
-
|
|
15950
|
-
|
|
16001
|
+
await runWithWorkspaceTeamId(
|
|
16002
|
+
slackWorkspaceTeamId,
|
|
16003
|
+
() => handleAuthenticatedSlackMessageChangedMention({
|
|
16004
|
+
body: parsedBody,
|
|
16005
|
+
bot,
|
|
16006
|
+
rawBody,
|
|
16007
|
+
request,
|
|
16008
|
+
waitUntil
|
|
16009
|
+
})
|
|
16010
|
+
);
|
|
15951
16011
|
} catch (error) {
|
|
15952
16012
|
logException(error, "slack_message_changed_side_channel_failed");
|
|
15953
16013
|
}
|
|
@@ -15965,9 +16025,12 @@ async function handlePlatformWebhook(request, platform, waitUntil, bot = getProd
|
|
|
15965
16025
|
requestContext,
|
|
15966
16026
|
async () => {
|
|
15967
16027
|
try {
|
|
15968
|
-
const response = await
|
|
15969
|
-
|
|
15970
|
-
|
|
16028
|
+
const response = await runWithWorkspaceTeamId(
|
|
16029
|
+
slackWorkspaceTeamId,
|
|
16030
|
+
() => handler(rebuiltRequest, {
|
|
16031
|
+
waitUntil: (task) => waitUntil(task)
|
|
16032
|
+
})
|
|
16033
|
+
);
|
|
15971
16034
|
if (response.status >= 400) {
|
|
15972
16035
|
let responseBodySnippet;
|
|
15973
16036
|
try {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
serializeGenAiAttribute,
|
|
8
8
|
setSpanAttributes,
|
|
9
9
|
withSpan
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-QZRPUFO6.js";
|
|
11
11
|
|
|
12
12
|
// src/chat/state/adapter.ts
|
|
13
13
|
import { createMemoryState } from "@chat-adapter/state-memory";
|
|
@@ -128,68 +128,73 @@ async function completeText(params) {
|
|
|
128
128
|
const apiKey = getPiGatewayApiKeyOverride();
|
|
129
129
|
const requestMessagesAttribute = serializeGenAiAttribute(params.messages);
|
|
130
130
|
const systemInstructionsAttribute = params.system ? serializeGenAiAttribute([{ type: "text", content: params.system }]) : void 0;
|
|
131
|
-
const
|
|
131
|
+
const baseAttributes = {
|
|
132
132
|
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
133
133
|
"gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
|
|
134
134
|
"gen_ai.request.model": params.modelId,
|
|
135
|
+
...params.thinkingLevel ? { "app.ai.reasoning_effort": params.thinkingLevel } : {}
|
|
136
|
+
};
|
|
137
|
+
const startAttributes = {
|
|
138
|
+
...baseAttributes,
|
|
135
139
|
...systemInstructionsAttribute ? { "gen_ai.system_instructions": systemInstructionsAttribute } : {},
|
|
136
140
|
...requestMessagesAttribute ? { "gen_ai.input.messages": requestMessagesAttribute } : {},
|
|
137
|
-
"app.ai.auth_mode": apiKey ? "oidc" : "api_key"
|
|
138
|
-
...params.thinkingLevel ? { "app.ai.reasoning_effort": params.thinkingLevel } : {}
|
|
141
|
+
"app.ai.auth_mode": apiKey ? "oidc" : "api_key"
|
|
139
142
|
};
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
{
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
return withSpan(
|
|
144
|
+
"ai.chat_completion",
|
|
145
|
+
"gen_ai.chat",
|
|
146
|
+
{ modelId: params.modelId },
|
|
147
|
+
async () => {
|
|
148
|
+
const message = await completeSimple(
|
|
149
|
+
model,
|
|
150
|
+
{
|
|
151
|
+
systemPrompt: params.system,
|
|
152
|
+
messages: params.messages
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
...apiKey ? { apiKey } : {},
|
|
156
|
+
temperature: params.temperature,
|
|
157
|
+
maxTokens: params.maxTokens,
|
|
158
|
+
reasoning: params.thinkingLevel,
|
|
159
|
+
signal: params.signal,
|
|
160
|
+
metadata: params.metadata
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
const outputText = extractText(message);
|
|
164
|
+
const outputMessagesAttribute = serializeGenAiAttribute([
|
|
165
|
+
{
|
|
166
|
+
role: "assistant",
|
|
167
|
+
content: outputText ? [{ type: "text", text: outputText }] : []
|
|
168
|
+
}
|
|
169
|
+
]);
|
|
170
|
+
const usageAttributes = extractGenAiUsageAttributes(message);
|
|
171
|
+
const endAttributes = {
|
|
172
|
+
...baseAttributes,
|
|
173
|
+
...outputMessagesAttribute ? { "gen_ai.output.messages": outputMessagesAttribute } : {},
|
|
174
|
+
...usageAttributes,
|
|
175
|
+
...message.stopReason ? { "gen_ai.response.finish_reasons": [message.stopReason] } : {}
|
|
176
|
+
};
|
|
177
|
+
setSpanAttributes(endAttributes);
|
|
178
|
+
if (message.stopReason === "error") {
|
|
179
|
+
const providerMessage = message.errorMessage?.trim() || "Unknown provider error";
|
|
180
|
+
logWarn(
|
|
181
|
+
"ai_completion_provider_error",
|
|
182
|
+
{},
|
|
183
|
+
{
|
|
184
|
+
...baseAttributes,
|
|
185
|
+
"error.message": providerMessage
|
|
186
|
+
},
|
|
187
|
+
"AI completion returned provider error"
|
|
188
|
+
);
|
|
189
|
+
throw new Error(`AI provider error: ${providerMessage}`);
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
message,
|
|
193
|
+
text: outputText
|
|
194
|
+
};
|
|
146
195
|
},
|
|
147
|
-
|
|
148
|
-
...apiKey ? { apiKey } : {},
|
|
149
|
-
temperature: params.temperature,
|
|
150
|
-
maxTokens: params.maxTokens,
|
|
151
|
-
reasoning: params.thinkingLevel,
|
|
152
|
-
signal: params.signal,
|
|
153
|
-
metadata: params.metadata
|
|
154
|
-
}
|
|
196
|
+
startAttributes
|
|
155
197
|
);
|
|
156
|
-
const outputText = extractText(message);
|
|
157
|
-
const outputMessagesAttribute = serializeGenAiAttribute([
|
|
158
|
-
{
|
|
159
|
-
role: "assistant",
|
|
160
|
-
content: outputText ? [{ type: "text", text: outputText }] : []
|
|
161
|
-
}
|
|
162
|
-
]);
|
|
163
|
-
const usageAttributes = extractGenAiUsageAttributes(message);
|
|
164
|
-
const endAttributes = {
|
|
165
|
-
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
166
|
-
"gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
|
|
167
|
-
"gen_ai.request.model": params.modelId,
|
|
168
|
-
...outputMessagesAttribute ? { "gen_ai.output.messages": outputMessagesAttribute } : {},
|
|
169
|
-
...usageAttributes,
|
|
170
|
-
...message.stopReason ? { "gen_ai.response.finish_reasons": [message.stopReason] } : {},
|
|
171
|
-
...params.thinkingLevel ? { "app.ai.reasoning_effort": params.thinkingLevel } : {}
|
|
172
|
-
};
|
|
173
|
-
setSpanAttributes(endAttributes);
|
|
174
|
-
if (message.stopReason === "error") {
|
|
175
|
-
const providerMessage = message.errorMessage?.trim() || "Unknown provider error";
|
|
176
|
-
logWarn(
|
|
177
|
-
"ai_completion_provider_error",
|
|
178
|
-
{},
|
|
179
|
-
{
|
|
180
|
-
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
181
|
-
"gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
|
|
182
|
-
"gen_ai.request.model": params.modelId,
|
|
183
|
-
"error.message": providerMessage
|
|
184
|
-
},
|
|
185
|
-
"AI completion returned provider error"
|
|
186
|
-
);
|
|
187
|
-
throw new Error(`AI provider error: ${providerMessage}`);
|
|
188
|
-
}
|
|
189
|
-
return {
|
|
190
|
-
message,
|
|
191
|
-
text: outputText
|
|
192
|
-
};
|
|
193
198
|
}
|
|
194
199
|
async function completeObject(params) {
|
|
195
200
|
const startedAt = Date.now();
|
|
@@ -971,6 +971,9 @@ function setLogContext(context) {
|
|
|
971
971
|
);
|
|
972
972
|
contextStorage.enterWith(merged);
|
|
973
973
|
}
|
|
974
|
+
function getLogContextAttributes() {
|
|
975
|
+
return contextStorage.getStore() ?? {};
|
|
976
|
+
}
|
|
974
977
|
function createLogContextFromRequest(request, context = {}) {
|
|
975
978
|
const url = new URL(request.url);
|
|
976
979
|
return {
|
|
@@ -1052,20 +1055,20 @@ async function withSpan(name, op, context, callback, attributes = {}) {
|
|
|
1052
1055
|
normalizedAttributes[key] = normalizedValue;
|
|
1053
1056
|
}
|
|
1054
1057
|
}
|
|
1055
|
-
return withLogContext(
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
+
return withLogContext(context, () => {
|
|
1059
|
+
const inheritedAttributes = getLogContextAttributes();
|
|
1060
|
+
return sentry_exports.startSpan(
|
|
1058
1061
|
{
|
|
1059
1062
|
name,
|
|
1060
1063
|
op,
|
|
1061
1064
|
attributes: {
|
|
1062
|
-
...
|
|
1065
|
+
...inheritedAttributes,
|
|
1063
1066
|
...normalizedAttributes
|
|
1064
1067
|
}
|
|
1065
1068
|
},
|
|
1066
1069
|
callback
|
|
1067
|
-
)
|
|
1068
|
-
);
|
|
1070
|
+
);
|
|
1071
|
+
});
|
|
1069
1072
|
}
|
|
1070
1073
|
function setSpanAttributes(attributes) {
|
|
1071
1074
|
const sentry = sentry_exports;
|
|
@@ -1246,6 +1249,7 @@ var SHORT_CONFIG_KEY_RE = /^[a-z0-9]+(\.[a-z0-9-]+)*$/;
|
|
|
1246
1249
|
var TARGET_FLAG_RE = /^-{1,2}[A-Za-z0-9][A-Za-z0-9-]*$/;
|
|
1247
1250
|
var AUTH_TOKEN_ENV_RE = /^[A-Z][A-Z0-9_]*$/;
|
|
1248
1251
|
var ENV_VAR_NAME_RE = /^[A-Z_][A-Z0-9_]*$/;
|
|
1252
|
+
var ENV_PLACEHOLDER_RE = /\$\{([A-Z_][A-Z0-9_]*)\}/g;
|
|
1249
1253
|
var API_DOMAIN_RE = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
1250
1254
|
var RUNTIME_POSTINSTALL_CMD_RE = /^[A-Za-z0-9._/-]+$/;
|
|
1251
1255
|
var RESERVED_AUTHORIZE_PARAM_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -1340,7 +1344,7 @@ var stringMapSchema = z.record(z.string(), z.unknown()).transform((record, ctx)
|
|
|
1340
1344
|
seen.add(normalizedKey);
|
|
1341
1345
|
result[key] = rawValue.trim();
|
|
1342
1346
|
}
|
|
1343
|
-
return
|
|
1347
|
+
return result;
|
|
1344
1348
|
});
|
|
1345
1349
|
var apiDomainsSchema = z.array(z.unknown()).min(1, {
|
|
1346
1350
|
error: "must be a non-empty array of strings"
|
|
@@ -1433,6 +1437,8 @@ var manifestSourceSchema = z.object({
|
|
|
1433
1437
|
"config-keys": z.array(z.string(), {
|
|
1434
1438
|
error: "must be an array when provided"
|
|
1435
1439
|
}).optional(),
|
|
1440
|
+
"api-domains": apiDomainsSchema.optional(),
|
|
1441
|
+
"api-headers": stringMapSchema.optional(),
|
|
1436
1442
|
credentials: z.record(z.string(), z.unknown(), {
|
|
1437
1443
|
error: "must be an object when provided"
|
|
1438
1444
|
}).optional(),
|
|
@@ -1470,7 +1476,11 @@ function normalizeStringMap(value, prefix, options = {}) {
|
|
|
1470
1476
|
if (!value) {
|
|
1471
1477
|
return void 0;
|
|
1472
1478
|
}
|
|
1473
|
-
|
|
1479
|
+
const keys = Object.keys(value);
|
|
1480
|
+
if (keys.length === 0) {
|
|
1481
|
+
return void 0;
|
|
1482
|
+
}
|
|
1483
|
+
for (const key of keys) {
|
|
1474
1484
|
const normalizedKey = key.toLowerCase();
|
|
1475
1485
|
if (options.reservedKeys?.has(normalizedKey)) {
|
|
1476
1486
|
throw new Error(`${prefix}.${key} is reserved by the runtime`);
|
|
@@ -1481,6 +1491,31 @@ function normalizeStringMap(value, prefix, options = {}) {
|
|
|
1481
1491
|
}
|
|
1482
1492
|
return value;
|
|
1483
1493
|
}
|
|
1494
|
+
function assertDeclaredEnvReferences(value, envVars, context) {
|
|
1495
|
+
for (const match of value.matchAll(ENV_PLACEHOLDER_RE)) {
|
|
1496
|
+
const name = match[1];
|
|
1497
|
+
if (!Object.prototype.hasOwnProperty.call(envVars, name)) {
|
|
1498
|
+
throw new Error(
|
|
1499
|
+
`${context} references env var ${name} which is not declared in env-vars`
|
|
1500
|
+
);
|
|
1501
|
+
}
|
|
1502
|
+
if (envVars[name]?.default !== void 0) {
|
|
1503
|
+
throw new Error(
|
|
1504
|
+
`${context} references env var ${name}, but API header env vars must not declare defaults`
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
function normalizeRequiredApiHeaders(value, prefix, envVars) {
|
|
1510
|
+
const apiHeaders = normalizeStringMap(value, prefix);
|
|
1511
|
+
if (!apiHeaders) {
|
|
1512
|
+
throw new Error(`${prefix} must contain at least one header`);
|
|
1513
|
+
}
|
|
1514
|
+
for (const [key, headerValue] of Object.entries(apiHeaders)) {
|
|
1515
|
+
assertDeclaredEnvReferences(headerValue, envVars, `${prefix}.${key}`);
|
|
1516
|
+
}
|
|
1517
|
+
return apiHeaders;
|
|
1518
|
+
}
|
|
1484
1519
|
function normalizeCredentials(data, name) {
|
|
1485
1520
|
const schema = data.type === "oauth-bearer" ? oauthBearerCredentialsSchema : data.type === "github-app" ? githubAppCredentialsSchema : void 0;
|
|
1486
1521
|
if (!schema) {
|
|
@@ -1493,30 +1528,28 @@ function normalizeCredentials(data, name) {
|
|
|
1493
1528
|
throw new Error(issueMessage(result.error, `Plugin ${name} credentials`));
|
|
1494
1529
|
}
|
|
1495
1530
|
if (result.data.type === "oauth-bearer") {
|
|
1531
|
+
const apiHeaders2 = result.data["api-headers"] ? normalizeStringMap(
|
|
1532
|
+
result.data["api-headers"],
|
|
1533
|
+
`Plugin ${name} credentials.api-headers`,
|
|
1534
|
+
{ forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
|
|
1535
|
+
) : void 0;
|
|
1496
1536
|
return {
|
|
1497
1537
|
type: "oauth-bearer",
|
|
1498
1538
|
apiDomains: result.data["api-domains"],
|
|
1499
|
-
...
|
|
1500
|
-
apiHeaders: normalizeStringMap(
|
|
1501
|
-
result.data["api-headers"],
|
|
1502
|
-
`Plugin ${name} credentials.api-headers`,
|
|
1503
|
-
{ forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
|
|
1504
|
-
)
|
|
1505
|
-
} : {},
|
|
1539
|
+
...apiHeaders2 ? { apiHeaders: apiHeaders2 } : {},
|
|
1506
1540
|
authTokenEnv: result.data["auth-token-env"],
|
|
1507
1541
|
...result.data["auth-token-placeholder"] ? { authTokenPlaceholder: result.data["auth-token-placeholder"] } : {}
|
|
1508
1542
|
};
|
|
1509
1543
|
}
|
|
1544
|
+
const apiHeaders = result.data["api-headers"] ? normalizeStringMap(
|
|
1545
|
+
result.data["api-headers"],
|
|
1546
|
+
`Plugin ${name} credentials.api-headers`,
|
|
1547
|
+
{ forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
|
|
1548
|
+
) : void 0;
|
|
1510
1549
|
return {
|
|
1511
1550
|
type: "github-app",
|
|
1512
1551
|
apiDomains: result.data["api-domains"],
|
|
1513
|
-
...
|
|
1514
|
-
apiHeaders: normalizeStringMap(
|
|
1515
|
-
result.data["api-headers"],
|
|
1516
|
-
`Plugin ${name} credentials.api-headers`,
|
|
1517
|
-
{ forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
|
|
1518
|
-
)
|
|
1519
|
-
} : {},
|
|
1552
|
+
...apiHeaders ? { apiHeaders } : {},
|
|
1520
1553
|
authTokenEnv: result.data["auth-token-env"],
|
|
1521
1554
|
...result.data["auth-token-placeholder"] ? { authTokenPlaceholder: result.data["auth-token-placeholder"] } : {},
|
|
1522
1555
|
appIdEnv: result.data["app-id-env"],
|
|
@@ -1650,7 +1683,6 @@ function normalizeRuntimePostinstall(commands, name) {
|
|
|
1650
1683
|
}
|
|
1651
1684
|
return parsed.length > 0 ? parsed : void 0;
|
|
1652
1685
|
}
|
|
1653
|
-
var ENV_PLACEHOLDER_RE = /\$\{([A-Z_][A-Z0-9_]*)\}/g;
|
|
1654
1686
|
var envVarDeclarationSchema = z.preprocess(
|
|
1655
1687
|
(value) => value === null || value === void 0 ? {} : value,
|
|
1656
1688
|
z.object({
|
|
@@ -1714,16 +1746,13 @@ function normalizeMcp(data, envVars, name) {
|
|
|
1714
1746
|
if (!result.success) {
|
|
1715
1747
|
throw new Error(issueMessage(result.error, `Plugin ${name} mcp`));
|
|
1716
1748
|
}
|
|
1749
|
+
const headers = result.data.headers ? normalizeStringMap(result.data.headers, `Plugin ${name} mcp.headers`, {
|
|
1750
|
+
forbiddenKeys: FORBIDDEN_API_HEADER_NAMES
|
|
1751
|
+
}) : void 0;
|
|
1717
1752
|
return {
|
|
1718
1753
|
transport: "http",
|
|
1719
1754
|
url: result.data.url,
|
|
1720
|
-
...
|
|
1721
|
-
headers: normalizeStringMap(
|
|
1722
|
-
result.data.headers,
|
|
1723
|
-
`Plugin ${name} mcp.headers`,
|
|
1724
|
-
{ forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
|
|
1725
|
-
)
|
|
1726
|
-
} : {},
|
|
1755
|
+
...headers ? { headers } : {},
|
|
1727
1756
|
...result.data["allowed-tools"] ? { allowedTools: result.data["allowed-tools"] } : {}
|
|
1728
1757
|
};
|
|
1729
1758
|
}
|
|
@@ -1761,6 +1790,16 @@ function parsePluginManifest(raw, dir) {
|
|
|
1761
1790
|
`Plugin ${parsedYaml.name ?? "unknown"} config-keys must be an array when provided`
|
|
1762
1791
|
);
|
|
1763
1792
|
}
|
|
1793
|
+
if (path3 === "api-domains") {
|
|
1794
|
+
throw new Error(
|
|
1795
|
+
`Plugin ${parsedYaml.name ?? "unknown"} api-domains must be a non-empty array of domains`
|
|
1796
|
+
);
|
|
1797
|
+
}
|
|
1798
|
+
if (path3 === "api-headers") {
|
|
1799
|
+
throw new Error(
|
|
1800
|
+
`Plugin ${parsedYaml.name ?? "unknown"} api-headers must be an object when provided`
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
1764
1803
|
if (path3 === "credentials") {
|
|
1765
1804
|
throw new Error(
|
|
1766
1805
|
`Plugin ${parsedYaml.name ?? "unknown"} credentials must be an object when provided`
|
|
@@ -1813,16 +1852,29 @@ function parsePluginManifest(raw, dir) {
|
|
|
1813
1852
|
}
|
|
1814
1853
|
return `${data.name}.${key}`;
|
|
1815
1854
|
});
|
|
1855
|
+
const envVars = data["env-vars"] ? normalizeEnvVars(data["env-vars"], data.name) : {};
|
|
1856
|
+
const apiHeaders = data["api-headers"] ? normalizeRequiredApiHeaders(
|
|
1857
|
+
data["api-headers"],
|
|
1858
|
+
`Plugin ${data.name} api-headers`,
|
|
1859
|
+
envVars
|
|
1860
|
+
) : void 0;
|
|
1861
|
+
if (apiHeaders && !data["api-domains"]) {
|
|
1862
|
+
throw new Error(`Plugin ${data.name} api-headers requires api-domains`);
|
|
1863
|
+
}
|
|
1864
|
+
if (data["api-domains"] && !apiHeaders) {
|
|
1865
|
+
throw new Error(`Plugin ${data.name} api-domains requires api-headers`);
|
|
1866
|
+
}
|
|
1816
1867
|
const credentials = data.credentials ? normalizeCredentials(data.credentials, data.name) : void 0;
|
|
1817
1868
|
const runtimeDependencies = data["runtime-dependencies"] ? normalizeRuntimeDependencies(data["runtime-dependencies"], data.name) : void 0;
|
|
1818
1869
|
const runtimePostinstall = data["runtime-postinstall"] ? normalizeRuntimePostinstall(data["runtime-postinstall"], data.name) : void 0;
|
|
1819
|
-
const envVars = data["env-vars"] ? normalizeEnvVars(data["env-vars"], data.name) : {};
|
|
1820
1870
|
const mcp = data.mcp ? normalizeMcp(data.mcp, envVars, data.name) : void 0;
|
|
1821
1871
|
const manifest = {
|
|
1822
1872
|
name: data.name,
|
|
1823
1873
|
description: data.description,
|
|
1824
1874
|
capabilities,
|
|
1825
1875
|
configKeys,
|
|
1876
|
+
...data["api-domains"] ? { apiDomains: data["api-domains"] } : {},
|
|
1877
|
+
...apiHeaders ? { apiHeaders } : {},
|
|
1826
1878
|
...Object.keys(envVars).length > 0 ? { envVars } : {},
|
|
1827
1879
|
...credentials ? { credentials } : {},
|
|
1828
1880
|
...runtimeDependencies ? { runtimeDependencies } : {},
|
|
@@ -1903,7 +1955,76 @@ import { readFileSync, readdirSync, statSync } from "fs";
|
|
|
1903
1955
|
import path2 from "path";
|
|
1904
1956
|
|
|
1905
1957
|
// src/chat/plugins/auth/github-app-broker.ts
|
|
1906
|
-
import { createPrivateKey, createSign, randomUUID } from "crypto";
|
|
1958
|
+
import { createPrivateKey, createSign, randomUUID as randomUUID2 } from "crypto";
|
|
1959
|
+
|
|
1960
|
+
// src/chat/credentials/header-transforms.ts
|
|
1961
|
+
function mergeHeaderTransforms(transforms) {
|
|
1962
|
+
const byDomain = /* @__PURE__ */ new Map();
|
|
1963
|
+
for (const transform of transforms) {
|
|
1964
|
+
byDomain.set(transform.domain, {
|
|
1965
|
+
...byDomain.get(transform.domain) ?? {},
|
|
1966
|
+
...transform.headers
|
|
1967
|
+
});
|
|
1968
|
+
}
|
|
1969
|
+
return [...byDomain.entries()].map(([domain, headers]) => ({
|
|
1970
|
+
domain,
|
|
1971
|
+
headers
|
|
1972
|
+
}));
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
// src/chat/plugins/auth/api-headers-broker.ts
|
|
1976
|
+
import { randomUUID } from "crypto";
|
|
1977
|
+
var MAX_LEASE_MS = 60 * 60 * 1e3;
|
|
1978
|
+
var ENV_PLACEHOLDER_RE2 = /\$\{([A-Z_][A-Z0-9_]*)\}/g;
|
|
1979
|
+
function resolveHeaders(provider, headers) {
|
|
1980
|
+
return Object.fromEntries(
|
|
1981
|
+
Object.entries(headers).map(([key, value]) => {
|
|
1982
|
+
const resolved = value.replace(ENV_PLACEHOLDER_RE2, (_match, name) => {
|
|
1983
|
+
const envName = name;
|
|
1984
|
+
const envValue = process.env[envName]?.trim();
|
|
1985
|
+
if (!envValue) {
|
|
1986
|
+
throw new Error(
|
|
1987
|
+
`Missing ${envName} for API header provider "${provider}"`
|
|
1988
|
+
);
|
|
1989
|
+
}
|
|
1990
|
+
return envValue;
|
|
1991
|
+
});
|
|
1992
|
+
return [key, resolved];
|
|
1993
|
+
})
|
|
1994
|
+
);
|
|
1995
|
+
}
|
|
1996
|
+
function resolveApiHeaderTransforms(manifest) {
|
|
1997
|
+
const { apiDomains, apiHeaders } = manifest;
|
|
1998
|
+
if (!apiDomains || !apiHeaders) {
|
|
1999
|
+
return [];
|
|
2000
|
+
}
|
|
2001
|
+
const resolvedHeaders = resolveHeaders(manifest.name, apiHeaders);
|
|
2002
|
+
return apiDomains.map((domain) => ({
|
|
2003
|
+
domain,
|
|
2004
|
+
headers: resolvedHeaders
|
|
2005
|
+
}));
|
|
2006
|
+
}
|
|
2007
|
+
function createApiHeadersBroker(manifest) {
|
|
2008
|
+
const provider = manifest.name;
|
|
2009
|
+
return {
|
|
2010
|
+
async issue(input) {
|
|
2011
|
+
const headerTransforms = resolveApiHeaderTransforms(manifest);
|
|
2012
|
+
if (headerTransforms.length === 0) {
|
|
2013
|
+
throw new Error(`No API headers configured for plugin "${provider}"`);
|
|
2014
|
+
}
|
|
2015
|
+
return {
|
|
2016
|
+
id: randomUUID(),
|
|
2017
|
+
provider,
|
|
2018
|
+
env: {},
|
|
2019
|
+
headerTransforms,
|
|
2020
|
+
expiresAt: new Date(Date.now() + MAX_LEASE_MS).toISOString(),
|
|
2021
|
+
metadata: {
|
|
2022
|
+
reason: input.reason
|
|
2023
|
+
}
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
};
|
|
2027
|
+
}
|
|
1907
2028
|
|
|
1908
2029
|
// src/chat/plugins/auth/auth-token-placeholder.ts
|
|
1909
2030
|
var DEFAULT_PLACEHOLDERS = {
|
|
@@ -1915,7 +2036,7 @@ function resolveAuthTokenPlaceholder(credentials) {
|
|
|
1915
2036
|
}
|
|
1916
2037
|
|
|
1917
2038
|
// src/chat/plugins/auth/github-app-broker.ts
|
|
1918
|
-
var
|
|
2039
|
+
var MAX_LEASE_MS2 = 60 * 60 * 1e3;
|
|
1919
2040
|
function base64Url(input) {
|
|
1920
2041
|
return Buffer.from(input).toString("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
1921
2042
|
}
|
|
@@ -2060,6 +2181,7 @@ function createGitHubAppBroker(manifest, credentials) {
|
|
|
2060
2181
|
} = credentials;
|
|
2061
2182
|
const apiBase = `https://${apiDomains[0]}`;
|
|
2062
2183
|
const placeholder = resolveAuthTokenPlaceholder(credentials);
|
|
2184
|
+
const pluginHeaderTransforms = () => resolveApiHeaderTransforms(manifest);
|
|
2063
2185
|
const GIT_DOMAIN = "github.com";
|
|
2064
2186
|
const GIT_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
2065
2187
|
`${provider}.contents.read`,
|
|
@@ -2097,16 +2219,19 @@ function createGitHubAppBroker(manifest, credentials) {
|
|
|
2097
2219
|
const now = Date.now();
|
|
2098
2220
|
if (cached && cached.expiresAt - now > 2 * 60 * 1e3) {
|
|
2099
2221
|
return {
|
|
2100
|
-
id:
|
|
2222
|
+
id: randomUUID2(),
|
|
2101
2223
|
provider,
|
|
2102
2224
|
env: { [authTokenEnv]: placeholder },
|
|
2103
|
-
headerTransforms:
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2225
|
+
headerTransforms: mergeHeaderTransforms([
|
|
2226
|
+
...pluginHeaderTransforms(),
|
|
2227
|
+
...leaseDomains.map((domain) => ({
|
|
2228
|
+
domain,
|
|
2229
|
+
headers: {
|
|
2230
|
+
...apiHeaders ?? {},
|
|
2231
|
+
Authorization: authorizationFor(domain, cached.token)
|
|
2232
|
+
}
|
|
2233
|
+
}))
|
|
2234
|
+
]),
|
|
2110
2235
|
expiresAt: new Date(cached.expiresAt).toISOString(),
|
|
2111
2236
|
metadata: {
|
|
2112
2237
|
installationId: String(cached.installationId),
|
|
@@ -2130,7 +2255,7 @@ function createGitHubAppBroker(manifest, credentials) {
|
|
|
2130
2255
|
const providerExpiresAtMs = Date.parse(accessTokenResponse.expires_at);
|
|
2131
2256
|
const expiresAtMs = Math.min(
|
|
2132
2257
|
providerExpiresAtMs,
|
|
2133
|
-
Date.now() +
|
|
2258
|
+
Date.now() + MAX_LEASE_MS2
|
|
2134
2259
|
);
|
|
2135
2260
|
tokenCache.set(cacheKey, {
|
|
2136
2261
|
installationId,
|
|
@@ -2138,16 +2263,22 @@ function createGitHubAppBroker(manifest, credentials) {
|
|
|
2138
2263
|
expiresAt: expiresAtMs
|
|
2139
2264
|
});
|
|
2140
2265
|
return {
|
|
2141
|
-
id:
|
|
2266
|
+
id: randomUUID2(),
|
|
2142
2267
|
provider,
|
|
2143
2268
|
env: { [authTokenEnv]: placeholder },
|
|
2144
|
-
headerTransforms:
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2269
|
+
headerTransforms: mergeHeaderTransforms([
|
|
2270
|
+
...pluginHeaderTransforms(),
|
|
2271
|
+
...leaseDomains.map((domain) => ({
|
|
2272
|
+
domain,
|
|
2273
|
+
headers: {
|
|
2274
|
+
...apiHeaders ?? {},
|
|
2275
|
+
Authorization: authorizationFor(
|
|
2276
|
+
domain,
|
|
2277
|
+
accessTokenResponse.token
|
|
2278
|
+
)
|
|
2279
|
+
}
|
|
2280
|
+
}))
|
|
2281
|
+
]),
|
|
2151
2282
|
expiresAt: new Date(expiresAtMs).toISOString(),
|
|
2152
2283
|
metadata: {
|
|
2153
2284
|
installationId: String(installationId),
|
|
@@ -2159,7 +2290,7 @@ function createGitHubAppBroker(manifest, credentials) {
|
|
|
2159
2290
|
}
|
|
2160
2291
|
|
|
2161
2292
|
// src/chat/plugins/auth/oauth-bearer-broker.ts
|
|
2162
|
-
import { randomUUID as
|
|
2293
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
2163
2294
|
|
|
2164
2295
|
// src/chat/credentials/broker.ts
|
|
2165
2296
|
var CredentialUnavailableError = class extends Error {
|
|
@@ -2270,7 +2401,7 @@ function parseOAuthTokenResponse(data, fallbackScope) {
|
|
|
2270
2401
|
}
|
|
2271
2402
|
|
|
2272
2403
|
// src/chat/plugins/auth/oauth-bearer-broker.ts
|
|
2273
|
-
var
|
|
2404
|
+
var MAX_LEASE_MS3 = 60 * 60 * 1e3;
|
|
2274
2405
|
var REFRESH_BUFFER_MS = 5 * 60 * 1e3;
|
|
2275
2406
|
async function refreshAccessToken(refreshToken, oauth, fallbackScope) {
|
|
2276
2407
|
const clientId = process.env[oauth.clientIdEnv]?.trim();
|
|
@@ -2302,21 +2433,25 @@ async function refreshAccessToken(refreshToken, oauth, fallbackScope) {
|
|
|
2302
2433
|
return parseOAuthTokenResponse(data, fallbackScope);
|
|
2303
2434
|
}
|
|
2304
2435
|
function getLeaseExpiry(expiresAt) {
|
|
2305
|
-
return expiresAt ? Math.min(expiresAt, Date.now() +
|
|
2436
|
+
return expiresAt ? Math.min(expiresAt, Date.now() + MAX_LEASE_MS3) : Date.now() + MAX_LEASE_MS3;
|
|
2306
2437
|
}
|
|
2307
2438
|
function createOAuthBearerBroker(manifest, credentials, deps) {
|
|
2308
2439
|
const provider = manifest.name;
|
|
2309
2440
|
const { apiDomains, apiHeaders, authTokenEnv } = credentials;
|
|
2310
2441
|
const authTokenPlaceholder = resolveAuthTokenPlaceholder(credentials);
|
|
2442
|
+
const pluginHeaderTransforms = () => resolveApiHeaderTransforms(manifest);
|
|
2311
2443
|
function buildLease(token, expiresAtMs, reason) {
|
|
2312
2444
|
return {
|
|
2313
|
-
id:
|
|
2445
|
+
id: randomUUID3(),
|
|
2314
2446
|
provider,
|
|
2315
2447
|
env: { [authTokenEnv]: authTokenPlaceholder },
|
|
2316
|
-
headerTransforms:
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2448
|
+
headerTransforms: mergeHeaderTransforms([
|
|
2449
|
+
...pluginHeaderTransforms(),
|
|
2450
|
+
...apiDomains.map((domain) => ({
|
|
2451
|
+
domain,
|
|
2452
|
+
headers: { ...apiHeaders ?? {}, Authorization: `Bearer ${token}` }
|
|
2453
|
+
}))
|
|
2454
|
+
]),
|
|
2320
2455
|
expiresAt: new Date(expiresAtMs).toISOString(),
|
|
2321
2456
|
metadata: { reason }
|
|
2322
2457
|
};
|
|
@@ -2327,7 +2462,7 @@ function createOAuthBearerBroker(manifest, credentials, deps) {
|
|
|
2327
2462
|
const oauth = manifest.oauth;
|
|
2328
2463
|
if (!oauth) {
|
|
2329
2464
|
if (envToken) {
|
|
2330
|
-
return buildLease(envToken, Date.now() +
|
|
2465
|
+
return buildLease(envToken, Date.now() + MAX_LEASE_MS3, input.reason);
|
|
2331
2466
|
}
|
|
2332
2467
|
throw new CredentialUnavailableError(
|
|
2333
2468
|
provider,
|
|
@@ -2734,11 +2869,15 @@ function createPluginBroker(provider, deps) {
|
|
|
2734
2869
|
throw new Error(`Unknown plugin provider: "${provider}"`);
|
|
2735
2870
|
}
|
|
2736
2871
|
const { credentials, name } = plugin.manifest;
|
|
2737
|
-
if (!credentials) {
|
|
2738
|
-
throw new Error(
|
|
2872
|
+
if (!credentials && !plugin.manifest.apiHeaders) {
|
|
2873
|
+
throw new Error(
|
|
2874
|
+
`Provider "${name}" has no credentials or API headers configured`
|
|
2875
|
+
);
|
|
2739
2876
|
}
|
|
2740
2877
|
let broker;
|
|
2741
|
-
if (credentials
|
|
2878
|
+
if (!credentials) {
|
|
2879
|
+
broker = createApiHeadersBroker(plugin.manifest);
|
|
2880
|
+
} else if (credentials.type === "oauth-bearer") {
|
|
2742
2881
|
broker = createOAuthBearerBroker(plugin.manifest, credentials, deps);
|
|
2743
2882
|
} else if (credentials.type === "github-app") {
|
|
2744
2883
|
broker = createGitHubAppBroker(plugin.manifest, credentials);
|
|
@@ -2773,6 +2912,7 @@ export {
|
|
|
2773
2912
|
serializeGenAiAttribute,
|
|
2774
2913
|
extractGenAiUsageSummary,
|
|
2775
2914
|
extractGenAiUsageAttributes,
|
|
2915
|
+
mergeHeaderTransforms,
|
|
2776
2916
|
resolveAuthTokenPlaceholder,
|
|
2777
2917
|
parsePluginManifest,
|
|
2778
2918
|
CredentialUnavailableError,
|
package/dist/cli/check.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parseSkillFile
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-LAD5O3RX.js";
|
|
4
4
|
import {
|
|
5
5
|
parsePluginManifest
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-QZRPUFO6.js";
|
|
7
7
|
import "../chunk-Z3YD6NHK.js";
|
|
8
8
|
import "../chunk-XPXD3FCE.js";
|
|
9
9
|
import "../chunk-2KG3PWR4.js";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
disconnectStateAdapter,
|
|
3
3
|
resolveRuntimeDependencySnapshot
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-HZIJ4BSE.js";
|
|
5
5
|
import {
|
|
6
6
|
getPluginProviders,
|
|
7
7
|
getPluginRuntimeDependencies,
|
|
8
8
|
getPluginRuntimePostinstall
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-QZRPUFO6.js";
|
|
10
10
|
import "../chunk-Z3YD6NHK.js";
|
|
11
11
|
import "../chunk-XPXD3FCE.js";
|
|
12
12
|
import "../chunk-2KG3PWR4.js";
|