@pensar/apex 0.0.37-canary.0 → 0.0.39-canary.efda0f61

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/pentest.js CHANGED
@@ -40120,11 +40120,38 @@ async function summarizeConversation(messages, opts, model) {
40120
40120
  content: `Summarize this conversation to pass to another agent. This was the system prompt: ${opts.system} `
40121
40121
  }
40122
40122
  ];
40123
- const { text: summary } = await generateText({
40123
+ const { text: summary, usage: summaryUsage } = await generateText({
40124
40124
  model,
40125
40125
  system: `You are a helpful assistant that summarizes conversations to pass to another agent. Review the conversation and system prompt at the end provided by the user.`,
40126
40126
  messages: summarizedMessages
40127
40127
  });
40128
+ if (opts.onStepFinish && summaryUsage) {
40129
+ opts.onStepFinish({
40130
+ text: "",
40131
+ reasoning: undefined,
40132
+ reasoningDetails: [],
40133
+ files: [],
40134
+ sources: [],
40135
+ toolCalls: [],
40136
+ toolResults: [],
40137
+ finishReason: "stop",
40138
+ usage: {
40139
+ inputTokens: summaryUsage.inputTokens ?? 0,
40140
+ outputTokens: summaryUsage.outputTokens ?? 0,
40141
+ totalTokens: summaryUsage.totalTokens ?? 0
40142
+ },
40143
+ warnings: [],
40144
+ request: {},
40145
+ response: {
40146
+ id: "summarization",
40147
+ timestamp: new Date,
40148
+ modelId: ""
40149
+ },
40150
+ providerMetadata: undefined,
40151
+ stepType: "initial",
40152
+ isContinued: false
40153
+ });
40154
+ }
40128
40155
  const originalLength = typeof opts.prompt === "string" ? opts.prompt.length : 0;
40129
40156
  const enhancedPrompt = originalLength > 1e5 ? `Context: The previous conversation contained very long content that was summarized.
40130
40157
 
@@ -40287,6 +40314,7 @@ function streamResponse(opts) {
40287
40314
  } = opts;
40288
40315
  const messagesContainer = { current: messages || [] };
40289
40316
  const providerModel = getProviderModel(model, authConfig);
40317
+ let rateLimitRetryCount = 0;
40290
40318
  try {
40291
40319
  const response = streamText({
40292
40320
  model: providerModel,
@@ -40300,6 +40328,16 @@ function streamResponse(opts) {
40300
40328
  messagesContainer.current = opts2.messages;
40301
40329
  return;
40302
40330
  },
40331
+ onError: async ({ error: error46 }) => {
40332
+ if (error46.message.toLowerCase().includes("too many tokens") || error46.message.toLowerCase().includes("overloaded")) {
40333
+ rateLimitRetryCount++;
40334
+ await new Promise((resolve2) => setTimeout(resolve2, 1000 * rateLimitRetryCount));
40335
+ if (rateLimitRetryCount < 20) {
40336
+ return;
40337
+ }
40338
+ }
40339
+ throw error46;
40340
+ },
40303
40341
  onStepFinish,
40304
40342
  abortSignal,
40305
40343
  activeTools,
@@ -40318,7 +40356,7 @@ function streamResponse(opts) {
40318
40356
  throw new Error(`Tool ${toolCall.toolName} not found or has no schema`);
40319
40357
  }
40320
40358
  const jsonSchema2 = inputSchema({ toolName: toolCall.toolName });
40321
- const { object: repairedArgs } = await generateObject({
40359
+ const { object: repairedArgs, usage: repairUsage } = await generateObject({
40322
40360
  model: providerModel,
40323
40361
  schema: tool2.inputSchema,
40324
40362
  prompt: [
@@ -40331,6 +40369,33 @@ function streamResponse(opts) {
40331
40369
  ].join(`
40332
40370
  `)
40333
40371
  });
40372
+ if (onStepFinish && repairUsage) {
40373
+ onStepFinish({
40374
+ text: "",
40375
+ reasoning: undefined,
40376
+ reasoningDetails: [],
40377
+ files: [],
40378
+ sources: [],
40379
+ toolCalls: [],
40380
+ toolResults: [],
40381
+ finishReason: "stop",
40382
+ usage: {
40383
+ inputTokens: repairUsage.inputTokens ?? 0,
40384
+ outputTokens: repairUsage.outputTokens ?? 0,
40385
+ totalTokens: repairUsage.totalTokens ?? 0
40386
+ },
40387
+ warnings: [],
40388
+ request: {},
40389
+ response: {
40390
+ id: "tool-repair",
40391
+ timestamp: new Date,
40392
+ modelId: ""
40393
+ },
40394
+ providerMetadata: undefined,
40395
+ stepType: "initial",
40396
+ isContinued: false
40397
+ });
40398
+ }
40334
40399
  return { ...toolCall, input: JSON.stringify(repairedArgs) };
40335
40400
  } catch (repairError) {
40336
40401
  if (!silent) {
@@ -40357,9 +40422,9 @@ function streamResponse(opts) {
40357
40422
  }
40358
40423
  }
40359
40424
  async function generateObjectResponse(opts) {
40360
- const { model, schema, prompt, system, maxTokens, temperature, authConfig } = opts;
40425
+ const { model, schema, prompt, system, maxTokens, temperature, authConfig, onTokenUsage } = opts;
40361
40426
  const providerModel = getProviderModel(model, authConfig);
40362
- const { object: object3 } = await generateObject({
40427
+ const { object: object3, usage } = await generateObject({
40363
40428
  model: providerModel,
40364
40429
  schema,
40365
40430
  prompt,
@@ -40367,6 +40432,9 @@ async function generateObjectResponse(opts) {
40367
40432
  maxTokens,
40368
40433
  temperature
40369
40434
  });
40435
+ if (onTokenUsage && usage) {
40436
+ onTokenUsage(usage.inputTokens ?? 0, usage.outputTokens ?? 0);
40437
+ }
40370
40438
  return object3;
40371
40439
  }
40372
40440
  // src/core/agent/thoroughPentestAgent/prompts.ts
@@ -44917,6 +44985,7 @@ function runAgent(opts) {
44917
44985
  objective,
44918
44986
  model,
44919
44987
  onStepFinish,
44988
+ onToolTokenUsage,
44920
44989
  abortSignal,
44921
44990
  silent,
44922
44991
  authConfig,
@@ -44936,7 +45005,7 @@ function runAgent(opts) {
44936
45005
  analyze_scan,
44937
45006
  scratchpad,
44938
45007
  generate_report
44939
- } = createPentestTools(session, undefined, toolOverride);
45008
+ } = createPentestTools(session, undefined, toolOverride, onToolTokenUsage);
44940
45009
  const document_finding = tool({
44941
45010
  name: "document_finding",
44942
45011
  description: `Document a security finding with severity, impact, and remediation guidance.
@@ -46767,7 +46836,7 @@ Example workflow:
46767
46836
  execute: async (params) => recordTestResultCore(session, params)
46768
46837
  });
