@probelabs/probe 0.6.0-rc294 → 0.6.0-rc296
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/README.md +7 -0
- package/bin/binaries/{probe-v0.6.0-rc294-aarch64-apple-darwin.tar.gz → probe-v0.6.0-rc296-aarch64-apple-darwin.tar.gz} +0 -0
- package/bin/binaries/{probe-v0.6.0-rc294-aarch64-unknown-linux-musl.tar.gz → probe-v0.6.0-rc296-aarch64-unknown-linux-musl.tar.gz} +0 -0
- package/bin/binaries/{probe-v0.6.0-rc294-x86_64-apple-darwin.tar.gz → probe-v0.6.0-rc296-x86_64-apple-darwin.tar.gz} +0 -0
- package/bin/binaries/{probe-v0.6.0-rc294-x86_64-pc-windows-msvc.zip → probe-v0.6.0-rc296-x86_64-pc-windows-msvc.zip} +0 -0
- package/bin/binaries/{probe-v0.6.0-rc294-x86_64-unknown-linux-musl.tar.gz → probe-v0.6.0-rc296-x86_64-unknown-linux-musl.tar.gz} +0 -0
- package/build/agent/ProbeAgent.d.ts +10 -0
- package/build/agent/ProbeAgent.js +868 -29
- package/build/agent/mcp/client.js +81 -4
- package/build/agent/mcp/xmlBridge.js +11 -0
- package/build/agent/otelLogBridge.js +184 -0
- package/build/agent/simpleTelemetry.js +8 -0
- package/build/delegate.js +75 -6
- package/build/index.js +6 -2
- package/build/tools/common.js +84 -11
- package/build/tools/vercel.js +78 -18
- package/cjs/agent/ProbeAgent.cjs +1004 -48
- package/cjs/agent/simpleTelemetry.cjs +112 -0
- package/cjs/index.cjs +1116 -48
- package/index.d.ts +26 -0
- package/package.json +1 -1
- package/src/agent/ProbeAgent.d.ts +10 -0
- package/src/agent/ProbeAgent.js +868 -29
- package/src/agent/mcp/client.js +81 -4
- package/src/agent/mcp/xmlBridge.js +11 -0
- package/src/agent/otelLogBridge.js +184 -0
- package/src/agent/simpleTelemetry.js +8 -0
- package/src/delegate.js +75 -6
- package/src/index.js +6 -2
- package/src/tools/common.js +84 -11
- package/src/tools/vercel.js +78 -18
package/cjs/index.cjs
CHANGED
|
@@ -27051,14 +27051,64 @@ function detectStuckResponse(response) {
|
|
|
27051
27051
|
}
|
|
27052
27052
|
return false;
|
|
27053
27053
|
}
|
|
27054
|
+
function splitQuotedString(input) {
|
|
27055
|
+
const tokens = [];
|
|
27056
|
+
let current2 = "";
|
|
27057
|
+
let inQuote = null;
|
|
27058
|
+
let i = 0;
|
|
27059
|
+
while (i < input.length) {
|
|
27060
|
+
const ch = input[i];
|
|
27061
|
+
if (inQuote) {
|
|
27062
|
+
if (ch === "\\" && i + 1 < input.length) {
|
|
27063
|
+
current2 += input[i + 1];
|
|
27064
|
+
i += 2;
|
|
27065
|
+
continue;
|
|
27066
|
+
}
|
|
27067
|
+
if (ch === inQuote) {
|
|
27068
|
+
inQuote = null;
|
|
27069
|
+
i++;
|
|
27070
|
+
continue;
|
|
27071
|
+
}
|
|
27072
|
+
current2 += ch;
|
|
27073
|
+
i++;
|
|
27074
|
+
} else {
|
|
27075
|
+
if (ch === '"' || ch === "'") {
|
|
27076
|
+
inQuote = ch;
|
|
27077
|
+
i++;
|
|
27078
|
+
continue;
|
|
27079
|
+
}
|
|
27080
|
+
if (/[\s,]/.test(ch)) {
|
|
27081
|
+
if (current2.length > 0) {
|
|
27082
|
+
tokens.push(current2);
|
|
27083
|
+
current2 = "";
|
|
27084
|
+
}
|
|
27085
|
+
i++;
|
|
27086
|
+
continue;
|
|
27087
|
+
}
|
|
27088
|
+
current2 += ch;
|
|
27089
|
+
i++;
|
|
27090
|
+
}
|
|
27091
|
+
}
|
|
27092
|
+
if (current2.length > 0) {
|
|
27093
|
+
tokens.push(current2);
|
|
27094
|
+
}
|
|
27095
|
+
return tokens;
|
|
27096
|
+
}
|
|
27054
27097
|
function parseTargets(targets) {
|
|
27055
27098
|
if (!targets || typeof targets !== "string") {
|
|
27056
27099
|
return [];
|
|
27057
27100
|
}
|
|
27058
|
-
return targets
|
|
27101
|
+
return splitQuotedString(targets);
|
|
27059
27102
|
}
|
|
27060
27103
|
function parseAndResolvePaths(pathStr, cwd) {
|
|
27061
27104
|
if (!pathStr) return [];
|
|
27105
|
+
if (/["']/.test(pathStr)) {
|
|
27106
|
+
const paths2 = splitQuotedString(pathStr);
|
|
27107
|
+
return paths2.map((p) => {
|
|
27108
|
+
if ((0, import_path5.isAbsolute)(p)) return p;
|
|
27109
|
+
return cwd ? (0, import_path5.resolve)(cwd, p) : p;
|
|
27110
|
+
});
|
|
27111
|
+
}
|
|
27062
27112
|
let paths = pathStr.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
|
|
27063
27113
|
paths = paths.flatMap((p) => {
|
|
27064
27114
|
if (!/\s/.test(p)) return [p];
|
|
@@ -27068,9 +27118,7 @@ function parseAndResolvePaths(pathStr, cwd) {
|
|
|
27068
27118
|
return allLookLikePaths ? parts : [p];
|
|
27069
27119
|
});
|
|
27070
27120
|
return paths.map((p) => {
|
|
27071
|
-
if ((0, import_path5.isAbsolute)(p))
|
|
27072
|
-
return p;
|
|
27073
|
-
}
|
|
27121
|
+
if ((0, import_path5.isAbsolute)(p)) return p;
|
|
27074
27122
|
return cwd ? (0, import_path5.resolve)(cwd, p) : p;
|
|
27075
27123
|
});
|
|
27076
27124
|
}
|
|
@@ -27103,7 +27151,7 @@ var init_common = __esm({
|
|
|
27103
27151
|
searchSchema = external_exports2.object({
|
|
27104
27152
|
query: external_exports2.string().describe("Search query \u2014 natural language questions or Elasticsearch-style keywords both work. For keywords: use quotes for exact phrases, AND/OR for boolean logic, - for negation. Probe handles stemming and camelCase/snake_case splitting automatically, so do NOT try case or style variations of the same keyword."),
|
|
27105
27153
|
path: external_exports2.string().optional().default(".").describe('Path to search in. For dependencies use "go:github.com/owner/repo", "js:package_name", or "rust:cargo_name" etc.'),
|
|
27106
|
-
exact: external_exports2.boolean().optional().default(false).describe(
|
|
27154
|
+
exact: external_exports2.boolean().optional().default(false).describe(`Default (false) enables stemming and keyword splitting for exploratory search - "getUserData" matches "get", "user", "data", etc. Set true for precise symbol lookup OR when searching for strings with punctuation/quotes/empty values (e.g. 'description: ""' \u2014 BM25 strips punctuation so exact=true is required for literal matching). Use true when you know the exact symbol name or need literal string matching.`),
|
|
27107
27155
|
maxTokens: external_exports2.number().nullable().optional().describe("Maximum tokens to return. Default is 20000. Set to null for unlimited results."),
|
|
27108
27156
|
session: external_exports2.string().optional().describe("Session ID for result caching and pagination. Pass the session ID from a previous search to get additional results (next page). Results already shown in a session are automatically excluded. Omit for a fresh search."),
|
|
27109
27157
|
nextPage: external_exports2.boolean().optional().default(false).describe("Set to true when requesting the next page of results. Requires passing the same session ID from the previous search output.")
|
|
@@ -73542,6 +73590,9 @@ function isMethodAllowed(methodName, allowedMethods, blockedMethods) {
|
|
|
73542
73590
|
}
|
|
73543
73591
|
function createTransport(serverConfig) {
|
|
73544
73592
|
const { transport, command, args, url: url2, env } = serverConfig;
|
|
73593
|
+
if (serverConfig.transportInstance) {
|
|
73594
|
+
return serverConfig.transportInstance;
|
|
73595
|
+
}
|
|
73545
73596
|
switch (transport) {
|
|
73546
73597
|
case "stdio":
|
|
73547
73598
|
return new import_stdio.StdioClientTransport({
|
|
@@ -73904,6 +73955,53 @@ var init_client = __esm({
|
|
|
73904
73955
|
throw error40;
|
|
73905
73956
|
}
|
|
73906
73957
|
}
|
|
73958
|
+
/**
|
|
73959
|
+
* Call graceful_stop on all MCP servers that expose it.
|
|
73960
|
+
* This signals agent-type MCP servers to wrap up their work.
|
|
73961
|
+
* @returns {Promise<Array<{server: string, success: boolean, error?: string}>>}
|
|
73962
|
+
*/
|
|
73963
|
+
async callGracefulStopAll() {
|
|
73964
|
+
const results = [];
|
|
73965
|
+
for (const [serverName, clientInfo] of this.clients) {
|
|
73966
|
+
const qualifiedName = `${serverName}_graceful_stop`;
|
|
73967
|
+
if (this.tools.has(qualifiedName)) {
|
|
73968
|
+
if (this.debug) {
|
|
73969
|
+
console.log(`[DEBUG] MCP callGracefulStopAll: calling graceful_stop on server "${serverName}"`);
|
|
73970
|
+
}
|
|
73971
|
+
try {
|
|
73972
|
+
const timeoutMs = 5e3;
|
|
73973
|
+
const timeoutPromise = new Promise(
|
|
73974
|
+
(_, reject2) => setTimeout(() => reject2(new Error("graceful_stop timeout")), timeoutMs)
|
|
73975
|
+
);
|
|
73976
|
+
await Promise.race([
|
|
73977
|
+
clientInfo.client.callTool({ name: "graceful_stop", arguments: {} }, void 0, { timeout: timeoutMs }),
|
|
73978
|
+
timeoutPromise
|
|
73979
|
+
]);
|
|
73980
|
+
results.push({ server: serverName, success: true });
|
|
73981
|
+
if (this.debug) {
|
|
73982
|
+
console.log(`[DEBUG] MCP callGracefulStopAll: server "${serverName}" acknowledged graceful_stop`);
|
|
73983
|
+
}
|
|
73984
|
+
} catch (e) {
|
|
73985
|
+
results.push({ server: serverName, success: false, error: e.message });
|
|
73986
|
+
if (this.debug) {
|
|
73987
|
+
console.log(`[DEBUG] MCP callGracefulStopAll: server "${serverName}" graceful_stop failed: ${e.message}`);
|
|
73988
|
+
}
|
|
73989
|
+
}
|
|
73990
|
+
}
|
|
73991
|
+
}
|
|
73992
|
+
if (this.debug) {
|
|
73993
|
+
const withStop = results.length;
|
|
73994
|
+
const total = this.clients.size;
|
|
73995
|
+
console.log(`[DEBUG] MCP callGracefulStopAll: ${withStop}/${total} servers had graceful_stop tool`);
|
|
73996
|
+
}
|
|
73997
|
+
this.recordMcpEvent("graceful_stop.sweep_completed", {
|
|
73998
|
+
servers_total: this.clients.size,
|
|
73999
|
+
servers_with_graceful_stop: results.length,
|
|
74000
|
+
servers_acknowledged: results.filter((r) => r.success).length,
|
|
74001
|
+
servers_failed: results.filter((r) => !r.success).length
|
|
74002
|
+
});
|
|
74003
|
+
return results;
|
|
74004
|
+
}
|
|
73907
74005
|
/**
|
|
73908
74006
|
* Get all available tools with their schemas
|
|
73909
74007
|
* @returns {Object} Map of tool name to tool definition
|
|
@@ -73931,10 +74029,29 @@ var init_client = __esm({
|
|
|
73931
74029
|
inputSchema: tool6.inputSchema,
|
|
73932
74030
|
execute: async (args) => {
|
|
73933
74031
|
const result = await this.callTool(name15, args);
|
|
73934
|
-
if (result.content
|
|
73935
|
-
return result
|
|
74032
|
+
if (!result.content || !result.content[0]) {
|
|
74033
|
+
return JSON.stringify(result);
|
|
74034
|
+
}
|
|
74035
|
+
const hasImage = result.content.some((block) => block.type === "image");
|
|
74036
|
+
if (hasImage) {
|
|
74037
|
+
return { _mcpContent: result.content };
|
|
73936
74038
|
}
|
|
73937
|
-
return
|
|
74039
|
+
return result.content[0].text;
|
|
74040
|
+
},
|
|
74041
|
+
// Convert MCP content blocks (including images) to Vercel AI SDK format
|
|
74042
|
+
toModelOutput: ({ output }) => {
|
|
74043
|
+
if (output && typeof output === "object" && output._mcpContent) {
|
|
74044
|
+
const parts = [];
|
|
74045
|
+
for (const block of output._mcpContent) {
|
|
74046
|
+
if (block.type === "text") {
|
|
74047
|
+
parts.push({ type: "text", text: block.text });
|
|
74048
|
+
} else if (block.type === "image") {
|
|
74049
|
+
parts.push({ type: "image-data", data: block.data, mediaType: block.mimeType });
|
|
74050
|
+
}
|
|
74051
|
+
}
|
|
74052
|
+
return { type: "content", value: parts };
|
|
74053
|
+
}
|
|
74054
|
+
return { type: "text", value: typeof output === "string" ? output : JSON.stringify(output) };
|
|
73938
74055
|
}
|
|
73939
74056
|
};
|
|
73940
74057
|
}
|
|
@@ -74114,6 +74231,16 @@ var init_xmlBridge = __esm({
|
|
|
74114
74231
|
isMcpTool(toolName) {
|
|
74115
74232
|
return toolName in this.mcpTools;
|
|
74116
74233
|
}
|
|
74234
|
+
/**
|
|
74235
|
+
* Call graceful_stop on all MCP servers that expose it.
|
|
74236
|
+
* @returns {Promise<Array>}
|
|
74237
|
+
*/
|
|
74238
|
+
async callGracefulStopAll() {
|
|
74239
|
+
if (this.mcpManager) {
|
|
74240
|
+
return this.mcpManager.callGracefulStopAll();
|
|
74241
|
+
}
|
|
74242
|
+
return [];
|
|
74243
|
+
}
|
|
74117
74244
|
/**
|
|
74118
74245
|
* Clean up MCP connections
|
|
74119
74246
|
*/
|
|
@@ -96673,6 +96800,7 @@ var init_ProbeAgent = __esm({
|
|
|
96673
96800
|
this.debug = options.debug || process.env.DEBUG === "1";
|
|
96674
96801
|
this.cancelled = false;
|
|
96675
96802
|
this._abortController = new AbortController();
|
|
96803
|
+
this._activeSubagents = /* @__PURE__ */ new Map();
|
|
96676
96804
|
this.tracer = options.tracer || null;
|
|
96677
96805
|
this.outline = !!options.outline;
|
|
96678
96806
|
this.searchDelegate = options.searchDelegate !== void 0 ? !!options.searchDelegate : true;
|
|
@@ -96781,6 +96909,35 @@ var init_ProbeAgent = __esm({
|
|
|
96781
96909
|
if (this.debug) {
|
|
96782
96910
|
console.log(`[DEBUG] Max operation timeout: ${this.maxOperationTimeout}ms`);
|
|
96783
96911
|
}
|
|
96912
|
+
this.timeoutBehavior = options.timeoutBehavior ?? (() => {
|
|
96913
|
+
const val = process.env.TIMEOUT_BEHAVIOR;
|
|
96914
|
+
if (val === "hard") return "hard";
|
|
96915
|
+
if (val === "negotiated") return "negotiated";
|
|
96916
|
+
return "graceful";
|
|
96917
|
+
})();
|
|
96918
|
+
this.gracefulTimeoutBonusSteps = options.gracefulTimeoutBonusSteps ?? (() => {
|
|
96919
|
+
const parsed = parseInt(process.env.GRACEFUL_TIMEOUT_BONUS_STEPS, 10);
|
|
96920
|
+
return isNaN(parsed) || parsed < 1 || parsed > 20 ? 4 : parsed;
|
|
96921
|
+
})();
|
|
96922
|
+
this.negotiatedTimeoutBudget = options.negotiatedTimeoutBudget ?? (() => {
|
|
96923
|
+
const parsed = parseInt(process.env.NEGOTIATED_TIMEOUT_BUDGET, 10);
|
|
96924
|
+
return isNaN(parsed) || parsed < 6e4 || parsed > 72e5 ? 18e5 : parsed;
|
|
96925
|
+
})();
|
|
96926
|
+
this.negotiatedTimeoutMaxRequests = options.negotiatedTimeoutMaxRequests ?? (() => {
|
|
96927
|
+
const parsed = parseInt(process.env.NEGOTIATED_TIMEOUT_MAX_REQUESTS, 10);
|
|
96928
|
+
return isNaN(parsed) || parsed < 1 || parsed > 10 ? 3 : parsed;
|
|
96929
|
+
})();
|
|
96930
|
+
this.negotiatedTimeoutMaxPerRequest = options.negotiatedTimeoutMaxPerRequest ?? (() => {
|
|
96931
|
+
const parsed = parseInt(process.env.NEGOTIATED_TIMEOUT_MAX_PER_REQUEST, 10);
|
|
96932
|
+
return isNaN(parsed) || parsed < 6e4 || parsed > 36e5 ? 6e5 : parsed;
|
|
96933
|
+
})();
|
|
96934
|
+
this.gracefulStopDeadline = options.gracefulStopDeadline ?? (() => {
|
|
96935
|
+
const parsed = parseInt(process.env.GRACEFUL_STOP_DEADLINE, 10);
|
|
96936
|
+
return isNaN(parsed) || parsed < 5e3 || parsed > 3e5 ? 45e3 : parsed;
|
|
96937
|
+
})();
|
|
96938
|
+
if (this.debug) {
|
|
96939
|
+
console.log(`[DEBUG] Timeout behavior: ${this.timeoutBehavior}, bonus steps: ${this.gracefulTimeoutBonusSteps}, graceful stop deadline: ${this.gracefulStopDeadline}ms`);
|
|
96940
|
+
}
|
|
96784
96941
|
this.retryConfig = options.retry || {};
|
|
96785
96942
|
this.retryManager = null;
|
|
96786
96943
|
this.fallbackConfig = options.fallback || null;
|
|
@@ -97131,6 +97288,18 @@ var init_ProbeAgent = __esm({
|
|
|
97131
97288
|
// Per-instance delegation limits
|
|
97132
97289
|
parentAbortSignal: this._abortController.signal,
|
|
97133
97290
|
// Propagate cancellation to delegations
|
|
97291
|
+
// Timeout settings for delegate subagents to inherit
|
|
97292
|
+
timeoutBehavior: this.timeoutBehavior,
|
|
97293
|
+
maxOperationTimeout: this.maxOperationTimeout,
|
|
97294
|
+
requestTimeout: this.requestTimeout,
|
|
97295
|
+
gracefulTimeoutBonusSteps: this.gracefulTimeoutBonusSteps,
|
|
97296
|
+
negotiatedTimeoutBudget: this.negotiatedTimeoutBudget,
|
|
97297
|
+
negotiatedTimeoutMaxRequests: this.negotiatedTimeoutMaxRequests,
|
|
97298
|
+
negotiatedTimeoutMaxPerRequest: this.negotiatedTimeoutMaxPerRequest,
|
|
97299
|
+
parentOperationStartTime: this._operationStartTime,
|
|
97300
|
+
// For remaining budget calculation
|
|
97301
|
+
onSubagentCreated: (sid, subagent) => this._registerSubagent(sid, subagent),
|
|
97302
|
+
onSubagentCompleted: (sid) => this._unregisterSubagent(sid),
|
|
97134
97303
|
outputBuffer: this._outputBuffer,
|
|
97135
97304
|
concurrencyLimiter: this.concurrencyLimiter,
|
|
97136
97305
|
// Global AI concurrency limiter
|
|
@@ -97714,12 +97883,16 @@ var init_ProbeAgent = __esm({
|
|
|
97714
97883
|
}, { once: true });
|
|
97715
97884
|
}
|
|
97716
97885
|
if (this.maxOperationTimeout && this.maxOperationTimeout > 0) {
|
|
97717
|
-
|
|
97718
|
-
|
|
97719
|
-
|
|
97720
|
-
|
|
97721
|
-
|
|
97722
|
-
|
|
97886
|
+
const gts = this._gracefulTimeoutState;
|
|
97887
|
+
if ((this.timeoutBehavior === "graceful" || this.timeoutBehavior === "negotiated") && gts) {
|
|
97888
|
+
} else {
|
|
97889
|
+
timeoutState.timeoutId = setTimeout(() => {
|
|
97890
|
+
controller.abort();
|
|
97891
|
+
if (this.debug) {
|
|
97892
|
+
console.log(`[DEBUG] Operation timed out after ${this.maxOperationTimeout}ms (max operation timeout)`);
|
|
97893
|
+
}
|
|
97894
|
+
}, this.maxOperationTimeout);
|
|
97895
|
+
}
|
|
97723
97896
|
}
|
|
97724
97897
|
try {
|
|
97725
97898
|
const useClaudeCode = this.clientApiProvider === "claude-code" || process.env.USE_CLAUDE_CODE === "true";
|
|
@@ -99098,6 +99271,7 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
99098
99271
|
} else {
|
|
99099
99272
|
options = schemaOrOptions || {};
|
|
99100
99273
|
}
|
|
99274
|
+
this._operationStartTime = Date.now();
|
|
99101
99275
|
try {
|
|
99102
99276
|
const oldHistoryLength = this.history.length;
|
|
99103
99277
|
if (this._outputBuffer && !options?._schemaFormatted && !options?._completionPromptProcessed) {
|
|
@@ -99178,7 +99352,10 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
99178
99352
|
}
|
|
99179
99353
|
}
|
|
99180
99354
|
let currentIteration = 0;
|
|
99181
|
-
let finalResult =
|
|
99355
|
+
let finalResult = null;
|
|
99356
|
+
const DEFAULT_MAX_ITER_MSG = "I was unable to complete your request due to reaching the maximum number of tool iterations.";
|
|
99357
|
+
const _toolCallLog = [];
|
|
99358
|
+
let abortSummaryTaken = false;
|
|
99182
99359
|
const baseMaxIterations = options._maxIterationsOverride || this.maxIterations || MAX_TOOL_ITERATIONS;
|
|
99183
99360
|
const maxIterations = options._maxIterationsOverride ? baseMaxIterations : options.schema ? baseMaxIterations + 4 : baseMaxIterations;
|
|
99184
99361
|
const isClaudeCode = this.clientApiProvider === "claude-code" || process.env.USE_CLAUDE_CODE === "true";
|
|
@@ -99310,6 +99487,228 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
99310
99487
|
}
|
|
99311
99488
|
let completionPromptInjected = false;
|
|
99312
99489
|
let preCompletionResult = null;
|
|
99490
|
+
const gracefulTimeoutState = {
|
|
99491
|
+
triggered: false,
|
|
99492
|
+
// Set to true when soft timeout fires
|
|
99493
|
+
bonusStepsUsed: 0,
|
|
99494
|
+
// Steps taken after soft timeout
|
|
99495
|
+
bonusStepsMax: this.gracefulTimeoutBonusSteps
|
|
99496
|
+
};
|
|
99497
|
+
this._gracefulTimeoutState = gracefulTimeoutState;
|
|
99498
|
+
const negotiatedTimeoutState = {
|
|
99499
|
+
extensionsUsed: 0,
|
|
99500
|
+
totalExtraTimeMs: 0,
|
|
99501
|
+
softTimeoutId: null,
|
|
99502
|
+
hardAbortTimeoutId: null,
|
|
99503
|
+
maxRequests: this.negotiatedTimeoutMaxRequests,
|
|
99504
|
+
maxPerRequestMs: this.negotiatedTimeoutMaxPerRequest,
|
|
99505
|
+
budgetMs: this.negotiatedTimeoutBudget,
|
|
99506
|
+
observerRunning: false,
|
|
99507
|
+
// true while observer LLM call is in flight
|
|
99508
|
+
extensionMessage: null,
|
|
99509
|
+
// message to show in prepareStep after extension granted
|
|
99510
|
+
startTime: Date.now()
|
|
99511
|
+
};
|
|
99512
|
+
this._negotiatedTimeoutState = negotiatedTimeoutState;
|
|
99513
|
+
const activeTools = /* @__PURE__ */ new Map();
|
|
99514
|
+
this._activeTools = activeTools;
|
|
99515
|
+
const onToolCall = (event) => {
|
|
99516
|
+
const key = event.toolCallId || `${event.name}:${JSON.stringify(event.args || {}).slice(0, 100)}`;
|
|
99517
|
+
if (event.status === "started") {
|
|
99518
|
+
activeTools.set(key, {
|
|
99519
|
+
name: event.name,
|
|
99520
|
+
args: event.args,
|
|
99521
|
+
startedAt: event.timestamp || (/* @__PURE__ */ new Date()).toISOString()
|
|
99522
|
+
});
|
|
99523
|
+
} else if (event.status === "completed" || event.status === "error") {
|
|
99524
|
+
activeTools.delete(key);
|
|
99525
|
+
}
|
|
99526
|
+
};
|
|
99527
|
+
this.events.on("toolCall", onToolCall);
|
|
99528
|
+
const runTimeoutObserver = async () => {
|
|
99529
|
+
if (negotiatedTimeoutState.observerRunning) return;
|
|
99530
|
+
negotiatedTimeoutState.observerRunning = true;
|
|
99531
|
+
const remainingRequests = negotiatedTimeoutState.maxRequests - negotiatedTimeoutState.extensionsUsed;
|
|
99532
|
+
const remainingBudgetMs = negotiatedTimeoutState.budgetMs - negotiatedTimeoutState.totalExtraTimeMs;
|
|
99533
|
+
const maxPerReqMin = Math.round(negotiatedTimeoutState.maxPerRequestMs / 6e4);
|
|
99534
|
+
const elapsedMin = Math.round((Date.now() - negotiatedTimeoutState.startTime) / 6e4);
|
|
99535
|
+
if (remainingRequests <= 0 || remainingBudgetMs <= 0) {
|
|
99536
|
+
if (this.debug) {
|
|
99537
|
+
console.log(`[DEBUG] Timeout observer: no extensions/budget remaining \u2014 aborting in-flight tools and triggering graceful wind-down`);
|
|
99538
|
+
}
|
|
99539
|
+
if (this.tracer) {
|
|
99540
|
+
this.tracer.addEvent("negotiated_timeout.observer_exhausted", {
|
|
99541
|
+
extensions_used: negotiatedTimeoutState.extensionsUsed,
|
|
99542
|
+
max_requests: negotiatedTimeoutState.maxRequests,
|
|
99543
|
+
total_extra_time_ms: negotiatedTimeoutState.totalExtraTimeMs,
|
|
99544
|
+
budget_ms: negotiatedTimeoutState.budgetMs,
|
|
99545
|
+
elapsed_min: elapsedMin,
|
|
99546
|
+
active_tools: Array.from(activeTools.values()).map((t) => t.name)
|
|
99547
|
+
});
|
|
99548
|
+
}
|
|
99549
|
+
await this._initiateGracefulStop(gracefulTimeoutState, "budget/extensions exhausted");
|
|
99550
|
+
negotiatedTimeoutState.observerRunning = false;
|
|
99551
|
+
return;
|
|
99552
|
+
}
|
|
99553
|
+
const activeToolsList = Array.from(activeTools.values());
|
|
99554
|
+
const now = Date.now();
|
|
99555
|
+
const formatDuration = (ms) => {
|
|
99556
|
+
const totalSec = Math.round(ms / 1e3);
|
|
99557
|
+
if (totalSec < 60) return `${totalSec}s`;
|
|
99558
|
+
const min = Math.floor(totalSec / 60);
|
|
99559
|
+
const sec = totalSec % 60;
|
|
99560
|
+
if (min < 60) return `${min}m ${sec}s`;
|
|
99561
|
+
const hr = Math.floor(min / 60);
|
|
99562
|
+
const remainMin = min % 60;
|
|
99563
|
+
return `${hr}h ${remainMin}m`;
|
|
99564
|
+
};
|
|
99565
|
+
const activeToolsDesc = activeToolsList.length > 0 ? activeToolsList.map((t) => {
|
|
99566
|
+
const runningForMs = now - new Date(t.startedAt).getTime();
|
|
99567
|
+
return `- ${t.name}(${JSON.stringify(t.args || {}).slice(0, 200)}) \u2014 running for ${formatDuration(runningForMs)}`;
|
|
99568
|
+
}).join("\n") : "(none currently running)";
|
|
99569
|
+
const recentHistory = this.history.slice(-6).map((msg) => {
|
|
99570
|
+
const content = typeof msg.content === "string" ? msg.content.slice(0, 300) : JSON.stringify(msg.content).slice(0, 300);
|
|
99571
|
+
return `[${msg.role}]: ${content}`;
|
|
99572
|
+
}).join("\n");
|
|
99573
|
+
const observerPrompt = `You are a timeout observer for an AI coding agent. The agent has been working for ${elapsedMin} minute(s) and has reached its time limit.
|
|
99574
|
+
|
|
99575
|
+
## Recent Conversation
|
|
99576
|
+
${recentHistory || "(no history yet)"}
|
|
99577
|
+
|
|
99578
|
+
## Currently Running Tools
|
|
99579
|
+
${activeToolsDesc}
|
|
99580
|
+
|
|
99581
|
+
## Budget
|
|
99582
|
+
- Extensions used: ${negotiatedTimeoutState.extensionsUsed}/${negotiatedTimeoutState.maxRequests}
|
|
99583
|
+
- Time budget remaining: ${Math.round(remainingBudgetMs / 6e4)} minutes
|
|
99584
|
+
- Max per extension: ${maxPerReqMin} minutes
|
|
99585
|
+
|
|
99586
|
+
Decide whether the agent should get more time. EXTEND if:
|
|
99587
|
+
- Tools are actively running (especially delegates or complex analysis) \u2014 they need time to finish
|
|
99588
|
+
- The agent is making clear progress on a complex task
|
|
99589
|
+
- New information is being gathered that will improve the final answer
|
|
99590
|
+
|
|
99591
|
+
DO NOT EXTEND if:
|
|
99592
|
+
- The agent appears stuck in a loop (repeating the same tool calls or getting the same errors)
|
|
99593
|
+
- The conversation shows the agent retrying failed operations without changing approach
|
|
99594
|
+
- The agent has enough information to answer but keeps searching for more
|
|
99595
|
+
- Tool calls are returning empty or error results repeatedly
|
|
99596
|
+
- The agent is doing redundant work (searching for things it already found)
|
|
99597
|
+
|
|
99598
|
+
A stuck agent will not recover with more time \u2014 it will just burn the budget. Better to force it to answer with what it has.
|
|
99599
|
+
|
|
99600
|
+
Respond with ONLY valid JSON (no markdown, no explanation):
|
|
99601
|
+
{"extend": true, "minutes": <1-${maxPerReqMin}>, "reason": "your reason here"}
|
|
99602
|
+
or
|
|
99603
|
+
{"extend": false, "reason": "your reason here"}`;
|
|
99604
|
+
const observerFn = async () => {
|
|
99605
|
+
const modelInstance = this.provider ? this.provider(this.model) : this.model;
|
|
99606
|
+
if (this.debug) {
|
|
99607
|
+
console.log(`[DEBUG] Timeout observer: making LLM call (${activeToolsList.length} active tools, ${elapsedMin} min elapsed)`);
|
|
99608
|
+
}
|
|
99609
|
+
if (this.tracer) {
|
|
99610
|
+
this.tracer.addEvent("negotiated_timeout.observer_invoked", {
|
|
99611
|
+
elapsed_min: elapsedMin,
|
|
99612
|
+
active_tools: activeToolsList.map((t) => t.name),
|
|
99613
|
+
active_tools_detail: activeToolsList.map((t) => ({
|
|
99614
|
+
name: t.name,
|
|
99615
|
+
running_for_ms: now - new Date(t.startedAt).getTime(),
|
|
99616
|
+
args_preview: JSON.stringify(t.args || {}).slice(0, 100)
|
|
99617
|
+
})),
|
|
99618
|
+
active_tools_count: activeToolsList.length,
|
|
99619
|
+
extensions_used: negotiatedTimeoutState.extensionsUsed,
|
|
99620
|
+
remaining_requests: remainingRequests,
|
|
99621
|
+
remaining_budget_ms: remainingBudgetMs,
|
|
99622
|
+
history_length: this.history.length
|
|
99623
|
+
});
|
|
99624
|
+
}
|
|
99625
|
+
const observerResult = await (0, import_ai4.generateText)({
|
|
99626
|
+
model: modelInstance,
|
|
99627
|
+
messages: [{ role: "user", content: observerPrompt }],
|
|
99628
|
+
maxTokens: 500
|
|
99629
|
+
});
|
|
99630
|
+
const responseText = observerResult.text.trim();
|
|
99631
|
+
if (this.tracer) {
|
|
99632
|
+
this.tracer.addEvent("negotiated_timeout.observer_response", {
|
|
99633
|
+
response_text: responseText,
|
|
99634
|
+
usage_prompt_tokens: observerResult.usage?.promptTokens,
|
|
99635
|
+
usage_completion_tokens: observerResult.usage?.completionTokens
|
|
99636
|
+
});
|
|
99637
|
+
}
|
|
99638
|
+
const jsonStr = responseText.replace(/^```(?:json)?\s*/, "").replace(/\s*```$/, "");
|
|
99639
|
+
const decision = JSON.parse(jsonStr);
|
|
99640
|
+
if (decision.extend && decision.minutes > 0) {
|
|
99641
|
+
const requestedMs = Math.min(decision.minutes, maxPerReqMin) * 6e4;
|
|
99642
|
+
const grantedMs = Math.min(requestedMs, remainingBudgetMs, negotiatedTimeoutState.maxPerRequestMs);
|
|
99643
|
+
const grantedMin = Math.round(grantedMs / 6e4 * 10) / 10;
|
|
99644
|
+
negotiatedTimeoutState.extensionsUsed++;
|
|
99645
|
+
negotiatedTimeoutState.totalExtraTimeMs += grantedMs;
|
|
99646
|
+
negotiatedTimeoutState.extensionMessage = `\u23F0 Time limit was reached. The timeout observer granted ${grantedMin} more minute(s) (reason: ${decision.reason || "work in progress"}). Extensions remaining: ${negotiatedTimeoutState.maxRequests - negotiatedTimeoutState.extensionsUsed}. Continue your work efficiently.`;
|
|
99647
|
+
negotiatedTimeoutState.softTimeoutId = setTimeout(() => {
|
|
99648
|
+
runTimeoutObserver();
|
|
99649
|
+
}, grantedMs);
|
|
99650
|
+
if (this.debug) {
|
|
99651
|
+
console.log(`[DEBUG] Timeout observer: granted ${grantedMin} min (reason: ${decision.reason}). Extensions: ${negotiatedTimeoutState.extensionsUsed}/${negotiatedTimeoutState.maxRequests}`);
|
|
99652
|
+
}
|
|
99653
|
+
if (this.tracer) {
|
|
99654
|
+
this.tracer.addEvent("negotiated_timeout.observer_extended", {
|
|
99655
|
+
decision_reason: decision.reason,
|
|
99656
|
+
requested_minutes: decision.minutes,
|
|
99657
|
+
granted_ms: grantedMs,
|
|
99658
|
+
granted_min: grantedMin,
|
|
99659
|
+
extensions_used: negotiatedTimeoutState.extensionsUsed,
|
|
99660
|
+
max_requests: negotiatedTimeoutState.maxRequests,
|
|
99661
|
+
total_extra_time_ms: negotiatedTimeoutState.totalExtraTimeMs,
|
|
99662
|
+
budget_remaining_ms: remainingBudgetMs - grantedMs,
|
|
99663
|
+
active_tools: activeToolsList.map((t) => t.name),
|
|
99664
|
+
active_tools_count: activeToolsList.length
|
|
99665
|
+
});
|
|
99666
|
+
}
|
|
99667
|
+
} else {
|
|
99668
|
+
if (this.debug) {
|
|
99669
|
+
console.log(`[DEBUG] Timeout observer: declined extension (reason: ${decision.reason}). Initiating graceful stop.`);
|
|
99670
|
+
}
|
|
99671
|
+
if (this.tracer) {
|
|
99672
|
+
this.tracer.addEvent("negotiated_timeout.observer_declined", {
|
|
99673
|
+
decision_reason: decision.reason,
|
|
99674
|
+
extensions_used: negotiatedTimeoutState.extensionsUsed,
|
|
99675
|
+
total_extra_time_ms: negotiatedTimeoutState.totalExtraTimeMs,
|
|
99676
|
+
elapsed_min: elapsedMin,
|
|
99677
|
+
active_tools: activeToolsList.map((t) => t.name)
|
|
99678
|
+
});
|
|
99679
|
+
}
|
|
99680
|
+
await this._initiateGracefulStop(gracefulTimeoutState, `observer declined: ${decision.reason}`);
|
|
99681
|
+
}
|
|
99682
|
+
};
|
|
99683
|
+
try {
|
|
99684
|
+
if (this.tracer) {
|
|
99685
|
+
await this.tracer.withSpan("negotiated_timeout.observer", observerFn, {
|
|
99686
|
+
"timeout.elapsed_min": elapsedMin,
|
|
99687
|
+
"timeout.extensions_used": negotiatedTimeoutState.extensionsUsed,
|
|
99688
|
+
"timeout.active_tools_count": activeToolsList.length,
|
|
99689
|
+
"timeout.remaining_budget_ms": remainingBudgetMs
|
|
99690
|
+
});
|
|
99691
|
+
} else {
|
|
99692
|
+
await observerFn();
|
|
99693
|
+
}
|
|
99694
|
+
} catch (err) {
|
|
99695
|
+
if (this.debug) {
|
|
99696
|
+
console.log(`[DEBUG] Timeout observer: LLM call failed (${err.message}). Initiating graceful stop.`);
|
|
99697
|
+
}
|
|
99698
|
+
if (this.tracer) {
|
|
99699
|
+
this.tracer.addEvent("negotiated_timeout.observer_error", {
|
|
99700
|
+
error_message: err.message,
|
|
99701
|
+
error_name: err.name,
|
|
99702
|
+
extensions_used: negotiatedTimeoutState.extensionsUsed,
|
|
99703
|
+
elapsed_min: elapsedMin
|
|
99704
|
+
});
|
|
99705
|
+
}
|
|
99706
|
+
await this._initiateGracefulStop(gracefulTimeoutState, `observer error: ${err.message}`);
|
|
99707
|
+
} finally {
|
|
99708
|
+
negotiatedTimeoutState.observerRunning = false;
|
|
99709
|
+
}
|
|
99710
|
+
};
|
|
99711
|
+
negotiatedTimeoutState.runObserver = runTimeoutObserver;
|
|
99313
99712
|
let compactionAttempted = false;
|
|
99314
99713
|
while (true) {
|
|
99315
99714
|
try {
|
|
@@ -99319,6 +99718,15 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
99319
99718
|
messages: messagesForAI,
|
|
99320
99719
|
tools: tools2,
|
|
99321
99720
|
stopWhen: ({ steps }) => {
|
|
99721
|
+
if (gracefulTimeoutState.triggered) {
|
|
99722
|
+
if (gracefulTimeoutState.bonusStepsUsed >= gracefulTimeoutState.bonusStepsMax) {
|
|
99723
|
+
if (this.debug) {
|
|
99724
|
+
console.log(`[DEBUG] stopWhen: graceful timeout bonus steps exhausted (${gracefulTimeoutState.bonusStepsUsed}/${gracefulTimeoutState.bonusStepsMax}), forcing stop`);
|
|
99725
|
+
}
|
|
99726
|
+
return true;
|
|
99727
|
+
}
|
|
99728
|
+
return false;
|
|
99729
|
+
}
|
|
99322
99730
|
if (steps.length >= maxIterations) return true;
|
|
99323
99731
|
const lastStep = steps[steps.length - 1];
|
|
99324
99732
|
const modelWantsToStop = lastStep?.finishReason === "stop" && (!lastStep?.toolCalls || lastStep.toolCalls.length === 0);
|
|
@@ -99362,9 +99770,45 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
99362
99770
|
return false;
|
|
99363
99771
|
},
|
|
99364
99772
|
prepareStep: ({ steps, stepNumber }) => {
|
|
99773
|
+
if (negotiatedTimeoutState.extensionMessage && !gracefulTimeoutState.triggered) {
|
|
99774
|
+
const msg = negotiatedTimeoutState.extensionMessage;
|
|
99775
|
+
negotiatedTimeoutState.extensionMessage = null;
|
|
99776
|
+
if (this.debug) {
|
|
99777
|
+
console.log(`[DEBUG] prepareStep: delivering timeout observer extension message`);
|
|
99778
|
+
}
|
|
99779
|
+
return { userMessage: msg };
|
|
99780
|
+
}
|
|
99781
|
+
if (gracefulTimeoutState.triggered) {
|
|
99782
|
+
gracefulTimeoutState.bonusStepsUsed++;
|
|
99783
|
+
const remaining = gracefulTimeoutState.bonusStepsMax - gracefulTimeoutState.bonusStepsUsed;
|
|
99784
|
+
if (gracefulTimeoutState.bonusStepsUsed === 1) {
|
|
99785
|
+
if (this.debug) {
|
|
99786
|
+
console.log(`[DEBUG] prepareStep: graceful timeout wind-down step 1/${gracefulTimeoutState.bonusStepsMax}`);
|
|
99787
|
+
}
|
|
99788
|
+
if (this.tracer) {
|
|
99789
|
+
this.tracer.addEvent("graceful_timeout.wind_down_started", {
|
|
99790
|
+
bonus_steps_max: gracefulTimeoutState.bonusStepsMax,
|
|
99791
|
+
current_iteration: currentIteration,
|
|
99792
|
+
max_iterations: maxIterations
|
|
99793
|
+
});
|
|
99794
|
+
}
|
|
99795
|
+
return {
|
|
99796
|
+
toolChoice: "none",
|
|
99797
|
+
userMessage: `\u26A0\uFE0F TIME LIMIT REACHED. You are running out of time. You have ${remaining} step(s) remaining. Provide your BEST answer NOW using the information you have already gathered. Do NOT call any more tools. Summarize your findings and respond completely. If something was not completed, honestly state what was not done and provide any partial results or recommendations you can offer.`
|
|
99798
|
+
};
|
|
99799
|
+
}
|
|
99800
|
+
if (this.debug) {
|
|
99801
|
+
console.log(`[DEBUG] prepareStep: graceful timeout wind-down step ${gracefulTimeoutState.bonusStepsUsed}/${gracefulTimeoutState.bonusStepsMax} (${remaining} remaining)`);
|
|
99802
|
+
}
|
|
99803
|
+
return { toolChoice: "none" };
|
|
99804
|
+
}
|
|
99365
99805
|
if (stepNumber === maxIterations - 1) {
|
|
99806
|
+
const searchesTried = _toolCallLog.filter((tc) => tc.name === "search").map((tc) => `"${tc.args.query || ""}"${tc.args.exact ? " (exact)" : ""}`).filter((v, i, a) => a.indexOf(v) === i);
|
|
99807
|
+
const searchSummary = searchesTried.length > 0 ? `
|
|
99808
|
+
Searches attempted: ${searchesTried.join(", ")}` : "";
|
|
99366
99809
|
return {
|
|
99367
|
-
toolChoice: "none"
|
|
99810
|
+
toolChoice: "none",
|
|
99811
|
+
userMessage: `\u26A0\uFE0F LAST ITERATION \u2014 you are out of tool calls. Provide your BEST answer NOW with the information gathered so far. If you could not find what was requested, explain exactly what you searched for and why it did not work, so the caller can try a different approach.${searchSummary}`
|
|
99368
99812
|
};
|
|
99369
99813
|
}
|
|
99370
99814
|
if (steps.length >= 2) {
|
|
@@ -99443,6 +99887,11 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
99443
99887
|
const { toolResults, toolCalls, text, reasoningText, finishReason, usage } = stepResult;
|
|
99444
99888
|
currentIteration++;
|
|
99445
99889
|
toolContext.currentIteration = currentIteration;
|
|
99890
|
+
if (toolCalls?.length > 0) {
|
|
99891
|
+
for (const tc of toolCalls) {
|
|
99892
|
+
_toolCallLog.push({ name: tc.toolName, args: tc.args || {} });
|
|
99893
|
+
}
|
|
99894
|
+
}
|
|
99446
99895
|
if (this.tracer) {
|
|
99447
99896
|
const stepEvent = {
|
|
99448
99897
|
"iteration": currentIteration,
|
|
@@ -99465,6 +99914,12 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
99465
99914
|
}));
|
|
99466
99915
|
}
|
|
99467
99916
|
this.tracer.addEvent("iteration.step", stepEvent);
|
|
99917
|
+
if (gracefulTimeoutState.triggered) {
|
|
99918
|
+
this.tracer.addEvent("graceful_timeout.wind_down_step", {
|
|
99919
|
+
bonus_step: gracefulTimeoutState.bonusStepsUsed,
|
|
99920
|
+
bonus_max: gracefulTimeoutState.bonusStepsMax
|
|
99921
|
+
});
|
|
99922
|
+
}
|
|
99468
99923
|
}
|
|
99469
99924
|
if (usage) {
|
|
99470
99925
|
this.tokenCounter.recordUsage(usage);
|
|
@@ -99510,22 +99965,59 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
99510
99965
|
}
|
|
99511
99966
|
const executeAIRequest = async () => {
|
|
99512
99967
|
const result = await this.streamTextWithRetryAndFallback(streamOptions);
|
|
99513
|
-
|
|
99514
|
-
let
|
|
99515
|
-
if (
|
|
99516
|
-
|
|
99517
|
-
|
|
99518
|
-
|
|
99519
|
-
|
|
99968
|
+
let gracefulTimeoutId = null;
|
|
99969
|
+
let hardAbortTimeoutId = null;
|
|
99970
|
+
if (this.timeoutBehavior === "graceful" && gracefulTimeoutState && this.maxOperationTimeout > 0) {
|
|
99971
|
+
gracefulTimeoutId = setTimeout(() => {
|
|
99972
|
+
gracefulTimeoutState.triggered = true;
|
|
99973
|
+
if (this.debug) {
|
|
99974
|
+
console.log(`[DEBUG] Soft timeout after ${this.maxOperationTimeout}ms \u2014 entering wind-down mode (${gracefulTimeoutState.bonusStepsMax} bonus steps)`);
|
|
99975
|
+
}
|
|
99976
|
+
hardAbortTimeoutId = setTimeout(() => {
|
|
99977
|
+
if (this._abortController) {
|
|
99978
|
+
this._abortController.abort();
|
|
99979
|
+
}
|
|
99980
|
+
if (this.debug) {
|
|
99981
|
+
console.log(`[DEBUG] Hard abort \u2014 wind-down safety net expired after 60s`);
|
|
99982
|
+
}
|
|
99983
|
+
}, 6e4);
|
|
99984
|
+
}, this.maxOperationTimeout);
|
|
99520
99985
|
}
|
|
99521
|
-
if (this.
|
|
99522
|
-
|
|
99986
|
+
if (this.timeoutBehavior === "negotiated" && this.maxOperationTimeout > 0) {
|
|
99987
|
+
negotiatedTimeoutState.softTimeoutId = setTimeout(() => {
|
|
99988
|
+
if (this.debug) {
|
|
99989
|
+
console.log(`[DEBUG] Soft timeout after ${this.maxOperationTimeout}ms \u2014 invoking timeout observer`);
|
|
99990
|
+
}
|
|
99991
|
+
runTimeoutObserver();
|
|
99992
|
+
}, this.maxOperationTimeout);
|
|
99523
99993
|
}
|
|
99524
|
-
|
|
99525
|
-
|
|
99526
|
-
|
|
99994
|
+
try {
|
|
99995
|
+
const steps = await result.steps;
|
|
99996
|
+
let finalText;
|
|
99997
|
+
if (steps && steps.length > 1) {
|
|
99998
|
+
const lastStepText = steps[steps.length - 1].text;
|
|
99999
|
+
finalText = lastStepText || await result.text;
|
|
100000
|
+
} else {
|
|
100001
|
+
finalText = await result.text;
|
|
100002
|
+
}
|
|
100003
|
+
if (this.debug) {
|
|
100004
|
+
console.log(`[DEBUG] streamText completed: ${steps?.length || 0} steps, finalText=${finalText?.length || 0} chars`);
|
|
100005
|
+
}
|
|
100006
|
+
const usage = await result.usage;
|
|
100007
|
+
if (usage) {
|
|
100008
|
+
this.tokenCounter.recordUsage(usage, result.experimental_providerMetadata);
|
|
100009
|
+
}
|
|
100010
|
+
return { finalText, result };
|
|
100011
|
+
} finally {
|
|
100012
|
+
if (gracefulTimeoutId) clearTimeout(gracefulTimeoutId);
|
|
100013
|
+
if (hardAbortTimeoutId) clearTimeout(hardAbortTimeoutId);
|
|
100014
|
+
if (negotiatedTimeoutState.softTimeoutId) clearTimeout(negotiatedTimeoutState.softTimeoutId);
|
|
100015
|
+
if (this._gracefulStopHardAbortId) {
|
|
100016
|
+
clearTimeout(this._gracefulStopHardAbortId);
|
|
100017
|
+
this._gracefulStopHardAbortId = null;
|
|
100018
|
+
}
|
|
100019
|
+
this.events.removeListener("toolCall", onToolCall);
|
|
99527
100020
|
}
|
|
99528
|
-
return { finalText, result };
|
|
99529
100021
|
};
|
|
99530
100022
|
let aiResult;
|
|
99531
100023
|
if (this.tracer) {
|
|
@@ -99562,13 +100054,57 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
99562
100054
|
} else if (aiResult.finalText) {
|
|
99563
100055
|
finalResult = aiResult.finalText;
|
|
99564
100056
|
}
|
|
100057
|
+
if (gracefulTimeoutState.triggered) {
|
|
100058
|
+
const timeoutNotice = "**Note: This response was generated under a time constraint. The research may be incomplete, and some planned searches or analysis steps were not completed.**\n\n";
|
|
100059
|
+
if (!finalResult || finalResult === DEFAULT_MAX_ITER_MSG || finalResult.startsWith("I was unable to complete your request after")) {
|
|
100060
|
+
try {
|
|
100061
|
+
const allText = await aiResult.result.text;
|
|
100062
|
+
if (allText && allText.trim()) {
|
|
100063
|
+
finalResult = timeoutNotice + allText;
|
|
100064
|
+
if (this.debug) {
|
|
100065
|
+
console.log(`[DEBUG] Graceful timeout: using concatenated step text (${allText.length} chars)`);
|
|
100066
|
+
}
|
|
100067
|
+
} else {
|
|
100068
|
+
const steps = await aiResult.result.steps;
|
|
100069
|
+
const toolSummaries = [];
|
|
100070
|
+
for (const step of steps || []) {
|
|
100071
|
+
if (step.toolResults?.length > 0) {
|
|
100072
|
+
for (const tr of step.toolResults) {
|
|
100073
|
+
const resultText = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
|
|
100074
|
+
if (resultText && resultText.length > 0 && resultText.length < 5e3) {
|
|
100075
|
+
toolSummaries.push(resultText.substring(0, 2e3));
|
|
100076
|
+
}
|
|
100077
|
+
}
|
|
100078
|
+
}
|
|
100079
|
+
}
|
|
100080
|
+
if (toolSummaries.length > 0) {
|
|
100081
|
+
finalResult = `${timeoutNotice}The operation timed out before a complete answer could be generated. Here is the partial information gathered:
|
|
100082
|
+
|
|
100083
|
+
${toolSummaries.join("\n\n---\n\n")}`;
|
|
100084
|
+
if (this.debug) {
|
|
100085
|
+
console.log(`[DEBUG] Graceful timeout: built fallback from ${toolSummaries.length} tool results`);
|
|
100086
|
+
}
|
|
100087
|
+
} else {
|
|
100088
|
+
finalResult = "The operation timed out before enough information could be gathered to provide an answer. Please try again with a simpler query or increase the timeout.";
|
|
100089
|
+
}
|
|
100090
|
+
}
|
|
100091
|
+
} catch (e) {
|
|
100092
|
+
if (this.debug) {
|
|
100093
|
+
console.log(`[DEBUG] Graceful timeout fallback error: ${e.message}`);
|
|
100094
|
+
}
|
|
100095
|
+
finalResult = "The operation timed out before enough information could be gathered to provide an answer. Please try again with a simpler query or increase the timeout.";
|
|
100096
|
+
}
|
|
100097
|
+
} else {
|
|
100098
|
+
finalResult = timeoutNotice + finalResult;
|
|
100099
|
+
}
|
|
100100
|
+
}
|
|
99565
100101
|
const resultMessages = await aiResult.result.response?.messages;
|
|
99566
100102
|
if (resultMessages) {
|
|
99567
100103
|
for (const msg of resultMessages) {
|
|
99568
100104
|
currentMessages.push(msg);
|
|
99569
100105
|
}
|
|
99570
100106
|
}
|
|
99571
|
-
if (this.completionPrompt && !options._completionPromptProcessed && !completionPromptInjected && finalResult) {
|
|
100107
|
+
if (this.completionPrompt && !options._completionPromptProcessed && !completionPromptInjected && !abortSummaryTaken && finalResult) {
|
|
99572
100108
|
completionPromptInjected = true;
|
|
99573
100109
|
preCompletionResult = finalResult;
|
|
99574
100110
|
if (this.debug) {
|
|
@@ -99640,6 +100176,118 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
99640
100176
|
}
|
|
99641
100177
|
break;
|
|
99642
100178
|
} catch (error40) {
|
|
100179
|
+
if (gracefulTimeoutState.triggered && error40?.name === "AbortError") {
|
|
100180
|
+
if (this.debug) {
|
|
100181
|
+
console.log(`[DEBUG] Negotiated timeout: abort caught \u2014 making summary LLM call with conversation context`);
|
|
100182
|
+
}
|
|
100183
|
+
if (this.tracer) {
|
|
100184
|
+
this.tracer.addEvent("negotiated_timeout.abort_summary_started", {
|
|
100185
|
+
conversation_messages: currentMessages.length,
|
|
100186
|
+
has_schema: !!options.schema,
|
|
100187
|
+
has_tasks: !!(this.enableTasks && this.taskManager)
|
|
100188
|
+
});
|
|
100189
|
+
}
|
|
100190
|
+
try {
|
|
100191
|
+
let taskContext = "";
|
|
100192
|
+
if (this.enableTasks && this.taskManager) {
|
|
100193
|
+
const taskSummary = this.taskManager.getTaskSummary?.();
|
|
100194
|
+
if (taskSummary) {
|
|
100195
|
+
taskContext = `
|
|
100196
|
+
|
|
100197
|
+
## Task Status
|
|
100198
|
+
${taskSummary}
|
|
100199
|
+
|
|
100200
|
+
Acknowledge which tasks were completed and which were not.`;
|
|
100201
|
+
}
|
|
100202
|
+
}
|
|
100203
|
+
let schemaContext = "";
|
|
100204
|
+
if (options.schema) {
|
|
100205
|
+
try {
|
|
100206
|
+
const parsedSchema = typeof options.schema === "string" ? JSON.parse(options.schema) : options.schema;
|
|
100207
|
+
schemaContext = `
|
|
100208
|
+
|
|
100209
|
+
IMPORTANT: Your response MUST be valid JSON matching this schema:
|
|
100210
|
+
${JSON.stringify(parsedSchema, null, 2)}
|
|
100211
|
+
|
|
100212
|
+
Respond with ONLY valid JSON \u2014 no markdown, no explanation, no text outside the JSON object. Include all findings and partial results within the JSON structure. If fields cannot be fully populated due to the interruption, use partial data or null values as appropriate.`;
|
|
100213
|
+
} catch {
|
|
100214
|
+
}
|
|
100215
|
+
}
|
|
100216
|
+
const summaryPrompt = `Your operation was interrupted by a timeout observer because the time limit was reached. Some of your tool calls were cancelled mid-execution.
|
|
100217
|
+
|
|
100218
|
+
Please provide a DETAILED summary of:
|
|
100219
|
+
1. What you were asked to do (the original task)
|
|
100220
|
+
2. What you accomplished \u2014 include ALL findings, code snippets, data, and conclusions you gathered
|
|
100221
|
+
3. What was still in progress or not yet started
|
|
100222
|
+
4. Any partial results or recommendations you can offer based on what you found so far${taskContext}${schemaContext}
|
|
100223
|
+
|
|
100224
|
+
Be thorough \u2014 this is the user's only response. Include all useful information you collected.`;
|
|
100225
|
+
const summaryMessages = [
|
|
100226
|
+
...currentMessages,
|
|
100227
|
+
{ role: "user", content: summaryPrompt }
|
|
100228
|
+
];
|
|
100229
|
+
const modelInstance = this.provider ? this.provider(this.model) : this.model;
|
|
100230
|
+
const summaryFn = async () => {
|
|
100231
|
+
const summaryResult = await (0, import_ai4.generateText)({
|
|
100232
|
+
model: modelInstance,
|
|
100233
|
+
messages: this.prepareMessagesWithImages(summaryMessages),
|
|
100234
|
+
maxTokens: 4e3
|
|
100235
|
+
});
|
|
100236
|
+
if (this.tracer) {
|
|
100237
|
+
this.tracer.addEvent("negotiated_timeout.abort_summary_completed", {
|
|
100238
|
+
summary_length: summaryResult.text?.length || 0,
|
|
100239
|
+
usage_prompt_tokens: summaryResult.usage?.promptTokens,
|
|
100240
|
+
usage_completion_tokens: summaryResult.usage?.completionTokens
|
|
100241
|
+
});
|
|
100242
|
+
}
|
|
100243
|
+
if (summaryResult.usage) {
|
|
100244
|
+
this.tokenCounter.recordUsage(summaryResult.usage);
|
|
100245
|
+
}
|
|
100246
|
+
return summaryResult.text;
|
|
100247
|
+
};
|
|
100248
|
+
let summaryText;
|
|
100249
|
+
if (this.tracer) {
|
|
100250
|
+
summaryText = await this.tracer.withSpan("negotiated_timeout.abort_summary", summaryFn, {
|
|
100251
|
+
"summary.conversation_messages": currentMessages.length
|
|
100252
|
+
});
|
|
100253
|
+
} else {
|
|
100254
|
+
summaryText = await summaryFn();
|
|
100255
|
+
}
|
|
100256
|
+
if (options.schema) {
|
|
100257
|
+
finalResult = summaryText || "{}";
|
|
100258
|
+
} else {
|
|
100259
|
+
const timeoutNotice = "**Note: This response was generated under a time constraint. The timeout observer interrupted the operation because the time budget was exhausted.**\n\n";
|
|
100260
|
+
finalResult = timeoutNotice + (summaryText || "The operation was interrupted before a response could be generated.");
|
|
100261
|
+
}
|
|
100262
|
+
if (options.onStream && finalResult) {
|
|
100263
|
+
options.onStream(finalResult);
|
|
100264
|
+
}
|
|
100265
|
+
if (this.debug) {
|
|
100266
|
+
console.log(`[DEBUG] Negotiated timeout: summary produced ${summaryText?.length || 0} chars`);
|
|
100267
|
+
}
|
|
100268
|
+
} catch (summaryErr) {
|
|
100269
|
+
if (this.debug) {
|
|
100270
|
+
console.log(`[DEBUG] Negotiated timeout: summary call failed (${summaryErr.message}), falling back to partial text`);
|
|
100271
|
+
}
|
|
100272
|
+
if (this.tracer) {
|
|
100273
|
+
this.tracer.addEvent("negotiated_timeout.abort_summary_error", {
|
|
100274
|
+
error_message: summaryErr.message
|
|
100275
|
+
});
|
|
100276
|
+
}
|
|
100277
|
+
const partialTexts = currentMessages.filter((m) => m.role === "assistant" && typeof m.content === "string" && m.content.trim()).map((m) => m.content);
|
|
100278
|
+
if (options.schema) {
|
|
100279
|
+
finalResult = partialTexts.length > 0 ? partialTexts[partialTexts.length - 1] : "{}";
|
|
100280
|
+
} else {
|
|
100281
|
+
const timeoutNotice = "**Note: This response was generated under a time constraint. The operation was interrupted and some work was not completed.**\n\n";
|
|
100282
|
+
finalResult = partialTexts.length > 0 ? timeoutNotice + partialTexts[partialTexts.length - 1] : timeoutNotice + "The operation was interrupted before enough information could be gathered. Please try again with a simpler query or increase the timeout.";
|
|
100283
|
+
}
|
|
100284
|
+
if (options.onStream && finalResult) {
|
|
100285
|
+
options.onStream(finalResult);
|
|
100286
|
+
}
|
|
100287
|
+
}
|
|
100288
|
+
abortSummaryTaken = true;
|
|
100289
|
+
break;
|
|
100290
|
+
}
|
|
99643
100291
|
if (!compactionAttempted && handleContextLimitError) {
|
|
99644
100292
|
const compactionResult = handleContextLimitError(error40, currentMessages, {
|
|
99645
100293
|
keepLastSegment: true,
|
|
@@ -99674,6 +100322,36 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
99674
100322
|
}
|
|
99675
100323
|
if (currentIteration >= maxIterations) {
|
|
99676
100324
|
console.warn(`[WARN] Max tool iterations (${maxIterations}) reached for session ${this.sessionId}.`);
|
|
100325
|
+
if (!finalResult || finalResult === DEFAULT_MAX_ITER_MSG) {
|
|
100326
|
+
try {
|
|
100327
|
+
const searchQueries = [];
|
|
100328
|
+
const toolCounts = {};
|
|
100329
|
+
for (const tc of _toolCallLog) {
|
|
100330
|
+
toolCounts[tc.name] = (toolCounts[tc.name] || 0) + 1;
|
|
100331
|
+
if (tc.name === "search") {
|
|
100332
|
+
const q = tc.args.query || "";
|
|
100333
|
+
const exact = tc.args.exact ? " (exact)" : "";
|
|
100334
|
+
searchQueries.push(`"${q}"${exact}`);
|
|
100335
|
+
}
|
|
100336
|
+
}
|
|
100337
|
+
const toolBreakdown = Object.entries(toolCounts).map(([name15, count]) => `${name15}: ${count}x`).join(", ");
|
|
100338
|
+
const uniqueSearches = [...new Set(searchQueries)];
|
|
100339
|
+
let summary = `I was unable to complete your request after ${currentIteration} tool iterations.
|
|
100340
|
+
|
|
100341
|
+
`;
|
|
100342
|
+
summary += `Tool calls made: ${toolBreakdown || "none"}
|
|
100343
|
+
`;
|
|
100344
|
+
if (uniqueSearches.length > 0) {
|
|
100345
|
+
summary += `Search queries tried: ${uniqueSearches.join(", ")}
|
|
100346
|
+
`;
|
|
100347
|
+
}
|
|
100348
|
+
summary += `
|
|
100349
|
+
The search approach may be fundamentally wrong for this query. Consider: using exact=true for literal string matching, using bash/grep for pattern-based file searches, or trying a completely different strategy instead of repeating similar searches.`;
|
|
100350
|
+
finalResult = summary;
|
|
100351
|
+
} catch {
|
|
100352
|
+
finalResult = DEFAULT_MAX_ITER_MSG;
|
|
100353
|
+
}
|
|
100354
|
+
}
|
|
99677
100355
|
}
|
|
99678
100356
|
this.history = currentMessages.map((msg) => ({ ...msg }));
|
|
99679
100357
|
if (this.history.length > MAX_HISTORY_MESSAGES) {
|
|
@@ -100208,6 +100886,134 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
100208
100886
|
console.log(`[DEBUG] Agent cancelled for session ${this.sessionId}`);
|
|
100209
100887
|
}
|
|
100210
100888
|
}
|
|
100889
|
+
/**
|
|
100890
|
+
* Trigger graceful wind-down from outside (e.g., parent agent).
|
|
100891
|
+
* Unlike cancel(), this does NOT abort — it sets the graceful timeout flag
|
|
100892
|
+
* so the agent finishes its current step and then winds down naturally.
|
|
100893
|
+
*/
|
|
100894
|
+
triggerGracefulWindDown() {
|
|
100895
|
+
if (this._gracefulTimeoutState && !this._gracefulTimeoutState.triggered) {
|
|
100896
|
+
this._gracefulTimeoutState.triggered = true;
|
|
100897
|
+
if (this.debug) {
|
|
100898
|
+
console.log(`[DEBUG] Graceful wind-down triggered externally for session ${this.sessionId}`);
|
|
100899
|
+
}
|
|
100900
|
+
if (this.tracer) {
|
|
100901
|
+
this.tracer.addEvent("graceful_stop.external_trigger", {
|
|
100902
|
+
"session.id": this.sessionId
|
|
100903
|
+
});
|
|
100904
|
+
}
|
|
100905
|
+
} else if (this.debug) {
|
|
100906
|
+
console.log(`[DEBUG] Graceful wind-down already active for session ${this.sessionId}, skipping`);
|
|
100907
|
+
}
|
|
100908
|
+
}
|
|
100909
|
+
/**
|
|
100910
|
+
* Initiate two-phase graceful stop: signal subagents and MCP servers to wind down,
|
|
100911
|
+
* then hard-abort after a deadline if they haven't finished.
|
|
100912
|
+
* @param {Object} gracefulTimeoutState - The graceful timeout state object from run()
|
|
100913
|
+
* @param {string} reason - Why the graceful stop was initiated
|
|
100914
|
+
*/
|
|
100915
|
+
async _initiateGracefulStop(gracefulTimeoutState, reason) {
|
|
100916
|
+
if (gracefulTimeoutState.triggered) return;
|
|
100917
|
+
if (this.debug) {
|
|
100918
|
+
console.log(`[DEBUG] Initiating graceful stop: ${reason} (subagents: ${this._activeSubagents.size}, hasMcpBridge: ${!!this.mcpBridge}, deadline: ${this.gracefulStopDeadline}ms)`);
|
|
100919
|
+
}
|
|
100920
|
+
gracefulTimeoutState.triggered = true;
|
|
100921
|
+
if (this.tracer) {
|
|
100922
|
+
this.tracer.addEvent("graceful_stop.initiated", {
|
|
100923
|
+
"session.id": this.sessionId,
|
|
100924
|
+
"graceful_stop.reason": reason,
|
|
100925
|
+
"graceful_stop.active_subagents": this._activeSubagents.size,
|
|
100926
|
+
"graceful_stop.has_mcp_bridge": !!this.mcpBridge,
|
|
100927
|
+
"graceful_stop.deadline_ms": this.gracefulStopDeadline
|
|
100928
|
+
});
|
|
100929
|
+
}
|
|
100930
|
+
let subagentsSignalled = 0;
|
|
100931
|
+
let subagentErrors = 0;
|
|
100932
|
+
for (const [sid, subagent] of this._activeSubagents) {
|
|
100933
|
+
try {
|
|
100934
|
+
subagent.triggerGracefulWindDown();
|
|
100935
|
+
subagentsSignalled++;
|
|
100936
|
+
if (this.debug) {
|
|
100937
|
+
console.log(`[DEBUG] Triggered graceful wind-down on subagent ${sid}`);
|
|
100938
|
+
}
|
|
100939
|
+
} catch (e) {
|
|
100940
|
+
subagentErrors++;
|
|
100941
|
+
if (this.debug) {
|
|
100942
|
+
console.log(`[DEBUG] Failed to trigger wind-down on subagent ${sid}: ${e.message}`);
|
|
100943
|
+
}
|
|
100944
|
+
}
|
|
100945
|
+
}
|
|
100946
|
+
let mcpResults = [];
|
|
100947
|
+
if (this.mcpBridge) {
|
|
100948
|
+
try {
|
|
100949
|
+
mcpResults = await this.mcpBridge.callGracefulStopAll();
|
|
100950
|
+
if (this.debug && mcpResults.length > 0) {
|
|
100951
|
+
console.log(`[DEBUG] MCP graceful_stop results: ${JSON.stringify(mcpResults)}`);
|
|
100952
|
+
}
|
|
100953
|
+
} catch (e) {
|
|
100954
|
+
if (this.debug) {
|
|
100955
|
+
console.log(`[DEBUG] MCP graceful_stop failed: ${e.message}`);
|
|
100956
|
+
}
|
|
100957
|
+
}
|
|
100958
|
+
}
|
|
100959
|
+
if (this.tracer) {
|
|
100960
|
+
this.tracer.addEvent("graceful_stop.signals_sent", {
|
|
100961
|
+
"session.id": this.sessionId,
|
|
100962
|
+
"graceful_stop.subagents_signalled": subagentsSignalled,
|
|
100963
|
+
"graceful_stop.subagent_errors": subagentErrors,
|
|
100964
|
+
"graceful_stop.mcp_servers_called": mcpResults.filter((r) => r.success).length,
|
|
100965
|
+
"graceful_stop.mcp_servers_failed": mcpResults.filter((r) => !r.success).length,
|
|
100966
|
+
"graceful_stop.mcp_servers_total": mcpResults.length
|
|
100967
|
+
});
|
|
100968
|
+
}
|
|
100969
|
+
this._gracefulStopHardAbortId = setTimeout(() => {
|
|
100970
|
+
if (this.debug) {
|
|
100971
|
+
console.log(`[DEBUG] Graceful stop deadline (${this.gracefulStopDeadline}ms) expired \u2014 hard aborting`);
|
|
100972
|
+
}
|
|
100973
|
+
if (this.tracer) {
|
|
100974
|
+
this.tracer.addEvent("graceful_stop.deadline_expired", {
|
|
100975
|
+
"session.id": this.sessionId,
|
|
100976
|
+
"graceful_stop.deadline_ms": this.gracefulStopDeadline
|
|
100977
|
+
});
|
|
100978
|
+
}
|
|
100979
|
+
if (this._abortController) this._abortController.abort();
|
|
100980
|
+
}, this.gracefulStopDeadline);
|
|
100981
|
+
}
|
|
100982
|
+
/**
|
|
100983
|
+
* Register an active subagent for graceful stop coordination.
|
|
100984
|
+
* @param {string} sessionId
|
|
100985
|
+
* @param {ProbeAgent} subagent
|
|
100986
|
+
*/
|
|
100987
|
+
_registerSubagent(sessionId, subagent) {
|
|
100988
|
+
this._activeSubagents.set(sessionId, subagent);
|
|
100989
|
+
if (this.debug) {
|
|
100990
|
+
console.log(`[DEBUG] Registered subagent ${sessionId} (active: ${this._activeSubagents.size})`);
|
|
100991
|
+
}
|
|
100992
|
+
if (this.tracer) {
|
|
100993
|
+
this.tracer.addEvent("subagent.registered", {
|
|
100994
|
+
"session.id": this.sessionId,
|
|
100995
|
+
"subagent.session_id": sessionId,
|
|
100996
|
+
"subagent.active_count": this._activeSubagents.size
|
|
100997
|
+
});
|
|
100998
|
+
}
|
|
100999
|
+
}
|
|
101000
|
+
/**
|
|
101001
|
+
* Unregister a completed subagent.
|
|
101002
|
+
* @param {string} sessionId
|
|
101003
|
+
*/
|
|
101004
|
+
_unregisterSubagent(sessionId) {
|
|
101005
|
+
this._activeSubagents.delete(sessionId);
|
|
101006
|
+
if (this.debug) {
|
|
101007
|
+
console.log(`[DEBUG] Unregistered subagent ${sessionId} (active: ${this._activeSubagents.size})`);
|
|
101008
|
+
}
|
|
101009
|
+
if (this.tracer) {
|
|
101010
|
+
this.tracer.addEvent("subagent.unregistered", {
|
|
101011
|
+
"session.id": this.sessionId,
|
|
101012
|
+
"subagent.session_id": sessionId,
|
|
101013
|
+
"subagent.active_count": this._activeSubagents.size
|
|
101014
|
+
});
|
|
101015
|
+
}
|
|
101016
|
+
}
|
|
100211
101017
|
/**
|
|
100212
101018
|
* Get the abort signal for this agent.
|
|
100213
101019
|
* Delegations and subagents should check this signal.
|
|
@@ -100250,8 +101056,15 @@ async function delegate({
|
|
|
100250
101056
|
// Optional per-instance manager, falls back to default singleton
|
|
100251
101057
|
concurrencyLimiter = null,
|
|
100252
101058
|
// Optional global AI concurrency limiter
|
|
100253
|
-
parentAbortSignal = null
|
|
101059
|
+
parentAbortSignal = null,
|
|
100254
101060
|
// Optional AbortSignal from parent to cancel this delegation
|
|
101061
|
+
// Timeout settings inherited from parent agent
|
|
101062
|
+
timeoutBehavior = void 0,
|
|
101063
|
+
requestTimeout = void 0,
|
|
101064
|
+
gracefulTimeoutBonusSteps = void 0,
|
|
101065
|
+
// Subagent lifecycle callbacks for graceful stop coordination
|
|
101066
|
+
onSubagentCreated = null,
|
|
101067
|
+
onSubagentCompleted = null
|
|
100255
101068
|
}) {
|
|
100256
101069
|
if (!task || typeof task !== "string") {
|
|
100257
101070
|
throw new Error("Task parameter is required and must be a string");
|
|
@@ -100334,12 +101147,38 @@ async function delegate({
|
|
|
100334
101147
|
// Inherit from parent
|
|
100335
101148
|
mcpConfigPath,
|
|
100336
101149
|
// Inherit from parent
|
|
100337
|
-
concurrencyLimiter
|
|
101150
|
+
concurrencyLimiter,
|
|
100338
101151
|
// Inherit global AI concurrency limiter
|
|
101152
|
+
// Inherit timeout behavior from parent — subagent gets its own graceful wind-down
|
|
101153
|
+
// so it can produce partial results instead of being hard-killed by the external timer.
|
|
101154
|
+
// The external delegate timeout (capped to parent's remaining budget) is the hard limit;
|
|
101155
|
+
// maxOperationTimeout on the subagent is set slightly shorter so its own wind-down
|
|
101156
|
+
// fires before the external kill.
|
|
101157
|
+
maxOperationTimeout: Math.max(1e4, timeout * 1e3 - 15e3),
|
|
101158
|
+
// 15s before external kill
|
|
101159
|
+
timeoutBehavior: timeoutBehavior || "graceful",
|
|
101160
|
+
requestTimeout,
|
|
101161
|
+
gracefulTimeoutBonusSteps: gracefulTimeoutBonusSteps ?? 2
|
|
101162
|
+
// fewer steps for subagents
|
|
100339
101163
|
});
|
|
101164
|
+
if (onSubagentCreated) {
|
|
101165
|
+
onSubagentCreated(sessionId, subagent);
|
|
101166
|
+
}
|
|
100340
101167
|
if (debug) {
|
|
100341
101168
|
console.error(`[DELEGATE] Created subagent with session ${sessionId}`);
|
|
100342
101169
|
console.error(`[DELEGATE] Subagent config: promptType=${promptType}, enableDelegate=false, maxIterations=${remainingIterations}`);
|
|
101170
|
+
console.error(`[DELEGATE] Timeout inheritance: externalTimeout=${timeout}s, maxOperationTimeout=${Math.max(1e4, timeout * 1e3 - 15e3)}ms, behavior=${timeoutBehavior || "graceful"}, bonusSteps=${gracefulTimeoutBonusSteps ?? 2}`);
|
|
101171
|
+
}
|
|
101172
|
+
if (tracer) {
|
|
101173
|
+
tracer.addEvent("delegation.subagent_created", {
|
|
101174
|
+
"delegation.session_id": sessionId,
|
|
101175
|
+
"delegation.parent_session_id": parentSessionId,
|
|
101176
|
+
"delegation.external_timeout_s": timeout,
|
|
101177
|
+
"delegation.internal_timeout_ms": Math.max(1e4, timeout * 1e3 - 15e3),
|
|
101178
|
+
"delegation.timeout_behavior": timeoutBehavior || "graceful",
|
|
101179
|
+
"delegation.bonus_steps": gracefulTimeoutBonusSteps ?? 2,
|
|
101180
|
+
"delegation.max_iterations": remainingIterations
|
|
101181
|
+
});
|
|
100343
101182
|
}
|
|
100344
101183
|
const timeoutPromise = new Promise((_, reject2) => {
|
|
100345
101184
|
timeoutId = setTimeout(() => {
|
|
@@ -100348,6 +101187,7 @@ async function delegate({
|
|
|
100348
101187
|
}, timeout * 1e3);
|
|
100349
101188
|
});
|
|
100350
101189
|
let parentAbortHandler;
|
|
101190
|
+
let parentAbortHardCancelId = null;
|
|
100351
101191
|
const parentAbortPromise = new Promise((_, reject2) => {
|
|
100352
101192
|
if (parentAbortSignal) {
|
|
100353
101193
|
if (parentAbortSignal.aborted) {
|
|
@@ -100356,8 +101196,31 @@ async function delegate({
|
|
|
100356
101196
|
return;
|
|
100357
101197
|
}
|
|
100358
101198
|
parentAbortHandler = () => {
|
|
100359
|
-
subagent.
|
|
100360
|
-
|
|
101199
|
+
subagent.triggerGracefulWindDown();
|
|
101200
|
+
if (debug) {
|
|
101201
|
+
console.error(`[DELEGATE] Parent abort signal received \u2014 triggered graceful wind-down on subagent ${sessionId}`);
|
|
101202
|
+
}
|
|
101203
|
+
if (tracer) {
|
|
101204
|
+
tracer.addEvent("delegation.parent_abort_phase1", {
|
|
101205
|
+
"delegation.session_id": sessionId,
|
|
101206
|
+
"delegation.parent_session_id": parentSessionId,
|
|
101207
|
+
"delegation.action": "graceful_wind_down"
|
|
101208
|
+
});
|
|
101209
|
+
}
|
|
101210
|
+
parentAbortHardCancelId = setTimeout(() => {
|
|
101211
|
+
if (debug) {
|
|
101212
|
+
console.error(`[DELEGATE] Graceful wind-down deadline expired \u2014 hard cancelling subagent ${sessionId}`);
|
|
101213
|
+
}
|
|
101214
|
+
if (tracer) {
|
|
101215
|
+
tracer.addEvent("delegation.parent_abort_phase2", {
|
|
101216
|
+
"delegation.session_id": sessionId,
|
|
101217
|
+
"delegation.parent_session_id": parentSessionId,
|
|
101218
|
+
"delegation.action": "hard_cancel"
|
|
101219
|
+
});
|
|
101220
|
+
}
|
|
101221
|
+
subagent.cancel();
|
|
101222
|
+
reject2(new Error("Delegation cancelled: parent operation was aborted (graceful wind-down deadline expired)"));
|
|
101223
|
+
}, 3e4);
|
|
100361
101224
|
};
|
|
100362
101225
|
parentAbortSignal.addEventListener("abort", parentAbortHandler, { once: true });
|
|
100363
101226
|
}
|
|
@@ -100373,6 +101236,13 @@ async function delegate({
|
|
|
100373
101236
|
if (parentAbortHandler && parentAbortSignal) {
|
|
100374
101237
|
parentAbortSignal.removeEventListener("abort", parentAbortHandler);
|
|
100375
101238
|
}
|
|
101239
|
+
if (parentAbortHardCancelId) {
|
|
101240
|
+
clearTimeout(parentAbortHardCancelId);
|
|
101241
|
+
parentAbortHardCancelId = null;
|
|
101242
|
+
}
|
|
101243
|
+
if (onSubagentCompleted) {
|
|
101244
|
+
onSubagentCompleted(sessionId);
|
|
101245
|
+
}
|
|
100376
101246
|
}
|
|
100377
101247
|
if (timeoutId !== null) {
|
|
100378
101248
|
clearTimeout(timeoutId);
|
|
@@ -101397,6 +102267,10 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
101397
102267
|
"- Use exact=true when searching for a KNOWN symbol name (function, type, variable, struct).",
|
|
101398
102268
|
"- exact=true matches the literal string only \u2014 no stemming, no splitting.",
|
|
101399
102269
|
'- This is ideal for precise lookups: exact=true "ForwardMessage", exact=true "SessionLimiter", exact=true "ThrottleRetryLimit".',
|
|
102270
|
+
"- IMPORTANT: Use exact=true when searching for strings containing punctuation, quotes, or empty values.",
|
|
102271
|
+
" Default BM25 search strips punctuation and treats quoted empty strings as noise.",
|
|
102272
|
+
` Example: searching for 'description: ""' with exact=false will NOT find empty description fields \u2014 it just matches "description".`,
|
|
102273
|
+
` Use exact=true for literal patterns like 'description: ""', 'value: \\'\\'', or any YAML/config field with specific punctuation.`,
|
|
101400
102274
|
"- Do NOT use exact=true for exploratory/conceptual queries \u2014 use the default for those.",
|
|
101401
102275
|
"",
|
|
101402
102276
|
"Combining searches with OR:",
|
|
@@ -101456,7 +102330,13 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
101456
102330
|
"WHEN TO STOP:",
|
|
101457
102331
|
"- After you have explored the main concept AND related subsystems.",
|
|
101458
102332
|
"- Once you have 5-15 targets covering different aspects of the query.",
|
|
101459
|
-
'- If you get a "DUPLICATE SEARCH BLOCKED" message,
|
|
102333
|
+
'- If you get a "DUPLICATE SEARCH BLOCKED" message, do NOT rephrase the same query \u2014 try a FUNDAMENTALLY different approach:',
|
|
102334
|
+
" * Switch between exact=true and exact=false",
|
|
102335
|
+
" * Search for a broader term and filter results manually",
|
|
102336
|
+
" * Use listFiles to browse the directory structure directly",
|
|
102337
|
+
" * Look for related/surrounding patterns instead of the exact string",
|
|
102338
|
+
"- If 2-3 genuinely different search approaches fail, STOP and report what you tried and why it failed.",
|
|
102339
|
+
" Do NOT keep trying variations of the same failing concept.",
|
|
101460
102340
|
"",
|
|
101461
102341
|
"Strategy:",
|
|
101462
102342
|
"1. Analyze the query \u2014 identify key concepts, then brainstorm SYNONYMS and alternative terms for each.",
|
|
@@ -101528,8 +102408,8 @@ var init_vercel = __esm({
|
|
|
101528
102408
|
}
|
|
101529
102409
|
return result;
|
|
101530
102410
|
};
|
|
101531
|
-
const previousSearches = /* @__PURE__ */ new
|
|
101532
|
-
|
|
102411
|
+
const previousSearches = /* @__PURE__ */ new Map();
|
|
102412
|
+
const dupBlockCounts = /* @__PURE__ */ new Map();
|
|
101533
102413
|
const paginationCounts = /* @__PURE__ */ new Map();
|
|
101534
102414
|
const MAX_PAGES_PER_QUERY = 3;
|
|
101535
102415
|
return (0, import_ai5.tool)({
|
|
@@ -101580,20 +102460,25 @@ var init_vercel = __esm({
|
|
|
101580
102460
|
return await search(searchOptions);
|
|
101581
102461
|
};
|
|
101582
102462
|
if (!searchDelegate) {
|
|
101583
|
-
const searchKey = `${searchQuery}::${exact || false}`;
|
|
102463
|
+
const searchKey = `${searchPath}::${searchQuery}::${exact || false}`;
|
|
101584
102464
|
if (!nextPage) {
|
|
101585
102465
|
if (previousSearches.has(searchKey)) {
|
|
101586
|
-
|
|
102466
|
+
const blockCount = (dupBlockCounts.get(searchKey) || 0) + 1;
|
|
102467
|
+
dupBlockCounts.set(searchKey, blockCount);
|
|
101587
102468
|
if (debug) {
|
|
101588
|
-
console.error(`[DEDUP] Blocked duplicate search (${
|
|
102469
|
+
console.error(`[DEDUP] Blocked duplicate search (${blockCount}x): "${searchQuery}" (path: "${searchPath}")`);
|
|
102470
|
+
}
|
|
102471
|
+
if (blockCount >= 3) {
|
|
102472
|
+
return "STOP. You have been blocked " + blockCount + " times for repeating the same search. You MUST provide your final answer NOW with whatever information you have. Do NOT call any more tools.";
|
|
101589
102473
|
}
|
|
101590
|
-
|
|
101591
|
-
|
|
102474
|
+
const prev = previousSearches.get(searchKey);
|
|
102475
|
+
if (prev.hadResults) {
|
|
102476
|
+
return `DUPLICATE SEARCH BLOCKED (${blockCount}x). You already searched for "${searchQuery}" in this path and found results. Do NOT repeat. Use extract to examine the files you already found, try a COMPLETELY different keyword, or provide your final answer.`;
|
|
101592
102477
|
}
|
|
101593
|
-
|
|
102478
|
+
const exactHint = exact ? "You used exact=true. Try a broader search with exact=false, or use listFiles to browse the directory structure." : `Try exact=true if you need literal/punctuation matching (e.g. 'description: ""'), or use listFiles to explore directories, or search for a broader/related term and filter manually.`;
|
|
102479
|
+
return `DUPLICATE SEARCH BLOCKED (${blockCount}x). You already searched for "${searchQuery}" in this path and got NO results. This term does not appear in the codebase. Do NOT repeat or rephrase \u2014 try a FUNDAMENTALLY different approach: ${exactHint} If multiple approaches have failed, provide your final answer with what you know.`;
|
|
101594
102480
|
}
|
|
101595
|
-
previousSearches.
|
|
101596
|
-
consecutiveDupBlocks = 0;
|
|
102481
|
+
previousSearches.set(searchKey, { hadResults: false });
|
|
101597
102482
|
paginationCounts.set(searchKey, 0);
|
|
101598
102483
|
} else {
|
|
101599
102484
|
const pageCount = (paginationCounts.get(searchKey) || 0) + 1;
|
|
@@ -101607,6 +102492,14 @@ var init_vercel = __esm({
|
|
|
101607
102492
|
}
|
|
101608
102493
|
try {
|
|
101609
102494
|
const result = maybeAnnotate(await runRawSearch());
|
|
102495
|
+
if (typeof result === "string" && result.includes("No results found")) {
|
|
102496
|
+
if (/^[A-Z]+-\d+$/.test(searchQuery.trim()) || /^[A-Z]+-\d+$/.test(searchQuery.replace(/"/g, "").trim())) {
|
|
102497
|
+
return result + "\n\n\u26A0\uFE0F Your query looks like a ticket/issue ID (e.g., JIRA-1234). Ticket IDs are rarely present in source code. Search for the technical concepts described in the ticket instead (e.g., function names, error messages, variable names).";
|
|
102498
|
+
}
|
|
102499
|
+
} else if (typeof result === "string") {
|
|
102500
|
+
const entry = previousSearches.get(searchKey);
|
|
102501
|
+
if (entry) entry.hadResults = true;
|
|
102502
|
+
}
|
|
101610
102503
|
if (options.fileTracker && typeof result === "string") {
|
|
101611
102504
|
options.fileTracker.trackFilesFromOutput(result, effectiveSearchCwd).catch(() => {
|
|
101612
102505
|
});
|
|
@@ -101889,7 +102782,31 @@ var init_vercel = __esm({
|
|
|
101889
102782
|
});
|
|
101890
102783
|
};
|
|
101891
102784
|
delegateTool = (options = {}) => {
|
|
101892
|
-
const {
|
|
102785
|
+
const {
|
|
102786
|
+
debug = false,
|
|
102787
|
+
timeout = 300,
|
|
102788
|
+
cwd,
|
|
102789
|
+
allowedFolders,
|
|
102790
|
+
workspaceRoot,
|
|
102791
|
+
enableBash = false,
|
|
102792
|
+
bashConfig,
|
|
102793
|
+
architectureFileName,
|
|
102794
|
+
enableMcp = false,
|
|
102795
|
+
mcpConfig = null,
|
|
102796
|
+
mcpConfigPath = null,
|
|
102797
|
+
delegationManager = null,
|
|
102798
|
+
// Timeout settings inherited from parent agent
|
|
102799
|
+
timeoutBehavior,
|
|
102800
|
+
maxOperationTimeout,
|
|
102801
|
+
requestTimeout,
|
|
102802
|
+
gracefulTimeoutBonusSteps,
|
|
102803
|
+
negotiatedTimeoutBudget,
|
|
102804
|
+
negotiatedTimeoutMaxRequests,
|
|
102805
|
+
negotiatedTimeoutMaxPerRequest,
|
|
102806
|
+
parentOperationStartTime,
|
|
102807
|
+
onSubagentCreated,
|
|
102808
|
+
onSubagentCompleted
|
|
102809
|
+
} = options;
|
|
101893
102810
|
return (0, import_ai5.tool)({
|
|
101894
102811
|
name: "delegate",
|
|
101895
102812
|
description: delegateDescription,
|
|
@@ -101933,9 +102850,30 @@ var init_vercel = __esm({
|
|
|
101933
102850
|
console.error(`Using workspace root: ${effectivePath} (cwd was: ${cwd || "not set"})`);
|
|
101934
102851
|
}
|
|
101935
102852
|
}
|
|
102853
|
+
let effectiveTimeout = timeout;
|
|
102854
|
+
if (parentOperationStartTime && maxOperationTimeout) {
|
|
102855
|
+
const elapsed = Date.now() - parentOperationStartTime;
|
|
102856
|
+
const remaining = maxOperationTimeout - elapsed;
|
|
102857
|
+
const budgetCap = Math.max(30, Math.floor(remaining * 0.9 / 1e3));
|
|
102858
|
+
if (budgetCap < effectiveTimeout) {
|
|
102859
|
+
effectiveTimeout = budgetCap;
|
|
102860
|
+
if (debug) {
|
|
102861
|
+
console.error(`[DELEGATE] Capping timeout from ${timeout}s to ${effectiveTimeout}s (remaining parent budget: ${Math.floor(remaining / 1e3)}s)`);
|
|
102862
|
+
}
|
|
102863
|
+
if (tracer) {
|
|
102864
|
+
tracer.addEvent("delegation.budget_capped", {
|
|
102865
|
+
"delegation.original_timeout_s": timeout,
|
|
102866
|
+
"delegation.effective_timeout_s": effectiveTimeout,
|
|
102867
|
+
"delegation.parent_elapsed_ms": elapsed,
|
|
102868
|
+
"delegation.parent_remaining_ms": remaining,
|
|
102869
|
+
"delegation.parent_session_id": parentSessionId
|
|
102870
|
+
});
|
|
102871
|
+
}
|
|
102872
|
+
}
|
|
102873
|
+
}
|
|
101936
102874
|
const result = await delegate({
|
|
101937
102875
|
task,
|
|
101938
|
-
timeout,
|
|
102876
|
+
timeout: effectiveTimeout,
|
|
101939
102877
|
debug,
|
|
101940
102878
|
currentIteration: currentIteration || 0,
|
|
101941
102879
|
maxIterations: maxIterations || 30,
|
|
@@ -101954,7 +102892,14 @@ var init_vercel = __esm({
|
|
|
101954
102892
|
mcpConfigPath,
|
|
101955
102893
|
delegationManager,
|
|
101956
102894
|
// Per-instance delegation limits
|
|
101957
|
-
parentAbortSignal
|
|
102895
|
+
parentAbortSignal,
|
|
102896
|
+
// Inherit timeout settings for subagent
|
|
102897
|
+
timeoutBehavior,
|
|
102898
|
+
requestTimeout,
|
|
102899
|
+
gracefulTimeoutBonusSteps,
|
|
102900
|
+
// Subagent lifecycle callbacks for graceful stop coordination
|
|
102901
|
+
onSubagentCreated,
|
|
102902
|
+
onSubagentCompleted
|
|
101958
102903
|
});
|
|
101959
102904
|
return result;
|
|
101960
102905
|
}
|
|
@@ -103433,6 +104378,121 @@ var init_file_lister = __esm({
|
|
|
103433
104378
|
}
|
|
103434
104379
|
});
|
|
103435
104380
|
|
|
104381
|
+
// src/agent/otelLogBridge.js
|
|
104382
|
+
function getOtelApi() {
|
|
104383
|
+
if (otelApiAttempted) return otelApi;
|
|
104384
|
+
otelApiAttempted = true;
|
|
104385
|
+
try {
|
|
104386
|
+
otelApi = (function(name15) {
|
|
104387
|
+
return _require(name15);
|
|
104388
|
+
})("@opentelemetry/api");
|
|
104389
|
+
} catch {
|
|
104390
|
+
}
|
|
104391
|
+
return otelApi;
|
|
104392
|
+
}
|
|
104393
|
+
function getOtelLogger() {
|
|
104394
|
+
if (otelLoggerAttempted) return otelLogger;
|
|
104395
|
+
otelLoggerAttempted = true;
|
|
104396
|
+
try {
|
|
104397
|
+
const { logs } = (function(name15) {
|
|
104398
|
+
return _require(name15);
|
|
104399
|
+
})("@opentelemetry/api-logs");
|
|
104400
|
+
otelLogger = logs.getLogger("probe-agent");
|
|
104401
|
+
} catch {
|
|
104402
|
+
}
|
|
104403
|
+
return otelLogger;
|
|
104404
|
+
}
|
|
104405
|
+
function getTraceSuffix() {
|
|
104406
|
+
try {
|
|
104407
|
+
const api2 = getOtelApi();
|
|
104408
|
+
if (!api2) return "";
|
|
104409
|
+
const span = api2.trace.getSpan(api2.context.active());
|
|
104410
|
+
const ctx = span?.spanContext?.();
|
|
104411
|
+
if (!ctx?.traceId) return "";
|
|
104412
|
+
return ` [trace_id=${ctx.traceId} span_id=${ctx.spanId}]`;
|
|
104413
|
+
} catch {
|
|
104414
|
+
return "";
|
|
104415
|
+
}
|
|
104416
|
+
}
|
|
104417
|
+
function emitOtelLog(msg, level) {
|
|
104418
|
+
try {
|
|
104419
|
+
const logger = getOtelLogger();
|
|
104420
|
+
if (!logger) return;
|
|
104421
|
+
const api2 = getOtelApi();
|
|
104422
|
+
let traceId, spanId;
|
|
104423
|
+
if (api2) {
|
|
104424
|
+
const span = api2.trace.getSpan(api2.context.active());
|
|
104425
|
+
const ctx = span?.spanContext?.();
|
|
104426
|
+
if (ctx?.traceId) {
|
|
104427
|
+
traceId = ctx.traceId;
|
|
104428
|
+
spanId = ctx.spanId;
|
|
104429
|
+
}
|
|
104430
|
+
}
|
|
104431
|
+
logger.emit({
|
|
104432
|
+
severityNumber: OTEL_SEVERITY[level] || 9,
|
|
104433
|
+
severityText: level.toUpperCase(),
|
|
104434
|
+
body: msg,
|
|
104435
|
+
attributes: {
|
|
104436
|
+
"probe.logger": true,
|
|
104437
|
+
...traceId ? { trace_id: traceId, span_id: spanId } : {}
|
|
104438
|
+
}
|
|
104439
|
+
});
|
|
104440
|
+
} catch {
|
|
104441
|
+
}
|
|
104442
|
+
}
|
|
104443
|
+
function patchConsole() {
|
|
104444
|
+
if (patched) return;
|
|
104445
|
+
const methods = ["log", "info", "warn", "error"];
|
|
104446
|
+
const c = globalThis.console;
|
|
104447
|
+
for (const m of methods) {
|
|
104448
|
+
const orig = c[m].bind(c);
|
|
104449
|
+
originals[m] = orig;
|
|
104450
|
+
c[m] = (...args) => {
|
|
104451
|
+
const msgParts = args.map(
|
|
104452
|
+
(a) => typeof a === "string" ? a : a instanceof Error ? a.message : JSON.stringify(a)
|
|
104453
|
+
);
|
|
104454
|
+
const msg = msgParts.join(" ");
|
|
104455
|
+
emitOtelLog(msg, m === "log" ? "log" : m);
|
|
104456
|
+
const suffix = getTraceSuffix();
|
|
104457
|
+
if (suffix) {
|
|
104458
|
+
if (typeof args[0] === "string") {
|
|
104459
|
+
args[0] = args[0] + suffix;
|
|
104460
|
+
} else {
|
|
104461
|
+
args.push(suffix);
|
|
104462
|
+
}
|
|
104463
|
+
}
|
|
104464
|
+
return orig(...args);
|
|
104465
|
+
};
|
|
104466
|
+
}
|
|
104467
|
+
patched = true;
|
|
104468
|
+
}
|
|
104469
|
+
var import_module, _require, OTEL_SEVERITY, patched, originals, otelApi, otelApiAttempted, otelLogger, otelLoggerAttempted;
|
|
104470
|
+
var init_otelLogBridge = __esm({
|
|
104471
|
+
"src/agent/otelLogBridge.js"() {
|
|
104472
|
+
"use strict";
|
|
104473
|
+
import_module = require("module");
|
|
104474
|
+
_require = (0, import_module.createRequire)("file:///");
|
|
104475
|
+
OTEL_SEVERITY = {
|
|
104476
|
+
log: 9,
|
|
104477
|
+
// INFO
|
|
104478
|
+
info: 9,
|
|
104479
|
+
// INFO
|
|
104480
|
+
warn: 13,
|
|
104481
|
+
// WARN
|
|
104482
|
+
error: 17,
|
|
104483
|
+
// ERROR
|
|
104484
|
+
debug: 5
|
|
104485
|
+
// DEBUG
|
|
104486
|
+
};
|
|
104487
|
+
patched = false;
|
|
104488
|
+
originals = {};
|
|
104489
|
+
otelApi = null;
|
|
104490
|
+
otelApiAttempted = false;
|
|
104491
|
+
otelLogger = null;
|
|
104492
|
+
otelLoggerAttempted = false;
|
|
104493
|
+
}
|
|
104494
|
+
});
|
|
104495
|
+
|
|
103436
104496
|
// src/agent/simpleTelemetry.js
|
|
103437
104497
|
function initializeSimpleTelemetryFromOptions(options) {
|
|
103438
104498
|
const telemetry = new SimpleTelemetry({
|
|
@@ -103441,6 +104501,7 @@ function initializeSimpleTelemetryFromOptions(options) {
|
|
|
103441
104501
|
enableConsole: options.traceConsole,
|
|
103442
104502
|
filePath: options.traceFile || "./traces.jsonl"
|
|
103443
104503
|
});
|
|
104504
|
+
patchConsole();
|
|
103444
104505
|
return telemetry;
|
|
103445
104506
|
}
|
|
103446
104507
|
var import_fs15, import_path18, SimpleTelemetry, SimpleAppTracer;
|
|
@@ -103449,6 +104510,7 @@ var init_simpleTelemetry = __esm({
|
|
|
103449
104510
|
"use strict";
|
|
103450
104511
|
import_fs15 = require("fs");
|
|
103451
104512
|
import_path18 = require("path");
|
|
104513
|
+
init_otelLogBridge();
|
|
103452
104514
|
SimpleTelemetry = class {
|
|
103453
104515
|
constructor(options = {}) {
|
|
103454
104516
|
this.serviceName = options.serviceName || "probe-agent";
|
|
@@ -103899,6 +104961,9 @@ var init_hooks = __esm({
|
|
|
103899
104961
|
var index_exports = {};
|
|
103900
104962
|
__export(index_exports, {
|
|
103901
104963
|
DEFAULT_SYSTEM_MESSAGE: () => DEFAULT_SYSTEM_MESSAGE,
|
|
104964
|
+
ENGINE_ACTIVITY_TIMEOUT_DEFAULT: () => ENGINE_ACTIVITY_TIMEOUT_DEFAULT,
|
|
104965
|
+
ENGINE_ACTIVITY_TIMEOUT_MAX: () => ENGINE_ACTIVITY_TIMEOUT_MAX,
|
|
104966
|
+
ENGINE_ACTIVITY_TIMEOUT_MIN: () => ENGINE_ACTIVITY_TIMEOUT_MIN,
|
|
103902
104967
|
FileTracker: () => FileTracker,
|
|
103903
104968
|
HOOK_TYPES: () => HOOK_TYPES,
|
|
103904
104969
|
HookManager: () => HookManager,
|
|
@@ -103985,6 +105050,9 @@ init_index();
|
|
|
103985
105050
|
// Annotate the CommonJS export names for ESM import in node:
|
|
103986
105051
|
0 && (module.exports = {
|
|
103987
105052
|
DEFAULT_SYSTEM_MESSAGE,
|
|
105053
|
+
ENGINE_ACTIVITY_TIMEOUT_DEFAULT,
|
|
105054
|
+
ENGINE_ACTIVITY_TIMEOUT_MAX,
|
|
105055
|
+
ENGINE_ACTIVITY_TIMEOUT_MIN,
|
|
103988
105056
|
FileTracker,
|
|
103989
105057
|
HOOK_TYPES,
|
|
103990
105058
|
HookManager,
|