@ai-sdk/harness-cline 1.0.27 → 1.0.29

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/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // src/cline-harness.ts
2
2
  import {
3
- commonTool
3
+ commonTool,
4
+ HARNESS_V1_BUILTIN_TOOLS
4
5
  } from "@ai-sdk/harness";
5
6
  import { isHarnessAuthenticationEnvironment as isHarnessAuthenticationEnvironment2 } from "@ai-sdk/harness/utils";
6
7
  import { tool } from "@ai-sdk/provider-utils";
@@ -623,6 +624,7 @@ ${description}${skill.content}${files}
623
624
  import {
624
625
  createTool
625
626
  } from "@cline/agents";
627
+ import { createDefaultTools as createDefaultTools2 } from "@cline/core";
626
628
 
627
629
  // src/cline-utils.ts
628
630
  import {
@@ -725,6 +727,7 @@ function usageFromMessageMetrics(metrics) {
725
727
 
726
728
  // src/cline-tools.ts
727
729
  var CLINE_NATIVE_BUILTIN_NAMES = [
730
+ "ask_question",
728
731
  "read",
729
732
  "write",
730
733
  "edit",
@@ -735,6 +738,7 @@ var CLINE_NATIVE_BUILTIN_NAMES = [
735
738
  "skills"
736
739
  ];
737
740
  var CLINE_NATIVE_TOOL_KINDS = {
741
+ ask_question: "readonly",
738
742
  read: "readonly",
739
743
  write: "edit",
740
744
  edit: "edit",
@@ -749,15 +753,21 @@ function isClineBuiltinToolName(name) {
749
753
  }
750
754
  function resolveActiveClineBuiltinNames(toolFiltering) {
751
755
  if (toolFiltering == null) return CLINE_NATIVE_BUILTIN_NAMES;
756
+ const filteredNames = toolFiltering.toolNames.map(
757
+ (name) => name === "askUserQuestions" ? "ask_question" : name
758
+ );
752
759
  if (toolFiltering.mode === "allow") {
753
760
  return CLINE_NATIVE_BUILTIN_NAMES.filter(
754
- (name) => toolFiltering.toolNames.includes(name)
761
+ (name) => filteredNames.includes(name)
755
762
  );
756
763
  }
757
764
  return CLINE_NATIVE_BUILTIN_NAMES.filter(
758
- (name) => !toolFiltering.toolNames.includes(name)
765
+ (name) => !filteredNames.includes(name)
759
766
  );
760
767
  }
768
+ function clineQuestionKey(input) {
769
+ return JSON.stringify([input.question, input.options]);
770
+ }
761
771
  var clineToolResultMarker = /* @__PURE__ */ Symbol("cline-tool-result");
762
772
  function createClineToolResult({
763
773
  output,
@@ -791,9 +801,45 @@ async function guarded(run) {
791
801
  }
792
802
  function buildBuiltinAgentTools({
793
803
  ops,
794
- activeNames
804
+ activeNames,
805
+ pendingQuestions = /* @__PURE__ */ new Map(),
806
+ pendingQuestionResults = /* @__PURE__ */ new Map()
795
807
  }) {
796
808
  const tools = {
809
+ ask_question: createDefaultTools2({
810
+ executors: {
811
+ askQuestion: async (question, options, context) => {
812
+ if (context.toolCallId == null) {
813
+ throw new Error(
814
+ "Cline ask_question did not provide a tool call id."
815
+ );
816
+ }
817
+ const questionKey = clineQuestionKey({ question, options });
818
+ const pendingResult = pendingQuestionResults.get(questionKey);
819
+ if (pendingResult != null) {
820
+ pendingQuestionResults.delete(questionKey);
821
+ return toClineQuestionResult({
822
+ nativeInput: { question, options },
823
+ output: pendingResult.output
824
+ });
825
+ }
826
+ return new Promise((resolve) => {
827
+ pendingQuestions.set(context.toolCallId, {
828
+ input: { question, options },
829
+ resolve
830
+ });
831
+ });
832
+ }
833
+ },
834
+ enableReadFiles: false,
835
+ enableSearch: false,
836
+ enableBash: false,
837
+ enableWebFetch: false,
838
+ enableApplyPatch: false,
839
+ enableEditor: false,
840
+ enableSkills: false,
841
+ enableAskQuestion: true
842
+ }).find((tool2) => tool2.name === "ask_question"),
797
843
  read: createTool({
798
844
  name: "read",
799
845
  description: "Read file contents.",
@@ -948,6 +994,19 @@ function buildBuiltinAgentTools({
948
994
  };
949
995
  return activeNames.map((name) => tools[name]).filter((tool2) => tool2 != null);
950
996
  }
997
+ function toClineQuestionResult(input) {
998
+ if (input.output.action === "declined" || input.output.action === "cancelled") {
999
+ return `The user ${input.output.action} the question.`;
1000
+ }
1001
+ const answer = input.output.answers["question-1"];
1002
+ if (answer == null) return "The user did not answer the question.";
1003
+ if (answer.freeform != null) return answer.freeform;
1004
+ const result = answer.optionIds.map((id) => {
1005
+ const index = Number(id.replace(/^option-/, "")) - 1;
1006
+ return input.nativeInput.options[index];
1007
+ }).filter((value) => value != null).join(", ");
1008
+ return result;
1009
+ }
951
1010
  function buildUserAgentTools({
952
1011
  specs,
953
1012
  pendingToolResults
@@ -1027,6 +1086,35 @@ function toolCallPart(state, toolCall) {
1027
1086
  if (isMcpTool) {
1028
1087
  state.dynamicToolCallIds.add(toolCall.toolCallId);
1029
1088
  }
1089
+ if (toolCall.toolName === "ask_question") {
1090
+ const nativeInput = toolCall.input;
1091
+ return {
1092
+ type: "tool-call",
1093
+ toolCallId: toolCall.toolCallId,
1094
+ toolName: "askUserQuestions",
1095
+ input: JSON.stringify({
1096
+ allowPartialAnswers: false,
1097
+ questions: [
1098
+ {
1099
+ id: "question-1",
1100
+ question: nativeInput.question,
1101
+ options: nativeInput.options.map((label, index) => ({
1102
+ id: `option-${index + 1}`,
1103
+ label
1104
+ })),
1105
+ allowFreeForm: true
1106
+ }
1107
+ ]
1108
+ }),
1109
+ providerExecuted: false,
1110
+ providerMetadata: {
1111
+ cline: {
1112
+ nativeRequest: nativeInput
1113
+ }
1114
+ },
1115
+ nativeName: "ask_question"
1116
+ };
1117
+ }
1030
1118
  return {
1031
1119
  type: "tool-call",
1032
1120
  toolCallId: toolCall.toolCallId,
@@ -1128,7 +1216,7 @@ function translateClineEvent(event, state) {
1128
1216
  {
1129
1217
  type: "tool-result",
1130
1218
  toolCallId: event.toolCall.toolCallId,
1131
- toolName: event.toolCall.toolName,
1219
+ toolName: event.toolCall.toolName === "ask_question" ? "askUserQuestions" : event.toolCall.toolName,
1132
1220
  result: toToolResultValue(output),
1133
1221
  ...resultPart?.isError ? { isError: true } : {},
1134
1222
  ...dynamic ? { dynamic: true } : {}
@@ -1215,9 +1303,13 @@ function createClineAgentModel({
1215
1303
  const baseUrl = isAiGateway ? toAiGatewayProviderBaseUrl(gatewayBaseUrl) : settings.baseUrl ?? (providerId === "cline" && settings.authEnv.CLINE_API_BASE_URL ? toClineBackendProviderBaseUrl(settings.authEnv.CLINE_API_BASE_URL) : void 0);
1216
1304
  const headers = isAiGateway ? {
1217
1305
  ...settings.headers,
1306
+ ...settings.agentHeaders,
1218
1307
  "User-Agent": clientApp,
1219
1308
  "x-client-app": clientApp
1220
- } : settings.headers;
1309
+ } : settings.headers != null || settings.agentHeaders != null ? {
1310
+ ...settings.headers,
1311
+ ...settings.agentHeaders
1312
+ } : void 0;
1221
1313
  const gateway = Llms.createGateway({
1222
1314
  providerConfigs: [
1223
1315
  {
@@ -1309,6 +1401,8 @@ async function createClineSession(input) {
1309
1401
  let acceptingUserMessages = false;
1310
1402
  let currentEmit;
1311
1403
  let translatorState;
1404
+ const pendingQuestions = /* @__PURE__ */ new Map();
1405
+ const pendingQuestionResults = /* @__PURE__ */ new Map();
1312
1406
  let activeTurn;
1313
1407
  function settlePendingToolResults(reason) {
1314
1408
  for (const pending of pendingToolResults.values()) {
@@ -1339,6 +1433,13 @@ async function createClineSession(input) {
1339
1433
  }
1340
1434
  pendingUserMessages.length = 0;
1341
1435
  }
1436
+ function settlePendingQuestions(reason) {
1437
+ for (const pending of pendingQuestions.values()) {
1438
+ pending.resolve(reason);
1439
+ }
1440
+ pendingQuestions.clear();
1441
+ pendingQuestionResults.clear();
1442
+ }
1342
1443
  async function persistHistory() {
1343
1444
  const messages = agent?.snapshot().messages ?? currentMessages;
1344
1445
  await persistHistoryToSandbox({
@@ -1383,7 +1484,12 @@ ${rebuildInput.instructions}` : baseSystemPrompt;
1383
1484
  toolExecution: "parallel",
1384
1485
  ...input.settings.maxIterations !== void 0 ? { maxIterations: input.settings.maxIterations } : {},
1385
1486
  tools: [
1386
- ...buildBuiltinAgentTools({ ops, activeNames: activeBuiltinNames }),
1487
+ ...buildBuiltinAgentTools({
1488
+ ops,
1489
+ activeNames: activeBuiltinNames,
1490
+ pendingQuestions,
1491
+ pendingQuestionResults
1492
+ }),
1387
1493
  ...rebuildInput.skillsRuntime.tool && activeBuiltinNames.includes("skills") ? [rebuildInput.skillsRuntime.tool] : [],
1388
1494
  ...mcpRuntime.tools,
1389
1495
  ...buildUserAgentTools({
@@ -1452,6 +1558,7 @@ ${rebuildInput.instructions}` : baseSystemPrompt;
1452
1558
  const abortHandler = () => {
1453
1559
  settlePendingToolResults("Turn aborted");
1454
1560
  settlePendingToolApprovals("Turn aborted");
1561
+ settlePendingQuestions("The question was cancelled.");
1455
1562
  agent?.abort("Turn aborted by caller");
1456
1563
  };
1457
1564
  if (controlInput.abortSignal) {
@@ -1469,6 +1576,25 @@ ${rebuildInput.instructions}` : baseSystemPrompt;
1469
1576
  }
1470
1577
  return {
1471
1578
  async submitToolResult(args) {
1579
+ const pendingQuestion = pendingQuestions.get(args.toolCallId);
1580
+ if (pendingQuestion != null) {
1581
+ pendingQuestions.delete(args.toolCallId);
1582
+ pendingQuestion.resolve(
1583
+ toClineQuestionResult({
1584
+ nativeInput: pendingQuestion.input,
1585
+ output: args.output
1586
+ })
1587
+ );
1588
+ return;
1589
+ }
1590
+ if (args.toolResult?.toolName === "askUserQuestions") {
1591
+ const nativeRequest = args.toolResult.providerOptions?.cline?.nativeRequest;
1592
+ if (nativeRequest == null) return;
1593
+ pendingQuestionResults.set(clineQuestionKey(nativeRequest), {
1594
+ output: args.output
1595
+ });
1596
+ return;
1597
+ }
1472
1598
  const pending = pendingToolResults.get(args.toolCallId);
1473
1599
  if (!pending) return;
1474
1600
  pendingToolResults.delete(args.toolCallId);
@@ -1668,6 +1794,7 @@ ${rebuildInput.instructions}` : baseSystemPrompt;
1668
1794
  parkedClineSessions.delete(input.sessionId);
1669
1795
  settlePendingToolResults("Cline session stopped");
1670
1796
  settlePendingToolApprovals("Cline session stopped");
1797
+ settlePendingQuestions("The question was cancelled.");
1671
1798
  try {
1672
1799
  await persistHistory();
1673
1800
  } catch {
@@ -1735,7 +1862,7 @@ ${rebuildInput.instructions}` : baseSystemPrompt;
1735
1862
  },
1736
1863
  doStop,
1737
1864
  doDetach: async () => {
1738
- if (activeTurn != null || pendingToolResults.size > 0) {
1865
+ if (activeTurn != null || pendingToolResults.size > 0 || pendingQuestions.size > 0) {
1739
1866
  parkedClineSessions.set(input.sessionId, sessionImpl);
1740
1867
  try {
1741
1868
  await persistHistory();
@@ -1754,7 +1881,7 @@ ${rebuildInput.instructions}` : baseSystemPrompt;
1754
1881
  if (stopped) {
1755
1882
  throw new Error("Cline session has been stopped.");
1756
1883
  }
1757
- if (activeTurn != null && (pendingToolResults.size > 0 || pendingToolApprovals.size > 0)) {
1884
+ if (activeTurn != null && (pendingToolResults.size > 0 || pendingToolApprovals.size > 0 || pendingQuestions.size > 0)) {
1758
1885
  parkedClineSessions.set(input.sessionId, sessionImpl);
1759
1886
  try {
1760
1887
  await persistHistory();
@@ -1794,11 +1921,16 @@ ${rebuildInput.instructions}` : baseSystemPrompt;
1794
1921
  }
1795
1922
 
1796
1923
  // src/version.ts
1797
- var VERSION = true ? "1.0.27" : "0.0.0-test";
1924
+ var VERSION = true ? "1.0.29" : "0.0.0-test";
1798
1925
 
1799
1926
  // src/cline-harness.ts
1800
1927
  var CLINE_CLIENT_APP = `ai-sdk/harness-cline/${VERSION}`;
1801
1928
  var CLINE_BUILTIN_TOOLS = {
1929
+ askUserQuestions: {
1930
+ ...HARNESS_V1_BUILTIN_TOOLS.askUserQuestions,
1931
+ nativeName: "ask_question",
1932
+ toolUseKind: "readonly"
1933
+ },
1802
1934
  read: commonTool("read", {
1803
1935
  nativeName: "read",
1804
1936
  toolUseKind: "readonly",
@@ -1909,6 +2041,7 @@ function createCline(settings = {}) {
1909
2041
  ...settings.apiKey ? { apiKey: settings.apiKey } : {},
1910
2042
  ...settings.baseUrl ? { baseUrl: settings.baseUrl } : {},
1911
2043
  ...settings.headers ? { headers: settings.headers } : {},
2044
+ ...startOpts.headers ? { agentHeaders: startOpts.headers } : {},
1912
2045
  ...settings.reasoningEffort !== void 0 ? { reasoningEffort: settings.reasoningEffort } : {},
1913
2046
  ...settings.maxIterations !== void 0 ? { maxIterations: settings.maxIterations } : {}
1914
2047
  },