46769
46838
  }
46770
- async function generateTestStrategy(params, model) {
46839
+ async function generateTestStrategy(params, model, onTokenUsage) {
46771
46840
  const prompt = `You are a penetration testing expert. Generate a concise testing strategy:
46772
46841
 
46773
46842
  Attack Type: ${params.knowledge.name}
@@ -46793,12 +46862,15 @@ Be tactical and specific.`;
46793
46862
  model: providerModel,
46794
46863
  prompt
46795
46864
  });
46865
+ if (onTokenUsage && result.usage) {
46866
+ onTokenUsage(result.usage.inputTokens ?? 0, result.usage.outputTokens ?? 0);
46867
+ }
46796
46868
  return result.text;
46797
46869
  } catch (error46) {
46798
46870
  return params.knowledge.adaptiveStrategy;
46799
46871
  }
46800
46872
  }
46801
- async function generatePayload(params, model) {
46873
+ async function generatePayload(params, model, onTokenUsage) {
46802
46874
  const prompt = `Generate ONE ${params.knowledge.name} payload for testing.
46803
46875
 
46804
46876
  Techniques:
@@ -46822,7 +46894,8 @@ Generate ONE specific payload. Return ONLY JSON:
46822
46894
  const result = await generateObjectResponse({
46823
46895
  model,
46824
46896
  schema: PayloadSchema,
46825
- prompt
46897
+ prompt,
46898
+ onTokenUsage
46826
46899
  });
46827
46900
  return result;
46828
46901
  } catch (error46) {
@@ -46835,7 +46908,7 @@ Generate ONE specific payload. Return ONLY JSON:
46835
46908
  technique: technique.name
46836
46909
  };
46837
46910
  }
46838
- async function analyzeResponse(params, model) {
46911
+ async function analyzeResponse(params, model, onTokenUsage) {
46839
46912
  const prompt = `Analyze this security test response:
46840
46913
 
46841
46914
  Attack: ${params.knowledge.name}
@@ -46863,7 +46936,8 @@ Analyze: Is this vulnerable? Return ONLY JSON:
46863
46936
  const result = await generateObjectResponse({
46864
46937
  model,
46865
46938
  schema: AnalysisSchema,
46866
- prompt
46939
+ prompt,
46940
+ onTokenUsage
46867
46941
  });
46868
46942
  return result;
46869
46943
  } catch (error46) {
@@ -46882,7 +46956,7 @@ Analyze: Is this vulnerable? Return ONLY JSON:
46882
46956
  suggestedNextTest: "Try alternative payload or technique"
46883
46957
  };
46884
46958
  }
