@probelabs/probe 0.6.0-rc167 → 0.6.0-rc169
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.d.ts +7 -1
- package/build/agent/ProbeAgent.js +353 -32
- package/build/agent/engines/codex.js +347 -0
- package/build/agent/engines/enhanced-claude-code.js +3 -42
- package/build/agent/index.js +1036 -81
- package/build/agent/mcp/built-in-server.js +334 -8
- package/build/agent/shared/Session.js +53 -0
- package/build/agent/shared/prompts.js +129 -0
- package/build/agent/tools.js +26 -9
- package/cjs/agent/ProbeAgent.cjs +1074 -92
- package/cjs/index.cjs +1083 -101
- package/index.d.ts +7 -1
- package/package.json +1 -1
- package/src/agent/ProbeAgent.d.ts +7 -1
- package/src/agent/ProbeAgent.js +353 -32
- package/src/agent/engines/codex.js +347 -0
- package/src/agent/engines/enhanced-claude-code.js +3 -42
- package/src/agent/mcp/built-in-server.js +334 -8
- package/src/agent/shared/Session.js +53 -0
- package/src/agent/shared/prompts.js +129 -0
- package/src/agent/tools.js +26 -9
package/cjs/index.cjs
CHANGED
|
@@ -6750,11 +6750,11 @@ var require_randomUUID = __commonJS({
|
|
|
6750
6750
|
var require_dist_cjs19 = __commonJS({
|
|
6751
6751
|
"node_modules/@smithy/uuid/dist-cjs/index.js"(exports2) {
|
|
6752
6752
|
"use strict";
|
|
6753
|
-
var
|
|
6753
|
+
var randomUUID6 = require_randomUUID();
|
|
6754
6754
|
var decimalToHex = Array.from({ length: 256 }, (_, i4) => i4.toString(16).padStart(2, "0"));
|
|
6755
6755
|
var v4 = () => {
|
|
6756
|
-
if (
|
|
6757
|
-
return
|
|
6756
|
+
if (randomUUID6.randomUUID) {
|
|
6757
|
+
return randomUUID6.randomUUID();
|
|
6758
6758
|
}
|
|
6759
6759
|
const rnds = new Uint8Array(16);
|
|
6760
6760
|
crypto.getRandomValues(rnds);
|
|
@@ -18445,7 +18445,7 @@ var require_package2 = __commonJS({
|
|
|
18445
18445
|
module2.exports = {
|
|
18446
18446
|
name: "@aws-sdk/client-bedrock-runtime",
|
|
18447
18447
|
description: "AWS SDK for JavaScript Bedrock Runtime Client for Node.js, Browser and React Native",
|
|
18448
|
-
version: "3.
|
|
18448
|
+
version: "3.938.0",
|
|
18449
18449
|
scripts: {
|
|
18450
18450
|
build: "concurrently 'yarn:build:cjs' 'yarn:build:es' 'yarn:build:types'",
|
|
18451
18451
|
"build:cjs": "node ../../scripts/compilation/inline client-bedrock-runtime",
|
|
@@ -24718,6 +24718,7 @@ var require_dist_cjs66 = __commonJS({
|
|
|
24718
24718
|
var _A2 = "Accept";
|
|
24719
24719
|
var _ADE3 = "AccessDeniedException";
|
|
24720
24720
|
var _AG = "ApplyGuardrail";
|
|
24721
|
+
var _AGD = "AppliedGuardrailDetails";
|
|
24721
24722
|
var _AGR = "ApplyGuardrailRequest";
|
|
24722
24723
|
var _AGRp = "ApplyGuardrailResponse";
|
|
24723
24724
|
var _AIM = "AsyncInvokeMessage";
|
|
@@ -24933,6 +24934,7 @@ var require_dist_cjs66 = __commonJS({
|
|
|
24933
24934
|
var _XABST = "X-Amzn-Bedrock-Service-Tier";
|
|
24934
24935
|
var _XABT = "X-Amzn-Bedrock-Trace";
|
|
24935
24936
|
var _a16 = "action";
|
|
24937
|
+
var _aGD = "appliedGuardrailDetails";
|
|
24936
24938
|
var _aIS = "asyncInvokeSummaries";
|
|
24937
24939
|
var _aMRF = "additionalModelRequestFields";
|
|
24938
24940
|
var _aMRFP = "additionalModelResponseFieldPaths";
|
|
@@ -24996,10 +24998,14 @@ var require_dist_cjs66 = __commonJS({
|
|
|
24996
24998
|
var _fi = "findings";
|
|
24997
24999
|
var _fil = "filters";
|
|
24998
25000
|
var _g = "guardrail";
|
|
25001
|
+
var _gA = "guardrailArn";
|
|
24999
25002
|
var _gC = "guardrailCoverage";
|
|
25000
25003
|
var _gCu = "guardrailConfig";
|
|
25001
25004
|
var _gCua = "guardContent";
|
|
25002
|
-
var _gI = "
|
|
25005
|
+
var _gI = "guardrailId";
|
|
25006
|
+
var _gIu = "guardrailIdentifier";
|
|
25007
|
+
var _gO = "guardrailOrigin";
|
|
25008
|
+
var _gOu = "guardrailOwnership";
|
|
25003
25009
|
var _gPL = "guardrailProcessingLatency";
|
|
25004
25010
|
var _gV = "guardrailVersion";
|
|
25005
25011
|
var _gu = "guarded";
|
|
@@ -25170,12 +25176,20 @@ var require_dist_cjs66 = __commonJS({
|
|
|
25170
25176
|
];
|
|
25171
25177
|
schema.TypeRegistry.for(n04).registerError(AccessDeniedException5, AccessDeniedException$1);
|
|
25172
25178
|
var AnyToolChoice = [3, n04, _ATC, 0, [], []];
|
|
25179
|
+
var AppliedGuardrailDetails = [
|
|
25180
|
+
3,
|
|
25181
|
+
n04,
|
|
25182
|
+
_AGD,
|
|
25183
|
+
0,
|
|
25184
|
+
[_gI, _gV, _gA, _gO, _gOu],
|
|
25185
|
+
[0, 0, 0, 64 | 0, 0]
|
|
25186
|
+
];
|
|
25173
25187
|
var ApplyGuardrailRequest = [
|
|
25174
25188
|
3,
|
|
25175
25189
|
n04,
|
|
25176
25190
|
_AGR,
|
|
25177
25191
|
0,
|
|
25178
|
-
[
|
|
25192
|
+
[_gIu, _gV, _s4, _co3, _oS],
|
|
25179
25193
|
[[0, 1], [0, 1], 0, [() => GuardrailContentBlockList, 0], 0]
|
|
25180
25194
|
];
|
|
25181
25195
|
var ApplyGuardrailResponse = [
|
|
@@ -25405,7 +25419,7 @@ var require_dist_cjs66 = __commonJS({
|
|
|
25405
25419
|
n04,
|
|
25406
25420
|
_GA,
|
|
25407
25421
|
0,
|
|
25408
|
-
[_tP, _cP, _wP, _sIP, _cGP, _aRP, _iM],
|
|
25422
|
+
[_tP, _cP, _wP, _sIP, _cGP, _aRP, _iM, _aGD],
|
|
25409
25423
|
[
|
|
25410
25424
|
() => GuardrailTopicPolicyAssessment,
|
|
25411
25425
|
() => GuardrailContentPolicyAssessment,
|
|
@@ -25413,7 +25427,8 @@ var require_dist_cjs66 = __commonJS({
|
|
|
25413
25427
|
() => GuardrailSensitiveInformationPolicyAssessment,
|
|
25414
25428
|
() => GuardrailContextualGroundingPolicyAssessment,
|
|
25415
25429
|
[() => GuardrailAutomatedReasoningPolicyAssessment, 0],
|
|
25416
|
-
() => GuardrailInvocationMetrics
|
|
25430
|
+
() => GuardrailInvocationMetrics,
|
|
25431
|
+
() => AppliedGuardrailDetails
|
|
25417
25432
|
]
|
|
25418
25433
|
];
|
|
25419
25434
|
var GuardrailAutomatedReasoningImpossibleFinding = [
|
|
@@ -25545,7 +25560,7 @@ var require_dist_cjs66 = __commonJS({
|
|
|
25545
25560
|
[() => GuardrailAutomatedReasoningLogicWarning, 0]
|
|
25546
25561
|
]
|
|
25547
25562
|
];
|
|
25548
|
-
var GuardrailConfiguration = [3, n04, _GC, 0, [
|
|
25563
|
+
var GuardrailConfiguration = [3, n04, _GC, 0, [_gIu, _gV, _tr], [0, 0, 0]];
|
|
25549
25564
|
var GuardrailContentFilter = [3, n04, _GCF, 0, [_t, _conf, _fS, _a16, _de], [0, 0, 0, 0, 2]];
|
|
25550
25565
|
var GuardrailContentPolicyAssessment = [
|
|
25551
25566
|
3,
|
|
@@ -25618,7 +25633,7 @@ var require_dist_cjs66 = __commonJS({
|
|
|
25618
25633
|
[_pE, _re],
|
|
25619
25634
|
[() => GuardrailPiiEntityFilterList, () => GuardrailRegexFilterList]
|
|
25620
25635
|
];
|
|
25621
|
-
var GuardrailStreamConfiguration = [3, n04, _GSC, 0, [
|
|
25636
|
+
var GuardrailStreamConfiguration = [3, n04, _GSC, 0, [_gIu, _gV, _tr, _sPM], [0, 0, 0, 0]];
|
|
25622
25637
|
var GuardrailTextBlock = [3, n04, _GTB, 0, [_te, _q], [0, 64 | 0]];
|
|
25623
25638
|
var GuardrailTextCharactersCoverage = [3, n04, _GTCC, 0, [_gu, _to], [1, 1]];
|
|
25624
25639
|
var GuardrailTopic = [3, n04, _GT, 0, [_n, _t, _a16, _de], [0, 0, 0, 2]];
|
|
@@ -25673,7 +25688,7 @@ var require_dist_cjs66 = __commonJS({
|
|
|
25673
25688
|
n04,
|
|
25674
25689
|
_IMR,
|
|
25675
25690
|
0,
|
|
25676
|
-
[_bo, _cT, _ac, _mI, _tr,
|
|
25691
|
+
[_bo, _cT, _ac, _mI, _tr, _gIu, _gV, _pCL, _sTe],
|
|
25677
25692
|
[
|
|
25678
25693
|
[() => Body, 16],
|
|
25679
25694
|
[
|
|
@@ -25774,7 +25789,7 @@ var require_dist_cjs66 = __commonJS({
|
|
|
25774
25789
|
n04,
|
|
25775
25790
|
_IMWRSR,
|
|
25776
25791
|
0,
|
|
25777
|
-
[_bo, _cT, _ac, _mI, _tr,
|
|
25792
|
+
[_bo, _cT, _ac, _mI, _tr, _gIu, _gV, _pCL, _sTe],
|
|
25778
25793
|
[
|
|
25779
25794
|
[() => Body, 16],
|
|
25780
25795
|
[
|
|
@@ -26593,6 +26608,15 @@ var require_dist_cjs66 = __commonJS({
|
|
|
26593
26608
|
GUARDRAIL_INTERVENED: "GUARDRAIL_INTERVENED",
|
|
26594
26609
|
NONE: "NONE"
|
|
26595
26610
|
};
|
|
26611
|
+
var GuardrailOrigin = {
|
|
26612
|
+
ACCOUNT_ENFORCED: "ACCOUNT_ENFORCED",
|
|
26613
|
+
ORGANIZATION_ENFORCED: "ORGANIZATION_ENFORCED",
|
|
26614
|
+
REQUEST: "REQUEST"
|
|
26615
|
+
};
|
|
26616
|
+
var GuardrailOwnership = {
|
|
26617
|
+
CROSS_ACCOUNT: "CROSS_ACCOUNT",
|
|
26618
|
+
SELF: "SELF"
|
|
26619
|
+
};
|
|
26596
26620
|
var GuardrailAutomatedReasoningLogicWarningType = {
|
|
26597
26621
|
ALWAYS_FALSE: "ALWAYS_FALSE",
|
|
26598
26622
|
ALWAYS_TRUE: "ALWAYS_TRUE"
|
|
@@ -26804,7 +26828,9 @@ var require_dist_cjs66 = __commonJS({
|
|
|
26804
26828
|
exports2.GuardrailConverseImageFormat = GuardrailConverseImageFormat;
|
|
26805
26829
|
exports2.GuardrailImageFormat = GuardrailImageFormat;
|
|
26806
26830
|
exports2.GuardrailManagedWordType = GuardrailManagedWordType;
|
|
26831
|
+
exports2.GuardrailOrigin = GuardrailOrigin;
|
|
26807
26832
|
exports2.GuardrailOutputScope = GuardrailOutputScope;
|
|
26833
|
+
exports2.GuardrailOwnership = GuardrailOwnership;
|
|
26808
26834
|
exports2.GuardrailPiiEntityType = GuardrailPiiEntityType;
|
|
26809
26835
|
exports2.GuardrailSensitiveInformationPolicyAction = GuardrailSensitiveInformationPolicyAction;
|
|
26810
26836
|
exports2.GuardrailStreamProcessingMode = GuardrailStreamProcessingMode;
|
|
@@ -29596,17 +29622,30 @@ var init_xmlParsingUtils = __esm({
|
|
|
29596
29622
|
|
|
29597
29623
|
// src/agent/tools.js
|
|
29598
29624
|
function createTools(configOptions) {
|
|
29599
|
-
const tools2 = {
|
|
29600
|
-
|
|
29601
|
-
|
|
29602
|
-
|
|
29603
|
-
|
|
29604
|
-
|
|
29605
|
-
|
|
29625
|
+
const tools2 = {};
|
|
29626
|
+
const isToolAllowed = configOptions.isToolAllowed || ((toolName) => {
|
|
29627
|
+
if (!configOptions.allowedTools) return true;
|
|
29628
|
+
return configOptions.allowedTools.isEnabled(toolName);
|
|
29629
|
+
});
|
|
29630
|
+
if (isToolAllowed("search")) {
|
|
29631
|
+
tools2.searchTool = searchTool(configOptions);
|
|
29632
|
+
}
|
|
29633
|
+
if (isToolAllowed("query")) {
|
|
29634
|
+
tools2.queryTool = queryTool(configOptions);
|
|
29635
|
+
}
|
|
29636
|
+
if (isToolAllowed("extract")) {
|
|
29637
|
+
tools2.extractTool = extractTool(configOptions);
|
|
29638
|
+
}
|
|
29639
|
+
if (configOptions.enableDelegate && isToolAllowed("delegate")) {
|
|
29640
|
+
tools2.delegateTool = delegateTool(configOptions);
|
|
29641
|
+
}
|
|
29642
|
+
if (configOptions.enableBash && isToolAllowed("bash")) {
|
|
29606
29643
|
tools2.bashTool = bashTool(configOptions);
|
|
29607
29644
|
}
|
|
29608
|
-
if (configOptions.allowEdit) {
|
|
29645
|
+
if (configOptions.allowEdit && isToolAllowed("edit")) {
|
|
29609
29646
|
tools2.editTool = editTool(configOptions);
|
|
29647
|
+
}
|
|
29648
|
+
if (configOptions.allowEdit && isToolAllowed("create")) {
|
|
29610
29649
|
tools2.createTool = createTool(configOptions);
|
|
29611
29650
|
}
|
|
29612
29651
|
return tools2;
|
|
@@ -79400,6 +79439,126 @@ Provide only the corrected Mermaid diagram within a mermaid code block. Do not a
|
|
|
79400
79439
|
}
|
|
79401
79440
|
});
|
|
79402
79441
|
|
|
79442
|
+
// src/agent/shared/prompts.js
|
|
79443
|
+
var predefinedPrompts;
|
|
79444
|
+
var init_prompts = __esm({
|
|
79445
|
+
"src/agent/shared/prompts.js"() {
|
|
79446
|
+
"use strict";
|
|
79447
|
+
predefinedPrompts = {
|
|
79448
|
+
"code-explorer": `You are ProbeChat Code Explorer - an AI assistant focused on reading and explaining code using Probe's semantic search capabilities.
|
|
79449
|
+
|
|
79450
|
+
Your primary role is to explore codebases, understand code structure, and provide clear explanations. You should:
|
|
79451
|
+
|
|
79452
|
+
1. Use the 'search' tool to find relevant code snippets across the codebase
|
|
79453
|
+
2. Use the 'query' tool to locate specific symbols, functions, or classes
|
|
79454
|
+
3. Use the 'extract' tool to get full context for files or specific code blocks
|
|
79455
|
+
4. Explain code behavior, architecture patterns, and relationships between components
|
|
79456
|
+
5. Provide concise summaries with key insights highlighted
|
|
79457
|
+
|
|
79458
|
+
When exploring code:
|
|
79459
|
+
- Start with targeted searches to find relevant areas
|
|
79460
|
+
- Extract full context when you need to understand implementation details
|
|
79461
|
+
- Trace function calls and data flow to understand how components interact
|
|
79462
|
+
- Focus on "why" and "how" rather than just describing what the code does
|
|
79463
|
+
|
|
79464
|
+
You should NOT:
|
|
79465
|
+
- Make changes to the codebase (read-only access)
|
|
79466
|
+
- Execute or run code
|
|
79467
|
+
- Make assumptions without verifying through search/query/extract`,
|
|
79468
|
+
"architect": `You are ProbeChat Architect - a senior software architect specialized in analyzing and designing software systems.
|
|
79469
|
+
|
|
79470
|
+
Your role is to:
|
|
79471
|
+
|
|
79472
|
+
1. Analyze existing codebases to understand architecture patterns and design decisions
|
|
79473
|
+
2. Identify architectural issues, technical debt, and improvement opportunities
|
|
79474
|
+
3. Propose refactoring strategies and architectural changes
|
|
79475
|
+
4. Design new features that fit well with existing architecture
|
|
79476
|
+
5. Create high-level architecture diagrams and documentation
|
|
79477
|
+
|
|
79478
|
+
When analyzing architecture:
|
|
79479
|
+
- Use search/query/extract to understand component boundaries and dependencies
|
|
79480
|
+
- Identify layers, modules, and their responsibilities
|
|
79481
|
+
- Look for patterns like MVC, microservices, event-driven, etc.
|
|
79482
|
+
- Assess coupling, cohesion, and separation of concerns
|
|
79483
|
+
- Consider scalability, maintainability, and testability
|
|
79484
|
+
|
|
79485
|
+
When proposing changes:
|
|
79486
|
+
- Provide clear rationale backed by architectural principles
|
|
79487
|
+
- Consider migration paths and backwards compatibility
|
|
79488
|
+
- Identify risks and tradeoffs
|
|
79489
|
+
- Suggest incremental implementation steps`,
|
|
79490
|
+
"code-review": `You are ProbeChat Code Reviewer - a meticulous code reviewer focused on quality, best practices, and maintainability.
|
|
79491
|
+
|
|
79492
|
+
Your role is to:
|
|
79493
|
+
|
|
79494
|
+
1. Review code changes for correctness, clarity, and best practices
|
|
79495
|
+
2. Identify bugs, security issues, and performance problems
|
|
79496
|
+
3. Suggest improvements for readability and maintainability
|
|
79497
|
+
4. Ensure consistency with project conventions and patterns
|
|
79498
|
+
5. Verify test coverage and edge case handling
|
|
79499
|
+
|
|
79500
|
+
When reviewing code:
|
|
79501
|
+
- Use search to find similar patterns in the codebase for consistency
|
|
79502
|
+
- Look for common issues: null checks, error handling, resource leaks
|
|
79503
|
+
- Check for security vulnerabilities: injection, XSS, etc.
|
|
79504
|
+
- Assess complexity and suggest simplifications
|
|
79505
|
+
- Verify naming conventions and code organization
|
|
79506
|
+
|
|
79507
|
+
Provide constructive feedback:
|
|
79508
|
+
- Start with what's good about the code
|
|
79509
|
+
- Be specific about issues with examples
|
|
79510
|
+
- Suggest concrete improvements with code snippets
|
|
79511
|
+
- Prioritize critical issues over style preferences
|
|
79512
|
+
- Explain the "why" behind your suggestions`,
|
|
79513
|
+
"engineer": `You are a senior engineer who helps implement features and fix bugs.
|
|
79514
|
+
|
|
79515
|
+
Your role is to:
|
|
79516
|
+
|
|
79517
|
+
1. Implement new features following project conventions
|
|
79518
|
+
2. Fix bugs by understanding root causes
|
|
79519
|
+
3. Refactor code to improve quality
|
|
79520
|
+
4. Write clear, maintainable code
|
|
79521
|
+
5. Add appropriate tests and documentation
|
|
79522
|
+
|
|
79523
|
+
When implementing:
|
|
79524
|
+
- Use search/query to understand existing patterns
|
|
79525
|
+
- Follow the project's coding style and conventions
|
|
79526
|
+
- Consider edge cases and error handling
|
|
79527
|
+
- Write self-documenting code with clear names
|
|
79528
|
+
- Add comments for complex logic
|
|
79529
|
+
|
|
79530
|
+
You have access to:
|
|
79531
|
+
- search: Find relevant code patterns
|
|
79532
|
+
- query: Locate specific symbols/functions
|
|
79533
|
+
- extract: Get full file context
|
|
79534
|
+
- implement: Create or modify files (use carefully)
|
|
79535
|
+
- delegate: Break down complex tasks`,
|
|
79536
|
+
"support": `You are ProbeChat Support - a helpful assistant focused on answering questions about codebases.
|
|
79537
|
+
|
|
79538
|
+
Your role is to:
|
|
79539
|
+
|
|
79540
|
+
1. Answer questions about how code works
|
|
79541
|
+
2. Help users locate specific functionality
|
|
79542
|
+
3. Explain error messages and debugging approaches
|
|
79543
|
+
4. Guide users to relevant documentation
|
|
79544
|
+
5. Provide examples and usage patterns
|
|
79545
|
+
|
|
79546
|
+
When helping users:
|
|
79547
|
+
- Ask clarifying questions if the request is ambiguous
|
|
79548
|
+
- Use search/query to find relevant code quickly
|
|
79549
|
+
- Provide clear, step-by-step explanations
|
|
79550
|
+
- Include code examples when helpful
|
|
79551
|
+
- Point to relevant files and line numbers
|
|
79552
|
+
|
|
79553
|
+
You should be:
|
|
79554
|
+
- Patient and encouraging
|
|
79555
|
+
- Clear and concise
|
|
79556
|
+
- Thorough but not overwhelming
|
|
79557
|
+
- Honest about limitations (say "I don't know" when appropriate)`
|
|
79558
|
+
};
|
|
79559
|
+
}
|
|
79560
|
+
});
|
|
79561
|
+
|
|
79403
79562
|
// src/agent/mcp/config.js
|
|
79404
79563
|
function loadMCPConfigurationFromPath(configPath) {
|
|
79405
79564
|
if (!configPath) {
|
|
@@ -80937,14 +81096,58 @@ var init_contextCompactor = __esm({
|
|
|
80937
81096
|
});
|
|
80938
81097
|
|
|
80939
81098
|
// src/agent/mcp/built-in-server.js
|
|
80940
|
-
var import_http, import_events2, import_server, import_types3, BuiltInMCPServer;
|
|
81099
|
+
var import_http, import_events2, import_crypto4, import_server, import_sse2, import_streamableHttp, import_types3, InMemoryEventStore, BuiltInMCPServer;
|
|
80941
81100
|
var init_built_in_server = __esm({
|
|
80942
81101
|
"src/agent/mcp/built-in-server.js"() {
|
|
80943
81102
|
"use strict";
|
|
80944
81103
|
import_http = require("http");
|
|
80945
81104
|
import_events2 = require("events");
|
|
81105
|
+
import_crypto4 = require("crypto");
|
|
80946
81106
|
import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
81107
|
+
import_sse2 = require("@modelcontextprotocol/sdk/server/sse.js");
|
|
81108
|
+
import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
80947
81109
|
import_types3 = require("@modelcontextprotocol/sdk/types.js");
|
|
81110
|
+
InMemoryEventStore = class {
|
|
81111
|
+
constructor() {
|
|
81112
|
+
this.events = /* @__PURE__ */ new Map();
|
|
81113
|
+
}
|
|
81114
|
+
generateEventId(streamId) {
|
|
81115
|
+
return `${streamId}_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
|
|
81116
|
+
}
|
|
81117
|
+
getStreamIdFromEventId(eventId) {
|
|
81118
|
+
const parts = eventId.split("_");
|
|
81119
|
+
return parts.length > 0 ? parts[0] : "";
|
|
81120
|
+
}
|
|
81121
|
+
async storeEvent(streamId, message) {
|
|
81122
|
+
const eventId = this.generateEventId(streamId);
|
|
81123
|
+
this.events.set(eventId, { streamId, message });
|
|
81124
|
+
return eventId;
|
|
81125
|
+
}
|
|
81126
|
+
async replayEventsAfter(lastEventId, { send }) {
|
|
81127
|
+
if (!lastEventId || !this.events.has(lastEventId)) {
|
|
81128
|
+
return "";
|
|
81129
|
+
}
|
|
81130
|
+
const streamId = this.getStreamIdFromEventId(lastEventId);
|
|
81131
|
+
if (!streamId) {
|
|
81132
|
+
return "";
|
|
81133
|
+
}
|
|
81134
|
+
let foundLastEvent = false;
|
|
81135
|
+
const sortedEvents = [...this.events.entries()].sort((a4, b4) => a4[0].localeCompare(b4[0]));
|
|
81136
|
+
for (const [eventId, { streamId: eventStreamId, message }] of sortedEvents) {
|
|
81137
|
+
if (eventStreamId !== streamId) {
|
|
81138
|
+
continue;
|
|
81139
|
+
}
|
|
81140
|
+
if (eventId === lastEventId) {
|
|
81141
|
+
foundLastEvent = true;
|
|
81142
|
+
continue;
|
|
81143
|
+
}
|
|
81144
|
+
if (foundLastEvent) {
|
|
81145
|
+
await send(eventId, message);
|
|
81146
|
+
}
|
|
81147
|
+
}
|
|
81148
|
+
return streamId;
|
|
81149
|
+
}
|
|
81150
|
+
};
|
|
80948
81151
|
BuiltInMCPServer = class extends import_events2.EventEmitter {
|
|
80949
81152
|
constructor(agent, options = {}) {
|
|
80950
81153
|
super();
|
|
@@ -80953,6 +81156,8 @@ var init_built_in_server = __esm({
|
|
|
80953
81156
|
this.host = options.host || "127.0.0.1";
|
|
80954
81157
|
this.httpServer = null;
|
|
80955
81158
|
this.mcpServer = null;
|
|
81159
|
+
this.sseTransports = /* @__PURE__ */ new Map();
|
|
81160
|
+
this.streamableTransports = /* @__PURE__ */ new Map();
|
|
80956
81161
|
this.connections = /* @__PURE__ */ new Set();
|
|
80957
81162
|
this.debug = options.debug || false;
|
|
80958
81163
|
}
|
|
@@ -80974,11 +81179,13 @@ var init_built_in_server = __esm({
|
|
|
80974
81179
|
});
|
|
80975
81180
|
this.registerHandlers();
|
|
80976
81181
|
return new Promise((resolve5, reject2) => {
|
|
80977
|
-
this.httpServer.listen(this.port, this.host, () => {
|
|
81182
|
+
this.httpServer.listen(this.port, this.host, async () => {
|
|
80978
81183
|
const address = this.httpServer.address();
|
|
80979
81184
|
this.port = address.port;
|
|
80980
81185
|
if (this.debug) {
|
|
80981
81186
|
console.log(`[MCP] Built-in server started at http://${this.host}:${this.port}`);
|
|
81187
|
+
console.log(`[MCP] SSE endpoint: http://${this.host}:${this.port}/sse`);
|
|
81188
|
+
console.log(`[MCP] Messages endpoint: http://${this.host}:${this.port}/messages`);
|
|
80982
81189
|
}
|
|
80983
81190
|
this.emit("ready", { host: this.host, port: this.port });
|
|
80984
81191
|
resolve5({ host: this.host, port: this.port });
|
|
@@ -80991,6 +81198,9 @@ var init_built_in_server = __esm({
|
|
|
80991
81198
|
*/
|
|
80992
81199
|
handleRequest(req, res) {
|
|
80993
81200
|
const { method, url } = req;
|
|
81201
|
+
if (this.debug) {
|
|
81202
|
+
console.log(`[MCP] Request: ${method} ${url}`);
|
|
81203
|
+
}
|
|
80994
81204
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
80995
81205
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
80996
81206
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
@@ -81000,15 +81210,22 @@ var init_built_in_server = __esm({
|
|
|
81000
81210
|
return;
|
|
81001
81211
|
}
|
|
81002
81212
|
if (url === "/sse" && method === "GET") {
|
|
81003
|
-
this.
|
|
81213
|
+
if (this.debug) {
|
|
81214
|
+
console.log("[MCP] Routing to handleSSEConnection");
|
|
81215
|
+
}
|
|
81216
|
+
this.handleSSEConnection(req, res);
|
|
81217
|
+
return;
|
|
81218
|
+
}
|
|
81219
|
+
if (url.startsWith("/messages") && method === "POST") {
|
|
81220
|
+
this.handleSSEMessage(req, res);
|
|
81004
81221
|
return;
|
|
81005
81222
|
}
|
|
81006
81223
|
if (url === "/rpc" && method === "POST") {
|
|
81007
81224
|
this.handleJSONRPC(req, res);
|
|
81008
81225
|
return;
|
|
81009
81226
|
}
|
|
81010
|
-
if (url === "/mcp"
|
|
81011
|
-
this.
|
|
81227
|
+
if (url === "/mcp") {
|
|
81228
|
+
this.handleStreamableHTTP(req, res);
|
|
81012
81229
|
return;
|
|
81013
81230
|
}
|
|
81014
81231
|
if (url === "/health") {
|
|
@@ -81024,7 +81241,190 @@ var init_built_in_server = __esm({
|
|
|
81024
81241
|
res.end("Not Found");
|
|
81025
81242
|
}
|
|
81026
81243
|
/**
|
|
81027
|
-
* Handle
|
|
81244
|
+
* Handle SSE connection (GET /sse) - creates new transport
|
|
81245
|
+
*/
|
|
81246
|
+
async handleSSEConnection(req, res) {
|
|
81247
|
+
if (this.debug) {
|
|
81248
|
+
console.log("[MCP] New SSE connection request");
|
|
81249
|
+
}
|
|
81250
|
+
const transport = new import_sse2.SSEServerTransport("/messages", res);
|
|
81251
|
+
this.sseTransports.set(transport.sessionId, transport);
|
|
81252
|
+
res.on("close", () => {
|
|
81253
|
+
if (this.debug) {
|
|
81254
|
+
console.log("[MCP] SSE connection closed, sessionId:", transport.sessionId);
|
|
81255
|
+
}
|
|
81256
|
+
this.sseTransports.delete(transport.sessionId);
|
|
81257
|
+
});
|
|
81258
|
+
try {
|
|
81259
|
+
await this.mcpServer.connect(transport);
|
|
81260
|
+
if (this.debug) {
|
|
81261
|
+
console.log("[MCP] MCP server connected to SSE transport, sessionId:", transport.sessionId);
|
|
81262
|
+
}
|
|
81263
|
+
} catch (error2) {
|
|
81264
|
+
if (this.debug) {
|
|
81265
|
+
console.error("[MCP] Error connecting MCP server to transport:", error2);
|
|
81266
|
+
}
|
|
81267
|
+
this.sseTransports.delete(transport.sessionId);
|
|
81268
|
+
}
|
|
81269
|
+
}
|
|
81270
|
+
/**
|
|
81271
|
+
* Handle SSE message (POST /messages?sessionId=...) - routes to existing transport
|
|
81272
|
+
*/
|
|
81273
|
+
async handleSSEMessage(req, res) {
|
|
81274
|
+
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
81275
|
+
const sessionId = url.searchParams.get("sessionId");
|
|
81276
|
+
if (!sessionId) {
|
|
81277
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
81278
|
+
res.end(JSON.stringify({
|
|
81279
|
+
jsonrpc: "2.0",
|
|
81280
|
+
error: {
|
|
81281
|
+
code: -32e3,
|
|
81282
|
+
message: "Bad Request: sessionId query parameter is required"
|
|
81283
|
+
},
|
|
81284
|
+
id: null
|
|
81285
|
+
}));
|
|
81286
|
+
return;
|
|
81287
|
+
}
|
|
81288
|
+
const transport = this.sseTransports.get(sessionId);
|
|
81289
|
+
if (!transport) {
|
|
81290
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
81291
|
+
res.end(JSON.stringify({
|
|
81292
|
+
jsonrpc: "2.0",
|
|
81293
|
+
error: {
|
|
81294
|
+
code: -32e3,
|
|
81295
|
+
message: `Bad Request: No transport found for sessionId: ${sessionId}`
|
|
81296
|
+
},
|
|
81297
|
+
id: null
|
|
81298
|
+
}));
|
|
81299
|
+
return;
|
|
81300
|
+
}
|
|
81301
|
+
let body = "";
|
|
81302
|
+
req.on("data", (chunk) => {
|
|
81303
|
+
body += chunk.toString();
|
|
81304
|
+
});
|
|
81305
|
+
req.on("end", async () => {
|
|
81306
|
+
try {
|
|
81307
|
+
const message = JSON.parse(body);
|
|
81308
|
+
await transport.handlePostMessage(req, res, message);
|
|
81309
|
+
} catch (error2) {
|
|
81310
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
81311
|
+
res.end(JSON.stringify({
|
|
81312
|
+
jsonrpc: "2.0",
|
|
81313
|
+
error: {
|
|
81314
|
+
code: -32603,
|
|
81315
|
+
message: "Internal error",
|
|
81316
|
+
data: error2.message
|
|
81317
|
+
},
|
|
81318
|
+
id: null
|
|
81319
|
+
}));
|
|
81320
|
+
}
|
|
81321
|
+
});
|
|
81322
|
+
}
|
|
81323
|
+
/**
|
|
81324
|
+
* Handle Streamable HTTP protocol (GET/POST/DELETE on /mcp)
|
|
81325
|
+
*/
|
|
81326
|
+
async handleStreamableHTTP(req, res) {
|
|
81327
|
+
const { method } = req;
|
|
81328
|
+
if (this.debug) {
|
|
81329
|
+
console.log(`[MCP] Streamable HTTP ${method} request`);
|
|
81330
|
+
}
|
|
81331
|
+
try {
|
|
81332
|
+
let body = null;
|
|
81333
|
+
if (method === "POST") {
|
|
81334
|
+
body = await this.parseRequestBody(req);
|
|
81335
|
+
}
|
|
81336
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
81337
|
+
let transport;
|
|
81338
|
+
if (sessionId && this.streamableTransports.has(sessionId)) {
|
|
81339
|
+
transport = this.streamableTransports.get(sessionId);
|
|
81340
|
+
if (this.debug) {
|
|
81341
|
+
console.log(`[MCP] Reusing existing transport for session: ${sessionId}`);
|
|
81342
|
+
}
|
|
81343
|
+
} else if (!sessionId && method === "POST" && body && (0, import_types3.isInitializeRequest)(body)) {
|
|
81344
|
+
if (this.debug) {
|
|
81345
|
+
console.log("[MCP] Creating new Streamable HTTP transport for initialization");
|
|
81346
|
+
}
|
|
81347
|
+
const eventStore = new InMemoryEventStore();
|
|
81348
|
+
transport = new import_streamableHttp.StreamableHTTPServerTransport({
|
|
81349
|
+
sessionIdGenerator: () => (0, import_crypto4.randomUUID)(),
|
|
81350
|
+
eventStore,
|
|
81351
|
+
// Enable resumability
|
|
81352
|
+
onsessioninitialized: (newSessionId) => {
|
|
81353
|
+
if (this.debug) {
|
|
81354
|
+
console.log(`[MCP] Streamable HTTP session initialized: ${newSessionId}`);
|
|
81355
|
+
}
|
|
81356
|
+
this.streamableTransports.set(newSessionId, transport);
|
|
81357
|
+
},
|
|
81358
|
+
onsessionclosed: (closedSessionId) => {
|
|
81359
|
+
if (this.debug) {
|
|
81360
|
+
console.log(`[MCP] Streamable HTTP session closed: ${closedSessionId}`);
|
|
81361
|
+
}
|
|
81362
|
+
this.streamableTransports.delete(closedSessionId);
|
|
81363
|
+
}
|
|
81364
|
+
});
|
|
81365
|
+
transport.onclose = () => {
|
|
81366
|
+
const sid = transport.sessionId;
|
|
81367
|
+
if (sid && this.streamableTransports.has(sid)) {
|
|
81368
|
+
if (this.debug) {
|
|
81369
|
+
console.log(`[MCP] Transport closed for session ${sid}`);
|
|
81370
|
+
}
|
|
81371
|
+
this.streamableTransports.delete(sid);
|
|
81372
|
+
}
|
|
81373
|
+
};
|
|
81374
|
+
await this.mcpServer.connect(transport);
|
|
81375
|
+
} else {
|
|
81376
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
81377
|
+
res.end(JSON.stringify({
|
|
81378
|
+
jsonrpc: "2.0",
|
|
81379
|
+
error: {
|
|
81380
|
+
code: -32e3,
|
|
81381
|
+
message: "Bad Request: No valid session ID provided or not an initialization request"
|
|
81382
|
+
},
|
|
81383
|
+
id: null
|
|
81384
|
+
}));
|
|
81385
|
+
return;
|
|
81386
|
+
}
|
|
81387
|
+
await transport.handleRequest(req, res, body);
|
|
81388
|
+
} catch (error2) {
|
|
81389
|
+
if (this.debug) {
|
|
81390
|
+
console.error("[MCP] Error handling Streamable HTTP request:", error2);
|
|
81391
|
+
}
|
|
81392
|
+
if (!res.headersSent) {
|
|
81393
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
81394
|
+
res.end(JSON.stringify({
|
|
81395
|
+
jsonrpc: "2.0",
|
|
81396
|
+
error: {
|
|
81397
|
+
code: -32603,
|
|
81398
|
+
message: "Internal server error",
|
|
81399
|
+
data: error2.message
|
|
81400
|
+
},
|
|
81401
|
+
id: null
|
|
81402
|
+
}));
|
|
81403
|
+
}
|
|
81404
|
+
}
|
|
81405
|
+
}
|
|
81406
|
+
/**
|
|
81407
|
+
* Parse request body as JSON
|
|
81408
|
+
*/
|
|
81409
|
+
async parseRequestBody(req) {
|
|
81410
|
+
return new Promise((resolve5, reject2) => {
|
|
81411
|
+
let body = "";
|
|
81412
|
+
req.on("data", (chunk) => {
|
|
81413
|
+
body += chunk.toString();
|
|
81414
|
+
});
|
|
81415
|
+
req.on("end", () => {
|
|
81416
|
+
try {
|
|
81417
|
+
const parsed = body ? JSON.parse(body) : null;
|
|
81418
|
+
resolve5(parsed);
|
|
81419
|
+
} catch (error2) {
|
|
81420
|
+
reject2(error2);
|
|
81421
|
+
}
|
|
81422
|
+
});
|
|
81423
|
+
req.on("error", reject2);
|
|
81424
|
+
});
|
|
81425
|
+
}
|
|
81426
|
+
/**
|
|
81427
|
+
* Handle Server-Sent Events connection (DEPRECATED - use handleSSEConnection instead)
|
|
81028
81428
|
*/
|
|
81029
81429
|
handleSSE(req, res) {
|
|
81030
81430
|
res.writeHead(200, {
|
|
@@ -81291,6 +81691,32 @@ data: ${JSON.stringify(data2)}
|
|
|
81291
81691
|
* Stop the server
|
|
81292
81692
|
*/
|
|
81293
81693
|
async stop() {
|
|
81694
|
+
for (const [sessionId, transport] of this.streamableTransports.entries()) {
|
|
81695
|
+
try {
|
|
81696
|
+
await transport.close();
|
|
81697
|
+
if (this.debug) {
|
|
81698
|
+
console.log(`[MCP] Closed Streamable HTTP transport for session: ${sessionId}`);
|
|
81699
|
+
}
|
|
81700
|
+
} catch (error2) {
|
|
81701
|
+
if (this.debug) {
|
|
81702
|
+
console.error(`[MCP] Error closing Streamable HTTP transport ${sessionId}:`, error2);
|
|
81703
|
+
}
|
|
81704
|
+
}
|
|
81705
|
+
}
|
|
81706
|
+
this.streamableTransports.clear();
|
|
81707
|
+
for (const [sessionId, transport] of this.sseTransports.entries()) {
|
|
81708
|
+
try {
|
|
81709
|
+
await transport.close();
|
|
81710
|
+
if (this.debug) {
|
|
81711
|
+
console.log(`[MCP] Closed SSE transport for session: ${sessionId}`);
|
|
81712
|
+
}
|
|
81713
|
+
} catch (error2) {
|
|
81714
|
+
if (this.debug) {
|
|
81715
|
+
console.error(`[MCP] Error closing SSE transport ${sessionId}:`, error2);
|
|
81716
|
+
}
|
|
81717
|
+
}
|
|
81718
|
+
}
|
|
81719
|
+
this.sseTransports.clear();
|
|
81294
81720
|
for (const connection of this.connections) {
|
|
81295
81721
|
connection.end();
|
|
81296
81722
|
}
|
|
@@ -81322,6 +81748,59 @@ data: ${JSON.stringify(data2)}
|
|
|
81322
81748
|
}
|
|
81323
81749
|
});
|
|
81324
81750
|
|
|
81751
|
+
// src/agent/shared/Session.js
|
|
81752
|
+
var Session;
|
|
81753
|
+
var init_Session = __esm({
|
|
81754
|
+
"src/agent/shared/Session.js"() {
|
|
81755
|
+
"use strict";
|
|
81756
|
+
Session = class {
|
|
81757
|
+
constructor(id, debug = false) {
|
|
81758
|
+
this.id = id;
|
|
81759
|
+
this.conversationId = null;
|
|
81760
|
+
this.messageCount = 0;
|
|
81761
|
+
this.debug = debug;
|
|
81762
|
+
}
|
|
81763
|
+
/**
|
|
81764
|
+
* Set the conversation ID for session resumption
|
|
81765
|
+
* @param {string} conversationId - Provider's conversation/thread ID
|
|
81766
|
+
*/
|
|
81767
|
+
setConversationId(conversationId) {
|
|
81768
|
+
this.conversationId = conversationId;
|
|
81769
|
+
if (this.debug) {
|
|
81770
|
+
console.log(`[Session ${this.id}] Conversation ID: ${conversationId}`);
|
|
81771
|
+
}
|
|
81772
|
+
}
|
|
81773
|
+
/**
|
|
81774
|
+
* Increment the message count
|
|
81775
|
+
*/
|
|
81776
|
+
incrementMessageCount() {
|
|
81777
|
+
this.messageCount++;
|
|
81778
|
+
}
|
|
81779
|
+
/**
|
|
81780
|
+
* Get session info as plain object
|
|
81781
|
+
* @returns {Object} Session information
|
|
81782
|
+
*/
|
|
81783
|
+
getInfo() {
|
|
81784
|
+
return {
|
|
81785
|
+
id: this.id,
|
|
81786
|
+
conversationId: this.conversationId,
|
|
81787
|
+
messageCount: this.messageCount
|
|
81788
|
+
};
|
|
81789
|
+
}
|
|
81790
|
+
/**
|
|
81791
|
+
* Get resume arguments for CLI commands (used by Claude Code)
|
|
81792
|
+
* @returns {Array<string>} CLI arguments for resuming conversation
|
|
81793
|
+
*/
|
|
81794
|
+
getResumeArgs() {
|
|
81795
|
+
if (this.conversationId && this.messageCount > 0) {
|
|
81796
|
+
return ["--resume", this.conversationId];
|
|
81797
|
+
}
|
|
81798
|
+
return [];
|
|
81799
|
+
}
|
|
81800
|
+
};
|
|
81801
|
+
}
|
|
81802
|
+
});
|
|
81803
|
+
|
|
81325
81804
|
// src/agent/engines/enhanced-claude-code.js
|
|
81326
81805
|
var enhanced_claude_code_exports = {};
|
|
81327
81806
|
__export(enhanced_claude_code_exports, {
|
|
@@ -81329,8 +81808,8 @@ __export(enhanced_claude_code_exports, {
|
|
|
81329
81808
|
});
|
|
81330
81809
|
async function createEnhancedClaudeCLIEngine(options = {}) {
|
|
81331
81810
|
const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools } = options;
|
|
81332
|
-
const session = new
|
|
81333
|
-
sessionId || (0,
|
|
81811
|
+
const session = new Session(
|
|
81812
|
+
sessionId || (0, import_crypto5.randomBytes)(8).toString("hex"),
|
|
81334
81813
|
debug
|
|
81335
81814
|
);
|
|
81336
81815
|
let mcpServer = null;
|
|
@@ -81540,11 +82019,7 @@ ${opts.schema}`;
|
|
|
81540
82019
|
* Get session info
|
|
81541
82020
|
*/
|
|
81542
82021
|
getSession() {
|
|
81543
|
-
return
|
|
81544
|
-
id: session.id,
|
|
81545
|
-
conversationId: session.conversationId,
|
|
81546
|
-
messageCount: session.messageCount
|
|
81547
|
-
};
|
|
82022
|
+
return session.getInfo();
|
|
81548
82023
|
},
|
|
81549
82024
|
/**
|
|
81550
82025
|
* Clean up - MUST be called to stop MCP server and clean resources
|
|
@@ -81725,46 +82200,293 @@ function combinePrompts(systemPrompt, customPrompt, agent) {
|
|
|
81725
82200
|
}
|
|
81726
82201
|
return systemPrompt || "";
|
|
81727
82202
|
}
|
|
81728
|
-
var import_child_process7,
|
|
82203
|
+
var import_child_process7, import_crypto5, import_promises2, import_path6, import_os4, import_events3;
|
|
81729
82204
|
var init_enhanced_claude_code = __esm({
|
|
81730
82205
|
"src/agent/engines/enhanced-claude-code.js"() {
|
|
81731
82206
|
"use strict";
|
|
81732
82207
|
import_child_process7 = require("child_process");
|
|
81733
|
-
|
|
82208
|
+
import_crypto5 = require("crypto");
|
|
81734
82209
|
import_promises2 = __toESM(require("fs/promises"), 1);
|
|
81735
82210
|
import_path6 = __toESM(require("path"), 1);
|
|
81736
82211
|
import_os4 = __toESM(require("os"), 1);
|
|
81737
82212
|
import_events3 = require("events");
|
|
81738
82213
|
init_built_in_server();
|
|
81739
|
-
|
|
81740
|
-
|
|
81741
|
-
|
|
81742
|
-
|
|
81743
|
-
|
|
81744
|
-
|
|
82214
|
+
init_Session();
|
|
82215
|
+
}
|
|
82216
|
+
});
|
|
82217
|
+
|
|
82218
|
+
// src/agent/engines/codex.js
|
|
82219
|
+
var codex_exports = {};
|
|
82220
|
+
__export(codex_exports, {
|
|
82221
|
+
createCodexEngine: () => createCodexEngine
|
|
82222
|
+
});
|
|
82223
|
+
async function createCodexEngine(options = {}) {
|
|
82224
|
+
const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools, model } = options;
|
|
82225
|
+
const session = new Session(
|
|
82226
|
+
sessionId || (0, import_crypto6.randomBytes)(8).toString("hex"),
|
|
82227
|
+
debug
|
|
82228
|
+
);
|
|
82229
|
+
let mcpServer = null;
|
|
82230
|
+
let mcpServerUrl = null;
|
|
82231
|
+
let mcpServerName = null;
|
|
82232
|
+
if (agent) {
|
|
82233
|
+
mcpServer = new BuiltInMCPServer(agent, {
|
|
82234
|
+
port: 0,
|
|
82235
|
+
host: "127.0.0.1",
|
|
82236
|
+
debug
|
|
82237
|
+
});
|
|
82238
|
+
const { host, port } = await mcpServer.start();
|
|
82239
|
+
mcpServerUrl = `http://${host}:${port}/mcp`;
|
|
82240
|
+
mcpServerName = `probe_${session.id}`;
|
|
82241
|
+
if (debug) {
|
|
82242
|
+
console.log("[DEBUG] Built-in Probe MCP server started");
|
|
82243
|
+
console.log("[DEBUG] Probe MCP URL:", mcpServerUrl);
|
|
82244
|
+
}
|
|
82245
|
+
}
|
|
82246
|
+
if (debug) {
|
|
82247
|
+
console.log("[DEBUG] Starting Codex MCP server...");
|
|
82248
|
+
}
|
|
82249
|
+
const codexProcess = (0, import_child_process8.spawn)("codex", ["mcp-server"], {
|
|
82250
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
82251
|
+
});
|
|
82252
|
+
let requestId = 0;
|
|
82253
|
+
const pendingRequests = /* @__PURE__ */ new Map();
|
|
82254
|
+
const eventHandlers = /* @__PURE__ */ new Map();
|
|
82255
|
+
const stdoutReader = (0, import_readline.createInterface)({
|
|
82256
|
+
input: codexProcess.stdout,
|
|
82257
|
+
crlfDelay: Infinity
|
|
82258
|
+
});
|
|
82259
|
+
stdoutReader.on("line", (line) => {
|
|
82260
|
+
try {
|
|
82261
|
+
const message = JSON.parse(line);
|
|
82262
|
+
if (debug) {
|
|
82263
|
+
if (message.method === "codex/event") {
|
|
82264
|
+
console.log(`[DEBUG] Codex event: ${message.params?.msg?.type}`);
|
|
82265
|
+
}
|
|
81745
82266
|
}
|
|
81746
|
-
|
|
81747
|
-
|
|
81748
|
-
|
|
81749
|
-
|
|
81750
|
-
|
|
81751
|
-
|
|
81752
|
-
|
|
82267
|
+
if (message.id !== void 0 && pendingRequests.has(message.id)) {
|
|
82268
|
+
const { resolve: resolve5, reject: reject2 } = pendingRequests.get(message.id);
|
|
82269
|
+
pendingRequests.delete(message.id);
|
|
82270
|
+
if (message.error) {
|
|
82271
|
+
reject2(new Error(message.error.message || JSON.stringify(message.error)));
|
|
82272
|
+
} else {
|
|
82273
|
+
resolve5(message.result);
|
|
81753
82274
|
}
|
|
81754
82275
|
}
|
|
81755
|
-
|
|
81756
|
-
|
|
81757
|
-
|
|
81758
|
-
|
|
81759
|
-
if (this.conversationId && this.messageCount > 0) {
|
|
81760
|
-
return ["--resume", this.conversationId];
|
|
82276
|
+
if (message.method === "codex/event" && message.params) {
|
|
82277
|
+
const requestId2 = message.params._meta?.requestId;
|
|
82278
|
+
if (requestId2 !== void 0 && eventHandlers.has(requestId2)) {
|
|
82279
|
+
eventHandlers.get(requestId2)(message.params);
|
|
81761
82280
|
}
|
|
81762
|
-
return [];
|
|
81763
82281
|
}
|
|
81764
|
-
|
|
81765
|
-
|
|
82282
|
+
} catch (e4) {
|
|
82283
|
+
if (debug) {
|
|
82284
|
+
console.error("[DEBUG] Failed to parse message:", line);
|
|
81766
82285
|
}
|
|
81767
|
-
}
|
|
82286
|
+
}
|
|
82287
|
+
});
|
|
82288
|
+
if (debug) {
|
|
82289
|
+
codexProcess.stderr.on("data", (data2) => {
|
|
82290
|
+
console.error("[CODEX STDERR]", data2.toString());
|
|
82291
|
+
});
|
|
82292
|
+
}
|
|
82293
|
+
function sendRequest(method, params = {}) {
|
|
82294
|
+
return new Promise((resolve5, reject2) => {
|
|
82295
|
+
const id = ++requestId;
|
|
82296
|
+
const request = {
|
|
82297
|
+
jsonrpc: "2.0",
|
|
82298
|
+
id,
|
|
82299
|
+
method,
|
|
82300
|
+
params
|
|
82301
|
+
};
|
|
82302
|
+
pendingRequests.set(id, { resolve: resolve5, reject: reject2 });
|
|
82303
|
+
setTimeout(() => {
|
|
82304
|
+
if (pendingRequests.has(id)) {
|
|
82305
|
+
pendingRequests.delete(id);
|
|
82306
|
+
reject2(new Error(`Request ${method} timed out after 10 minutes`));
|
|
82307
|
+
}
|
|
82308
|
+
}, 6e5);
|
|
82309
|
+
codexProcess.stdin.write(JSON.stringify(request) + "\n");
|
|
82310
|
+
});
|
|
82311
|
+
}
|
|
82312
|
+
await sendRequest("initialize", {
|
|
82313
|
+
protocolVersion: "2024-11-05",
|
|
82314
|
+
capabilities: { tools: {} },
|
|
82315
|
+
clientInfo: {
|
|
82316
|
+
name: "probe-codex-client",
|
|
82317
|
+
version: "1.0.0"
|
|
82318
|
+
}
|
|
82319
|
+
});
|
|
82320
|
+
if (debug) {
|
|
82321
|
+
console.log("[DEBUG] Connected to Codex MCP server");
|
|
82322
|
+
console.log("[DEBUG] Session:", session.id);
|
|
82323
|
+
}
|
|
82324
|
+
const fullPrompt = combinePrompts2(systemPrompt, customPrompt, agent);
|
|
82325
|
+
return {
|
|
82326
|
+
sessionId: session.id,
|
|
82327
|
+
session,
|
|
82328
|
+
/**
|
|
82329
|
+
* Query Codex via MCP protocol with event streaming
|
|
82330
|
+
*/
|
|
82331
|
+
async *query(prompt, opts = {}) {
|
|
82332
|
+
let finalPrompt = prompt;
|
|
82333
|
+
if (!session.conversationId && fullPrompt) {
|
|
82334
|
+
finalPrompt = `${fullPrompt}
|
|
82335
|
+
|
|
82336
|
+
${prompt}`;
|
|
82337
|
+
}
|
|
82338
|
+
const isFollowUp = session.conversationId !== null;
|
|
82339
|
+
const toolName = isFollowUp ? "codex-reply" : "codex";
|
|
82340
|
+
const toolArgs = { prompt: finalPrompt };
|
|
82341
|
+
if (isFollowUp) {
|
|
82342
|
+
toolArgs.conversationId = session.conversationId;
|
|
82343
|
+
if (debug) {
|
|
82344
|
+
console.log(`[DEBUG] Follow-up with conversationId: ${session.conversationId}`);
|
|
82345
|
+
}
|
|
82346
|
+
} else {
|
|
82347
|
+
if (model) {
|
|
82348
|
+
toolArgs.model = model;
|
|
82349
|
+
}
|
|
82350
|
+
if (mcpServerUrl && mcpServerName) {
|
|
82351
|
+
toolArgs.config = {
|
|
82352
|
+
mcp_servers: {
|
|
82353
|
+
[mcpServerName]: { url: mcpServerUrl }
|
|
82354
|
+
}
|
|
82355
|
+
};
|
|
82356
|
+
}
|
|
82357
|
+
if (debug) {
|
|
82358
|
+
console.log(`[DEBUG] Initial query with tool: ${toolName}`);
|
|
82359
|
+
}
|
|
82360
|
+
}
|
|
82361
|
+
try {
|
|
82362
|
+
const reqId = requestId + 1;
|
|
82363
|
+
let fullResponse = "";
|
|
82364
|
+
let gotSessionId = false;
|
|
82365
|
+
const eventPromise = new Promise((resolve5) => {
|
|
82366
|
+
eventHandlers.set(reqId, (eventParams) => {
|
|
82367
|
+
const msg = eventParams.msg;
|
|
82368
|
+
if (msg.type === "session_configured" && msg.session_id && !gotSessionId) {
|
|
82369
|
+
session.setConversationId(msg.session_id);
|
|
82370
|
+
gotSessionId = true;
|
|
82371
|
+
}
|
|
82372
|
+
if (msg.type === "raw_response_item" && msg.item?.role === "assistant") {
|
|
82373
|
+
const content = msg.item.content;
|
|
82374
|
+
if (Array.isArray(content)) {
|
|
82375
|
+
for (const part of content) {
|
|
82376
|
+
if (part.type === "text" && part.text) {
|
|
82377
|
+
fullResponse += part.text;
|
|
82378
|
+
}
|
|
82379
|
+
}
|
|
82380
|
+
}
|
|
82381
|
+
}
|
|
82382
|
+
});
|
|
82383
|
+
setTimeout(() => {
|
|
82384
|
+
eventHandlers.delete(reqId);
|
|
82385
|
+
resolve5();
|
|
82386
|
+
}, 6e5);
|
|
82387
|
+
});
|
|
82388
|
+
const resultPromise = sendRequest("tools/call", {
|
|
82389
|
+
name: toolName,
|
|
82390
|
+
arguments: toolArgs
|
|
82391
|
+
});
|
|
82392
|
+
const result = await resultPromise;
|
|
82393
|
+
eventHandlers.delete(reqId);
|
|
82394
|
+
if (result && result.content && Array.isArray(result.content)) {
|
|
82395
|
+
for (const item of result.content) {
|
|
82396
|
+
if (item.type === "text" && item.text) {
|
|
82397
|
+
yield {
|
|
82398
|
+
type: "text",
|
|
82399
|
+
content: item.text
|
|
82400
|
+
};
|
|
82401
|
+
fullResponse = item.text;
|
|
82402
|
+
}
|
|
82403
|
+
}
|
|
82404
|
+
}
|
|
82405
|
+
if (fullResponse && (!result.content || result.content.length === 0)) {
|
|
82406
|
+
yield {
|
|
82407
|
+
type: "text",
|
|
82408
|
+
content: fullResponse
|
|
82409
|
+
};
|
|
82410
|
+
}
|
|
82411
|
+
session.incrementMessageCount();
|
|
82412
|
+
yield {
|
|
82413
|
+
type: "metadata",
|
|
82414
|
+
data: {
|
|
82415
|
+
sessionId: session.id,
|
|
82416
|
+
conversationId: session.conversationId,
|
|
82417
|
+
messageCount: session.messageCount
|
|
82418
|
+
}
|
|
82419
|
+
};
|
|
82420
|
+
} catch (error2) {
|
|
82421
|
+
if (debug) {
|
|
82422
|
+
console.error("[DEBUG] Codex query error:", error2);
|
|
82423
|
+
}
|
|
82424
|
+
yield {
|
|
82425
|
+
type: "error",
|
|
82426
|
+
error: error2
|
|
82427
|
+
};
|
|
82428
|
+
}
|
|
82429
|
+
},
|
|
82430
|
+
/**
|
|
82431
|
+
* Get session info
|
|
82432
|
+
*/
|
|
82433
|
+
getSession() {
|
|
82434
|
+
return session.getInfo();
|
|
82435
|
+
},
|
|
82436
|
+
/**
|
|
82437
|
+
* Clean up resources
|
|
82438
|
+
*/
|
|
82439
|
+
async close() {
|
|
82440
|
+
try {
|
|
82441
|
+
if (stdoutReader) {
|
|
82442
|
+
stdoutReader.close();
|
|
82443
|
+
if (debug) {
|
|
82444
|
+
console.log("[DEBUG] Closed stdout reader");
|
|
82445
|
+
}
|
|
82446
|
+
}
|
|
82447
|
+
pendingRequests.clear();
|
|
82448
|
+
eventHandlers.clear();
|
|
82449
|
+
if (codexProcess && !codexProcess.killed) {
|
|
82450
|
+
codexProcess.kill();
|
|
82451
|
+
if (debug) {
|
|
82452
|
+
console.log("[DEBUG] Killed Codex MCP server process");
|
|
82453
|
+
}
|
|
82454
|
+
}
|
|
82455
|
+
if (mcpServer) {
|
|
82456
|
+
await mcpServer.stop();
|
|
82457
|
+
if (debug) {
|
|
82458
|
+
console.log("[DEBUG] Stopped Probe MCP server");
|
|
82459
|
+
}
|
|
82460
|
+
}
|
|
82461
|
+
if (debug) {
|
|
82462
|
+
console.log("[DEBUG] Engine closed, session:", session.id);
|
|
82463
|
+
}
|
|
82464
|
+
} catch (error2) {
|
|
82465
|
+
if (debug) {
|
|
82466
|
+
console.error("[DEBUG] Error during cleanup:", error2.message);
|
|
82467
|
+
}
|
|
82468
|
+
}
|
|
82469
|
+
}
|
|
82470
|
+
};
|
|
82471
|
+
}
|
|
82472
|
+
function combinePrompts2(systemPrompt, customPrompt, agent) {
|
|
82473
|
+
if (!systemPrompt && customPrompt) {
|
|
82474
|
+
return customPrompt;
|
|
82475
|
+
}
|
|
82476
|
+
if (systemPrompt && customPrompt) {
|
|
82477
|
+
return systemPrompt + "\n\n## Additional Instructions\n" + customPrompt;
|
|
82478
|
+
}
|
|
82479
|
+
return systemPrompt || "";
|
|
82480
|
+
}
|
|
82481
|
+
var import_child_process8, import_crypto6, import_readline;
|
|
82482
|
+
var init_codex = __esm({
|
|
82483
|
+
"src/agent/engines/codex.js"() {
|
|
82484
|
+
"use strict";
|
|
82485
|
+
import_child_process8 = require("child_process");
|
|
82486
|
+
import_crypto6 = require("crypto");
|
|
82487
|
+
import_readline = require("readline");
|
|
82488
|
+
init_built_in_server();
|
|
82489
|
+
init_Session();
|
|
81768
82490
|
}
|
|
81769
82491
|
});
|
|
81770
82492
|
|
|
@@ -81842,7 +82564,7 @@ var ProbeAgent_exports = {};
|
|
|
81842
82564
|
__export(ProbeAgent_exports, {
|
|
81843
82565
|
ProbeAgent: () => ProbeAgent
|
|
81844
82566
|
});
|
|
81845
|
-
var import_dotenv, import_anthropic2, import_openai2, import_google2, import_ai2,
|
|
82567
|
+
var import_dotenv, import_anthropic2, import_openai2, import_google2, import_ai2, import_crypto7, import_events4, import_fs5, import_promises3, import_path7, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
|
|
81846
82568
|
var init_ProbeAgent = __esm({
|
|
81847
82569
|
"src/agent/ProbeAgent.js"() {
|
|
81848
82570
|
"use strict";
|
|
@@ -81852,7 +82574,7 @@ var init_ProbeAgent = __esm({
|
|
|
81852
82574
|
import_google2 = require("@ai-sdk/google");
|
|
81853
82575
|
init_dist3();
|
|
81854
82576
|
import_ai2 = require("ai");
|
|
81855
|
-
|
|
82577
|
+
import_crypto7 = require("crypto");
|
|
81856
82578
|
import_events4 = require("events");
|
|
81857
82579
|
import_fs5 = require("fs");
|
|
81858
82580
|
import_promises3 = require("fs/promises");
|
|
@@ -81868,6 +82590,7 @@ var init_ProbeAgent = __esm({
|
|
|
81868
82590
|
init_index();
|
|
81869
82591
|
init_schemaUtils();
|
|
81870
82592
|
init_xmlParsingUtils();
|
|
82593
|
+
init_prompts();
|
|
81871
82594
|
init_mcp();
|
|
81872
82595
|
init_RetryManager();
|
|
81873
82596
|
init_FallbackManager();
|
|
@@ -81889,6 +82612,7 @@ var init_ProbeAgent = __esm({
|
|
|
81889
82612
|
* @param {Object} options - Configuration options
|
|
81890
82613
|
* @param {string} [options.sessionId] - Optional session ID
|
|
81891
82614
|
* @param {string} [options.customPrompt] - Custom prompt to replace the default system message
|
|
82615
|
+
* @param {string} [options.systemPrompt] - Alias for customPrompt; takes precedence when both are provided
|
|
81892
82616
|
* @param {string} [options.promptType] - Predefined prompt type (architect, code-review, support)
|
|
81893
82617
|
* @param {boolean} [options.allowEdit=false] - Allow the use of the 'implement' tool
|
|
81894
82618
|
* @param {boolean} [options.enableDelegate=false] - Enable the delegate tool for task distribution to subagents
|
|
@@ -81923,8 +82647,8 @@ var init_ProbeAgent = __esm({
|
|
|
81923
82647
|
* @param {number} [options.fallback.maxTotalAttempts=10] - Maximum total attempts across all providers
|
|
81924
82648
|
*/
|
|
81925
82649
|
constructor(options = {}) {
|
|
81926
|
-
this.sessionId = options.sessionId || (0,
|
|
81927
|
-
this.customPrompt = options.customPrompt || null;
|
|
82650
|
+
this.sessionId = options.sessionId || (0, import_crypto7.randomUUID)();
|
|
82651
|
+
this.customPrompt = options.systemPrompt || options.customPrompt || null;
|
|
81928
82652
|
this.promptType = options.promptType || "code-explorer";
|
|
81929
82653
|
this.allowEdit = !!options.allowEdit;
|
|
81930
82654
|
this.enableDelegate = !!options.enableDelegate;
|
|
@@ -82048,9 +82772,10 @@ var init_ProbeAgent = __esm({
|
|
|
82048
82772
|
* This method initializes MCP and merges MCP tools into the tool list, and loads history from storage
|
|
82049
82773
|
*/
|
|
82050
82774
|
async initialize() {
|
|
82051
|
-
if (!this.provider && !this.clientApiProvider && this.apiType !== "claude-code") {
|
|
82775
|
+
if (!this.provider && !this.clientApiProvider && this.apiType !== "claude-code" && this.apiType !== "codex") {
|
|
82052
82776
|
if (this.apiType === "uninitialized") {
|
|
82053
82777
|
const claudeAvailable = await this.isClaudeCommandAvailable();
|
|
82778
|
+
const codexAvailable = await this.isCodexCommandAvailable();
|
|
82054
82779
|
if (claudeAvailable) {
|
|
82055
82780
|
if (this.debug) {
|
|
82056
82781
|
console.log("[DEBUG] No API keys found, but claude command detected");
|
|
@@ -82060,8 +82785,17 @@ var init_ProbeAgent = __esm({
|
|
|
82060
82785
|
this.provider = null;
|
|
82061
82786
|
this.model = this.clientApiModel || "claude-3-5-sonnet-20241022";
|
|
82062
82787
|
this.apiType = "claude-code";
|
|
82788
|
+
} else if (codexAvailable) {
|
|
82789
|
+
if (this.debug) {
|
|
82790
|
+
console.log("[DEBUG] No API keys found, but codex command detected");
|
|
82791
|
+
console.log("[DEBUG] Auto-switching to codex provider");
|
|
82792
|
+
}
|
|
82793
|
+
this.clientApiProvider = "codex";
|
|
82794
|
+
this.provider = null;
|
|
82795
|
+
this.model = this.clientApiModel || "gpt-4o";
|
|
82796
|
+
this.apiType = "codex";
|
|
82063
82797
|
} else {
|
|
82064
|
-
throw new Error("No API key provided and claude command
|
|
82798
|
+
throw new Error("No API key provided and neither claude nor codex command found. Please either:\n1. Set an API key: ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, or AWS credentials\n2. Install claude command from https://docs.claude.com/en/docs/claude-code\n3. Install codex command from https://openai.com/codex");
|
|
82065
82799
|
}
|
|
82066
82800
|
}
|
|
82067
82801
|
}
|
|
@@ -82124,25 +82858,43 @@ var init_ProbeAgent = __esm({
|
|
|
82124
82858
|
* Initialize tools with configuration
|
|
82125
82859
|
*/
|
|
82126
82860
|
initializeTools() {
|
|
82861
|
+
const isToolAllowed = (toolName) => this.allowedTools.isEnabled(toolName);
|
|
82127
82862
|
const configOptions = {
|
|
82128
82863
|
sessionId: this.sessionId,
|
|
82129
82864
|
debug: this.debug,
|
|
82130
82865
|
defaultPath: this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd(),
|
|
82131
82866
|
allowedFolders: this.allowedFolders,
|
|
82132
82867
|
outline: this.outline,
|
|
82868
|
+
allowEdit: this.allowEdit,
|
|
82869
|
+
enableDelegate: this.enableDelegate,
|
|
82133
82870
|
enableBash: this.enableBash,
|
|
82134
|
-
bashConfig: this.bashConfig
|
|
82871
|
+
bashConfig: this.bashConfig,
|
|
82872
|
+
allowedTools: this.allowedTools,
|
|
82873
|
+
isToolAllowed
|
|
82135
82874
|
};
|
|
82136
82875
|
const baseTools = createTools(configOptions);
|
|
82137
82876
|
const wrappedTools = createWrappedTools(baseTools);
|
|
82138
|
-
this.toolImplementations = {
|
|
82139
|
-
|
|
82140
|
-
|
|
82141
|
-
|
|
82142
|
-
|
|
82143
|
-
|
|
82144
|
-
|
|
82145
|
-
|
|
82877
|
+
this.toolImplementations = {};
|
|
82878
|
+
if (wrappedTools.searchToolInstance && isToolAllowed("search")) {
|
|
82879
|
+
this.toolImplementations.search = wrappedTools.searchToolInstance;
|
|
82880
|
+
}
|
|
82881
|
+
if (wrappedTools.queryToolInstance && isToolAllowed("query")) {
|
|
82882
|
+
this.toolImplementations.query = wrappedTools.queryToolInstance;
|
|
82883
|
+
}
|
|
82884
|
+
if (wrappedTools.extractToolInstance && isToolAllowed("extract")) {
|
|
82885
|
+
this.toolImplementations.extract = wrappedTools.extractToolInstance;
|
|
82886
|
+
}
|
|
82887
|
+
if (this.enableDelegate && wrappedTools.delegateToolInstance && isToolAllowed("delegate")) {
|
|
82888
|
+
this.toolImplementations.delegate = wrappedTools.delegateToolInstance;
|
|
82889
|
+
}
|
|
82890
|
+
if (isToolAllowed("listFiles")) {
|
|
82891
|
+
this.toolImplementations.listFiles = listFilesToolInstance;
|
|
82892
|
+
}
|
|
82893
|
+
if (isToolAllowed("searchFiles")) {
|
|
82894
|
+
this.toolImplementations.searchFiles = searchFilesToolInstance;
|
|
82895
|
+
}
|
|
82896
|
+
if (isToolAllowed("readImage")) {
|
|
82897
|
+
this.toolImplementations.readImage = {
|
|
82146
82898
|
execute: async (params) => {
|
|
82147
82899
|
const imagePath = params.path;
|
|
82148
82900
|
if (!imagePath) {
|
|
@@ -82154,16 +82906,16 @@ var init_ProbeAgent = __esm({
|
|
|
82154
82906
|
}
|
|
82155
82907
|
return `Image loaded successfully: ${imagePath}. The image is now available for analysis in the conversation.`;
|
|
82156
82908
|
}
|
|
82157
|
-
}
|
|
82158
|
-
}
|
|
82159
|
-
if (this.enableBash && wrappedTools.bashToolInstance) {
|
|
82909
|
+
};
|
|
82910
|
+
}
|
|
82911
|
+
if (this.enableBash && wrappedTools.bashToolInstance && isToolAllowed("bash")) {
|
|
82160
82912
|
this.toolImplementations.bash = wrappedTools.bashToolInstance;
|
|
82161
82913
|
}
|
|
82162
82914
|
if (this.allowEdit) {
|
|
82163
|
-
if (wrappedTools.editToolInstance) {
|
|
82915
|
+
if (wrappedTools.editToolInstance && isToolAllowed("edit")) {
|
|
82164
82916
|
this.toolImplementations.edit = wrappedTools.editToolInstance;
|
|
82165
82917
|
}
|
|
82166
|
-
if (wrappedTools.createToolInstance) {
|
|
82918
|
+
if (wrappedTools.createToolInstance && isToolAllowed("create")) {
|
|
82167
82919
|
this.toolImplementations.create = wrappedTools.createToolInstance;
|
|
82168
82920
|
}
|
|
82169
82921
|
}
|
|
@@ -82183,13 +82935,33 @@ var init_ProbeAgent = __esm({
|
|
|
82183
82935
|
}
|
|
82184
82936
|
/**
|
|
82185
82937
|
* Check if claude command is available on the system
|
|
82938
|
+
* Uses execFile instead of exec to avoid shell injection risks
|
|
82186
82939
|
* @returns {Promise<boolean>} True if claude command is available
|
|
82187
82940
|
* @private
|
|
82188
82941
|
*/
|
|
82189
82942
|
async isClaudeCommandAvailable() {
|
|
82190
82943
|
try {
|
|
82191
|
-
const {
|
|
82192
|
-
|
|
82944
|
+
const { execFile: execFile3 } = await import("child_process");
|
|
82945
|
+
const { promisify: promisify8 } = await import("util");
|
|
82946
|
+
const execFileAsync3 = promisify8(execFile3);
|
|
82947
|
+
await execFileAsync3("claude", ["--version"], { timeout: 5e3 });
|
|
82948
|
+
return true;
|
|
82949
|
+
} catch (error2) {
|
|
82950
|
+
return false;
|
|
82951
|
+
}
|
|
82952
|
+
}
|
|
82953
|
+
/**
|
|
82954
|
+
* Check if codex command is available on the system
|
|
82955
|
+
* Uses execFile instead of exec to avoid shell injection risks
|
|
82956
|
+
* @returns {Promise<boolean>} True if codex command is available
|
|
82957
|
+
* @private
|
|
82958
|
+
*/
|
|
82959
|
+
async isCodexCommandAvailable() {
|
|
82960
|
+
try {
|
|
82961
|
+
const { execFile: execFile3 } = await import("child_process");
|
|
82962
|
+
const { promisify: promisify8 } = await import("util");
|
|
82963
|
+
const execFileAsync3 = promisify8(execFile3);
|
|
82964
|
+
await execFileAsync3("codex", ["--version"], { timeout: 5e3 });
|
|
82193
82965
|
return true;
|
|
82194
82966
|
} catch (error2) {
|
|
82195
82967
|
return false;
|
|
@@ -82213,6 +82985,20 @@ var init_ProbeAgent = __esm({
|
|
|
82213
82985
|
}
|
|
82214
82986
|
return;
|
|
82215
82987
|
}
|
|
82988
|
+
if (this.clientApiProvider === "codex" || process.env.USE_CODEX === "true") {
|
|
82989
|
+
this.provider = null;
|
|
82990
|
+
this.model = modelName || null;
|
|
82991
|
+
this.apiType = "codex";
|
|
82992
|
+
if (this.debug) {
|
|
82993
|
+
console.log("[DEBUG] Codex CLI engine selected - will use built-in access if available");
|
|
82994
|
+
if (this.model) {
|
|
82995
|
+
console.log(`[DEBUG] Using model: ${this.model}`);
|
|
82996
|
+
} else {
|
|
82997
|
+
console.log("[DEBUG] Using Codex account default model");
|
|
82998
|
+
}
|
|
82999
|
+
}
|
|
83000
|
+
return;
|
|
83001
|
+
}
|
|
82216
83002
|
const anthropicApiKey = process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN;
|
|
82217
83003
|
const openaiApiKey = process.env.OPENAI_API_KEY;
|
|
82218
83004
|
const googleApiKey = process.env.GOOGLE_GENERATIVE_AI_API_KEY || process.env.GOOGLE_API_KEY;
|
|
@@ -82374,6 +83160,44 @@ var init_ProbeAgent = __esm({
|
|
|
82374
83160
|
}
|
|
82375
83161
|
}
|
|
82376
83162
|
}
|
|
83163
|
+
if (this.clientApiProvider === "codex" || process.env.USE_CODEX === "true") {
|
|
83164
|
+
try {
|
|
83165
|
+
const engine = await this.getEngine();
|
|
83166
|
+
if (engine && engine.query) {
|
|
83167
|
+
const userMessages = options.messages.filter(
|
|
83168
|
+
(m4) => m4.role === "user" && !m4.content.includes("WARNING: You have reached the maximum tool iterations limit")
|
|
83169
|
+
);
|
|
83170
|
+
const lastUserMessage = userMessages[userMessages.length - 1];
|
|
83171
|
+
const prompt = lastUserMessage ? lastUserMessage.content : "";
|
|
83172
|
+
const engineOptions = {
|
|
83173
|
+
maxTokens: options.maxTokens,
|
|
83174
|
+
temperature: options.temperature,
|
|
83175
|
+
messages: options.messages,
|
|
83176
|
+
systemPrompt: options.messages.find((m4) => m4.role === "system")?.content
|
|
83177
|
+
};
|
|
83178
|
+
const engineStream = engine.query(prompt, engineOptions);
|
|
83179
|
+
async function* createTextStream() {
|
|
83180
|
+
for await (const message of engineStream) {
|
|
83181
|
+
if (message.type === "text" && message.content) {
|
|
83182
|
+
yield message.content;
|
|
83183
|
+
} else if (typeof message === "string") {
|
|
83184
|
+
yield message;
|
|
83185
|
+
}
|
|
83186
|
+
}
|
|
83187
|
+
}
|
|
83188
|
+
return {
|
|
83189
|
+
textStream: createTextStream(),
|
|
83190
|
+
usage: Promise.resolve({})
|
|
83191
|
+
// Engine should handle its own usage tracking
|
|
83192
|
+
// Add other streamText-compatible properties as needed
|
|
83193
|
+
};
|
|
83194
|
+
}
|
|
83195
|
+
} catch (error2) {
|
|
83196
|
+
if (this.debug) {
|
|
83197
|
+
console.log(`[DEBUG] Failed to use Codex engine, falling back to Vercel:`, error2.message);
|
|
83198
|
+
}
|
|
83199
|
+
}
|
|
83200
|
+
}
|
|
82377
83201
|
if (!this.retryManager) {
|
|
82378
83202
|
this.retryManager = new RetryManager({
|
|
82379
83203
|
maxRetries: this.retryConfig.maxRetries ?? 3,
|
|
@@ -82526,6 +83350,35 @@ var init_ProbeAgent = __esm({
|
|
|
82526
83350
|
this.clientApiProvider = null;
|
|
82527
83351
|
}
|
|
82528
83352
|
}
|
|
83353
|
+
if (this.clientApiProvider === "codex" || process.env.USE_CODEX === "true") {
|
|
83354
|
+
try {
|
|
83355
|
+
const { createCodexEngine: createCodexEngine2 } = await Promise.resolve().then(() => (init_codex(), codex_exports));
|
|
83356
|
+
const systemPrompt = this.customPrompt || this.getCodexNativeSystemPrompt();
|
|
83357
|
+
this.engine = await createCodexEngine2({
|
|
83358
|
+
agent: this,
|
|
83359
|
+
// Pass reference to ProbeAgent for tool access
|
|
83360
|
+
systemPrompt,
|
|
83361
|
+
customPrompt: this.customPrompt,
|
|
83362
|
+
sessionId: this.options?.sessionId,
|
|
83363
|
+
debug: this.debug,
|
|
83364
|
+
allowedTools: this.allowedTools,
|
|
83365
|
+
// Pass tool filtering configuration
|
|
83366
|
+
model: this.model
|
|
83367
|
+
// Pass model name (e.g., gpt-4o, o3, etc.)
|
|
83368
|
+
});
|
|
83369
|
+
if (this.debug) {
|
|
83370
|
+
console.log("[DEBUG] Using Codex CLI engine with Probe tools");
|
|
83371
|
+
if (this.customPrompt) {
|
|
83372
|
+
console.log("[DEBUG] Using custom prompt/persona");
|
|
83373
|
+
}
|
|
83374
|
+
}
|
|
83375
|
+
return this.engine;
|
|
83376
|
+
} catch (error2) {
|
|
83377
|
+
console.warn("[WARNING] Failed to load Codex CLI engine:", error2.message);
|
|
83378
|
+
console.warn("[WARNING] Falling back to Vercel AI SDK");
|
|
83379
|
+
this.clientApiProvider = null;
|
|
83380
|
+
}
|
|
83381
|
+
}
|
|
82529
83382
|
const { createEnhancedVercelEngine: createEnhancedVercelEngine2 } = await Promise.resolve().then(() => (init_enhanced_vercel(), enhanced_vercel_exports));
|
|
82530
83383
|
this.engine = createEnhancedVercelEngine2(this);
|
|
82531
83384
|
if (this.debug) {
|
|
@@ -82533,6 +83386,32 @@ var init_ProbeAgent = __esm({
|
|
|
82533
83386
|
}
|
|
82534
83387
|
return this.engine;
|
|
82535
83388
|
}
|
|
83389
|
+
/**
|
|
83390
|
+
* Get session information including thread ID for resumability
|
|
83391
|
+
* @returns {Object} Session info with sessionId, threadId, messageCount
|
|
83392
|
+
*/
|
|
83393
|
+
getSessionInfo() {
|
|
83394
|
+
if (this.engine && this.engine.getSession) {
|
|
83395
|
+
return this.engine.getSession();
|
|
83396
|
+
}
|
|
83397
|
+
return {
|
|
83398
|
+
id: this.sessionId,
|
|
83399
|
+
threadId: null,
|
|
83400
|
+
messageCount: 0
|
|
83401
|
+
};
|
|
83402
|
+
}
|
|
83403
|
+
/**
|
|
83404
|
+
* Close the agent and clean up resources (e.g., MCP servers)
|
|
83405
|
+
* @returns {Promise<void>}
|
|
83406
|
+
*/
|
|
83407
|
+
async close() {
|
|
83408
|
+
if (this.engine && this.engine.close) {
|
|
83409
|
+
await this.engine.close();
|
|
83410
|
+
}
|
|
83411
|
+
if (this.mcpBridge) {
|
|
83412
|
+
this.mcpBridge = null;
|
|
83413
|
+
}
|
|
83414
|
+
}
|
|
82536
83415
|
/**
|
|
82537
83416
|
* Process assistant response content and detect/load image references
|
|
82538
83417
|
* @param {string} content - The assistant's response content
|
|
@@ -82825,11 +83704,61 @@ var init_ProbeAgent = __esm({
|
|
|
82825
83704
|
*/
|
|
82826
83705
|
getClaudeNativeSystemPrompt() {
|
|
82827
83706
|
let systemPrompt = "";
|
|
82828
|
-
if (this.
|
|
82829
|
-
|
|
82830
|
-
|
|
82831
|
-
|
|
82832
|
-
|
|
83707
|
+
if (this.customPrompt) {
|
|
83708
|
+
systemPrompt += this.customPrompt + "\n\n";
|
|
83709
|
+
} else if (this.promptType && predefinedPrompts[this.promptType]) {
|
|
83710
|
+
systemPrompt += predefinedPrompts[this.promptType] + "\n\n";
|
|
83711
|
+
} else {
|
|
83712
|
+
systemPrompt += predefinedPrompts["code-explorer"] + "\n\n";
|
|
83713
|
+
}
|
|
83714
|
+
systemPrompt += `You have access to powerful code search and analysis tools through MCP:
|
|
83715
|
+
- search: Find code patterns using semantic search
|
|
83716
|
+
- extract: Extract specific code sections with context
|
|
83717
|
+
- query: Use AST patterns for structural code matching
|
|
83718
|
+
- listFiles: Browse directory contents
|
|
83719
|
+
- searchFiles: Find files by name patterns`;
|
|
83720
|
+
if (this.enableBash) {
|
|
83721
|
+
systemPrompt += `
|
|
83722
|
+
- bash: Execute bash commands for system operations`;
|
|
83723
|
+
}
|
|
83724
|
+
systemPrompt += `
|
|
83725
|
+
|
|
83726
|
+
When exploring code:
|
|
83727
|
+
1. Start with search to find relevant code patterns
|
|
83728
|
+
2. Use extract to get detailed context when needed
|
|
83729
|
+
3. Prefer focused, specific searches over broad queries
|
|
83730
|
+
4. Combine multiple tools to build complete understanding`;
|
|
83731
|
+
if (this.allowedFolders && this.allowedFolders.length > 0) {
|
|
83732
|
+
systemPrompt += `
|
|
83733
|
+
|
|
83734
|
+
Workspace: ${this.allowedFolders.join(", ")}`;
|
|
83735
|
+
}
|
|
83736
|
+
if (this.fileList) {
|
|
83737
|
+
systemPrompt += `
|
|
83738
|
+
|
|
83739
|
+
# Repository Structure
|
|
83740
|
+
`;
|
|
83741
|
+
systemPrompt += `You are working with a repository located at: ${this.allowedFolders[0]}
|
|
83742
|
+
|
|
83743
|
+
`;
|
|
83744
|
+
systemPrompt += `Here's an overview of the repository structure (showing up to 100 most relevant files):
|
|
83745
|
+
|
|
83746
|
+
`;
|
|
83747
|
+
systemPrompt += "```\n" + this.fileList + "\n```\n";
|
|
83748
|
+
}
|
|
83749
|
+
return systemPrompt;
|
|
83750
|
+
}
|
|
83751
|
+
/**
|
|
83752
|
+
* Get system prompt for Codex CLI (similar to Claude but optimized for Codex)
|
|
83753
|
+
*/
|
|
83754
|
+
getCodexNativeSystemPrompt() {
|
|
83755
|
+
let systemPrompt = "";
|
|
83756
|
+
if (this.customPrompt) {
|
|
83757
|
+
systemPrompt += this.customPrompt + "\n\n";
|
|
83758
|
+
} else if (this.promptType && predefinedPrompts[this.promptType]) {
|
|
83759
|
+
systemPrompt += predefinedPrompts[this.promptType] + "\n\n";
|
|
83760
|
+
} else {
|
|
83761
|
+
systemPrompt += predefinedPrompts["code-explorer"] + "\n\n";
|
|
82833
83762
|
}
|
|
82834
83763
|
systemPrompt += `You have access to powerful code search and analysis tools through MCP:
|
|
82835
83764
|
- search: Find code patterns using semantic search
|
|
@@ -83025,7 +83954,7 @@ Follow these instructions carefully:
|
|
|
83025
83954
|
- Use 'create' for new files or complete file rewrites` : ""}
|
|
83026
83955
|
</instructions>
|
|
83027
83956
|
`;
|
|
83028
|
-
const
|
|
83957
|
+
const predefinedPrompts2 = {
|
|
83029
83958
|
"code-explorer": `You are ProbeChat Code Explorer, a specialized AI assistant focused on helping developers, product managers, and QAs understand and navigate codebases. Your primary function is to answer questions based on code, explain how systems work, and provide insights into code functionality using the provided code analysis tools.
|
|
83030
83959
|
|
|
83031
83960
|
When exploring code:
|
|
@@ -83081,14 +84010,14 @@ When troubleshooting:
|
|
|
83081
84010
|
if (this.debug) {
|
|
83082
84011
|
console.log(`[DEBUG] Using custom prompt`);
|
|
83083
84012
|
}
|
|
83084
|
-
} else if (this.promptType &&
|
|
83085
|
-
systemMessage = "<role>" +
|
|
84013
|
+
} else if (this.promptType && predefinedPrompts2[this.promptType]) {
|
|
84014
|
+
systemMessage = "<role>" + predefinedPrompts2[this.promptType] + "</role>";
|
|
83086
84015
|
if (this.debug) {
|
|
83087
84016
|
console.log(`[DEBUG] Using predefined prompt: ${this.promptType}`);
|
|
83088
84017
|
}
|
|
83089
84018
|
systemMessage += commonInstructions;
|
|
83090
84019
|
} else {
|
|
83091
|
-
systemMessage = "<role>" +
|
|
84020
|
+
systemMessage = "<role>" + predefinedPrompts2["code-explorer"] + "</role>";
|
|
83092
84021
|
if (this.debug) {
|
|
83093
84022
|
console.log(`[DEBUG] Using default prompt: code explorer`);
|
|
83094
84023
|
}
|
|
@@ -83229,6 +84158,7 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
83229
84158
|
const baseMaxIterations = this.maxIterations || MAX_TOOL_ITERATIONS;
|
|
83230
84159
|
const maxIterations = options.schema ? baseMaxIterations + 4 : baseMaxIterations;
|
|
83231
84160
|
const isClaudeCode = this.clientApiProvider === "claude-code" || process.env.USE_CLAUDE_CODE === "true";
|
|
84161
|
+
const isCodex = this.clientApiProvider === "codex" || process.env.USE_CODEX === "true";
|
|
83232
84162
|
if (isClaudeCode) {
|
|
83233
84163
|
if (this.debug) {
|
|
83234
84164
|
console.log(`[DEBUG] Using Claude Code engine - bypassing tool loop (black box mode)`);
|
|
@@ -83281,6 +84211,58 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
83281
84211
|
throw error2;
|
|
83282
84212
|
}
|
|
83283
84213
|
}
|
|
84214
|
+
if (isCodex) {
|
|
84215
|
+
if (this.debug) {
|
|
84216
|
+
console.log(`[DEBUG] Using Codex engine - bypassing tool loop (black box mode)`);
|
|
84217
|
+
console.log(`[DEBUG] Sending question directly to Codex: ${message.substring(0, 100)}...`);
|
|
84218
|
+
}
|
|
84219
|
+
try {
|
|
84220
|
+
const engine = await this.getEngine();
|
|
84221
|
+
if (engine && engine.query) {
|
|
84222
|
+
let assistantResponseContent = "";
|
|
84223
|
+
let toolBatch = null;
|
|
84224
|
+
for await (const chunk of engine.query(message, options)) {
|
|
84225
|
+
if (chunk.type === "text" && chunk.content) {
|
|
84226
|
+
assistantResponseContent += chunk.content;
|
|
84227
|
+
if (options.onStream) {
|
|
84228
|
+
options.onStream(chunk.content);
|
|
84229
|
+
}
|
|
84230
|
+
} else if (chunk.type === "toolBatch" && chunk.tools) {
|
|
84231
|
+
toolBatch = chunk.tools;
|
|
84232
|
+
if (this.debug) {
|
|
84233
|
+
console.log(`[DEBUG] Received batch of ${chunk.tools.length} tool events from Codex`);
|
|
84234
|
+
}
|
|
84235
|
+
} else if (chunk.type === "error") {
|
|
84236
|
+
throw chunk.error;
|
|
84237
|
+
}
|
|
84238
|
+
}
|
|
84239
|
+
if (toolBatch && toolBatch.length > 0 && this.events) {
|
|
84240
|
+
if (this.debug) {
|
|
84241
|
+
console.log(`[DEBUG] Emitting ${toolBatch.length} tool events from Codex batch`);
|
|
84242
|
+
}
|
|
84243
|
+
for (const toolEvent of toolBatch) {
|
|
84244
|
+
this.events.emit("toolCall", toolEvent);
|
|
84245
|
+
}
|
|
84246
|
+
}
|
|
84247
|
+
this.history.push(userMessage);
|
|
84248
|
+
this.history.push({
|
|
84249
|
+
role: "assistant",
|
|
84250
|
+
content: assistantResponseContent
|
|
84251
|
+
});
|
|
84252
|
+
await this.hooks.emit(HOOK_TYPES.COMPLETION, {
|
|
84253
|
+
sessionId: this.sessionId,
|
|
84254
|
+
prompt: message,
|
|
84255
|
+
response: assistantResponseContent
|
|
84256
|
+
});
|
|
84257
|
+
return assistantResponseContent;
|
|
84258
|
+
}
|
|
84259
|
+
} catch (error2) {
|
|
84260
|
+
if (this.debug) {
|
|
84261
|
+
console.error("[DEBUG] Codex error:", error2);
|
|
84262
|
+
}
|
|
84263
|
+
throw error2;
|
|
84264
|
+
}
|
|
84265
|
+
}
|
|
83284
84266
|
if (this.debug) {
|
|
83285
84267
|
console.log(`[DEBUG] Starting agentic flow for question: ${message.substring(0, 100)}...`);
|
|
83286
84268
|
if (options.schema) {
|
|
@@ -84161,7 +85143,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
84161
85143
|
*/
|
|
84162
85144
|
clone(options = {}) {
|
|
84163
85145
|
const {
|
|
84164
|
-
sessionId = (0,
|
|
85146
|
+
sessionId = (0, import_crypto7.randomUUID)(),
|
|
84165
85147
|
stripInternalMessages = true,
|
|
84166
85148
|
keepSystemMessage = true,
|
|
84167
85149
|
deepCopy = true,
|
|
@@ -84378,7 +85360,7 @@ async function delegate({
|
|
|
84378
85360
|
if (!task || typeof task !== "string") {
|
|
84379
85361
|
throw new Error("Task parameter is required and must be a string");
|
|
84380
85362
|
}
|
|
84381
|
-
const sessionId = (0,
|
|
85363
|
+
const sessionId = (0, import_crypto8.randomUUID)();
|
|
84382
85364
|
const startTime = Date.now();
|
|
84383
85365
|
const remainingIterations = Math.max(1, maxIterations - currentIteration);
|
|
84384
85366
|
const delegationSpan = tracer ? tracer.createDelegationSpan(sessionId, task) : null;
|
|
@@ -84506,11 +85488,11 @@ async function delegate({
|
|
|
84506
85488
|
throw new Error(`Delegation failed: ${error2.message}`);
|
|
84507
85489
|
}
|
|
84508
85490
|
}
|
|
84509
|
-
var
|
|
85491
|
+
var import_crypto8, DelegationManager, delegationManager;
|
|
84510
85492
|
var init_delegate = __esm({
|
|
84511
85493
|
"src/delegate.js"() {
|
|
84512
85494
|
"use strict";
|
|
84513
|
-
|
|
85495
|
+
import_crypto8 = require("crypto");
|
|
84514
85496
|
init_ProbeAgent();
|
|
84515
85497
|
DelegationManager = class {
|
|
84516
85498
|
constructor() {
|
|
@@ -84733,8 +85715,8 @@ var init_vercel = __esm({
|
|
|
84733
85715
|
const { writeFileSync: writeFileSync2, unlinkSync } = await import("fs");
|
|
84734
85716
|
const { join: join3 } = await import("path");
|
|
84735
85717
|
const { tmpdir } = await import("os");
|
|
84736
|
-
const { randomUUID:
|
|
84737
|
-
tempFilePath = join3(tmpdir(), `probe-extract-${
|
|
85718
|
+
const { randomUUID: randomUUID6 } = await import("crypto");
|
|
85719
|
+
tempFilePath = join3(tmpdir(), `probe-extract-${randomUUID6()}.txt`);
|
|
84738
85720
|
writeFileSync2(tempFilePath, input_content);
|
|
84739
85721
|
if (debug) {
|
|
84740
85722
|
console.error(`Created temporary file for input content: ${tempFilePath}`);
|
|
@@ -85716,7 +86698,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
85716
86698
|
return;
|
|
85717
86699
|
}
|
|
85718
86700
|
const [cmd, ...cmdArgs] = args;
|
|
85719
|
-
const child = (0,
|
|
86701
|
+
const child = (0, import_child_process9.spawn)(cmd, cmdArgs, {
|
|
85720
86702
|
cwd,
|
|
85721
86703
|
env: processEnv,
|
|
85722
86704
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -85900,11 +86882,11 @@ function validateExecutionOptions(options = {}) {
|
|
|
85900
86882
|
warnings
|
|
85901
86883
|
};
|
|
85902
86884
|
}
|
|
85903
|
-
var
|
|
86885
|
+
var import_child_process9, import_path8, import_fs6;
|
|
85904
86886
|
var init_bashExecutor = __esm({
|
|
85905
86887
|
"src/agent/bashExecutor.js"() {
|
|
85906
86888
|
"use strict";
|
|
85907
|
-
|
|
86889
|
+
import_child_process9 = require("child_process");
|
|
85908
86890
|
import_path8 = require("path");
|
|
85909
86891
|
import_fs6 = require("fs");
|
|
85910
86892
|
init_bashCommandUtils();
|
|
@@ -86756,15 +87738,15 @@ function shouldIgnore(filePath, ignorePatterns) {
|
|
|
86756
87738
|
}
|
|
86757
87739
|
return false;
|
|
86758
87740
|
}
|
|
86759
|
-
var import_fs9, import_path11, import_util12,
|
|
87741
|
+
var import_fs9, import_path11, import_util12, import_child_process10, execAsync3;
|
|
86760
87742
|
var init_file_lister = __esm({
|
|
86761
87743
|
"src/utils/file-lister.js"() {
|
|
86762
87744
|
"use strict";
|
|
86763
87745
|
import_fs9 = __toESM(require("fs"), 1);
|
|
86764
87746
|
import_path11 = __toESM(require("path"), 1);
|
|
86765
87747
|
import_util12 = require("util");
|
|
86766
|
-
|
|
86767
|
-
execAsync3 = (0, import_util12.promisify)(
|
|
87748
|
+
import_child_process10 = require("child_process");
|
|
87749
|
+
execAsync3 = (0, import_util12.promisify)(import_child_process10.exec);
|
|
86768
87750
|
}
|
|
86769
87751
|
});
|
|
86770
87752
|
|