@polka-codes/cli-shared 0.8.23 → 0.8.25

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.
Files changed (2) hide show
  1. package/dist/index.js +173 -35
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -27497,14 +27497,19 @@ import { join as join2 } from "node:path";
27497
27497
  class AiServiceBase {
27498
27498
  usageMeter;
27499
27499
  options;
27500
+ #abortController;
27500
27501
  constructor(options) {
27501
27502
  this.options = options;
27502
27503
  this.usageMeter = options.usageMeter;
27503
27504
  }
27505
+ abort() {
27506
+ this.#abortController?.abort();
27507
+ }
27504
27508
  async* send(systemPrompt, messages) {
27505
27509
  this.usageMeter.checkLimit();
27506
27510
  this.usageMeter.incrementMessageCount();
27507
- const stream = this.sendImpl(systemPrompt, messages);
27511
+ this.#abortController = new AbortController;
27512
+ const stream = this.sendImpl(systemPrompt, messages, this.#abortController.signal);
27508
27513
  for await (const chunk of stream) {
27509
27514
  switch (chunk.type) {
27510
27515
  case "usage":
@@ -27517,7 +27522,8 @@ class AiServiceBase {
27517
27522
  async request(systemPrompt, messages) {
27518
27523
  this.usageMeter.checkLimit();
27519
27524
  this.usageMeter.incrementMessageCount();
27520
- const stream = this.sendImpl(systemPrompt, messages);
27525
+ this.#abortController = new AbortController;
27526
+ const stream = this.sendImpl(systemPrompt, messages, this.#abortController.signal);
27521
27527
  const usage = {
27522
27528
  inputTokens: 0,
27523
27529
  outputTokens: 0,
@@ -31022,7 +31028,7 @@ class AnthropicService extends AiServiceBase {
31022
31028
  info: anthropicModels[id] ?? anthropicModels[anthropicDefaultModelId]
31023
31029
  };
31024
31030
  }
31025
- async* sendImpl(systemPrompt, messages) {
31031
+ async* sendImpl(systemPrompt, messages, signal) {
31026
31032
  let stream;
31027
31033
  const modelId = this.model.id;
31028
31034
  const cacheControl = this.#options.enableCache ? { type: "ephemeral" } : undefined;
@@ -31080,7 +31086,7 @@ class AnthropicService extends AiServiceBase {
31080
31086
  return message;
31081
31087
  }),
31082
31088
  stream: true
31083
- });
31089
+ }, { signal });
31084
31090
  break;
31085
31091
  }
31086
31092
  default: {
@@ -31091,7 +31097,7 @@ class AnthropicService extends AiServiceBase {
31091
31097
  system: [{ text: systemPrompt, type: "text" }],
31092
31098
  messages,
31093
31099
  stream: true
31094
- });
31100
+ }, { signal });
31095
31101
  break;
31096
31102
  }
31097
31103
  }
@@ -36449,7 +36455,7 @@ class DeepSeekService extends AiServiceBase {
36449
36455
  info: deepSeekModels[id] ?? deepSeekModels[deepSeekDefaultModelId]
36450
36456
  };
36451
36457
  }