46885
- function createSmartTestTool(session, model) {
46959
+ function createSmartTestTool(session, model, onTokenUsage) {
46886
46960
  return tool({
46887
46961
  name: "test_parameter",
46888
46962
  description: `Intelligently test a parameter for a vulnerability using AI-powered adaptive testing.
@@ -46952,7 +47026,7 @@ test_parameter({
46952
47026
  parameter,
46953
47027
  endpoint,
46954
47028
  context
46955
- }, model);
47029
+ }, model, onTokenUsage);
46956
47030
  console.log(`Strategy: ${strategy}`);
46957
47031
  const results = [];
46958
47032
  let vulnerable = false;
@@ -46965,7 +47039,7 @@ test_parameter({
46965
47039
  context: { ...context, parameter, endpoint },
46966
47040
  previousResults: results,
46967
47041
  round
46968
- }, model);
47042
+ }, model, onTokenUsage);
46969
47043
  console.log(` Payload: ${payloadData.payload}`);
46970
47044
  console.log(` Reasoning: ${payloadData.reasoning}`);
46971
47045
  let response;
@@ -46994,7 +47068,7 @@ test_parameter({
46994
47068
  attackType,
46995
47069
  knowledge,
46996
47070
  previousResults: results
46997
- }, model);
47071
+ }, model, onTokenUsage);
46998
47072
  console.log(` Analysis: ${analysis.reasoning}`);
46999
47073
  console.log(` Vulnerable: ${analysis.vulnerable} (confidence: ${analysis.confidence})`);
47000
47074
  results.push({
@@ -47444,7 +47518,7 @@ function wrapCommandWithHeaders(command, headers) {
47444
47518
  }
47445
47519
  return wrapped;
47446
47520
  }
47447
- function createPentestTools(session, model, toolOverride) {
47521
+ function createPentestTools(session, model, toolOverride, onTokenUsage) {
47448
47522
  const offensiveHeaders = getOffensiveHeaders(session);
47449
47523
  const rateLimiter = session._rateLimiter;
47450
47524
  const executeCommand = tool({
@@ -47618,7 +47692,7 @@ COMMON TESTING PATTERNS:
47618
47692
  http_request: httpRequest,
47619
47693
  document_finding: createDocumentFindingTool(session),
47620
47694
  record_test_result: createRecordTestResultTool(session),
47621
- test_parameter: createSmartTestTool(session, model || "claude-sonnet-4-20250514"),
47695
+ test_parameter: createSmartTestTool(session, model || "claude-sonnet-4-20250514", onTokenUsage),
47622
47696
  check_testing_coverage: createCheckTestingCoverageTool(session),
47623
47697
  validate_completeness: createValidateCompletenessTool(session),
47624
47698
  enumerate_endpoints: createEnumerateEndpointsTool(session),
@@ -47634,7 +47708,7 @@ COMMON TESTING PATTERNS:
47634
47708
  import { join as join5 } from "path";
47635
47709
  import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync7 } from "fs";
47636
47710
  function runAgent2(opts) {
47637
- const { target, model, onStepFinish, abortSignal } = opts;
47711
+ const { target, model, onStepFinish, onToolTokenUsage, abortSignal } = opts;
47638
47712
  const session = opts.session || createSession(target);
47639
47713
  const subagentId = `attack-surface-${nanoid3(6)}`;
47640
47714
  console.log(`Created attack surface session: ${session.id}`);
@@ -47643,7 +47717,7 @@ function runAgent2(opts) {
47643
47717
  if (!existsSync7(assetsPath)) {
47644
47718
  mkdirSync5(assetsPath, { recursive: true });
47645
47719
  }
47646
- const { analyze_scan, execute_command, http_request } = createPentestTools(session, model);
47720
+ const { analyze_scan, execute_command, http_request } = createPentestTools(session, model, undefined, onToolTokenUsage);
47647
47721
  const document_asset = tool({
47648
47722
  name: "document_asset",
47649
47723
  description: `Document a discovered asset during attack surface analysis.
@@ -47940,13 +48014,14 @@ function runAgent3(opts) {
47940
48014
  onSubagentSpawn,
47941
48015
  onSubagentMessage,
47942
48016
  onSubagentComplete,
48017
+ onSubagentTokenUsage,
47943
48018
  session: sessionProp
47944
48019
  } = opts;
47945
48020
  const session = sessionProp || createSession(target, undefined, undefined, sessionConfig);
47946
48021
  const logger = new Logger(session);
47947
48022
  logger.log(`Created thorough pentest session: ${session.id}`);
47948
48023
  logger.log(`Session path: ${session.rootPath}`);
47949
- const tools2 = createOrchestratorTools(session, model, abortSignal, onSubagentSpawn, onSubagentMessage, onSubagentComplete, logger);
48024
+ const tools2 = createOrchestratorTools(session, model, abortSignal, onSubagentSpawn, onSubagentMessage, onSubagentComplete, onSubagentTokenUsage, logger);
47950
48025
  const enhancedPrompt = `
47951
48026
  TARGET: ${target}
47952
48027
 
@@ -47982,7 +48057,7 @@ Begin by using the get_attack_surface tool to map the complete attack surface of
47982
48057
  streamResult.session = session;
47983
48058
  return { streamResult, session };
47984
48059
  }
47985
- function createOrchestratorTools(session, model, abortSignal, onSubagentSpawn, onSubagentMessage, onSubagentComplete, logger) {
48060
+ function createOrchestratorTools(session, model, abortSignal, onSubagentSpawn, onSubagentMessage, onSubagentComplete, onSubagentTokenUsage, logger) {
47986
48061
  const getAttackSurface = tool({
47987
48062
  name: "get_attack_surface",
47988
48063
  description: `Run the attack surface analysis agent to discover all assets and identify targets.
@@ -48014,7 +48089,19 @@ Use this as the FIRST step in your thorough penetration test.`,
48014
48089
  target,
48015
48090
  objective,
48016
48091
  model,
48017
- abortSignal
48092
+ abortSignal,
48093
+ onStepFinish: ({ usage }) => {
48094
+ if (onSubagentTokenUsage) {
48095
+ const inputTokens = usage.inputTokens ?? 0;
48096
+ const outputTokens = usage.outputTokens ?? 0;
48097
+ onSubagentTokenUsage(subagentId, inputTokens, outputTokens);
48098
+ }
48099
+ },
48100
+ onToolTokenUsage: (inputTokens, outputTokens) => {
48101
+ if (onSubagentTokenUsage) {
48102
+ onSubagentTokenUsage(subagentId, inputTokens, outputTokens);
48103
+ }
48104
+ }
48018
48105
  });
48019
48106
  const allMessages = [];
48020
48107
  let currentAssistantText = "";
@@ -48189,7 +48276,19 @@ You can spawn multiple agents in parallel - they will run concurrently.`,
48189
48276
  target: targetInfo.target,
48190
48277
  objective: targetInfo.objective,
48191
48278
  model,
48192
- abortSignal
48279
+ abortSignal,
48280
+ onStepFinish: ({ usage }) => {
48281
+ if (onSubagentTokenUsage) {
48282
+ const inputTokens = usage.inputTokens ?? 0;
48283
+ const outputTokens = usage.outputTokens ?? 0;
48284
+ onSubagentTokenUsage(subagentId, inputTokens, outputTokens);
48285
+ }
48286
+ },
48287
+ onToolTokenUsage: (inputTokens, outputTokens) => {
48288
+ if (onSubagentTokenUsage) {
48289
+ onSubagentTokenUsage(subagentId, inputTokens, outputTokens);
48290
+ }
48291
+ }
48193
48292
  });
48194
48293
  const allMessages = [];
48195
48294
  let currentAssistantText = "";
@@ -40120,11 +40120,38 @@ async function summarizeConversation(messages, opts, model) {
40120
40120
  content: `Summarize this conversation to pass to another agent. This was the system prompt: ${opts.system} `
40121
40121
  }
40122
40122
  ];
40123
- const { text: summary } = await generateText({
40123
+ const { text: summary, usage: summaryUsage } = await generateText({
40124
40124
  model,
40125
40125
  system: `You are a helpful assistant that summarizes conversations to pass to another agent. Review the conversation and system prompt at the end provided by the user.`,
40126
40126
  messages: summarizedMessages
40127
40127
  });
40128
+ if (opts.onStepFinish && summaryUsage) {
40129
+ opts.onStepFinish({
40130
+ text: "",
40131
+ reasoning: undefined,
40132
+ reasoningDetails: [],
40133
+ files: [],
40134
+ sources: [],
40135
+ toolCalls: [],
40136
+ toolResults: [],
40137
+ finishReason: "stop",
40138
+ usage: {
40139
+ inputTokens: summaryUsage.inputTokens ?? 0,
40140
+ outputTokens: summaryUsage.outputTokens ?? 0,
40141
+ totalTokens: summaryUsage.totalTokens ?? 0
40142
+ },
40143
+ warnings: [],
40144
+ request: {},
40145
+ response: {
40146
+ id: "summarization",
40147
+ timestamp: new Date,
40148
+ modelId: ""
40149
+ },
40150
+ providerMetadata: undefined,
40151
+ stepType: "initial",
40152
+ isContinued: false
40153
+ });
40154
+ }
40128
40155
  const originalLength = typeof opts.prompt === "string" ? opts.prompt.length : 0;
40129
40156
  const enhancedPrompt = originalLength > 1e5 ? `Context: The previous conversation contained very long content that was summarized.
40130
40157
 
@@ -40272,6 +40299,7 @@ function streamResponse(opts) {
40272
40299
  } = opts;
40273
40300
  const messagesContainer = { current: messages || [] };
40274
40301
  const providerModel = getProviderModel(model, authConfig);
40302
+ let rateLimitRetryCount = 0;
40275
40303
  try {
40276
40304
  const response = streamText({
40277
40305
  model: providerModel,
@@ -40285,6 +40313,16 @@ function streamResponse(opts) {
40285
40313
  messagesContainer.current = opts2.messages;
40286
40314
  return;
40287
40315
  },
40316
+ onError: async ({ error: error46 }) => {
40317
+ if (error46.message.toLowerCase().includes("too many tokens") || error46.message.toLowerCase().includes("overloaded")) {
40318
+ rateLimitRetryCount++;
40319
+ await new Promise((resolve2) => setTimeout(resolve2, 1000 * rateLimitRetryCount));
40320
+ if (rateLimitRetryCount < 20) {
40321
+ return;
40322
+ }
40323
+ }
40324
+ throw error46;
40325
+ },
40288
40326
  onStepFinish,
40289
40327
  abortSignal,
40290
40328
  activeTools,
@@ -40303,7 +40341,7 @@ function streamResponse(opts) {
40303
40341
  throw new Error(`Tool ${toolCall.toolName} not found or has no schema`);
40304
40342
  }
40305
40343
  const jsonSchema2 = inputSchema({ toolName: toolCall.toolName });
40306
- const { object: repairedArgs } = await generateObject({
40344
+ const { object: repairedArgs, usage: repairUsage } = await generateObject({
40307
40345
  model: providerModel,
40308
40346
  schema: tool2.inputSchema,
40309
40347
  prompt: [
@@ -40316,6 +40354,33 @@ function streamResponse(opts) {
40316
40354
  ].join(`
40317
40355
  `)
40318
40356
  });
40357
+ if (onStepFinish && repairUsage) {
40358
+ onStepFinish({
40359
+ text: "",
40360
+ reasoning: undefined,
40361
+ reasoningDetails: [],
40362
+ files: [],
40363
+ sources: [],
40364
+ toolCalls: [],
40365
+ toolResults: [],
40366
+ finishReason: "stop",
40367
+ usage: {
40368
+ inputTokens: repairUsage.inputTokens ?? 0,
40369
+ outputTokens: repairUsage.outputTokens ?? 0,
40370
+ totalTokens: repairUsage.totalTokens ?? 0
40371
+ },
40372
+ warnings: [],
40373
+ request: {},
40374
+ response: {
40375
+ id: "tool-repair",
40376
+ timestamp: new Date,
40377
+ modelId: ""
40378
+ },
40379
+ providerMetadata: undefined,
40380
+ stepType: "initial",
40381
+ isContinued: false
40382
+ });
40383
+ }
40319
40384
  return { ...toolCall, input: JSON.stringify(repairedArgs) };
40320
40385
  } catch (repairError) {
40321
40386
  if (!silent) {
@@ -40342,9 +40407,9 @@ function streamResponse(opts) {
40342
40407
  }
40343
40408
  }
40344
40409
  async function generateObjectResponse(opts) {
40345
- const { model, schema, prompt, system, maxTokens, temperature, authConfig } = opts;
40410
+ const { model, schema, prompt, system, maxTokens, temperature, authConfig, onTokenUsage } = opts;
40346
40411
  const providerModel = getProviderModel(model, authConfig);
40347
- const { object: object3 } = await generateObject({
40412
+ const { object: object3, usage } = await generateObject({
40348
40413
  model: providerModel,
40349
40414
  schema,
40350
40415
  prompt,
@@ -40352,6 +40417,9 @@ async function generateObjectResponse(opts) {
40352
40417
  maxTokens,
40353
40418
  temperature
40354
40419
  });
40420
+ if (onTokenUsage && usage) {
40421
+ onTokenUsage(usage.inputTokens ?? 0, usage.outputTokens ?? 0);
40422
+ }
40355
40423
  return object3;
40356
40424
  }
40357
40425
  // src/core/agent/pentestAgent/prompts.ts
@@ -43703,7 +43771,7 @@ Example workflow:
43703
43771
  execute: async (params) => recordTestResultCore(session, params)
43704
43772
  });
43705
43773
  }
43706
- async function generateTestStrategy(params, model) {
43774
+ async function generateTestStrategy(params, model, onTokenUsage) {
43707
43775
  const prompt = `You are a penetration testing expert. Generate a concise testing strategy:
43708
43776
 
43709
43777
  Attack Type: ${params.knowledge.name}
@@ -43729,12 +43797,15 @@ Be tactical and specific.`;
43729
43797
  model: providerModel,
43730
43798
  prompt
43731
43799
  });
43800
+ if (onTokenUsage && result.usage) {
43801
+ onTokenUsage(result.usage.inputTokens ?? 0, result.usage.outputTokens ?? 0);
43802
+ }
43732
43803
  return result.text;
43733
43804
  } catch (error46) {
43734
43805
  return params.knowledge.adaptiveStrategy;
43735
43806
  }
43736
43807
  }
43737
- async function generatePayload(params, model) {
43808
+ async function generatePayload(params, model, onTokenUsage) {
43738
43809
  const prompt = `Generate ONE ${params.knowledge.name} payload for testing.
43739
43810
 
43740
43811
  Techniques:
@@ -43758,7 +43829,8 @@ Generate ONE specific payload. Return ONLY JSON:
43758
43829
  const result = await generateObjectResponse({
43759
43830
  model,
43760
43831
  schema: PayloadSchema,
43761
- prompt
43832
+ prompt,
43833
+ onTokenUsage
43762
43834
  });
43763
43835
  return result;
43764
43836
  } catch (error46) {
@@ -43771,7 +43843,7 @@ Generate ONE specific payload. Return ONLY JSON:
43771
43843
  technique: technique.name
43772
43844
  };
43773
43845
  }
43774
- async function analyzeResponse(params, model) {
43846
+ async function analyzeResponse(params, model, onTokenUsage) {
43775
43847
  const prompt = `Analyze this security test response:
43776
43848
 
43777
43849
  Attack: ${params.knowledge.name}
@@ -43799,7 +43871,8 @@ Analyze: Is this vulnerable? Return ONLY JSON:
43799
43871
  const result = await generateObjectResponse({
43800
43872
  model,
43801
43873
  schema: AnalysisSchema,
43802
- prompt
43874
+ prompt,
43875
+ onTokenUsage
43803
43876
  });
43804
43877
  return result;
43805
43878
  } catch (error46) {
@@ -43818,7 +43891,7 @@ Analyze: Is this vulnerable? Return ONLY JSON:
43818
43891
  suggestedNextTest: "Try alternative payload or technique"
43819
43892
  };
43820
43893
  }
43821
- function createSmartTestTool(session, model) {
43894
+ function createSmartTestTool(session, model, onTokenUsage) {
43822
43895
  return tool({
43823
43896
  name: "test_parameter",
43824
43897
  description: `Intelligently test a parameter for a vulnerability using AI-powered adaptive testing.
@@ -43888,7 +43961,7 @@ test_parameter({
43888
43961
  parameter,
43889
43962
  endpoint,
43890
43963
  context
43891
- }, model);
43964
+ }, model, onTokenUsage);
43892
43965
  console.log(`Strategy: ${strategy}`);
43893
43966
  const results = [];
43894
43967
  let vulnerable = false;
@@ -43901,7 +43974,7 @@ test_parameter({
43901
43974
  context: { ...context, parameter, endpoint },
43902
43975
  previousResults: results,
43903
43976
  round
43904
- }, model);
43977
+ }, model, onTokenUsage);
43905
43978
  console.log(` Payload: ${payloadData.payload}`);
