@sentry/junior 0.117.0 → 0.119.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-5IK4LPLP.js → agent-hooks-NZSV4QQR.js} +9 -11
- package/dist/api/conversations/detail.d.ts +17 -0
- package/dist/api/conversations/event-list.d.ts +17 -0
- package/dist/api/schema/conversation.d.ts +68 -0
- package/dist/api/schema/stats.d.ts +22 -0
- package/dist/api/schema.d.ts +2 -0
- package/dist/api/schema.js +7 -3
- package/dist/api/stats.d.ts +16 -0
- package/dist/api/user-pages/routes.d.ts +4 -0
- package/dist/api.js +223 -20
- package/dist/app.js +43 -38
- package/dist/{catalog-runtime-MTUYW3AA.js → catalog-runtime-TAOYIZIZ.js} +5 -5
- package/dist/chat/agent/prompt.d.ts +4 -2
- package/dist/chat/plugins/user-pages.d.ts +15 -0
- package/dist/chat/plugins/viewer-actors.d.ts +6 -0
- package/dist/chat/prompt.d.ts +1 -2
- package/dist/chat/sandbox/paths.d.ts +2 -0
- package/dist/chat/sandbox/sandbox.d.ts +3 -1
- package/dist/chat/sandbox/workspace.d.ts +1 -0
- package/dist/chat/skills.d.ts +1 -2
- package/dist/chat/slack/tools/canvas/api.d.ts +2 -9
- package/dist/chat/slack/tools/canvas/markdown.d.ts +9 -0
- package/dist/chat/tools/index.d.ts +4 -1
- package/dist/chat/tools/sandbox/file-utils.d.ts +11 -0
- package/dist/chat/tools/sandbox/find-files.d.ts +2 -1
- package/dist/chat/tools/sandbox/grep.d.ts +2 -1
- package/dist/{chunk-6G45D3YG.js → chunk-4UIUDOOV.js} +16 -233
- package/dist/{chunk-LUMEBOWC.js → chunk-6ZR455DC.js} +2 -2
- package/dist/{chunk-STUI6NIL.js → chunk-BLQZACHV.js} +511 -14
- package/dist/{chunk-27KWTFP6.js → chunk-BNJEPYTC.js} +5 -14
- package/dist/{chunk-ZRQUQJUV.js → chunk-D3N4BPSL.js} +3 -3
- package/dist/{chunk-WKU7TY22.js → chunk-FIANEE7Z.js} +3 -1
- package/dist/{chunk-RXRQJF7Y.js → chunk-GCGJGSQL.js} +21 -0
- package/dist/{chunk-FAWBONPC.js → chunk-GKFDU3ZI.js} +5 -7
- package/dist/{chunk-FXOYURO4.js → chunk-HDFGNU5E.js} +1 -0
- package/dist/{chunk-3GE3F4LT.js → chunk-JLJLZS2N.js} +1 -1
- package/dist/{chunk-CU7HTGNI.js → chunk-JSTGI7TX.js} +1 -1
- package/dist/chunk-JXRAOOXQ.js +37 -0
- package/dist/{chunk-WUNPRM76.js → chunk-NUENIPQL.js} +1 -1
- package/dist/{chunk-BFIRIZPH.js → chunk-O2ULQJWR.js} +101 -2
- package/dist/{chunk-AKG4TZNH.js → chunk-QZ7XRJDB.js} +30 -9
- package/dist/{chunk-5O3JDQDG.js → chunk-R53UT2OI.js} +1 -1
- package/dist/{chunk-W5JEQQEA.js → chunk-TAGV4Z3J.js} +1 -1
- package/dist/{chunk-NHZEUHKH.js → chunk-TGIQN7QW.js} +388 -113
- package/dist/{chunk-KU6ALEJC.js → chunk-VJTWKJWQ.js} +30 -2
- package/dist/{chunk-DS27ZBSP.js → chunk-VLTWQQKH.js} +2 -2
- package/dist/{chunk-WEK3V5RI.js → chunk-YLYJIQRX.js} +226 -21
- package/dist/{chunk-LN765Y4N.js → chunk-ZFX4M743.js} +15 -9
- package/dist/{chunk-72Z3HNTQ.js → chunk-ZJ6IVZVO.js} +1 -1
- package/dist/cli/chat.js +24 -25
- package/dist/cli/check.js +6 -6
- package/dist/cli/init.js +2 -2
- package/dist/cli/plugins.js +13 -15
- package/dist/cli/snapshot-create.js +9 -10
- package/dist/cli/upgrade.js +8 -8
- package/dist/db/schema/stats.d.ts +93 -0
- package/dist/db/schema.d.ts +94 -1
- package/dist/{db-J2ITKS63.js → db-FWGP5CKY.js} +7 -7
- package/dist/instrumentation.js +3 -3
- package/dist/nitro.js +3 -3
- package/dist/{oauth-callback-server-NQYKBT24.js → oauth-callback-server-PM3QNXJQ.js} +16 -18
- package/dist/{plugins-IUJA4VBU.js → plugins-HW4VWW6G.js} +1 -1
- package/dist/{runner-53V5GIQM.js → runner-DV55N6ZB.js} +11 -13
- package/dist/{skills-BU3ZMLVB.js → skills-MANV5ZK6.js} +6 -6
- package/dist/stats.d.ts +18 -0
- package/dist/{validation-74EIKKE6.js → validation-QGB4INTI.js} +6 -6
- package/dist/version.js +1 -1
- package/migrations/0011_sour_golden_guardian.sql +8 -0
- package/migrations/meta/0011_snapshot.json +1195 -0
- package/migrations/meta/_journal.json +8 -1
- package/package.json +5 -5
- package/dist/chunk-4ZNGQH7C.js +0 -25
- package/dist/chunk-YRWJ3KEU.js +0 -517
|
@@ -25,13 +25,12 @@ import {
|
|
|
25
25
|
patchMcpAuthSession,
|
|
26
26
|
resolveBaseUrl,
|
|
27
27
|
selectPluginGrant,
|
|
28
|
-
slackOutputPolicy,
|
|
29
28
|
startOAuthFlow,
|
|
30
29
|
surfaceFromRouting,
|
|
31
30
|
toMcpProviderError,
|
|
32
31
|
toolInvocationDestination,
|
|
33
32
|
uploadFilesToConversation
|
|
34
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-4UIUDOOV.js";
|
|
35
34
|
import {
|
|
36
35
|
CooperativeTurnYieldError,
|
|
37
36
|
JUNIOR_THREAD_STATE_TTL_MS,
|
|
@@ -73,7 +72,7 @@ import {
|
|
|
73
72
|
stripRuntimeTurnContext,
|
|
74
73
|
trimTrailingAssistantMessages,
|
|
75
74
|
updateConversationStats
|
|
76
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-BNJEPYTC.js";
|
|
77
76
|
import {
|
|
78
77
|
parseSandboxEgressAuthRequiredSignal,
|
|
79
78
|
parseSandboxEgressPermissionDeniedSignal,
|
|
@@ -97,7 +96,10 @@ import {
|
|
|
97
96
|
runNonInteractiveCommand,
|
|
98
97
|
throwSandboxOperationError,
|
|
99
98
|
wrapSandboxSetupError
|
|
100
|
-
} from "./chunk-
|
|
99
|
+
} from "./chunk-GKFDU3ZI.js";
|
|
100
|
+
import {
|
|
101
|
+
incrementStat
|
|
102
|
+
} from "./chunk-JXRAOOXQ.js";
|
|
101
103
|
import {
|
|
102
104
|
addAgentTurnUsage,
|
|
103
105
|
hasAgentTurnUsage
|
|
@@ -106,30 +108,20 @@ import {
|
|
|
106
108
|
privateTraceResultAttributes
|
|
107
109
|
} from "./chunk-UIE3R5XU.js";
|
|
108
110
|
import {
|
|
111
|
+
SlackActionError,
|
|
109
112
|
createPluginHookRunner,
|
|
113
|
+
downloadPrivateSlackFile,
|
|
114
|
+
getFilePermalink,
|
|
110
115
|
getPluginSystemPromptContributions,
|
|
111
116
|
getPluginTools,
|
|
112
117
|
getPluginUserPromptContributions,
|
|
113
|
-
getSlackToolContext,
|
|
114
|
-
resolveChannelCapabilities
|
|
115
|
-
} from "./chunk-STUI6NIL.js";
|
|
116
|
-
import {
|
|
117
|
-
SANDBOX_DATA_ROOT,
|
|
118
|
-
SANDBOX_SKILLS_ROOT,
|
|
119
|
-
SANDBOX_WORKSPACE_ROOT,
|
|
120
|
-
getStateAdapter,
|
|
121
|
-
sandboxSkillDir,
|
|
122
|
-
sandboxSkillFile
|
|
123
|
-
} from "./chunk-KU6ALEJC.js";
|
|
124
|
-
import {
|
|
125
|
-
SlackActionError,
|
|
126
|
-
downloadPrivateSlackFile,
|
|
127
|
-
getFilePermalink,
|
|
128
118
|
getSlackClient,
|
|
119
|
+
getSlackToolContext,
|
|
129
120
|
isConversationScopedChannel,
|
|
130
121
|
normalizeSlackConversationId,
|
|
122
|
+
resolveChannelCapabilities,
|
|
131
123
|
withSlackRetries
|
|
132
|
-
} from "./chunk-
|
|
124
|
+
} from "./chunk-BLQZACHV.js";
|
|
133
125
|
import {
|
|
134
126
|
KNOWN_CONVERSATION_EVENT_TYPES,
|
|
135
127
|
contextProvenance,
|
|
@@ -138,10 +130,17 @@ import {
|
|
|
138
130
|
getConversationStore,
|
|
139
131
|
instructionActors,
|
|
140
132
|
instructionProvenanceFor
|
|
141
|
-
} from "./chunk-
|
|
133
|
+
} from "./chunk-D3N4BPSL.js";
|
|
142
134
|
import {
|
|
135
|
+
SANDBOX_DATA_ROOT,
|
|
136
|
+
SANDBOX_SKILLS_ROOT,
|
|
137
|
+
SANDBOX_WORKSPACE_ROOT,
|
|
138
|
+
getStateAdapter,
|
|
139
|
+
sandboxSkillDir,
|
|
140
|
+
sandboxSkillFile,
|
|
141
|
+
sandboxSkillPathResolution,
|
|
143
142
|
sleep
|
|
144
|
-
} from "./chunk-
|
|
143
|
+
} from "./chunk-VJTWKJWQ.js";
|
|
145
144
|
import {
|
|
146
145
|
ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX,
|
|
147
146
|
COMPACTION_SUMMARY_PREFIX,
|
|
@@ -172,7 +171,7 @@ import {
|
|
|
172
171
|
renderCurrentInstruction,
|
|
173
172
|
resolveGatewayModel,
|
|
174
173
|
unwrapCurrentInstruction
|
|
175
|
-
} from "./chunk-
|
|
174
|
+
} from "./chunk-VLTWQQKH.js";
|
|
176
175
|
import {
|
|
177
176
|
canExposeConversationPayload,
|
|
178
177
|
parseSlackThreadId,
|
|
@@ -183,16 +182,16 @@ import {
|
|
|
183
182
|
toGenAiMessagesTraceAttributes,
|
|
184
183
|
toGenAiPayloadMetadata,
|
|
185
184
|
toGenAiPayloadTraceAttributes
|
|
186
|
-
} from "./chunk-
|
|
185
|
+
} from "./chunk-HDFGNU5E.js";
|
|
187
186
|
import {
|
|
188
187
|
discoverSkills,
|
|
189
188
|
findSkillByName,
|
|
190
189
|
loadSkillsByName,
|
|
191
190
|
parseSkillInvocation
|
|
192
|
-
} from "./chunk-
|
|
191
|
+
} from "./chunk-QZ7XRJDB.js";
|
|
193
192
|
import {
|
|
194
193
|
pluginCatalogRuntime
|
|
195
|
-
} from "./chunk-
|
|
194
|
+
} from "./chunk-JSTGI7TX.js";
|
|
196
195
|
import {
|
|
197
196
|
CredentialUnavailableError,
|
|
198
197
|
OAuthProviderError,
|
|
@@ -200,7 +199,7 @@ import {
|
|
|
200
199
|
getOAuthProviderErrorAttributes,
|
|
201
200
|
resolveAuthTokenPlaceholder,
|
|
202
201
|
resolvePluginCommandEnv
|
|
203
|
-
} from "./chunk-
|
|
202
|
+
} from "./chunk-R53UT2OI.js";
|
|
204
203
|
import {
|
|
205
204
|
credentialUserSubjectId
|
|
206
205
|
} from "./chunk-W3U3YQYI.js";
|
|
@@ -224,7 +223,7 @@ import {
|
|
|
224
223
|
summarizeMessageText,
|
|
225
224
|
withLogContext,
|
|
226
225
|
withSpan
|
|
227
|
-
} from "./chunk-
|
|
226
|
+
} from "./chunk-ZJ6IVZVO.js";
|
|
228
227
|
import {
|
|
229
228
|
parseSlackChannelId,
|
|
230
229
|
parseSlackMessageTs,
|
|
@@ -1668,13 +1667,10 @@ function formatSkillEntry(skill) {
|
|
|
1668
1667
|
lines.push(" </skill>");
|
|
1669
1668
|
return lines;
|
|
1670
1669
|
}
|
|
1671
|
-
function formatAvailableSkillsForPrompt(skills
|
|
1670
|
+
function formatAvailableSkillsForPrompt(skills) {
|
|
1672
1671
|
const autoSelectable = skills.filter(
|
|
1673
1672
|
(s) => s.disableModelInvocation !== true
|
|
1674
1673
|
);
|
|
1675
|
-
const invokedExplicitOnly = invocation ? skills.filter(
|
|
1676
|
-
(s) => s.disableModelInvocation === true && s.name === invocation.skillName
|
|
1677
|
-
) : [];
|
|
1678
1674
|
const sections = [];
|
|
1679
1675
|
if (autoSelectable.length > 0) {
|
|
1680
1676
|
const available = [
|
|
@@ -1687,17 +1683,6 @@ function formatAvailableSkillsForPrompt(skills, invocation) {
|
|
|
1687
1683
|
available.push("</available-skills>");
|
|
1688
1684
|
sections.push(available.join("\n"));
|
|
1689
1685
|
}
|
|
1690
|
-
if (invokedExplicitOnly.length > 0) {
|
|
1691
|
-
const userCallable = [
|
|
1692
|
-
"<user-callable-skills>",
|
|
1693
|
-
"The user's current message explicitly references this skill by name. Load it when relevant to the request."
|
|
1694
|
-
];
|
|
1695
|
-
for (const skill of invokedExplicitOnly) {
|
|
1696
|
-
userCallable.push(...formatSkillEntry(skill));
|
|
1697
|
-
}
|
|
1698
|
-
userCallable.push("</user-callable-skills>");
|
|
1699
|
-
sections.push(userCallable.join("\n"));
|
|
1700
|
-
}
|
|
1701
1686
|
return sections.length > 0 ? sections.join("\n") : null;
|
|
1702
1687
|
}
|
|
1703
1688
|
function formatActiveMcpCatalogsForPrompt(catalogs) {
|
|
@@ -1810,7 +1795,8 @@ var TOOL_CALL_STYLE_RULES = [
|
|
|
1810
1795
|
"- Keep tool-call explanations separate from final answers; final answers should report results, evidence, or blockers."
|
|
1811
1796
|
];
|
|
1812
1797
|
var SKILL_POLICY_RULES = [
|
|
1813
|
-
"-
|
|
1798
|
+
"- A `<skill>` block in the current user turn is already loaded. Follow its instructions directly and do not call `loadSkill` for that skill.",
|
|
1799
|
+
"- Otherwise, only load skills listed in `<available-skills>`. Never guess or invent a skill name.",
|
|
1814
1800
|
"- Load one skill at a time. After `loadSkill`, follow the instructions returned by that tool result."
|
|
1815
1801
|
];
|
|
1816
1802
|
var EXECUTION_CONTRACT_RULES = [
|
|
@@ -1874,13 +1860,11 @@ function buildOutputSection(platform) {
|
|
|
1874
1860
|
"</output>"
|
|
1875
1861
|
].join("\n");
|
|
1876
1862
|
}
|
|
1877
|
-
const openTag = `<output format="slack-markdown" max_inline_chars="${slackOutputPolicy.maxInlineChars}" max_inline_lines="${slackOutputPolicy.maxInlineLines}">`;
|
|
1878
1863
|
return [
|
|
1879
|
-
|
|
1864
|
+
`<output format="slack-markdown">`,
|
|
1865
|
+
"- Default to the shortest complete reply\u2014usually 1\u20135 sentences and under 800 characters. Include only the outcome, decisive evidence, and any blocker or required next action. If useful detail would exceed that, put it in a Slack canvas and reply with the link. An explicit user request for detail overrides this target.",
|
|
1880
1866
|
"- Start with the answer or result, not internal process narration.",
|
|
1881
1867
|
"- Use Slack-flavored Markdown: **bold** section labels, `code`, [text](url) links, bullet lists, and fenced code blocks. No hash-prefixed headings and no tables. When the answer primarily lists several URLs, show each URL bare instead of as a labeled link.",
|
|
1882
|
-
"- Default to one compact thread reply containing the conclusion and only decisive evidence or action. Do not split an explainer across multiple Slack messages.",
|
|
1883
|
-
"- Put plans, research, and other long or multi-section explainers in a Slack canvas; reply with one or two short sentences plus the link, without recapping the canvas.",
|
|
1884
1868
|
"- End every turn with a final user-facing markdown response unless the Slack action rules allow a no-reply completion.",
|
|
1885
1869
|
"</output>"
|
|
1886
1870
|
].join("\n");
|
|
@@ -1995,14 +1979,6 @@ function buildContextSection(params) {
|
|
|
1995
1979
|
])
|
|
1996
1980
|
);
|
|
1997
1981
|
}
|
|
1998
|
-
if (params.invocation) {
|
|
1999
|
-
blocks.push(
|
|
2000
|
-
renderTag("explicit-skill-trigger", [
|
|
2001
|
-
"Treat this skill as selected. Load it unless the tool says it is unavailable.",
|
|
2002
|
-
`/${escapeXml(params.invocation.skillName)}`
|
|
2003
|
-
])
|
|
2004
|
-
);
|
|
2005
|
-
}
|
|
2006
1982
|
const body = blocks.map((block) => block.join("\n")).join("\n\n");
|
|
2007
1983
|
if (!body) {
|
|
2008
1984
|
return null;
|
|
@@ -2012,8 +1988,7 @@ function buildContextSection(params) {
|
|
|
2012
1988
|
function buildCapabilitiesSection(params) {
|
|
2013
1989
|
const blocks = [];
|
|
2014
1990
|
const availableSkills = formatAvailableSkillsForPrompt(
|
|
2015
|
-
params.availableSkills
|
|
2016
|
-
params.invocation
|
|
1991
|
+
params.availableSkills
|
|
2017
1992
|
);
|
|
2018
1993
|
if (availableSkills) {
|
|
2019
1994
|
blocks.push(availableSkills);
|
|
@@ -2094,7 +2069,6 @@ function buildTurnContextPrompt(params) {
|
|
|
2094
2069
|
includeSessionContext ? buildCapabilitiesSection({
|
|
2095
2070
|
availableSkills: params.availableSkills,
|
|
2096
2071
|
activeMcpCatalogs: params.activeMcpCatalogs ?? [],
|
|
2097
|
-
invocation: params.invocation,
|
|
2098
2072
|
toolGuidance: params.toolGuidance ?? []
|
|
2099
2073
|
}) : null,
|
|
2100
2074
|
pluginPromptContributions,
|
|
@@ -2102,8 +2076,7 @@ function buildTurnContextPrompt(params) {
|
|
|
2102
2076
|
actor: params.actor,
|
|
2103
2077
|
artifactState: params.artifactState,
|
|
2104
2078
|
configuration: params.configuration,
|
|
2105
|
-
dispatch: params.dispatch
|
|
2106
|
-
invocation: params.invocation
|
|
2079
|
+
dispatch: params.dispatch
|
|
2107
2080
|
}) : null,
|
|
2108
2081
|
includeSessionContext ? buildRuntimeSection(params.runtime ?? {}) : null
|
|
2109
2082
|
].filter((section) => Boolean(section));
|
|
@@ -2146,6 +2119,17 @@ function buildUserTurnText(userInput, conversationContext, actor) {
|
|
|
2146
2119
|
currentInstruction
|
|
2147
2120
|
].join("\n");
|
|
2148
2121
|
}
|
|
2122
|
+
function renderExplicitSkillInstructions(skill) {
|
|
2123
|
+
return [
|
|
2124
|
+
"<skill>",
|
|
2125
|
+
`<name>${escapeXml(skill.name)}</name>`,
|
|
2126
|
+
`<path>${escapeXml(sandboxSkillFile(skill.name))}</path>`,
|
|
2127
|
+
`<working_directory>${escapeXml(sandboxSkillDir(skill.name))}</working_directory>`,
|
|
2128
|
+
`<path_resolution>${escapeXml(sandboxSkillPathResolution(skill.name))}</path_resolution>`,
|
|
2129
|
+
skill.body,
|
|
2130
|
+
"</skill>"
|
|
2131
|
+
].join("\n");
|
|
2132
|
+
}
|
|
2149
2133
|
function encodeNonImageAttachmentForPrompt(attachment) {
|
|
2150
2134
|
const base64 = attachment.data.toString("base64");
|
|
2151
2135
|
const wasTruncated = base64.length > MAX_INLINE_ATTACHMENT_BASE64_CHARS;
|
|
@@ -2343,14 +2327,23 @@ async function assemblePrompt(args) {
|
|
|
2343
2327
|
const source = args.routing.source;
|
|
2344
2328
|
const hasPromptCheckpoint = args.resumedFromSessionRecord && args.existingTurnStartMessageIndex !== void 0;
|
|
2345
2329
|
const shouldPromptAgent = !args.resumedFromSessionRecord || !hasPromptCheckpoint;
|
|
2330
|
+
const requestContentParts = [
|
|
2331
|
+
...args.explicitSkill ? [
|
|
2332
|
+
{
|
|
2333
|
+
type: "text",
|
|
2334
|
+
text: renderExplicitSkillInstructions(args.explicitSkill)
|
|
2335
|
+
}
|
|
2336
|
+
] : [],
|
|
2337
|
+
...args.userContentParts
|
|
2338
|
+
];
|
|
2346
2339
|
const promptHistoryMessages = shouldPromptAgent ? withoutTrailingUncheckpointedUserPrompt(
|
|
2347
2340
|
args.priorPiMessages,
|
|
2348
|
-
|
|
2341
|
+
requestContentParts
|
|
2349
2342
|
) : args.existingSessionPiMessages;
|
|
2350
2343
|
const replayedPromptContent = shouldPromptAgent && !args.resumedFromSessionRecord ? checkpointedPromptContent({
|
|
2351
2344
|
messages: args.existingSessionPiMessages,
|
|
2352
2345
|
turnStartMessageIndex: args.existingTurnStartMessageIndex,
|
|
2353
|
-
userContentParts:
|
|
2346
|
+
userContentParts: requestContentParts
|
|
2354
2347
|
}) : void 0;
|
|
2355
2348
|
const needsBootstrapContextForPrompt = shouldPromptAgent && !replayedPromptContent && !hasRuntimeTurnContext(promptHistoryMessages);
|
|
2356
2349
|
const systemPromptContributions = await getPluginSystemPromptContributions(source);
|
|
@@ -2376,7 +2369,6 @@ async function assemblePrompt(args) {
|
|
|
2376
2369
|
destination: args.routing.destination,
|
|
2377
2370
|
source
|
|
2378
2371
|
} : void 0,
|
|
2379
|
-
invocation: args.invocation,
|
|
2380
2372
|
actor: isUserActor(args.currentActor) ? args.currentActor : void 0,
|
|
2381
2373
|
artifactState: args.artifactState,
|
|
2382
2374
|
configuration: args.configurationValues
|
|
@@ -2384,7 +2376,7 @@ async function assemblePrompt(args) {
|
|
|
2384
2376
|
const turnContextParts = turnContextPrompt ? [{ type: "text", text: turnContextPrompt }] : [];
|
|
2385
2377
|
const promptContentParts = replayedPromptContent ?? [
|
|
2386
2378
|
...turnContextParts,
|
|
2387
|
-
...
|
|
2379
|
+
...requestContentParts
|
|
2388
2380
|
];
|
|
2389
2381
|
const inputMessages = [
|
|
2390
2382
|
{
|
|
@@ -3076,6 +3068,7 @@ import { Sandbox } from "@vercel/sandbox";
|
|
|
3076
3068
|
// src/chat/sandbox/skill-sync.ts
|
|
3077
3069
|
import fs3 from "fs/promises";
|
|
3078
3070
|
import path3 from "path";
|
|
3071
|
+
var DIRECTORY_CREATE_CONCURRENCY = 8;
|
|
3079
3072
|
function toPosixRelative(base, absolute) {
|
|
3080
3073
|
return path3.relative(base, absolute).split(path3.sep).join("/");
|
|
3081
3074
|
}
|
|
@@ -3150,6 +3143,16 @@ function collectDirectories(filesToWrite, workspaceRoot) {
|
|
|
3150
3143
|
(directory) => directory === workspaceRoot || directory.startsWith(`${workspaceRoot}/`)
|
|
3151
3144
|
).sort((a, b) => a.length - b.length);
|
|
3152
3145
|
}
|
|
3146
|
+
function groupDirectoriesByDepth(directories) {
|
|
3147
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3148
|
+
for (const directory of directories) {
|
|
3149
|
+
const depth = directory.split("/").filter(Boolean).length;
|
|
3150
|
+
const group = groups.get(depth) ?? [];
|
|
3151
|
+
group.push(directory);
|
|
3152
|
+
groups.set(depth, group);
|
|
3153
|
+
}
|
|
3154
|
+
return [...groups.entries()].sort(([left], [right]) => left - right).map(([, group]) => group);
|
|
3155
|
+
}
|
|
3153
3156
|
function resolveHostSkillPath(availableSkills, sandboxPath) {
|
|
3154
3157
|
const normalizedPath = path3.posix.normalize(sandboxPath.trim());
|
|
3155
3158
|
for (const skill of availableSkills) {
|
|
@@ -3219,13 +3222,21 @@ async function syncSkillsToSandbox(params) {
|
|
|
3219
3222
|
},
|
|
3220
3223
|
async () => {
|
|
3221
3224
|
try {
|
|
3222
|
-
for (const
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3225
|
+
for (const directoriesAtDepth of groupDirectoriesByDepth(
|
|
3226
|
+
directories
|
|
3227
|
+
)) {
|
|
3228
|
+
for (let offset = 0; offset < directoriesAtDepth.length; offset += DIRECTORY_CREATE_CONCURRENCY) {
|
|
3229
|
+
await Promise.all(
|
|
3230
|
+
directoriesAtDepth.slice(offset, offset + DIRECTORY_CREATE_CONCURRENCY).map(async (directory) => {
|
|
3231
|
+
try {
|
|
3232
|
+
await params.sandbox.mkDir(directory);
|
|
3233
|
+
} catch (error) {
|
|
3234
|
+
if (!isAlreadyExistsError(error)) {
|
|
3235
|
+
throw error;
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
})
|
|
3239
|
+
);
|
|
3229
3240
|
}
|
|
3230
3241
|
}
|
|
3231
3242
|
await params.sandbox.writeFiles(filesToWrite);
|
|
@@ -3822,6 +3833,7 @@ var RIPGREP_EXCLUDED_GLOBS = [
|
|
|
3822
3833
|
"!**/.git/**",
|
|
3823
3834
|
"!**/node_modules/**"
|
|
3824
3835
|
];
|
|
3836
|
+
var DEFAULT_SEARCH_COMMAND_TIMEOUT_MS = 3e4;
|
|
3825
3837
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules"]);
|
|
3826
3838
|
function positiveInteger(value) {
|
|
3827
3839
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -4409,7 +4421,7 @@ function createEditFileTool() {
|
|
|
4409
4421
|
// src/chat/tools/sandbox/find-files.ts
|
|
4410
4422
|
import path5 from "path";
|
|
4411
4423
|
import { z as z5 } from "zod";
|
|
4412
|
-
var DEFAULT_FIND_LIMIT =
|
|
4424
|
+
var DEFAULT_FIND_LIMIT = 100;
|
|
4413
4425
|
async function findFiles(params) {
|
|
4414
4426
|
if (!params.pattern.trim()) {
|
|
4415
4427
|
throw new Error("pattern is required");
|
|
@@ -4420,6 +4432,7 @@ async function findFiles(params) {
|
|
|
4420
4432
|
return await findFilesWithRipgrep({
|
|
4421
4433
|
fs: params.fs,
|
|
4422
4434
|
limit,
|
|
4435
|
+
onTelemetry: params.onTelemetry,
|
|
4423
4436
|
path: params.path,
|
|
4424
4437
|
pattern: params.pattern,
|
|
4425
4438
|
root,
|
|
@@ -4488,25 +4501,45 @@ async function findFilesWithRipgrep(params) {
|
|
|
4488
4501
|
throw error;
|
|
4489
4502
|
}
|
|
4490
4503
|
const location = getRipgrepSearchLocation(params.root, rootIsDirectory);
|
|
4491
|
-
const
|
|
4504
|
+
const ripgrepArgs = [
|
|
4492
4505
|
"--files",
|
|
4493
4506
|
"--null",
|
|
4494
4507
|
"--hidden",
|
|
4495
|
-
"--sort=path",
|
|
4496
4508
|
"--glob",
|
|
4497
4509
|
params.pattern
|
|
4498
4510
|
];
|
|
4499
4511
|
for (const excludedGlob of RIPGREP_EXCLUDED_GLOBS) {
|
|
4500
|
-
|
|
4512
|
+
ripgrepArgs.push("--glob", excludedGlob);
|
|
4501
4513
|
}
|
|
4502
|
-
|
|
4514
|
+
ripgrepArgs.push("--", location.target);
|
|
4503
4515
|
const result = await params.runCommand({
|
|
4504
|
-
cmd: "
|
|
4505
|
-
args
|
|
4506
|
-
|
|
4516
|
+
cmd: "bash",
|
|
4517
|
+
args: [
|
|
4518
|
+
"-c",
|
|
4519
|
+
[
|
|
4520
|
+
`rg "$@" | head -z -n ${params.limit + 1}`,
|
|
4521
|
+
'statuses=("${PIPESTATUS[@]}")',
|
|
4522
|
+
"if (( statuses[1] != 0 )); then",
|
|
4523
|
+
' exit "${statuses[1]}"',
|
|
4524
|
+
"fi",
|
|
4525
|
+
"if (( statuses[0] == 0 || statuses[0] == 1 || statuses[0] == 141 )); then",
|
|
4526
|
+
" exit 0",
|
|
4527
|
+
"fi",
|
|
4528
|
+
'exit "${statuses[0]}"'
|
|
4529
|
+
].join("\n"),
|
|
4530
|
+
"find-files",
|
|
4531
|
+
...ripgrepArgs
|
|
4532
|
+
],
|
|
4533
|
+
cwd: location.cwd,
|
|
4534
|
+
timeoutMs: DEFAULT_SEARCH_COMMAND_TIMEOUT_MS
|
|
4507
4535
|
});
|
|
4508
|
-
if (result.exitCode !== 0
|
|
4536
|
+
if (result.exitCode !== 0) {
|
|
4509
4537
|
const detail = result.stderr.trim() || result.stdout.trim() || "command failed";
|
|
4538
|
+
if (/error parsing glob|invalid glob/i.test(detail)) {
|
|
4539
|
+
throw new ToolInputError(`Invalid glob pattern: ${params.pattern}`, {
|
|
4540
|
+
cause: new Error(detail)
|
|
4541
|
+
});
|
|
4542
|
+
}
|
|
4510
4543
|
throw new Error(`ripgrep file search failed: ${detail}`);
|
|
4511
4544
|
}
|
|
4512
4545
|
const allPaths = result.stdout.split("\0").filter(Boolean).map((filePath) => {
|
|
@@ -4530,7 +4563,7 @@ async function findFilesWithRipgrep(params) {
|
|
|
4530
4563
|
const text = notices.length > 0 ? `${bounded.content}
|
|
4531
4564
|
|
|
4532
4565
|
[${notices.join(" ")}]` : bounded.content;
|
|
4533
|
-
|
|
4566
|
+
const response = makeStructuredToolResult(
|
|
4534
4567
|
{
|
|
4535
4568
|
ok: true,
|
|
4536
4569
|
status: "success",
|
|
@@ -4547,6 +4580,19 @@ async function findFilesWithRipgrep(params) {
|
|
|
4547
4580
|
},
|
|
4548
4581
|
{ content: [{ type: "text", text }] }
|
|
4549
4582
|
);
|
|
4583
|
+
params.onTelemetry?.({
|
|
4584
|
+
emittedLineCount: relativePaths.length,
|
|
4585
|
+
limit: params.limit,
|
|
4586
|
+
limitReached,
|
|
4587
|
+
parsedRecordCount: allPaths.length,
|
|
4588
|
+
rawOutputBytes: Buffer.byteLength(result.stdout, "utf8"),
|
|
4589
|
+
resultBytes: response.content.reduce(
|
|
4590
|
+
(total, item) => total + (item.type === "text" ? Buffer.byteLength(item.text, "utf8") : 0),
|
|
4591
|
+
0
|
|
4592
|
+
),
|
|
4593
|
+
resultCount: relativePaths.length
|
|
4594
|
+
});
|
|
4595
|
+
return response;
|
|
4550
4596
|
}
|
|
4551
4597
|
function createFindFilesTool() {
|
|
4552
4598
|
return zodTool({
|
|
@@ -4559,7 +4605,7 @@ function createFindFilesTool() {
|
|
|
4559
4605
|
path: z5.string().min(1).describe(
|
|
4560
4606
|
"Directory or file path in the sandbox workspace. Defaults to the workspace root."
|
|
4561
4607
|
).optional(),
|
|
4562
|
-
limit: z5.coerce.number().int().min(1).describe("Maximum number of file paths to return. Defaults to
|
|
4608
|
+
limit: z5.coerce.number().int().min(1).describe("Maximum number of file paths to return. Defaults to 100.").optional()
|
|
4563
4609
|
}),
|
|
4564
4610
|
outputSchema: juniorToolResultSchema,
|
|
4565
4611
|
execute: async () => {
|
|
@@ -4612,6 +4658,7 @@ async function grepFiles(params) {
|
|
|
4612
4658
|
ignoreCase: params.ignoreCase,
|
|
4613
4659
|
limit,
|
|
4614
4660
|
literal: params.literal,
|
|
4661
|
+
onTelemetry: params.onTelemetry,
|
|
4615
4662
|
path: params.path,
|
|
4616
4663
|
pattern: params.pattern,
|
|
4617
4664
|
root,
|
|
@@ -4759,7 +4806,13 @@ async function grepFilesWithRipgrep(params) {
|
|
|
4759
4806
|
throw error;
|
|
4760
4807
|
}
|
|
4761
4808
|
const location = getRipgrepSearchLocation(params.root, rootIsDirectory);
|
|
4762
|
-
const args = [
|
|
4809
|
+
const args = [
|
|
4810
|
+
"--json",
|
|
4811
|
+
"--line-number",
|
|
4812
|
+
"--hidden",
|
|
4813
|
+
"--max-count",
|
|
4814
|
+
String(params.limit + 1)
|
|
4815
|
+
];
|
|
4763
4816
|
if (params.ignoreCase) {
|
|
4764
4817
|
args.push("--ignore-case");
|
|
4765
4818
|
}
|
|
@@ -4779,7 +4832,8 @@ async function grepFilesWithRipgrep(params) {
|
|
|
4779
4832
|
const result = await params.runCommand({
|
|
4780
4833
|
cmd: "rg",
|
|
4781
4834
|
args,
|
|
4782
|
-
cwd: location.cwd
|
|
4835
|
+
cwd: location.cwd,
|
|
4836
|
+
timeoutMs: DEFAULT_SEARCH_COMMAND_TIMEOUT_MS
|
|
4783
4837
|
});
|
|
4784
4838
|
if (result.exitCode !== 0 && result.exitCode !== 1) {
|
|
4785
4839
|
const detail = result.stderr.trim() || result.stdout.trim() || "command failed";
|
|
@@ -4793,6 +4847,7 @@ async function grepFilesWithRipgrep(params) {
|
|
|
4793
4847
|
const recordsByPath = /* @__PURE__ */ new Map();
|
|
4794
4848
|
const pathOrder = [];
|
|
4795
4849
|
let totalMatches = 0;
|
|
4850
|
+
let parsedRecordCount = 0;
|
|
4796
4851
|
for (const rawLine of normalizeToLf(result.stdout).split("\n")) {
|
|
4797
4852
|
if (!rawLine) {
|
|
4798
4853
|
continue;
|
|
@@ -4803,6 +4858,7 @@ async function grepFilesWithRipgrep(params) {
|
|
|
4803
4858
|
} catch (error) {
|
|
4804
4859
|
throw new Error("ripgrep returned invalid JSON output", { cause: error });
|
|
4805
4860
|
}
|
|
4861
|
+
parsedRecordCount += 1;
|
|
4806
4862
|
if (record.type !== "match" && record.type !== "context") {
|
|
4807
4863
|
continue;
|
|
4808
4864
|
}
|
|
@@ -4884,7 +4940,7 @@ async function grepFilesWithRipgrep(params) {
|
|
|
4884
4940
|
if (bounded.truncated) {
|
|
4885
4941
|
notices.push(`${MAX_TEXT_CHARS} character output limit reached.`);
|
|
4886
4942
|
}
|
|
4887
|
-
|
|
4943
|
+
const response = makeStructuredToolResult({
|
|
4888
4944
|
ok: true,
|
|
4889
4945
|
status: "success",
|
|
4890
4946
|
target: params.path ?? ".",
|
|
@@ -4903,6 +4959,19 @@ async function grepFilesWithRipgrep(params) {
|
|
|
4903
4959
|
...matchLimitReached ? { match_limit_reached: params.limit } : {},
|
|
4904
4960
|
...lineTruncated ? { line_truncated: true } : {}
|
|
4905
4961
|
});
|
|
4962
|
+
params.onTelemetry?.({
|
|
4963
|
+
emittedLineCount: output.length,
|
|
4964
|
+
limit: params.limit,
|
|
4965
|
+
limitReached: matchLimitReached,
|
|
4966
|
+
parsedRecordCount,
|
|
4967
|
+
rawOutputBytes: Buffer.byteLength(result.stdout, "utf8"),
|
|
4968
|
+
resultBytes: response.content.reduce(
|
|
4969
|
+
(total, item) => total + (item.type === "text" ? Buffer.byteLength(item.text, "utf8") : 0),
|
|
4970
|
+
0
|
|
4971
|
+
),
|
|
4972
|
+
resultCount: matchCount
|
|
4973
|
+
});
|
|
4974
|
+
return response;
|
|
4906
4975
|
}
|
|
4907
4976
|
function createGrepTool() {
|
|
4908
4977
|
return zodTool({
|
|
@@ -5242,11 +5311,12 @@ function createSandbox(options) {
|
|
|
5242
5311
|
onSandboxPrepare: options.prepare,
|
|
5243
5312
|
onSandboxRefChanged: options.onSandboxRefChanged
|
|
5244
5313
|
});
|
|
5245
|
-
const createToolCallContext = (signal) => {
|
|
5314
|
+
const createToolCallContext = (signal, setToolCallSpanAttributes) => {
|
|
5246
5315
|
let fileSystemPromise;
|
|
5247
5316
|
let commandRunnerPromise;
|
|
5248
5317
|
return {
|
|
5249
5318
|
signal,
|
|
5319
|
+
setToolCallSpanAttributes,
|
|
5250
5320
|
fileSystem() {
|
|
5251
5321
|
signal?.throwIfAborted();
|
|
5252
5322
|
return fileSystemPromise ??= runtime.tools().then(({ fs: fs5 }) => {
|
|
@@ -5267,10 +5337,31 @@ function createSandbox(options) {
|
|
|
5267
5337
|
};
|
|
5268
5338
|
};
|
|
5269
5339
|
const withSandboxSpan = (name, op, attributes, callback) => withSpan(name, op, traceContext, callback, attributes);
|
|
5270
|
-
const withSandboxToolSpan = (name, op, attributes, callback) => withSandboxSpan(name, op, attributes, async () => {
|
|
5340
|
+
const withSandboxToolSpan = (name, op, attributes, callback) => withSandboxSpan(name, op, attributes, async (setSpanAttributes2) => {
|
|
5271
5341
|
await runtime.refreshNetworkPolicy(getTracePropagationHeaders());
|
|
5272
|
-
return await callback();
|
|
5342
|
+
return await callback(setSpanAttributes2);
|
|
5273
5343
|
});
|
|
5344
|
+
const searchTelemetryAttributes = (telemetry) => ({
|
|
5345
|
+
"app.sandbox.search.raw_output_bytes": telemetry.rawOutputBytes,
|
|
5346
|
+
"app.sandbox.search.parsed_records": telemetry.parsedRecordCount,
|
|
5347
|
+
"app.sandbox.search.result_count": telemetry.resultCount,
|
|
5348
|
+
"app.sandbox.search.emitted_lines": telemetry.emittedLineCount,
|
|
5349
|
+
"app.sandbox.search.result_bytes": telemetry.resultBytes,
|
|
5350
|
+
"app.sandbox.search.limit": telemetry.limit,
|
|
5351
|
+
"app.sandbox.search.limit_reached": telemetry.limitReached
|
|
5352
|
+
});
|
|
5353
|
+
const recordSearchTelemetry = (telemetry, setSearchSpanAttributes, setToolCallSpanAttributes) => {
|
|
5354
|
+
const attributes = searchTelemetryAttributes(telemetry);
|
|
5355
|
+
for (const setAttributes of [
|
|
5356
|
+
setSearchSpanAttributes,
|
|
5357
|
+
setToolCallSpanAttributes
|
|
5358
|
+
]) {
|
|
5359
|
+
try {
|
|
5360
|
+
setAttributes?.(attributes);
|
|
5361
|
+
} catch {
|
|
5362
|
+
}
|
|
5363
|
+
}
|
|
5364
|
+
};
|
|
5274
5365
|
const logSandboxBootRequest = (trigger, details = {}) => {
|
|
5275
5366
|
if (runtime.sandboxRef()) {
|
|
5276
5367
|
return;
|
|
@@ -5515,10 +5606,15 @@ function createSandbox(options) {
|
|
|
5515
5606
|
{
|
|
5516
5607
|
"app.sandbox.pattern.length": pattern.length
|
|
5517
5608
|
},
|
|
5518
|
-
async () => {
|
|
5609
|
+
async (setSearchSpanAttributes) => {
|
|
5519
5610
|
const response = await grepFiles({
|
|
5520
5611
|
fs: fileSystem,
|
|
5521
5612
|
runCommand: await context.commandRunner(),
|
|
5613
|
+
onTelemetry: (telemetry) => recordSearchTelemetry(
|
|
5614
|
+
telemetry,
|
|
5615
|
+
setSearchSpanAttributes,
|
|
5616
|
+
context.setToolCallSpanAttributes
|
|
5617
|
+
),
|
|
5522
5618
|
pattern,
|
|
5523
5619
|
...typeof rawInput.path === "string" ? { path: rawInput.path } : {},
|
|
5524
5620
|
...typeof rawInput.glob === "string" ? { glob: rawInput.glob } : {},
|
|
@@ -5547,10 +5643,15 @@ function createSandbox(options) {
|
|
|
5547
5643
|
{
|
|
5548
5644
|
"app.sandbox.pattern.length": pattern.length
|
|
5549
5645
|
},
|
|
5550
|
-
async () => {
|
|
5646
|
+
async (setSearchSpanAttributes) => {
|
|
5551
5647
|
const response = await findFiles({
|
|
5552
5648
|
fs: fileSystem,
|
|
5553
5649
|
runCommand: await context.commandRunner(),
|
|
5650
|
+
onTelemetry: (telemetry) => recordSearchTelemetry(
|
|
5651
|
+
telemetry,
|
|
5652
|
+
setSearchSpanAttributes,
|
|
5653
|
+
context.setToolCallSpanAttributes
|
|
5654
|
+
),
|
|
5554
5655
|
pattern,
|
|
5555
5656
|
...typeof rawInput.path === "string" ? { path: rawInput.path } : {},
|
|
5556
5657
|
...limit ? { limit } : {}
|
|
@@ -5583,7 +5684,10 @@ function createSandbox(options) {
|
|
|
5583
5684
|
};
|
|
5584
5685
|
const execute = async (params) => {
|
|
5585
5686
|
const rawInput = params.input ?? {};
|
|
5586
|
-
const context = createToolCallContext(
|
|
5687
|
+
const context = createToolCallContext(
|
|
5688
|
+
params.signal,
|
|
5689
|
+
params.setToolCallSpanAttributes
|
|
5690
|
+
);
|
|
5587
5691
|
const bashCommand2 = params.toolName === "bash" ? String(rawInput.command ?? "").trim() : void 0;
|
|
5588
5692
|
if (params.toolName === "bash") {
|
|
5589
5693
|
if (!bashCommand2) {
|
|
@@ -6912,7 +7016,7 @@ async function loadSkillFromHost(availableSkills, skillName) {
|
|
|
6912
7016
|
skill_dir: skillDir,
|
|
6913
7017
|
working_directory: skillDir,
|
|
6914
7018
|
location: skillFilePath,
|
|
6915
|
-
path_resolution:
|
|
7019
|
+
path_resolution: sandboxSkillPathResolution(skill.name),
|
|
6916
7020
|
instructions: loaded.body
|
|
6917
7021
|
};
|
|
6918
7022
|
}
|
|
@@ -8540,20 +8644,156 @@ function extractCanvasId(input) {
|
|
|
8540
8644
|
}
|
|
8541
8645
|
}
|
|
8542
8646
|
|
|
8543
|
-
// src/chat/slack/tools/canvas/
|
|
8647
|
+
// src/chat/slack/tools/canvas/markdown.ts
|
|
8648
|
+
function getListType(marker) {
|
|
8649
|
+
return /^\d/.test(marker) ? "numbered" : "bullet";
|
|
8650
|
+
}
|
|
8651
|
+
function getPlainListMarker(marker, type) {
|
|
8652
|
+
return type === "numbered" ? `${marker.match(/^\d+/)?.[0] ?? "1"}:` : "\u2022";
|
|
8653
|
+
}
|
|
8654
|
+
function getIndentWidth(whitespace, startColumn = 0) {
|
|
8655
|
+
let column = startColumn;
|
|
8656
|
+
for (const character of whitespace) {
|
|
8657
|
+
column += character === " " ? 4 - column % 4 : 1;
|
|
8658
|
+
}
|
|
8659
|
+
return column - startColumn;
|
|
8660
|
+
}
|
|
8661
|
+
function getLineIndent(line) {
|
|
8662
|
+
return getIndentWidth(line.match(/^[ \t]*/)?.[0] ?? "");
|
|
8663
|
+
}
|
|
8664
|
+
function getFence(line) {
|
|
8665
|
+
const match = line.match(/^([ \t]*)(`{3,}|~{3,})(.*)$/);
|
|
8666
|
+
const run = match?.[2];
|
|
8667
|
+
if (!run) return void 0;
|
|
8668
|
+
return {
|
|
8669
|
+
fence: {
|
|
8670
|
+
marker: run[0],
|
|
8671
|
+
length: run.length
|
|
8672
|
+
},
|
|
8673
|
+
indent: getIndentWidth(match[1] ?? ""),
|
|
8674
|
+
suffix: match[3] ?? ""
|
|
8675
|
+
};
|
|
8676
|
+
}
|
|
8677
|
+
function isListBlockIndent(indent, listItems2) {
|
|
8678
|
+
return listItems2.some(
|
|
8679
|
+
(item) => indent >= item.contentIndent && indent <= item.contentIndent + 3
|
|
8680
|
+
);
|
|
8681
|
+
}
|
|
8682
|
+
function canOpenFence(fenceLine, listItems2) {
|
|
8683
|
+
return fenceLine.indent <= 3 || isListBlockIndent(fenceLine.indent, listItems2);
|
|
8684
|
+
}
|
|
8685
|
+
function unwrapNestedBlockquote(line, listItems2, maxQuoteDepth = Number.POSITIVE_INFINITY) {
|
|
8686
|
+
const match = line.match(/^([ \t]+)((?:>[ \t]*)+)(.*)$/);
|
|
8687
|
+
if (!match || !isListBlockIndent(getIndentWidth(match[1] ?? ""), listItems2)) {
|
|
8688
|
+
return { line, quoteDepth: 0 };
|
|
8689
|
+
}
|
|
8690
|
+
let quotePrefix = match[2] ?? "";
|
|
8691
|
+
const quoteDepth = Math.min(
|
|
8692
|
+
quotePrefix.match(/>/g)?.length ?? 0,
|
|
8693
|
+
maxQuoteDepth
|
|
8694
|
+
);
|
|
8695
|
+
for (let index = 0; index < quoteDepth; index += 1) {
|
|
8696
|
+
quotePrefix = quotePrefix.replace(/^>[ \t]*/, "");
|
|
8697
|
+
}
|
|
8698
|
+
return {
|
|
8699
|
+
line: `${match[1]}${quotePrefix}${match[3]}`,
|
|
8700
|
+
quoteDepth
|
|
8701
|
+
};
|
|
8702
|
+
}
|
|
8544
8703
|
function normalizeCanvasMarkdown(markdown) {
|
|
8545
8704
|
let normalizedHeadingCount = 0;
|
|
8546
|
-
|
|
8547
|
-
|
|
8705
|
+
let normalizedMixedListCount = 0;
|
|
8706
|
+
let unwrappedBlockquoteCount = 0;
|
|
8707
|
+
let openFence;
|
|
8708
|
+
const listItems2 = [];
|
|
8709
|
+
const lines = markdown.split("\n").map((originalLine) => {
|
|
8710
|
+
if (openFence) {
|
|
8711
|
+
const unwrapped2 = openFence.quoteDepth > 0 ? unwrapNestedBlockquote(
|
|
8712
|
+
originalLine,
|
|
8713
|
+
listItems2,
|
|
8714
|
+
openFence.quoteDepth
|
|
8715
|
+
) : { line: originalLine, quoteDepth: 0 };
|
|
8716
|
+
if (unwrapped2.quoteDepth > 0) {
|
|
8717
|
+
unwrappedBlockquoteCount += 1;
|
|
8718
|
+
}
|
|
8719
|
+
const fenceLine2 = getFence(unwrapped2.line);
|
|
8720
|
+
if (fenceLine2?.fence.marker === openFence.marker && fenceLine2.fence.length >= openFence.length && !fenceLine2.suffix.trim()) {
|
|
8721
|
+
openFence = void 0;
|
|
8722
|
+
}
|
|
8723
|
+
return unwrapped2.line;
|
|
8724
|
+
}
|
|
8725
|
+
const unwrapped = unwrapNestedBlockquote(originalLine, listItems2);
|
|
8726
|
+
if (unwrapped.quoteDepth > 0) {
|
|
8727
|
+
unwrappedBlockquoteCount += 1;
|
|
8728
|
+
}
|
|
8729
|
+
const line = unwrapped.line;
|
|
8730
|
+
const fenceLine = getFence(line);
|
|
8731
|
+
if (fenceLine && canOpenFence(fenceLine, listItems2)) {
|
|
8732
|
+
const rootListContentIndent2 = listItems2[0]?.contentIndent;
|
|
8733
|
+
if (rootListContentIndent2 !== void 0 && fenceLine.indent < rootListContentIndent2) {
|
|
8734
|
+
listItems2.length = 0;
|
|
8735
|
+
}
|
|
8736
|
+
openFence = {
|
|
8737
|
+
...fenceLine.fence,
|
|
8738
|
+
quoteDepth: unwrapped.quoteDepth
|
|
8739
|
+
};
|
|
8740
|
+
return line;
|
|
8741
|
+
}
|
|
8742
|
+
const listMatch = line.match(/^([ \t]*)([-+*]|\d+[.)])([ \t]+)(.*)$/);
|
|
8743
|
+
if (listMatch) {
|
|
8744
|
+
const [, whitespace = "", marker = "", gap = "", rawContent = ""] = listMatch;
|
|
8745
|
+
const indent = getIndentWidth(whitespace);
|
|
8746
|
+
const type = getListType(marker);
|
|
8747
|
+
const markerEnd = indent + getIndentWidth(marker);
|
|
8748
|
+
const contentIndent = markerEnd + getIndentWidth(gap, markerEnd);
|
|
8749
|
+
const contentMatch = rawContent.match(/^(?:>[ \t]*)+(.*)$/);
|
|
8750
|
+
const content = contentMatch?.[1] ?? rawContent;
|
|
8751
|
+
if (contentMatch) {
|
|
8752
|
+
unwrappedBlockquoteCount += 1;
|
|
8753
|
+
}
|
|
8754
|
+
while (listItems2.length > 0 && listItems2[listItems2.length - 1].indent >= indent) {
|
|
8755
|
+
listItems2.pop();
|
|
8756
|
+
}
|
|
8757
|
+
const parent = listItems2[listItems2.length - 1];
|
|
8758
|
+
if (parent && (parent.unwrapped || parent.type !== type)) {
|
|
8759
|
+
listItems2.push({
|
|
8760
|
+
contentIndent,
|
|
8761
|
+
indent,
|
|
8762
|
+
type: parent.type,
|
|
8763
|
+
unwrapped: true
|
|
8764
|
+
});
|
|
8765
|
+
normalizedMixedListCount += 1;
|
|
8766
|
+
return `${whitespace}${getPlainListMarker(marker, type)}${gap}${content}`;
|
|
8767
|
+
}
|
|
8768
|
+
listItems2.push({ contentIndent, indent, type, unwrapped: false });
|
|
8769
|
+
return contentMatch ? `${whitespace}${marker}${gap}${content}` : line;
|
|
8770
|
+
}
|
|
8771
|
+
const rootListContentIndent = listItems2[0]?.contentIndent;
|
|
8772
|
+
if (rootListContentIndent !== void 0 && line.trim() && getLineIndent(line) < rootListContentIndent) {
|
|
8773
|
+
listItems2.length = 0;
|
|
8774
|
+
}
|
|
8775
|
+
const headingMatch = line.match(/^([ \t]*)#{4,}(?=[ \t])/);
|
|
8776
|
+
const headingIndent = headingMatch ? getIndentWidth(headingMatch[1] ?? "") : void 0;
|
|
8777
|
+
if (headingMatch && headingIndent !== void 0 && (headingIndent <= 3 || isListBlockIndent(headingIndent, listItems2))) {
|
|
8548
8778
|
normalizedHeadingCount += 1;
|
|
8549
|
-
return
|
|
8550
|
-
|
|
8551
|
-
|
|
8779
|
+
return line.replace(
|
|
8780
|
+
/^([ \t]*)#{4,}(?=[ \t])/,
|
|
8781
|
+
(_, indent) => `${indent}###`
|
|
8782
|
+
);
|
|
8783
|
+
}
|
|
8784
|
+
return line;
|
|
8785
|
+
});
|
|
8786
|
+
const normalizedCount = normalizedHeadingCount + normalizedMixedListCount + unwrappedBlockquoteCount;
|
|
8552
8787
|
return {
|
|
8553
|
-
markdown:
|
|
8554
|
-
|
|
8788
|
+
markdown: lines.join("\n"),
|
|
8789
|
+
normalizedCount,
|
|
8790
|
+
normalizedHeadingCount,
|
|
8791
|
+
normalizedMixedListCount,
|
|
8792
|
+
unwrappedBlockquoteCount
|
|
8555
8793
|
};
|
|
8556
8794
|
}
|
|
8795
|
+
|
|
8796
|
+
// src/chat/slack/tools/canvas/api.ts
|
|
8557
8797
|
async function createCanvas(input) {
|
|
8558
8798
|
const client = getSlackClient();
|
|
8559
8799
|
const normalizedChannelId = normalizeSlackConversationId(input.channelId);
|
|
@@ -8577,8 +8817,10 @@ async function createCanvas(input) {
|
|
|
8577
8817
|
"app.slack.canvas.has_channel_id": Boolean(input.channelId),
|
|
8578
8818
|
"app.slack.canvas.title_length": input.title.length,
|
|
8579
8819
|
"app.slack.canvas.markdown_length": normalizedContent.markdown.length,
|
|
8580
|
-
"app.slack.canvas.markdown_normalized": normalizedContent.
|
|
8581
|
-
"app.slack.canvas.normalized_heading_count": normalizedContent.normalizedHeadingCount
|
|
8820
|
+
"app.slack.canvas.markdown_normalized": normalizedContent.normalizedCount > 0,
|
|
8821
|
+
"app.slack.canvas.normalized_heading_count": normalizedContent.normalizedHeadingCount,
|
|
8822
|
+
"app.slack.canvas.normalized_mixed_list_count": normalizedContent.normalizedMixedListCount,
|
|
8823
|
+
"app.slack.canvas.unwrapped_blockquote_count": normalizedContent.unwrappedBlockquoteCount
|
|
8582
8824
|
}
|
|
8583
8825
|
}
|
|
8584
8826
|
);
|
|
@@ -8654,8 +8896,10 @@ async function writeCanvasMarkdown(input) {
|
|
|
8654
8896
|
"app.slack.canvas.canvas_id_prefix": input.canvasId.slice(0, 1),
|
|
8655
8897
|
"app.slack.canvas.operation": "replace",
|
|
8656
8898
|
"app.slack.canvas.markdown_length": normalizedContent.markdown.length,
|
|
8657
|
-
"app.slack.canvas.markdown_normalized": normalizedContent.
|
|
8658
|
-
"app.slack.canvas.normalized_heading_count": normalizedContent.normalizedHeadingCount
|
|
8899
|
+
"app.slack.canvas.markdown_normalized": normalizedContent.normalizedCount > 0,
|
|
8900
|
+
"app.slack.canvas.normalized_heading_count": normalizedContent.normalizedHeadingCount,
|
|
8901
|
+
"app.slack.canvas.normalized_mixed_list_count": normalizedContent.normalizedMixedListCount,
|
|
8902
|
+
"app.slack.canvas.unwrapped_blockquote_count": normalizedContent.unwrappedBlockquoteCount
|
|
8659
8903
|
}
|
|
8660
8904
|
}
|
|
8661
8905
|
);
|
|
@@ -11056,7 +11300,7 @@ function createToolState(hooks, context) {
|
|
|
11056
11300
|
}
|
|
11057
11301
|
};
|
|
11058
11302
|
}
|
|
11059
|
-
function createTools(availableSkills, hooks = {}, context) {
|
|
11303
|
+
function createTools(availableSkills, hooks = {}, context, options = {}) {
|
|
11060
11304
|
const state = createToolState(hooks, context);
|
|
11061
11305
|
const slackContext = getSlackToolContext(context);
|
|
11062
11306
|
const slackSourceCapabilities = slackContext ? resolveChannelCapabilities(slackContext.sourceChannelId) : void 0;
|
|
@@ -11064,9 +11308,11 @@ function createTools(availableSkills, hooks = {}, context) {
|
|
|
11064
11308
|
slackContext && slackSourceCapabilities?.canSendFiles
|
|
11065
11309
|
);
|
|
11066
11310
|
const tools = {
|
|
11067
|
-
|
|
11068
|
-
|
|
11069
|
-
|
|
11311
|
+
...options.includeLoadSkill === false ? {} : {
|
|
11312
|
+
loadSkill: createLoadSkillTool(availableSkills, {
|
|
11313
|
+
onSkillLoaded: hooks.onSkillLoaded
|
|
11314
|
+
})
|
|
11315
|
+
},
|
|
11070
11316
|
reportProgress: createReportProgressTool(),
|
|
11071
11317
|
systemTime: createSystemTimeTool(),
|
|
11072
11318
|
bash: createBashTool(),
|
|
@@ -12175,7 +12421,8 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxTools,
|
|
|
12175
12421
|
const result = isSandbox ? await sandboxTools.execute({
|
|
12176
12422
|
toolName,
|
|
12177
12423
|
input: sandboxInput,
|
|
12178
|
-
...signal ? { signal } : {}
|
|
12424
|
+
...signal ? { signal } : {},
|
|
12425
|
+
...toolName === "grep" || toolName === "findFiles" ? { setToolCallSpanAttributes: setSpanAttributes2 } : {}
|
|
12179
12426
|
}) : await toolDef.execute(toolInput, {
|
|
12180
12427
|
experimental_context: sandbox,
|
|
12181
12428
|
...signal ? { signal } : {},
|
|
@@ -13322,6 +13569,27 @@ function createPluginEgress(deps) {
|
|
|
13322
13569
|
}
|
|
13323
13570
|
|
|
13324
13571
|
// src/chat/agent/tools.ts
|
|
13572
|
+
async function tryRecordSkillLoadStat(skill, spanContext) {
|
|
13573
|
+
if (!process.env.DATABASE_URL) return;
|
|
13574
|
+
try {
|
|
13575
|
+
await incrementStat({
|
|
13576
|
+
namespace: skill.pluginProvider ?? "junior",
|
|
13577
|
+
metric: "skill_load",
|
|
13578
|
+
name: skill.name
|
|
13579
|
+
});
|
|
13580
|
+
} catch (error) {
|
|
13581
|
+
logWarn(
|
|
13582
|
+
"skill_load_stat_failed",
|
|
13583
|
+
spanContext,
|
|
13584
|
+
{
|
|
13585
|
+
"app.skill.name": skill.name,
|
|
13586
|
+
"app.plugin.name": skill.pluginProvider,
|
|
13587
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
13588
|
+
},
|
|
13589
|
+
"Failed to record skill load stat"
|
|
13590
|
+
);
|
|
13591
|
+
}
|
|
13592
|
+
}
|
|
13325
13593
|
async function wireAgentTools(args) {
|
|
13326
13594
|
const runSource = args.routing.source;
|
|
13327
13595
|
const credentialUserId = args.routing.credentialContext ? credentialUserSubjectId(args.routing.credentialContext) : void 0;
|
|
@@ -13396,6 +13664,9 @@ async function wireAgentTools(args) {
|
|
|
13396
13664
|
const loadableSkills = args.availableSkills.filter(
|
|
13397
13665
|
(skill) => skill.disableModelInvocation !== true || skill.name === args.invokedSkill?.name
|
|
13398
13666
|
);
|
|
13667
|
+
const explicitSkillLoaded = Boolean(
|
|
13668
|
+
args.invokedSkill && args.activeSkills.some((skill) => skill.name === args.invokedSkill?.name)
|
|
13669
|
+
);
|
|
13399
13670
|
const commonToolRuntimeContext = {
|
|
13400
13671
|
conversationId: args.conversationId,
|
|
13401
13672
|
userText: args.userInput,
|
|
@@ -13476,6 +13747,7 @@ async function wireAgentTools(args) {
|
|
|
13476
13747
|
if (await mcpToolManager.activateForSkill(effective)) {
|
|
13477
13748
|
await args.recordConnectedMcpProvider(effective.pluginProvider);
|
|
13478
13749
|
}
|
|
13750
|
+
await tryRecordSkillLoadStat(effective, args.spanContext);
|
|
13479
13751
|
if (mcpAuth.getPendingPause()) {
|
|
13480
13752
|
return void 0;
|
|
13481
13753
|
}
|
|
@@ -13494,7 +13766,8 @@ async function wireAgentTools(args) {
|
|
|
13494
13766
|
};
|
|
13495
13767
|
}
|
|
13496
13768
|
},
|
|
13497
|
-
toolRuntimeContext
|
|
13769
|
+
toolRuntimeContext,
|
|
13770
|
+
{ includeLoadSkill: !explicitSkillLoaded }
|
|
13498
13771
|
);
|
|
13499
13772
|
const plannedToolExposure = planToolExposure(
|
|
13500
13773
|
tools
|
|
@@ -13948,7 +14221,8 @@ async function summarizeContext(args, deps) {
|
|
|
13948
14221
|
"- The immediate next action",
|
|
13949
14222
|
"- Durable constraints, user preferences, IDs, URLs, artifacts, sandbox references, auth state, and unresolved blockers",
|
|
13950
14223
|
"",
|
|
13951
|
-
"Do not write a user-facing reply
|
|
14224
|
+
"Do not write a user-facing reply or announce a plan.",
|
|
14225
|
+
"Treat the task as complete only when the source history contains concrete evidence that every requested outcome occurred. Do not infer completion from intent, plans, progress, intermediate artifacts, or adjacent tool activity. If evidence is missing or ambiguous, preserve the task as unfinished and state the next required action."
|
|
13952
14226
|
] : [
|
|
13953
14227
|
"You are performing a CONTEXT CHECKPOINT COMPACTION for Junior.",
|
|
13954
14228
|
"Create a concise continuation summary for the agent that will continue this Slack thread.",
|
|
@@ -14541,6 +14815,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
14541
14815
|
skillSandbox,
|
|
14542
14816
|
syncLoadedSkillNamesForResume
|
|
14543
14817
|
});
|
|
14818
|
+
const explicitSkill = invokedSkill ? activeSkills.find((skill) => skill.name === invokedSkill.name) ?? null : null;
|
|
14544
14819
|
const { routerBlocks, userContentParts } = buildPromptInput(input);
|
|
14545
14820
|
const preAgentPromptMessages = () => existingSessionRecord?.piMessages ?? [...input.piMessages ?? []];
|
|
14546
14821
|
const storedTurnRoute = await loadTurnRoute({ conversationId, turnId });
|
|
@@ -14771,7 +15046,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
14771
15046
|
conversationPrivacy,
|
|
14772
15047
|
existingSessionPiMessages: existingSessionRecord?.piMessages,
|
|
14773
15048
|
existingTurnStartMessageIndex: existingSessionRecord?.turnStartMessageIndex,
|
|
14774
|
-
|
|
15049
|
+
explicitSkill,
|
|
14775
15050
|
priorPiMessages,
|
|
14776
15051
|
resumedFromSessionRecord,
|
|
14777
15052
|
routing,
|