36452
- async* sendImpl(systemPrompt, messages) {
36458
+ async* sendImpl(systemPrompt, messages, signal) {
36453
36459
  const openAiMessages = [
36454
36460
  { role: "system", content: systemPrompt },
36455
36461
  ...convertToOpenAiMessages(messages)
@@ -36461,7 +36467,7 @@ class DeepSeekService extends AiServiceBase {
36461
36467
  temperature: 0,
36462
36468
  stream: true,
36463
36469
  stream_options: { include_usage: true }
36464
- });
36470
+ }, { signal });
36465
36471
  for await (const chunk of stream) {
36466
36472
  const delta = chunk.choices[0]?.delta;
36467
36473
  if (delta?.reasoning_content) {
@@ -36505,7 +36511,7 @@ class OllamaService extends AiServiceBase {
36505
36511
  info: openAiModelInfoSaneDefaults
36506
36512
  };
36507
36513
  }
36508
- async* sendImpl(systemPrompt, messages) {
36514
+ async* sendImpl(systemPrompt, messages, signal) {
36509
36515
  const openAiMessages = [
36510
36516
  { role: "system", content: systemPrompt },
36511
36517
  ...convertToOpenAiMessages(messages)
@@ -36515,7 +36521,7 @@ class OllamaService extends AiServiceBase {
36515
36521
  messages: openAiMessages,
36516
36522
  temperature: 0,
36517
36523
  stream: true
36518
- });
36524
+ }, { signal });
36519
36525
  for await (const chunk of stream) {
36520
36526
  const delta = chunk.choices[0]?.delta;
36521
36527
  if (delta?.content) {
@@ -36562,7 +36568,7 @@ class OpenRouterService extends AiServiceBase {
36562
36568
  this.#modelProviderInfo = data.data;
36563
36569
  });
36564
36570
  }
36565
- async* sendImpl(systemPrompt, messages) {
36571
+ async* sendImpl(systemPrompt, messages, signal) {
36566
36572
  const openAiMessages = [
36567
36573
  { role: "system", content: systemPrompt },
36568
36574
  ...convertToOpenAiMessages(messages)
@@ -36622,7 +36628,7 @@ class OpenRouterService extends AiServiceBase {
36622
36628
  transforms: shouldApplyMiddleOutTransform ? ["middle-out"] : undefined,
36623
36629
  include_reasoning: true,
36624
36630
  ...reasoning
36625
- });
36631
+ }, { signal });
36626
36632
  let genId;
36627
36633
  for await (const chunk of stream) {
36628
36634
  if ("error" in chunk) {
@@ -36876,7 +36882,7 @@ var getArray = (args, name, defaultValue) => {
36876
36882
  return [ret];
36877
36883
  };
36878
36884
  // ../core/src/tools/utils/replaceInFile.ts
36879
- var replaceInFile = async (fileContent, diff) => {
36885
+ var replaceInFile = (fileContent, diff) => {
36880
36886
  const blockPattern = /<<<<<+ SEARCH>?\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
36881
36887
  const blocks = [];
36882
36888
  for (let match = blockPattern.exec(diff);match !== null; match = blockPattern.exec(diff)) {
@@ -36921,14 +36927,32 @@ var replaceInFile = async (fileContent, diff) => {
36921
36927
  const startPos = endPos - strippedSearch.length;
36922
36928
  return content.slice(0, startPos) + replace + content.slice(endPos);
36923
36929
  }
36924
- throw new Error(`Could not find the following text in file:
36925
- ${search}`);
36930
+ return null;
36926
36931
  };
36927
36932
  let updatedFile = fileContent;
36933
+ let appliedCount = 0;
36934
+ const totalCount = blocks.length;
36928
36935
  for (const { search, replace } of blocks) {
36929
- updatedFile = findAndReplace(updatedFile, search, replace);
36936
+ const result = findAndReplace(updatedFile, search, replace);
36937
+ if (result !== null) {
36938
+ updatedFile = result;
36939
+ appliedCount++;
36940
+ }
36930
36941
  }
36931
- return updatedFile;
36942
+ let status;
36943
+ if (appliedCount === 0) {
36944
+ status = "no_diff_applied";
36945
+ } else if (appliedCount < totalCount) {
36946
+ status = "some_diff_applied";
36947
+ } else {
36948
+ status = "all_diff_applied";
36949
+ }
36950
+ return {
36951
+ content: updatedFile,
36952
+ status,
36953
+ appliedCount,
36954
+ totalCount
36955
+ };
36932
36956
  };
36933
36957
  // ../core/src/tools/askFollowupQuestion.ts
36934
36958
  var toolInfo = {
@@ -37623,14 +37647,26 @@ var handler8 = async (provider, args) => {
37623
37647
  if (fileContent == null) {
37624
37648
  return {
37625
37649
  type: "Error" /* Error */,
37626
- message: `<error><replace_in_file_path>${path}</replace_in_file_path><error_message>File not found</error_message></error>`
37650
+ message: `<replace_in_file_result path="${path}" status="failed" message="File not found" />`
37651
+ };
37652
+ }
37653
+ const result = replaceInFile(fileContent, diff);
37654
+ if (result.status === "no_diff_applied") {
37655
+ return {
37656
+ type: "Error" /* Error */,
37657
+ message: `<replace_in_file_result path="${path}" status="failed" message="Unable to apply changes" />`
37658
+ };
37659
+ }
37660
+ await provider.writeFile(path, result.content);
37661
+ if (result.status === "some_diff_applied") {
37662
+ return {
37663
+ type: "Reply" /* Reply */,
37664
+ message: `<replace_in_file_result path="${path}" status="some_diff_applied" applied_count="${result.appliedCount}" total_count="${result.totalCount}" />`
37627
37665
  };
37628
37666
  }
37629
- const result = await replaceInFile(fileContent, diff);
37630
- await provider.writeFile(path, result);
37631
37667
  return {
37632
37668
  type: "Reply" /* Reply */,
37633
- message: `<replace_in_file_path>${path}</replace_in_file_path>`
37669
+ message: `<replace_in_file_result path="${path}" status="all_diff_applied" />`
37634
37670
  };
37635
37671
  };
37636
37672
  var isAvailable8 = (provider) => {
@@ -38021,7 +38057,7 @@ var updateKnowledge_default = {
38021
38057
  // ../core/src/tools/writeToFile.ts
38022
38058
  var toolInfo11 = {
38023
38059
  name: "write_to_file",
38024
- description: "Request to write content to a file at the specified path. If the file exists, it will be overwritten with the provided content. If the file doesn't exist, it will be created. This tool will automatically create any directories needed to write the file. Ensure that the output content does not include incorrect escaped character patterns such as `&lt;` and `&gt;`.",
38060
+ description: "Request to write content to a file at the specified path. If the file exists, it will be overwritten with the provided content. If the file doesn't exist, it will be created. This tool will automatically create any directories needed to write the file. Ensure that the output content does not include incorrect escaped character patterns such as `&lt;`, `&gt;`, or `&amp;`. Also ensure there is no unwanted CDATA tags in the content.",
38025
38061
  parameters: [
38026
38062
  {
38027
38063
  name: "path",
@@ -38072,7 +38108,10 @@ var handler11 = async (provider, args) => {
38072
38108
  };
38073
38109
  }
38074
38110
  const path = getString(args, "path");
38075
- const content = getString(args, "content");
38111
+ let content = getString(args, "content");
38112
+ const trimmedContent = content.trim();
38113
+ if (trimmedContent.startsWith("<![CDATA[") && content.endsWith("]]>"))
38114
+ content = trimmedContent.slice(9, -3);
38076
38115
  await provider.writeFile(path, content);
38077
38116
  return {
38078
38117
  type: "Reply" /* Reply */,
@@ -38631,12 +38670,27 @@ Ensure the opening and closing tags are correctly nested and closed, and that yo
38631
38670
  Avoid unnecessary text or symbols before or after the tool use.
38632
38671
  Avoid unnecessary escape characters or special characters.
38633
38672
  `,
38634
- toolResults: (tool, result) => `<tool_response>
38635
- <tool_name>${tool}</tool_name>
38636
- <tool_result>
38637
- ${result}
38638
- </tool_result>
38639
- </tool_response>`,
38673
+ toolResults: (tool, result) => {
38674
+ if (typeof result === "string") {
38675
+ return [
38676
+ {
38677
+ type: "text",
38678
+ text: `<tool_response name=${tool}>${result}</tool_response>`
38679
+ }
38680
+ ];
38681
+ }
38682
+ return [
38683
+ {
38684
+ type: "text",
38685
+ text: `<tool_response name=${tool}>`
38686
+ },
38687
+ ...result,
38688
+ {
38689
+ type: "text",
38690
+ text: "</tool_response>"
38691
+ }
38692
+ ];
38693
+ },
38640
38694
  commandResult: (command, exitCode, stdout, stderr) => `<command>${command}</command>
38641
38695
  <command_exit_code>${exitCode}</command_exit_code>
38642
38696
  <command_stdout>
@@ -38654,6 +38708,7 @@ class AgentBase {
38654
38708
  handlers;
38655
38709
  #messages = [];
38656
38710
  #policies;
38711
+ #aborted = false;
38657
38712
  constructor(name, ai, config) {
38658
38713
  this.ai = ai;
38659
38714
  if (config.agents && config.agents.length > 0) {
@@ -38685,6 +38740,10 @@ ${instance.prompt}`;
38685
38740
  this.config = config;
38686
38741
  this.#policies = policies;
38687
38742
  }
38743
+ abort() {
38744
+ this.#aborted = true;
38745
+ this.ai.abort();
38746
+ }
38688
38747
  get parameters() {
38689
38748
  return this.ai.options.parameters;
38690
38749
  }
@@ -38713,11 +38772,17 @@ ${instance.prompt}`;
38713
38772
  async#processLoop(userMessage) {
38714
38773
  let nextRequest = userMessage;
38715
38774
  while (true) {
38775
+ if (this.#aborted) {
38776
+ return { type: "Aborted" };
38777
+ }
38716
38778
  if (this.ai.usageMeter.isLimitExceeded().result) {
38717
38779
  this.#callback({ kind: "UsageExceeded" /* UsageExceeded */, agent: this });
38718
38780
  return { type: "UsageExceeded" };
38719
38781
  }
38720
38782
  const response = await this.#request(nextRequest);
38783
+ if (this.#aborted) {
38784
+ return { type: "Aborted" };
38785
+ }
38721
38786
  const resp = await this.#handleResponse(response);
38722
38787
  if (resp.type === "exit") {
38723
38788
  this.#callback({ kind: "EndTask" /* EndTask */, agent: this, exitReason: resp.reason });
@@ -38764,14 +38829,23 @@ ${instance.prompt}`;
38764
38829
  }
38765
38830
  }
38766
38831
  } catch (error) {
38832
+ if (error instanceof Error && error.name === "AbortError") {
38833
+ break;
38834
+ }
38767
38835
  console.error("Error in stream:", error);
38768
38836
  }
38769
38837
  if (currentAssistantMessage) {
38770
38838
  break;
38771
38839
  }
38840
+ if (this.#aborted) {
38841
+ break;
38842
+ }
38772
38843
  console.debug(`Retrying request ${i2 + 1} of ${retryCount}`);
38773
38844
  }
38774
38845
  if (!currentAssistantMessage) {
38846
+ if (this.#aborted) {
38847
+ return [];
38848
+ }
38775
38849
  throw new Error("No assistant message received");
38776
38850
  }
38777
38851
  this.#messages.push({
@@ -38800,23 +38874,26 @@ ${instance.prompt}`;
38800
38874
  await this.#callback({ kind: "ToolUse" /* ToolUse */, agent: this, tool: content.name });
38801
38875
  const toolResp = await this.#invokeTool(content.name, content.params);
38802
38876
  switch (toolResp.type) {
38803
- case "Reply" /* Reply */:
38877
+ case "Reply" /* Reply */: {
38804
38878
  await this.#callback({ kind: "ToolReply" /* ToolReply */, agent: this, tool: content.name });
38805
38879
  toolResponses.push({ type: "response", tool: content.name, response: toolResp.message });
38806
38880
  break;
38881
+ }
38807
38882
  case "Exit" /* Exit */:
38808
38883
  if (toolResponses.length > 0) {
38809
38884
  break outer;
38810
38885
  }
38811
38886
  return { type: "exit", reason: toolResp };
38812
- case "Invalid" /* Invalid */:
38887
+ case "Invalid" /* Invalid */: {
38813
38888
  await this.#callback({ kind: "ToolInvalid" /* ToolInvalid */, agent: this, tool: content.name });
38814
38889
  toolResponses.push({ type: "response", tool: content.name, response: toolResp.message });
38815
38890
  break outer;
38816
- case "Error" /* Error */:
38891
+ }
38892
+ case "Error" /* Error */: {
38817
38893
  await this.#callback({ kind: "ToolError" /* ToolError */, agent: this, tool: content.name });
38818
38894
  toolResponses.push({ type: "response", tool: content.name, response: toolResp.message });
38819
38895
  break outer;
38896
+ }
38820
38897
  case "Interrupted" /* Interrupted */:
38821
38898
  await this.#callback({ kind: "ToolInterrupted" /* ToolInterrupted */, agent: this, tool: content.name });
38822
38899
  return { type: "exit", reason: toolResp };
@@ -38866,9 +38943,7 @@ ${instance.prompt}`;
38866
38943
  if (toolResponses.length === 0) {
38867
38944
  return { type: "reply", message: responsePrompts.requireUseTool };
38868
38945
  }
38869
- const finalResp = toolResponses.filter((resp) => resp.type === "response").map(({ tool, response: response2 }) => responsePrompts.toolResults(tool, response2)).join(`
38870
-
38871
- `);
38946
+ const finalResp = toolResponses.filter((resp) => resp.type === "response").flatMap(({ tool, response: response2 }) => responsePrompts.toolResults(tool, response2));
38872
38947
  return { type: "reply", message: finalResp };
38873
38948
  }
38874
38949
  async#invokeTool(name, args) {
@@ -39091,6 +39166,7 @@ class MultiAgent {
39091
39166
  case "Delegate" /* Delegate */:
39092
39167
  console.warn("Unexpected exit reason", delegateResult);
39093
39168
  break;
39169
+ case "Aborted":
39094
39170
  case "Interrupted" /* Interrupted */:
39095
39171
  return delegateResult;
39096
39172
  case "Exit" /* Exit */:
@@ -39098,6 +39174,7 @@ class MultiAgent {
39098
39174
  }
39099
39175
  return delegateResult;
39100
39176
  }
39177
+ case "Aborted":
39101
39178
  case "Interrupted" /* Interrupted */:
39102
39179
  case "Exit" /* Exit */:
39103
39180
  this.#agents.pop();
@@ -39130,6 +39207,11 @@ class MultiAgent {
39130
39207
  get hasActiveAgent() {
39131
39208
  return this.#agents.length > 0;
39132
39209
  }
39210
+ abort() {
39211
+ if (this.hasActiveAgent) {
39212
+ this.#agents[this.#agents.length - 1].abort();
39213
+ }
39214
+ }
39133
39215
  }
39134
39216
  // ../core/node_modules/zod/lib/index.mjs
39135
39217
  var util;
@@ -49576,11 +49658,13 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
49576
49658
  var source_default = chalk;
49577
49659
 
49578
49660
  // src/utils/eventHandler.ts
49661
+ var toolCallStats = new Map;
49579
49662
  var printEvent = (verbose, usageMeter) => {
49580
49663
  let hadReasoning = false;
49581
49664
  return (event) => {
49582
49665
  switch (event.kind) {
49583
49666
  case "StartTask" /* StartTask */:
49667
+ toolCallStats.clear();
49584
49668
  if (verbose > 1) {
49585
49669
  console.log(`
49586
49670
  ====== System Prompt ======
@@ -49597,7 +49681,28 @@ ${event.systemPrompt}`);
49597
49681
  ======== New Request ========
49598
49682
  `);
49599
49683
  if (verbose) {
49600
- console.log(event.userMessage);
49684
+ const { userMessage } = event;
49685
+ if (typeof userMessage === "string") {
49686
+ console.log(userMessage);
49687
+ } else {
49688
+ for (const content of userMessage) {
49689
+ if (content.type === "text") {
49690
+ console.log(content.text);
49691
+ } else if (content.type === "image") {
49692
+ if (content.source.type === "base64") {
49693
+ console.log(source_default.yellow(`[Image content: ${content.source.media_type}]`));
49694
+ } else if (content.source.type === "url") {
49695
+ console.log(source_default.yellow(`[Image content from URL: ${content.source.url}]`));
49696
+ } else {
49697
+ console.log(source_default.red("[Unknown image source type]"));
49698
+ console.log(content.source);
49699
+ }
49700
+ } else {
49701
+ console.log(source_default.red("[Unknown content type]"));
49702
+ console.log(content);
49703
+ }
49704
+ }
49705
+ }
49601
49706
  console.log(`
49602
49707
 
49603
49708
  ======== Request Message Ended ========
@@ -49629,12 +49734,27 @@ ${event.systemPrompt}`);
49629
49734
  hadReasoning = true;
49630
49735
  break;
49631
49736
  case "ToolUse" /* ToolUse */:
49737
+ {
49738
+ const stats = toolCallStats.get(event.tool) ?? { calls: 0, success: 0, errors: 0 };
49739
+ stats.calls++;
49740
+ toolCallStats.set(event.tool, stats);
49741
+ }
49632
49742
  break;
49633
49743
  case "ToolReply" /* ToolReply */:
49744
+ {
49745
+ const stats = toolCallStats.get(event.tool) ?? { calls: 0, success: 0, errors: 0 };
49746
+ stats.success++;
49747
+ toolCallStats.set(event.tool, stats);
49748
+ }
49634
49749
  break;
49635
49750
  case "ToolInvalid" /* ToolInvalid */:
49636
49751
  break;
49637
49752
  case "ToolError" /* ToolError */:
49753
+ {
49754
+ const stats = toolCallStats.get(event.tool) ?? { calls: 0, success: 0, errors: 0 };
49755
+ stats.errors++;
49756
+ toolCallStats.set(event.tool, stats);
49757
+ }
49638
49758
  break;
49639
49759
  case "ToolInterrupted" /* ToolInterrupted */:
49640
49760
  break;
@@ -49680,6 +49800,24 @@ ${event.systemPrompt}`);
49680
49800
  console.log("Interrupted Message:", event.exitReason.message);
49681
49801
  break;
49682
49802
  }
49803
+ console.log(`
49804
+
49805
+ ======== Tool Call Stats ========`);
49806
+ if (toolCallStats.size > 0) {
49807
+ const tableData = [...toolCallStats.entries()].map(([tool2, stats]) => {
49808
+ const successRate = stats.calls > 0 ? stats.success / stats.calls * 100 : 0;
49809
+ return {
49810
+ "Tool Name": tool2,
49811
+ Calls: stats.calls,
49812
+ Success: stats.success,
49813
+ Errors: stats.errors,
49814
+ "Success Rate": `${successRate.toFixed(2)}%`
49815
+ };
49816
+ });
49817
+ console.table(tableData);
49818
+ } else {
49819
+ console.log("No tools were called.");
49820
+ }
49683
49821
  break;
49684
49822
  }
49685
49823
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polka-codes/cli-shared",
3
- "version": "0.8.23",
3
+ "version": "0.8.25",
4
4
  "license": "AGPL-3.0",
5
5
  "author": "github@polka.codes",
6
6
  "type": "module",