@probelabs/probe 0.6.0-rc124 → 0.6.0-rc126
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/build/agent/ProbeAgent.js +105 -8
- package/build/agent/hooks/HookManager.js +146 -0
- package/build/agent/hooks/index.js +1 -0
- package/build/agent/index.js +334 -18
- package/build/agent/probeTool.js +20 -4
- package/build/agent/storage/InMemoryStorageAdapter.js +49 -0
- package/build/agent/storage/StorageAdapter.js +51 -0
- package/build/agent/storage/index.js +2 -0
- package/build/index.js +8 -0
- package/cjs/agent/ProbeAgent.cjs +4132 -4285
- package/cjs/index.cjs +4142 -4287
- package/index.d.ts +95 -0
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +105 -8
- package/src/agent/hooks/HookManager.js +146 -0
- package/src/agent/hooks/index.js +1 -0
- package/src/agent/probeTool.js +20 -4
- package/src/agent/storage/InMemoryStorageAdapter.js +49 -0
- package/src/agent/storage/StorageAdapter.js +51 -0
- package/src/agent/storage/index.js +2 -0
- package/src/index.js +8 -0
package/build/agent/index.js
CHANGED
|
@@ -556,7 +556,7 @@ var init_BytePairEncodingCore = __esm({
|
|
|
556
556
|
var chatEnabledModels;
|
|
557
557
|
var init_modelsChatEnabled_gen = __esm({
|
|
558
558
|
"node_modules/gpt-tokenizer/esm/modelsChatEnabled.gen.js"() {
|
|
559
|
-
chatEnabledModels = ["chatgpt-4o-latest", "codex-mini-latest", "computer-use-preview", "computer-use-preview-2025-03-11", "gpt-3.5", "gpt-3.5-0301", "gpt-3.5-turbo", "gpt-3.5-turbo-0125", "gpt-3.5-turbo-0613", "gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k-0613", "gpt-3.5-turbo-instruct", "gpt-4", "gpt-4-0125-preview", "gpt-4-0314", "gpt-4-0613", "gpt-4-1106-preview", "gpt-4-1106-vision-preview", "gpt-4-32k", "gpt-4-turbo", "gpt-4-turbo-2024-04-09", "gpt-4-turbo-preview", "gpt-4.1", "gpt-4.1-2025-04-14", "gpt-4.1-mini", "gpt-4.1-mini-2025-04-14", "gpt-4.1-nano", "gpt-4.1-nano-2025-04-14", "gpt-4.5-preview", "gpt-4.5-preview-2025-02-27", "gpt-4o", "gpt-4o-2024-05-13", "gpt-4o-2024-08-06", "gpt-4o-2024-11-20", "gpt-4o-audio-preview", "gpt-4o-audio-preview-2024-10-01", "gpt-4o-audio-preview-2024-12-17", "gpt-4o-audio-preview-2025-06-03", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", "gpt-4o-mini-audio-preview", "gpt-4o-mini-audio-preview-2024-12-17", "gpt-4o-mini-search-preview", "gpt-4o-mini-search-preview-2025-03-11", "gpt-4o-search-preview", "gpt-4o-search-preview-2025-03-11", "o1", "o1-2024-12-17", "o1-mini", "o1-mini-2024-09-12", "o1-preview", "o1-preview-2024-09-12", "o1-pro", "o1-pro-2025-03-19", "o3", "o3-2025-04-16", "o3-mini", "o3-mini-2025-01-31", "o3-pro", "o3-pro-2025-06-10", "o4-mini", "o4-mini-2025-04-16"];
|
|
559
|
+
chatEnabledModels = ["chatgpt-4o-latest", "codex-mini-latest", "computer-use-preview", "computer-use-preview-2025-03-11", "gpt-3.5", "gpt-3.5-0301", "gpt-3.5-turbo", "gpt-3.5-turbo-0125", "gpt-3.5-turbo-0613", "gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k-0613", "gpt-3.5-turbo-instruct", "gpt-4", "gpt-4-0125-preview", "gpt-4-0314", "gpt-4-0613", "gpt-4-1106-preview", "gpt-4-1106-vision-preview", "gpt-4-32k", "gpt-4-turbo", "gpt-4-turbo-2024-04-09", "gpt-4-turbo-preview", "gpt-4.1", "gpt-4.1-2025-04-14", "gpt-4.1-mini", "gpt-4.1-mini-2025-04-14", "gpt-4.1-nano", "gpt-4.1-nano-2025-04-14", "gpt-4.5-preview", "gpt-4.5-preview-2025-02-27", "gpt-4o", "gpt-4o-2024-05-13", "gpt-4o-2024-08-06", "gpt-4o-2024-11-20", "gpt-4o-audio-preview", "gpt-4o-audio-preview-2024-10-01", "gpt-4o-audio-preview-2024-12-17", "gpt-4o-audio-preview-2025-06-03", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", "gpt-4o-mini-audio-preview", "gpt-4o-mini-audio-preview-2024-12-17", "gpt-4o-mini-search-preview", "gpt-4o-mini-search-preview-2025-03-11", "gpt-4o-search-preview", "gpt-4o-search-preview-2025-03-11", "gpt-5", "gpt-5-2025-08-07", "gpt-5-chat-latest", "gpt-5-codex", "gpt-5-mini", "gpt-5-mini-2025-08-07", "gpt-5-nano", "gpt-5-nano-2025-08-07", "gpt-5-pro", "gpt-5-pro-2025-10-06", "gpt-audio", "gpt-audio-2025-08-28", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", "gpt-oss-120b", "gpt-oss-20b", "o1", "o1-2024-12-17", "o1-mini", "o1-mini-2024-09-12", "o1-preview", "o1-preview-2024-09-12", "o1-pro", "o1-pro-2025-03-19", "o3", "o3-2025-04-16", "o3-deep-research", "o3-deep-research-2025-06-26", "o3-mini", "o3-mini-2025-01-31", "o3-pro", "o3-pro-2025-06-10", "o4-mini", "o4-mini-2025-04-16", "o4-mini-deep-research", "o4-mini-deep-research-2025-06-26"];
|
|
560
560
|
}
|
|
561
561
|
});
|
|
562
562
|
|
|
@@ -952,8 +952,9 @@ var init_GptEncoding = __esm({
|
|
|
952
952
|
* Returns tokens assuming the 'gpt-3.5-turbo-0301' / 'gpt-4-0314' format.
|
|
953
953
|
* Based on OpenAI's guidelines: https://github.com/openai/openai-python/blob/main/chatml.md
|
|
954
954
|
* Also mentioned in section 6 of this document: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb
|
|
955
|
+
* @param encodeOptions Options controlling how special tokens are handled.
|
|
955
956
|
*/
|
|
956
|
-
*encodeChatGenerator(chat, model = this.modelName) {
|
|
957
|
+
*encodeChatGenerator(chat, model = this.modelName, encodeOptions) {
|
|
957
958
|
if (!model) {
|
|
958
959
|
throw new Error("Model name must be provided either during initialization or passed in to the method.");
|
|
959
960
|
}
|
|
@@ -979,12 +980,12 @@ var init_GptEncoding = __esm({
|
|
|
979
980
|
if (encodedRoleSeparator.length > 0) {
|
|
980
981
|
yield encodedRoleSeparator;
|
|
981
982
|
}
|
|
982
|
-
yield* this.encodeGenerator(content);
|
|
983
|
+
yield* this.encodeGenerator(content, encodeOptions);
|
|
983
984
|
yield [chatEndToken];
|
|
984
985
|
yield encodedMessageSeparator;
|
|
985
986
|
}
|
|
986
987
|
yield [chatStartToken];
|
|
987
|
-
yield* this.encodeGenerator("assistant");
|
|
988
|
+
yield* this.encodeGenerator("assistant", encodeOptions);
|
|
988
989
|
if (encodedRoleSeparator.length > 0) {
|
|
989
990
|
yield encodedRoleSeparator;
|
|
990
991
|
}
|
|
@@ -995,15 +996,20 @@ var init_GptEncoding = __esm({
|
|
|
995
996
|
* Returns tokens assuming the 'gpt-3.5-turbo-0301' / 'gpt-4-0314' format.
|
|
996
997
|
* Based on OpenAI's guidelines: https://github.com/openai/openai-python/blob/main/chatml.md
|
|
997
998
|
* Also mentioned in section 6 of this document: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb
|
|
999
|
+
* @param encodeOptions Options controlling how special tokens are handled.
|
|
998
1000
|
*/
|
|
999
|
-
encodeChat(chat, model = this.modelName) {
|
|
1000
|
-
return [...this.encodeChatGenerator(chat, model)].flat();
|
|
1001
|
+
encodeChat(chat, model = this.modelName, encodeOptions) {
|
|
1002
|
+
return [...this.encodeChatGenerator(chat, model, encodeOptions)].flat();
|
|
1001
1003
|
}
|
|
1002
1004
|
/**
|
|
1005
|
+
* Checks whether the provided input stays within the provided token limit.
|
|
1006
|
+
* @param input The string or chat messages to evaluate.
|
|
1007
|
+
* @param tokenLimit The maximum allowed number of tokens.
|
|
1008
|
+
* @param encodeOptions Options controlling how special tokens are handled.
|
|
1003
1009
|
* @returns {false | number} false if token limit is exceeded, otherwise the number of tokens
|
|
1004
1010
|
*/
|
|
1005
|
-
isWithinTokenLimit(input, tokenLimit) {
|
|
1006
|
-
const tokenGenerator = typeof input === "string" ? this.encodeGenerator(input) : this.encodeChatGenerator(input);
|
|
1011
|
+
isWithinTokenLimit(input, tokenLimit, encodeOptions) {
|
|
1012
|
+
const tokenGenerator = typeof input === "string" ? this.encodeGenerator(input, encodeOptions) : this.encodeChatGenerator(input, void 0, encodeOptions);
|
|
1007
1013
|
let count = 0;
|
|
1008
1014
|
for (const tokens of tokenGenerator) {
|
|
1009
1015
|
count += tokens.length;
|
|
@@ -1015,6 +1021,8 @@ var init_GptEncoding = __esm({
|
|
|
1015
1021
|
}
|
|
1016
1022
|
/**
|
|
1017
1023
|
* Counts the number of tokens in the input.
|
|
1024
|
+
* @param input The string or chat messages to evaluate.
|
|
1025
|
+
* @param encodeOptions Options controlling how special tokens are handled.
|
|
1018
1026
|
* @returns {number} The number of tokens.
|
|
1019
1027
|
*/
|
|
1020
1028
|
countTokens(input, encodeOptions) {
|
|
@@ -1028,7 +1036,7 @@ var init_GptEncoding = __esm({
|
|
|
1028
1036
|
}
|
|
1029
1037
|
return this.bytePairEncodingCoreProcessor.countNative(input, specialTokenConfig.allowedSpecial);
|
|
1030
1038
|
}
|
|
1031
|
-
const tokenGenerator = this.encodeChatGenerator(input);
|
|
1039
|
+
const tokenGenerator = this.encodeChatGenerator(input, void 0, encodeOptions);
|
|
1032
1040
|
let count = 0;
|
|
1033
1041
|
for (const tokens of tokenGenerator) {
|
|
1034
1042
|
count += tokens.length;
|
|
@@ -1466,6 +1474,226 @@ var init_tokenCounter = __esm({
|
|
|
1466
1474
|
}
|
|
1467
1475
|
});
|
|
1468
1476
|
|
|
1477
|
+
// src/agent/storage/StorageAdapter.js
|
|
1478
|
+
var StorageAdapter;
|
|
1479
|
+
var init_StorageAdapter = __esm({
|
|
1480
|
+
"src/agent/storage/StorageAdapter.js"() {
|
|
1481
|
+
"use strict";
|
|
1482
|
+
StorageAdapter = class {
|
|
1483
|
+
/**
|
|
1484
|
+
* Load conversation history for a session
|
|
1485
|
+
* @param {string} sessionId - Session identifier
|
|
1486
|
+
* @returns {Promise<Array<Object>>} Array of message objects with {role, content, ...}
|
|
1487
|
+
*/
|
|
1488
|
+
async loadHistory(sessionId) {
|
|
1489
|
+
throw new Error("StorageAdapter.loadHistory() must be implemented by subclass");
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Save a message to storage
|
|
1493
|
+
* @param {string} sessionId - Session identifier
|
|
1494
|
+
* @param {Object} message - Message object { role, content, ... }
|
|
1495
|
+
* @returns {Promise<void>}
|
|
1496
|
+
*/
|
|
1497
|
+
async saveMessage(sessionId, message) {
|
|
1498
|
+
throw new Error("StorageAdapter.saveMessage() must be implemented by subclass");
|
|
1499
|
+
}
|
|
1500
|
+
/**
|
|
1501
|
+
* Clear history for a session
|
|
1502
|
+
* @param {string} sessionId - Session identifier
|
|
1503
|
+
* @returns {Promise<void>}
|
|
1504
|
+
*/
|
|
1505
|
+
async clearHistory(sessionId) {
|
|
1506
|
+
throw new Error("StorageAdapter.clearHistory() must be implemented by subclass");
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* Get session metadata (optional)
|
|
1510
|
+
* @param {string} sessionId - Session identifier
|
|
1511
|
+
* @returns {Promise<Object|null>} Session metadata or null
|
|
1512
|
+
*/
|
|
1513
|
+
async getSessionMetadata(sessionId) {
|
|
1514
|
+
return null;
|
|
1515
|
+
}
|
|
1516
|
+
/**
|
|
1517
|
+
* Update session activity timestamp (optional)
|
|
1518
|
+
* @param {string} sessionId - Session identifier
|
|
1519
|
+
* @returns {Promise<void>}
|
|
1520
|
+
*/
|
|
1521
|
+
async updateSessionActivity(sessionId) {
|
|
1522
|
+
}
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
});
|
|
1526
|
+
|
|
1527
|
+
// src/agent/storage/InMemoryStorageAdapter.js
|
|
1528
|
+
var InMemoryStorageAdapter;
|
|
1529
|
+
var init_InMemoryStorageAdapter = __esm({
|
|
1530
|
+
"src/agent/storage/InMemoryStorageAdapter.js"() {
|
|
1531
|
+
"use strict";
|
|
1532
|
+
init_StorageAdapter();
|
|
1533
|
+
InMemoryStorageAdapter = class extends StorageAdapter {
|
|
1534
|
+
constructor() {
|
|
1535
|
+
super();
|
|
1536
|
+
this.sessions = /* @__PURE__ */ new Map();
|
|
1537
|
+
}
|
|
1538
|
+
async loadHistory(sessionId) {
|
|
1539
|
+
const session = this.sessions.get(sessionId);
|
|
1540
|
+
return session ? session.messages : [];
|
|
1541
|
+
}
|
|
1542
|
+
async saveMessage(sessionId, message) {
|
|
1543
|
+
if (!this.sessions.has(sessionId)) {
|
|
1544
|
+
this.sessions.set(sessionId, {
|
|
1545
|
+
messages: [],
|
|
1546
|
+
metadata: {
|
|
1547
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1548
|
+
lastActivity: (/* @__PURE__ */ new Date()).toISOString()
|
|
1549
|
+
}
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
const session = this.sessions.get(sessionId);
|
|
1553
|
+
session.messages.push(message);
|
|
1554
|
+
session.metadata.lastActivity = (/* @__PURE__ */ new Date()).toISOString();
|
|
1555
|
+
}
|
|
1556
|
+
async clearHistory(sessionId) {
|
|
1557
|
+
this.sessions.delete(sessionId);
|
|
1558
|
+
}
|
|
1559
|
+
async getSessionMetadata(sessionId) {
|
|
1560
|
+
const session = this.sessions.get(sessionId);
|
|
1561
|
+
return session ? session.metadata : null;
|
|
1562
|
+
}
|
|
1563
|
+
async updateSessionActivity(sessionId) {
|
|
1564
|
+
const session = this.sessions.get(sessionId);
|
|
1565
|
+
if (session) {
|
|
1566
|
+
session.metadata.lastActivity = (/* @__PURE__ */ new Date()).toISOString();
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
|
|
1573
|
+
// src/agent/hooks/HookManager.js
|
|
1574
|
+
var HookManager, HOOK_TYPES;
|
|
1575
|
+
var init_HookManager = __esm({
|
|
1576
|
+
"src/agent/hooks/HookManager.js"() {
|
|
1577
|
+
"use strict";
|
|
1578
|
+
HookManager = class {
|
|
1579
|
+
constructor() {
|
|
1580
|
+
this.hooks = /* @__PURE__ */ new Map();
|
|
1581
|
+
}
|
|
1582
|
+
/**
|
|
1583
|
+
* Register a hook callback
|
|
1584
|
+
* @param {string} hookName - Name of the hook
|
|
1585
|
+
* @param {Function} callback - Callback function
|
|
1586
|
+
* @returns {Function} Unregister function
|
|
1587
|
+
*/
|
|
1588
|
+
on(hookName, callback) {
|
|
1589
|
+
if (!this.hooks.has(hookName)) {
|
|
1590
|
+
this.hooks.set(hookName, /* @__PURE__ */ new Set());
|
|
1591
|
+
}
|
|
1592
|
+
this.hooks.get(hookName).add(callback);
|
|
1593
|
+
return () => this.off(hookName, callback);
|
|
1594
|
+
}
|
|
1595
|
+
/**
|
|
1596
|
+
* Register a one-time hook callback
|
|
1597
|
+
* @param {string} hookName - Name of the hook
|
|
1598
|
+
* @param {Function} callback - Callback function
|
|
1599
|
+
* @returns {Function} Unregister function
|
|
1600
|
+
*/
|
|
1601
|
+
once(hookName, callback) {
|
|
1602
|
+
const wrappedCallback = async (data) => {
|
|
1603
|
+
this.off(hookName, wrappedCallback);
|
|
1604
|
+
await callback(data);
|
|
1605
|
+
};
|
|
1606
|
+
return this.on(hookName, wrappedCallback);
|
|
1607
|
+
}
|
|
1608
|
+
/**
|
|
1609
|
+
* Unregister a hook callback
|
|
1610
|
+
* @param {string} hookName - Name of the hook
|
|
1611
|
+
* @param {Function} callback - Callback function
|
|
1612
|
+
*/
|
|
1613
|
+
off(hookName, callback) {
|
|
1614
|
+
const callbacks = this.hooks.get(hookName);
|
|
1615
|
+
if (callbacks) {
|
|
1616
|
+
callbacks.delete(callback);
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
/**
|
|
1620
|
+
* Emit a hook event
|
|
1621
|
+
* @param {string} hookName - Name of the hook
|
|
1622
|
+
* @param {any} data - Data to pass to callbacks
|
|
1623
|
+
* @returns {Promise<void>}
|
|
1624
|
+
*/
|
|
1625
|
+
async emit(hookName, data) {
|
|
1626
|
+
const callbacks = this.hooks.get(hookName);
|
|
1627
|
+
if (!callbacks || callbacks.size === 0) return;
|
|
1628
|
+
const promises = Array.from(callbacks).map((callback) => {
|
|
1629
|
+
try {
|
|
1630
|
+
return Promise.resolve(callback(data));
|
|
1631
|
+
} catch (error) {
|
|
1632
|
+
return Promise.reject(error);
|
|
1633
|
+
}
|
|
1634
|
+
});
|
|
1635
|
+
const results = await Promise.allSettled(promises);
|
|
1636
|
+
results.forEach((result, index) => {
|
|
1637
|
+
if (result.status === "rejected") {
|
|
1638
|
+
console.error(`[HookManager] Error in hook "${hookName}" (callback ${index + 1}):`, result.reason);
|
|
1639
|
+
}
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
/**
|
|
1643
|
+
* Clear all hooks or hooks for a specific event
|
|
1644
|
+
* @param {string} [hookName] - Optional hook name to clear
|
|
1645
|
+
*/
|
|
1646
|
+
clear(hookName) {
|
|
1647
|
+
if (hookName) {
|
|
1648
|
+
this.hooks.delete(hookName);
|
|
1649
|
+
} else {
|
|
1650
|
+
this.hooks.clear();
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
/**
|
|
1654
|
+
* Get list of registered hook names
|
|
1655
|
+
* @returns {string[]} Array of hook names
|
|
1656
|
+
*/
|
|
1657
|
+
getHookNames() {
|
|
1658
|
+
return Array.from(this.hooks.keys());
|
|
1659
|
+
}
|
|
1660
|
+
/**
|
|
1661
|
+
* Get number of callbacks for a hook
|
|
1662
|
+
* @param {string} hookName - Name of the hook
|
|
1663
|
+
* @returns {number} Number of callbacks
|
|
1664
|
+
*/
|
|
1665
|
+
getCallbackCount(hookName) {
|
|
1666
|
+
const callbacks = this.hooks.get(hookName);
|
|
1667
|
+
return callbacks ? callbacks.size : 0;
|
|
1668
|
+
}
|
|
1669
|
+
};
|
|
1670
|
+
HOOK_TYPES = {
|
|
1671
|
+
// Lifecycle hooks
|
|
1672
|
+
AGENT_INITIALIZED: "agent:initialized",
|
|
1673
|
+
AGENT_CLEANUP: "agent:cleanup",
|
|
1674
|
+
// Message hooks
|
|
1675
|
+
MESSAGE_USER: "message:user",
|
|
1676
|
+
MESSAGE_ASSISTANT: "message:assistant",
|
|
1677
|
+
MESSAGE_SYSTEM: "message:system",
|
|
1678
|
+
// Tool execution hooks
|
|
1679
|
+
TOOL_START: "tool:start",
|
|
1680
|
+
TOOL_END: "tool:end",
|
|
1681
|
+
TOOL_ERROR: "tool:error",
|
|
1682
|
+
// AI streaming hooks
|
|
1683
|
+
AI_STREAM_START: "ai:stream:start",
|
|
1684
|
+
AI_STREAM_DELTA: "ai:stream:delta",
|
|
1685
|
+
AI_STREAM_END: "ai:stream:end",
|
|
1686
|
+
// Storage hooks
|
|
1687
|
+
STORAGE_LOAD: "storage:load",
|
|
1688
|
+
STORAGE_SAVE: "storage:save",
|
|
1689
|
+
STORAGE_CLEAR: "storage:clear",
|
|
1690
|
+
// Iteration hooks
|
|
1691
|
+
ITERATION_START: "iteration:start",
|
|
1692
|
+
ITERATION_END: "iteration:end"
|
|
1693
|
+
};
|
|
1694
|
+
}
|
|
1695
|
+
});
|
|
1696
|
+
|
|
1469
1697
|
// src/directory-resolver.js
|
|
1470
1698
|
import path from "path";
|
|
1471
1699
|
import os from "os";
|
|
@@ -16001,15 +16229,16 @@ var init_probeTool = __esm({
|
|
|
16001
16229
|
const { directory = ".", workingDirectory } = params;
|
|
16002
16230
|
const baseCwd = workingDirectory || process.cwd();
|
|
16003
16231
|
const secureBaseDir = path6.resolve(baseCwd);
|
|
16232
|
+
const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
|
|
16004
16233
|
let targetDir;
|
|
16005
16234
|
if (path6.isAbsolute(directory)) {
|
|
16006
16235
|
targetDir = path6.resolve(directory);
|
|
16007
|
-
if (!targetDir.startsWith(secureBaseDir + path6.sep) && targetDir !== secureBaseDir) {
|
|
16236
|
+
if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + path6.sep) && targetDir !== secureBaseDir) {
|
|
16008
16237
|
throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
|
|
16009
16238
|
}
|
|
16010
16239
|
} else {
|
|
16011
16240
|
targetDir = path6.resolve(secureBaseDir, directory);
|
|
16012
|
-
if (!targetDir.startsWith(secureBaseDir + path6.sep) && targetDir !== secureBaseDir) {
|
|
16241
|
+
if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + path6.sep) && targetDir !== secureBaseDir) {
|
|
16013
16242
|
throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
|
|
16014
16243
|
}
|
|
16015
16244
|
}
|
|
@@ -16073,15 +16302,16 @@ var init_probeTool = __esm({
|
|
|
16073
16302
|
}
|
|
16074
16303
|
const baseCwd = workingDirectory || process.cwd();
|
|
16075
16304
|
const secureBaseDir = path6.resolve(baseCwd);
|
|
16305
|
+
const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
|
|
16076
16306
|
let targetDir;
|
|
16077
16307
|
if (path6.isAbsolute(directory)) {
|
|
16078
16308
|
targetDir = path6.resolve(directory);
|
|
16079
|
-
if (!targetDir.startsWith(secureBaseDir + path6.sep) && targetDir !== secureBaseDir) {
|
|
16309
|
+
if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + path6.sep) && targetDir !== secureBaseDir) {
|
|
16080
16310
|
throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
|
|
16081
16311
|
}
|
|
16082
16312
|
} else {
|
|
16083
16313
|
targetDir = path6.resolve(secureBaseDir, directory);
|
|
16084
|
-
if (!targetDir.startsWith(secureBaseDir + path6.sep) && targetDir !== secureBaseDir) {
|
|
16314
|
+
if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + path6.sep) && targetDir !== secureBaseDir) {
|
|
16085
16315
|
throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
|
|
16086
16316
|
}
|
|
16087
16317
|
}
|
|
@@ -16119,6 +16349,23 @@ var init_probeTool = __esm({
|
|
|
16119
16349
|
}
|
|
16120
16350
|
});
|
|
16121
16351
|
|
|
16352
|
+
// src/agent/storage/index.js
|
|
16353
|
+
var init_storage = __esm({
|
|
16354
|
+
"src/agent/storage/index.js"() {
|
|
16355
|
+
"use strict";
|
|
16356
|
+
init_StorageAdapter();
|
|
16357
|
+
init_InMemoryStorageAdapter();
|
|
16358
|
+
}
|
|
16359
|
+
});
|
|
16360
|
+
|
|
16361
|
+
// src/agent/hooks/index.js
|
|
16362
|
+
var init_hooks = __esm({
|
|
16363
|
+
"src/agent/hooks/index.js"() {
|
|
16364
|
+
"use strict";
|
|
16365
|
+
init_HookManager();
|
|
16366
|
+
}
|
|
16367
|
+
});
|
|
16368
|
+
|
|
16122
16369
|
// src/index.js
|
|
16123
16370
|
var init_index = __esm({
|
|
16124
16371
|
"src/index.js"() {
|
|
@@ -16138,6 +16385,8 @@ var init_index = __esm({
|
|
|
16138
16385
|
init_ProbeAgent();
|
|
16139
16386
|
init_simpleTelemetry();
|
|
16140
16387
|
init_probeTool();
|
|
16388
|
+
init_storage();
|
|
16389
|
+
init_hooks();
|
|
16141
16390
|
}
|
|
16142
16391
|
});
|
|
16143
16392
|
|
|
@@ -47311,6 +47560,8 @@ var init_ProbeAgent = __esm({
|
|
|
47311
47560
|
"src/agent/ProbeAgent.js"() {
|
|
47312
47561
|
"use strict";
|
|
47313
47562
|
init_tokenCounter();
|
|
47563
|
+
init_InMemoryStorageAdapter();
|
|
47564
|
+
init_HookManager();
|
|
47314
47565
|
init_tools2();
|
|
47315
47566
|
init_common();
|
|
47316
47567
|
init_probeTool();
|
|
@@ -47343,6 +47594,8 @@ var init_ProbeAgent = __esm({
|
|
|
47343
47594
|
* @param {string} [options.mcpConfigPath] - Path to MCP configuration file
|
|
47344
47595
|
* @param {Object} [options.mcpConfig] - MCP configuration object (overrides mcpConfigPath)
|
|
47345
47596
|
* @param {Array} [options.mcpServers] - Deprecated, use mcpConfig instead
|
|
47597
|
+
* @param {Object} [options.storageAdapter] - Custom storage adapter for history management
|
|
47598
|
+
* @param {Object} [options.hooks] - Hook callbacks for events (e.g., {'tool:start': callback})
|
|
47346
47599
|
*/
|
|
47347
47600
|
constructor(options = {}) {
|
|
47348
47601
|
this.sessionId = options.sessionId || randomUUID4();
|
|
@@ -47356,6 +47609,13 @@ var init_ProbeAgent = __esm({
|
|
|
47356
47609
|
this.maxResponseTokens = options.maxResponseTokens || parseInt(process.env.MAX_RESPONSE_TOKENS || "0", 10) || null;
|
|
47357
47610
|
this.maxIterations = options.maxIterations || null;
|
|
47358
47611
|
this.disableMermaidValidation = !!options.disableMermaidValidation;
|
|
47612
|
+
this.storageAdapter = options.storageAdapter || new InMemoryStorageAdapter();
|
|
47613
|
+
this.hooks = new HookManager();
|
|
47614
|
+
if (options.hooks) {
|
|
47615
|
+
for (const [hookName, callback] of Object.entries(options.hooks)) {
|
|
47616
|
+
this.hooks.on(hookName, callback);
|
|
47617
|
+
}
|
|
47618
|
+
}
|
|
47359
47619
|
this.enableBash = !!options.enableBash;
|
|
47360
47620
|
this.bashConfig = options.bashConfig || {};
|
|
47361
47621
|
if (options.allowedFolders && Array.isArray(options.allowedFolders)) {
|
|
@@ -47389,9 +47649,23 @@ var init_ProbeAgent = __esm({
|
|
|
47389
47649
|
}
|
|
47390
47650
|
/**
|
|
47391
47651
|
* Initialize the agent asynchronously (must be called after constructor)
|
|
47392
|
-
* This method initializes MCP and merges MCP tools into the tool list
|
|
47652
|
+
* This method initializes MCP and merges MCP tools into the tool list, and loads history from storage
|
|
47393
47653
|
*/
|
|
47394
47654
|
async initialize() {
|
|
47655
|
+
try {
|
|
47656
|
+
const history = await this.storageAdapter.loadHistory(this.sessionId);
|
|
47657
|
+
this.history = history;
|
|
47658
|
+
if (this.debug && history.length > 0) {
|
|
47659
|
+
console.log(`[DEBUG] Loaded ${history.length} messages from storage for session ${this.sessionId}`);
|
|
47660
|
+
}
|
|
47661
|
+
await this.hooks.emit(HOOK_TYPES.STORAGE_LOAD, {
|
|
47662
|
+
sessionId: this.sessionId,
|
|
47663
|
+
messages: history
|
|
47664
|
+
});
|
|
47665
|
+
} catch (error) {
|
|
47666
|
+
console.error(`[ERROR] Failed to load history from storage:`, error);
|
|
47667
|
+
this.history = [];
|
|
47668
|
+
}
|
|
47395
47669
|
if (this.enableMcp && !this._mcpInitialized) {
|
|
47396
47670
|
this._mcpInitialized = true;
|
|
47397
47671
|
try {
|
|
@@ -47424,6 +47698,10 @@ var init_ProbeAgent = __esm({
|
|
|
47424
47698
|
this.mcpBridge = null;
|
|
47425
47699
|
}
|
|
47426
47700
|
}
|
|
47701
|
+
await this.hooks.emit(HOOK_TYPES.AGENT_INITIALIZED, {
|
|
47702
|
+
sessionId: this.sessionId,
|
|
47703
|
+
agent: this
|
|
47704
|
+
});
|
|
47427
47705
|
}
|
|
47428
47706
|
/**
|
|
47429
47707
|
* Initialize tools with configuration
|
|
@@ -47475,7 +47753,7 @@ var init_ProbeAgent = __esm({
|
|
|
47475
47753
|
}
|
|
47476
47754
|
const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
|
|
47477
47755
|
const openaiApiKey = process.env.OPENAI_API_KEY;
|
|
47478
|
-
const googleApiKey = process.env.GOOGLE_API_KEY;
|
|
47756
|
+
const googleApiKey = process.env.GOOGLE_GENERATIVE_AI_API_KEY || process.env.GOOGLE_API_KEY;
|
|
47479
47757
|
const awsAccessKeyId = process.env.AWS_ACCESS_KEY_ID;
|
|
47480
47758
|
const awsSecretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
|
|
47481
47759
|
const awsRegion = process.env.AWS_REGION;
|
|
@@ -47523,7 +47801,7 @@ var init_ProbeAgent = __esm({
|
|
|
47523
47801
|
} else if (awsAccessKeyId && awsSecretAccessKey && awsRegion || awsApiKey) {
|
|
47524
47802
|
this.initializeBedrockModel(awsAccessKeyId, awsSecretAccessKey, awsRegion, awsSessionToken, awsApiKey, awsBedrockBaseUrl, modelName);
|
|
47525
47803
|
} else {
|
|
47526
|
-
throw new Error("No API key provided. Please set ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY, AWS credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION), or AWS_BEDROCK_API_KEY environment variables.");
|
|
47804
|
+
throw new Error("No API key provided. Please set ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY (or GOOGLE_API_KEY), AWS credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION), or AWS_BEDROCK_API_KEY environment variables.");
|
|
47527
47805
|
}
|
|
47528
47806
|
}
|
|
47529
47807
|
/**
|
|
@@ -48161,6 +48439,12 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
48161
48439
|
options = schemaOrOptions || {};
|
|
48162
48440
|
}
|
|
48163
48441
|
try {
|
|
48442
|
+
const oldHistoryLength = this.history.length;
|
|
48443
|
+
await this.hooks.emit(HOOK_TYPES.MESSAGE_USER, {
|
|
48444
|
+
sessionId: this.sessionId,
|
|
48445
|
+
message,
|
|
48446
|
+
images
|
|
48447
|
+
});
|
|
48164
48448
|
const systemMessage = await this.getSystemMessage();
|
|
48165
48449
|
let userMessage = { role: "user", content: message.trim() };
|
|
48166
48450
|
if (images && images.length > 0) {
|
|
@@ -48246,6 +48530,9 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
48246
48530
|
});
|
|
48247
48531
|
for await (const delta of result.textStream) {
|
|
48248
48532
|
assistantResponseContent += delta;
|
|
48533
|
+
if (options.onStream) {
|
|
48534
|
+
options.onStream(delta);
|
|
48535
|
+
}
|
|
48249
48536
|
}
|
|
48250
48537
|
const usage = await result.usage;
|
|
48251
48538
|
if (usage) {
|
|
@@ -48310,6 +48597,13 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
48310
48597
|
const validation = attemptCompletionSchema.safeParse(params);
|
|
48311
48598
|
if (validation.success) {
|
|
48312
48599
|
finalResult = validation.data.result;
|
|
48600
|
+
if (options.onStream && finalResult) {
|
|
48601
|
+
const chunkSize = 50;
|
|
48602
|
+
for (let i = 0; i < finalResult.length; i += chunkSize) {
|
|
48603
|
+
const chunk = finalResult.slice(i, Math.min(i + chunkSize, finalResult.length));
|
|
48604
|
+
options.onStream(chunk);
|
|
48605
|
+
}
|
|
48606
|
+
}
|
|
48313
48607
|
if (this.debug) console.log(`[DEBUG] Task completed successfully with result: ${finalResult.substring(0, 100)}...`);
|
|
48314
48608
|
} else {
|
|
48315
48609
|
console.error(`[ERROR] Invalid attempt_completion parameters:`, validation.error);
|
|
@@ -48384,7 +48678,9 @@ ${toolResultContent}
|
|
|
48384
48678
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
48385
48679
|
name: toolName,
|
|
48386
48680
|
args: toolParams,
|
|
48387
|
-
status: "started"
|
|
48681
|
+
status: "started",
|
|
48682
|
+
pauseStream: true
|
|
48683
|
+
// Signal to pause text streaming
|
|
48388
48684
|
});
|
|
48389
48685
|
const executeToolCall = async () => {
|
|
48390
48686
|
if (toolName === "delegate") {
|
|
@@ -48568,6 +48864,18 @@ IMPORTANT: When using <attempt_complete>, this must be the ONLY content in your
|
|
|
48568
48864
|
}
|
|
48569
48865
|
}
|
|
48570
48866
|
this.tokenCounter.updateHistory(this.history);
|
|
48867
|
+
try {
|
|
48868
|
+
const messagesToSave = currentMessages.slice(oldHistoryLength);
|
|
48869
|
+
for (const message2 of messagesToSave) {
|
|
48870
|
+
await this.storageAdapter.saveMessage(this.sessionId, message2);
|
|
48871
|
+
await this.hooks.emit(HOOK_TYPES.STORAGE_SAVE, {
|
|
48872
|
+
sessionId: this.sessionId,
|
|
48873
|
+
message: message2
|
|
48874
|
+
});
|
|
48875
|
+
}
|
|
48876
|
+
} catch (error) {
|
|
48877
|
+
console.error(`[ERROR] Failed to save messages to storage:`, error);
|
|
48878
|
+
}
|
|
48571
48879
|
const reachedMaxIterations = currentIteration >= maxIterations && !completionAttempted;
|
|
48572
48880
|
if (options.schema && !options._schemaFormatted && !completionAttempted && !reachedMaxIterations) {
|
|
48573
48881
|
if (this.debug) {
|
|
@@ -48932,10 +49240,18 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
48932
49240
|
/**
|
|
48933
49241
|
* Clear conversation history and reset counters
|
|
48934
49242
|
*/
|
|
48935
|
-
clearHistory() {
|
|
49243
|
+
async clearHistory() {
|
|
49244
|
+
try {
|
|
49245
|
+
await this.storageAdapter.clearHistory(this.sessionId);
|
|
49246
|
+
} catch (error) {
|
|
49247
|
+
console.error(`[ERROR] Failed to clear history in storage:`, error);
|
|
49248
|
+
}
|
|
48936
49249
|
this.history = [];
|
|
48937
49250
|
this.tokenCounter.clear();
|
|
48938
49251
|
clearToolExecutionData(this.sessionId);
|
|
49252
|
+
await this.hooks.emit(HOOK_TYPES.STORAGE_CLEAR, {
|
|
49253
|
+
sessionId: this.sessionId
|
|
49254
|
+
});
|
|
48939
49255
|
if (this.debug) {
|
|
48940
49256
|
console.log(`[DEBUG] Cleared conversation history and reset counters for session ${this.sessionId}`);
|
|
48941
49257
|
}
|
package/build/agent/probeTool.js
CHANGED
|
@@ -224,19 +224,27 @@ export const listFilesTool = {
|
|
|
224
224
|
// Security: Validate path to prevent traversal attacks
|
|
225
225
|
const secureBaseDir = path.resolve(baseCwd);
|
|
226
226
|
|
|
227
|
+
// Check if this is a dependency path that should bypass workspace restrictions
|
|
228
|
+
const isDependencyPath = directory.startsWith('/dep/') ||
|
|
229
|
+
directory.startsWith('go:') ||
|
|
230
|
+
directory.startsWith('js:') ||
|
|
231
|
+
directory.startsWith('rust:');
|
|
232
|
+
|
|
227
233
|
// If directory is absolute, check if it's within the secure base directory
|
|
228
234
|
// If it's relative, resolve it against the secure base directory
|
|
229
235
|
let targetDir;
|
|
230
236
|
if (path.isAbsolute(directory)) {
|
|
231
237
|
targetDir = path.resolve(directory);
|
|
232
238
|
// Check if the absolute path is within the secure base directory
|
|
233
|
-
|
|
239
|
+
// Allow dependency paths to bypass this restriction
|
|
240
|
+
if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + path.sep) && targetDir !== secureBaseDir) {
|
|
234
241
|
throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
|
|
235
242
|
}
|
|
236
243
|
} else {
|
|
237
244
|
targetDir = path.resolve(secureBaseDir, directory);
|
|
238
245
|
// Double-check the resolved path is still within the secure base directory
|
|
239
|
-
|
|
246
|
+
// Allow dependency paths to bypass this restriction
|
|
247
|
+
if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + path.sep) && targetDir !== secureBaseDir) {
|
|
240
248
|
throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
|
|
241
249
|
}
|
|
242
250
|
}
|
|
@@ -323,19 +331,27 @@ export const searchFilesTool = {
|
|
|
323
331
|
const baseCwd = workingDirectory || process.cwd();
|
|
324
332
|
const secureBaseDir = path.resolve(baseCwd);
|
|
325
333
|
|
|
334
|
+
// Check if this is a dependency path that should bypass workspace restrictions
|
|
335
|
+
const isDependencyPath = directory.startsWith('/dep/') ||
|
|
336
|
+
directory.startsWith('go:') ||
|
|
337
|
+
directory.startsWith('js:') ||
|
|
338
|
+
directory.startsWith('rust:');
|
|
339
|
+
|
|
326
340
|
// If directory is absolute, check if it's within the secure base directory
|
|
327
341
|
// If it's relative, resolve it against the secure base directory
|
|
328
342
|
let targetDir;
|
|
329
343
|
if (path.isAbsolute(directory)) {
|
|
330
344
|
targetDir = path.resolve(directory);
|
|
331
345
|
// Check if the absolute path is within the secure base directory
|
|
332
|
-
|
|
346
|
+
// Allow dependency paths to bypass this restriction
|
|
347
|
+
if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + path.sep) && targetDir !== secureBaseDir) {
|
|
333
348
|
throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
|
|
334
349
|
}
|
|
335
350
|
} else {
|
|
336
351
|
targetDir = path.resolve(secureBaseDir, directory);
|
|
337
352
|
// Double-check the resolved path is still within the secure base directory
|
|
338
|
-
|
|
353
|
+
// Allow dependency paths to bypass this restriction
|
|
354
|
+
if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + path.sep) && targetDir !== secureBaseDir) {
|
|
339
355
|
throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
|
|
340
356
|
}
|
|
341
357
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { StorageAdapter } from './StorageAdapter.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default in-memory storage adapter
|
|
5
|
+
* This is the default behavior - stores history in a Map in memory
|
|
6
|
+
*/
|
|
7
|
+
export class InMemoryStorageAdapter extends StorageAdapter {
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
this.sessions = new Map(); // sessionId -> {messages: [], metadata: {}}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async loadHistory(sessionId) {
|
|
14
|
+
const session = this.sessions.get(sessionId);
|
|
15
|
+
return session ? session.messages : [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async saveMessage(sessionId, message) {
|
|
19
|
+
if (!this.sessions.has(sessionId)) {
|
|
20
|
+
this.sessions.set(sessionId, {
|
|
21
|
+
messages: [],
|
|
22
|
+
metadata: {
|
|
23
|
+
createdAt: new Date().toISOString(),
|
|
24
|
+
lastActivity: new Date().toISOString()
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const session = this.sessions.get(sessionId);
|
|
30
|
+
session.messages.push(message);
|
|
31
|
+
session.metadata.lastActivity = new Date().toISOString();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async clearHistory(sessionId) {
|
|
35
|
+
this.sessions.delete(sessionId);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async getSessionMetadata(sessionId) {
|
|
39
|
+
const session = this.sessions.get(sessionId);
|
|
40
|
+
return session ? session.metadata : null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async updateSessionActivity(sessionId) {
|
|
44
|
+
const session = this.sessions.get(sessionId);
|
|
45
|
+
if (session) {
|
|
46
|
+
session.metadata.lastActivity = new Date().toISOString();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|