43906
43979
  console.log(` Reasoning: ${payloadData.reasoning}`);
43907
43980
  let response;
@@ -43930,7 +44003,7 @@ test_parameter({
43930
44003
  attackType,
43931
44004
  knowledge,
43932
44005
  previousResults: results
43933
- }, model);
44006
+ }, model, onTokenUsage);
43934
44007
  console.log(` Analysis: ${analysis.reasoning}`);
43935
44008
  console.log(` Vulnerable: ${analysis.vulnerable} (confidence: ${analysis.confidence})`);
43936
44009
  results.push({
@@ -44380,7 +44453,7 @@ function wrapCommandWithHeaders(command, headers) {
44380
44453
  }
44381
44454
  return wrapped;
44382
44455
  }
44383
- function createPentestTools(session, model, toolOverride) {
44456
+ function createPentestTools(session, model, toolOverride, onTokenUsage) {
44384
44457
  const offensiveHeaders = getOffensiveHeaders(session);
44385
44458
  const rateLimiter = session._rateLimiter;
44386
44459
  const executeCommand = tool({
@@ -44554,7 +44627,7 @@ COMMON TESTING PATTERNS:
44554
44627
  http_request: httpRequest,
44555
44628
  document_finding: createDocumentFindingTool(session),
44556
44629
  record_test_result: createRecordTestResultTool(session),
44557
- test_parameter: createSmartTestTool(session, model || "claude-sonnet-4-20250514"),
44630
+ test_parameter: createSmartTestTool(session, model || "claude-sonnet-4-20250514", onTokenUsage),
44558
44631
  check_testing_coverage: createCheckTestingCoverageTool(session),
44559
44632
  validate_completeness: createValidateCompletenessTool(session),
44560
44633
  enumerate_endpoints: createEnumerateEndpointsTool(session),
@@ -45606,6 +45679,7 @@ function runAgent(opts) {
45606
45679
  objective,
45607
45680
  model,
45608
45681
  onStepFinish,
45682
+ onToolTokenUsage,
45609
45683
  abortSignal,
45610
45684
  silent,
45611
45685
  authConfig,
@@ -45625,7 +45699,7 @@ function runAgent(opts) {
45625
45699
  analyze_scan,
45626
45700
  scratchpad,
45627
45701
  generate_report
45628
- } = createPentestTools(session, undefined, toolOverride);
45702
+ } = createPentestTools(session, undefined, toolOverride, onToolTokenUsage);
45629
45703
  const document_finding = tool({
45630
45704
  name: "document_finding",
45631
45705
  description: `Document a security finding with severity, impact, and remediation guidance.