@ai-sdk/harness-cline 1.0.19 → 1.0.21
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/CHANGELOG.md +28 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +193 -98
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/cline-harness.ts +15 -2
- package/src/cline-remote-ops.ts +5 -29
- package/src/cline-session.ts +65 -52
- package/src/cline-skills.ts +173 -48
- package/src/cline-tools.ts +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @ai-sdk/harness-cline
|
|
2
2
|
|
|
3
|
+
## 1.0.21
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8961fde: feat(harness): allow changing `model` between turns via call options
|
|
8
|
+
- Updated dependencies [8961fde]
|
|
9
|
+
- Updated dependencies [eb59f2a]
|
|
10
|
+
- Updated dependencies [aa45741]
|
|
11
|
+
- @ai-sdk/harness@1.0.94
|
|
12
|
+
- @ai-sdk/provider@4.0.9
|
|
13
|
+
- @ai-sdk/provider-utils@5.0.34
|
|
14
|
+
|
|
15
|
+
## 1.0.20
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 7608210: feat(harness): add `model` parameter to `HarnessAgent` instead of having each harness adapter support it on their own constructor functions
|
|
20
|
+
- f7bd978: chore(harness): update underlying adapter SDKs to their latest versions
|
|
21
|
+
- 14d4fc0: feat(harness): allow changing harness settings between turns via `prepareCall()` support on `HarnessAgent`
|
|
22
|
+
- 5021768: fix(harness-cline): use native `skills` tool instead of manual file-based workaround
|
|
23
|
+
- Updated dependencies [cc9f6ce]
|
|
24
|
+
- Updated dependencies [7608210]
|
|
25
|
+
- Updated dependencies [6f8a2d7]
|
|
26
|
+
- Updated dependencies [14d4fc0]
|
|
27
|
+
- Updated dependencies [90192f1]
|
|
28
|
+
- @ai-sdk/harness@1.0.93
|
|
29
|
+
- @ai-sdk/provider-utils@5.0.33
|
|
30
|
+
|
|
3
31
|
## 1.0.19
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ type ClineHarnessSettings = {
|
|
|
26
26
|
/**
|
|
27
27
|
* Model id for the configured provider. When omitted, Cline selects the
|
|
28
28
|
* provider's default model.
|
|
29
|
+
*
|
|
30
|
+
* @deprecated Use `model` on `HarnessAgent` instead.
|
|
29
31
|
*/
|
|
30
32
|
readonly modelId?: string;
|
|
31
33
|
/**
|
|
@@ -80,6 +82,7 @@ declare const CLINE_BUILTIN_TOOLS: {
|
|
|
80
82
|
limit?: number | undefined;
|
|
81
83
|
}, unknown>;
|
|
82
84
|
readonly ls: HarnessV1BuiltinTool;
|
|
85
|
+
readonly skills: HarnessV1BuiltinTool;
|
|
83
86
|
};
|
|
84
87
|
declare function createCline(settings?: ClineHarnessSettings): HarnessV1<typeof CLINE_BUILTIN_TOOLS>;
|
|
85
88
|
|
|
@@ -122,6 +125,7 @@ declare const cline: _ai_sdk_harness.HarnessV1<{
|
|
|
122
125
|
limit?: number | undefined;
|
|
123
126
|
}, unknown>;
|
|
124
127
|
readonly ls: _ai_sdk_harness.HarnessV1BuiltinTool;
|
|
128
|
+
readonly skills: _ai_sdk_harness.HarnessV1BuiltinTool;
|
|
125
129
|
}>;
|
|
126
130
|
|
|
127
131
|
export { type ClineAuthenticationMode, type ClineHarnessSettings, VERSION, cline, createCline };
|
package/dist/index.js
CHANGED
|
@@ -241,7 +241,6 @@ import { shellQuote } from "@ai-sdk/harness/utils";
|
|
|
241
241
|
function createClineRemoteOps(options) {
|
|
242
242
|
const { sandbox, workDir } = options;
|
|
243
243
|
const normalizedWorkDir = path2.posix.normalize(workDir);
|
|
244
|
-
const readableRoots = options.readableRoots?.map((root) => path2.posix.normalize(root.sandboxDir)) ?? [];
|
|
245
244
|
const isInsidePath = ({
|
|
246
245
|
parent,
|
|
247
246
|
candidate
|
|
@@ -256,25 +255,10 @@ function createClineRemoteOps(options) {
|
|
|
256
255
|
}
|
|
257
256
|
return normalized;
|
|
258
257
|
};
|
|
259
|
-
const assertReadablePath = (inputPath) => {
|
|
260
|
-
const normalized = path2.posix.normalize(inputPath);
|
|
261
|
-
if (!isInsidePath({ parent: normalizedWorkDir, candidate: normalized }) && !readableRoots.some(
|
|
262
|
-
(parent) => isInsidePath({ parent, candidate: normalized })
|
|
263
|
-
)) {
|
|
264
|
-
throw new Error(`Cline path escapes the readable roots: ${inputPath}`);
|
|
265
|
-
}
|
|
266
|
-
return normalized;
|
|
267
|
-
};
|
|
268
258
|
const resolvePath = (inputPath) => {
|
|
269
259
|
const resolved = path2.posix.isAbsolute(inputPath) ? path2.posix.normalize(inputPath) : path2.posix.normalize(path2.posix.join(normalizedWorkDir, inputPath));
|
|
270
260
|
return assertWorkspacePath(resolved);
|
|
271
261
|
};
|
|
272
|
-
const resolveReadablePath = (inputPath) => {
|
|
273
|
-
if (!path2.posix.isAbsolute(inputPath)) {
|
|
274
|
-
return resolvePath(inputPath);
|
|
275
|
-
}
|
|
276
|
-
return assertReadablePath(inputPath);
|
|
277
|
-
};
|
|
278
262
|
const runShell = async ({
|
|
279
263
|
command,
|
|
280
264
|
signal
|
|
@@ -319,7 +303,7 @@ function createClineRemoteOps(options) {
|
|
|
319
303
|
remotePath,
|
|
320
304
|
inputPath,
|
|
321
305
|
missingMessage
|
|
322
|
-
}) =>
|
|
306
|
+
}) => assertWorkspacePath(
|
|
323
307
|
await resolveExistingSandboxPath({
|
|
324
308
|
remotePath,
|
|
325
309
|
inputPath,
|
|
@@ -352,7 +336,7 @@ function createClineRemoteOps(options) {
|
|
|
352
336
|
return assertWorkspacePath(resolvedPath);
|
|
353
337
|
};
|
|
354
338
|
const readFile = async (inputPath) => {
|
|
355
|
-
const remotePath =
|
|
339
|
+
const remotePath = resolvePath(inputPath);
|
|
356
340
|
const resolved = await resolveReadableSandboxPath({
|
|
357
341
|
remotePath,
|
|
358
342
|
inputPath,
|
|
@@ -420,7 +404,7 @@ function createClineRemoteOps(options) {
|
|
|
420
404
|
},
|
|
421
405
|
async grep(pattern, input = {}) {
|
|
422
406
|
const inputPath = input.path ?? ".";
|
|
423
|
-
const remotePath =
|
|
407
|
+
const remotePath = resolvePath(inputPath);
|
|
424
408
|
const target = await resolveReadableSandboxPath({
|
|
425
409
|
remotePath,
|
|
426
410
|
inputPath
|
|
@@ -452,7 +436,7 @@ function createClineRemoteOps(options) {
|
|
|
452
436
|
return output || "No matches found";
|
|
453
437
|
},
|
|
454
438
|
async glob(pattern, inputPath = ".", limit = 1e3) {
|
|
455
|
-
const remotePath =
|
|
439
|
+
const remotePath = resolvePath(inputPath);
|
|
456
440
|
const target = await resolveReadableSandboxPath({
|
|
457
441
|
remotePath,
|
|
458
442
|
inputPath
|
|
@@ -483,7 +467,7 @@ function createClineRemoteOps(options) {
|
|
|
483
467
|
).slice(0, limit);
|
|
484
468
|
},
|
|
485
469
|
async ls(inputPath = ".", limit = 500) {
|
|
486
|
-
const remotePath =
|
|
470
|
+
const remotePath = resolvePath(inputPath);
|
|
487
471
|
const target = await resolveReadableSandboxPath({
|
|
488
472
|
remotePath,
|
|
489
473
|
inputPath
|
|
@@ -516,33 +500,123 @@ function createClineRemoteOps(options) {
|
|
|
516
500
|
|
|
517
501
|
// src/cline-skills.ts
|
|
518
502
|
import path3 from "path";
|
|
519
|
-
import {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
skills,
|
|
524
|
-
abortSignal
|
|
503
|
+
import { createDefaultTools } from "@cline/core";
|
|
504
|
+
var CLINE_SKILL_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;
|
|
505
|
+
function createClineSkillsRuntime({
|
|
506
|
+
skills
|
|
525
507
|
}) {
|
|
526
|
-
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
508
|
+
const projectedSkills = projectClineSkills({ skills });
|
|
509
|
+
const signature = JSON.stringify(projectedSkills);
|
|
510
|
+
if (projectedSkills.length === 0) {
|
|
511
|
+
return { signature };
|
|
512
|
+
}
|
|
513
|
+
const executor = async (...executorArguments) => {
|
|
514
|
+
const [requestedSkill, args] = executorArguments;
|
|
515
|
+
const skill = projectedSkills.find(
|
|
516
|
+
(candidate) => candidate.id === normalizeSkillToken(requestedSkill)
|
|
517
|
+
);
|
|
518
|
+
if (skill == null) {
|
|
519
|
+
const availableSkills = projectedSkills.map((skill2) => skill2.name);
|
|
520
|
+
return availableSkills.length > 0 ? `Skill "${requestedSkill}" not found. Available skills: ${availableSkills.join(", ")}` : "No skills are currently available.";
|
|
521
|
+
}
|
|
522
|
+
return renderSkillInstructions({ skill, args });
|
|
523
|
+
};
|
|
524
|
+
executor.configuredSkills = projectedSkills.map((skill) => ({
|
|
525
|
+
id: skill.id,
|
|
526
|
+
name: skill.name,
|
|
527
|
+
description: skill.description,
|
|
528
|
+
disabled: false
|
|
529
|
+
}));
|
|
530
|
+
const tool2 = createDefaultTools({
|
|
531
|
+
executors: { skills: executor },
|
|
532
|
+
enableReadFiles: false,
|
|
533
|
+
enableSearch: false,
|
|
534
|
+
enableBash: false,
|
|
535
|
+
enableWebFetch: false,
|
|
536
|
+
enableApplyPatch: false,
|
|
537
|
+
enableEditor: false,
|
|
538
|
+
enableSkills: true,
|
|
539
|
+
enableAskQuestion: false,
|
|
540
|
+
enableSubmitAndExit: false
|
|
541
|
+
}).find((tool3) => tool3.name === "skills");
|
|
542
|
+
if (tool2 == null) {
|
|
543
|
+
throw new Error("Cline did not create its native skills tool.");
|
|
544
|
+
}
|
|
545
|
+
return { signature, tool: tool2 };
|
|
546
|
+
}
|
|
547
|
+
function projectClineSkills({
|
|
548
|
+
skills
|
|
549
|
+
}) {
|
|
550
|
+
const names = /* @__PURE__ */ new Set();
|
|
551
|
+
const ids = /* @__PURE__ */ new Set();
|
|
552
|
+
return skills.map((skill) => {
|
|
553
|
+
if (!CLINE_SKILL_NAME_PATTERN.test(skill.name) || skill.name === "." || skill.name === "..") {
|
|
554
|
+
throw new Error(`Invalid Cline skill name: ${skill.name}`);
|
|
555
|
+
}
|
|
556
|
+
if (names.has(skill.name)) {
|
|
557
|
+
throw new Error(`Duplicate Cline skill name: ${skill.name}`);
|
|
558
|
+
}
|
|
559
|
+
names.add(skill.name);
|
|
560
|
+
const id = normalizeSkillToken(skill.name);
|
|
561
|
+
if (ids.has(id)) {
|
|
562
|
+
throw new Error(`Duplicate Cline skill identifier: ${id}`);
|
|
563
|
+
}
|
|
564
|
+
ids.add(id);
|
|
565
|
+
return {
|
|
566
|
+
id,
|
|
567
|
+
name: skill.name,
|
|
568
|
+
description: skill.description,
|
|
569
|
+
content: skill.content,
|
|
570
|
+
files: (skill.files ?? []).map((file) => ({
|
|
571
|
+
path: normalizeSkillFilePath({
|
|
572
|
+
skillName: skill.name,
|
|
573
|
+
filePath: file.path
|
|
574
|
+
}),
|
|
575
|
+
content: file.content
|
|
576
|
+
})).sort(
|
|
577
|
+
(left, right) => left.path.localeCompare(right.path) || left.content.localeCompare(right.content)
|
|
578
|
+
)
|
|
579
|
+
};
|
|
580
|
+
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
581
|
+
}
|
|
582
|
+
function normalizeSkillToken(skill) {
|
|
583
|
+
return skill.trim().replace(/^\/+/, "").toLowerCase();
|
|
584
|
+
}
|
|
585
|
+
function normalizeSkillFilePath({
|
|
586
|
+
skillName,
|
|
587
|
+
filePath
|
|
588
|
+
}) {
|
|
589
|
+
const normalized = path3.posix.normalize(filePath);
|
|
590
|
+
if (normalized === "" || normalized === "." || normalized.startsWith("../") || normalized.includes("/../") || normalized.endsWith("/..") || path3.posix.isAbsolute(normalized)) {
|
|
591
|
+
throw new Error(
|
|
592
|
+
`Invalid Cline skill file path for ${skillName}: ${filePath}`
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
return normalized;
|
|
535
596
|
}
|
|
536
|
-
function
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
597
|
+
function renderSkillInstructions({
|
|
598
|
+
skill,
|
|
599
|
+
args
|
|
600
|
+
}) {
|
|
601
|
+
const trimmedArgs = args?.trim();
|
|
602
|
+
const argsTag = trimmedArgs ? `
|
|
603
|
+
<command-args>${trimmedArgs}</command-args>` : "";
|
|
604
|
+
const description = skill.description.trim() ? `Description: ${skill.description.trim()}
|
|
605
|
+
|
|
606
|
+
` : "";
|
|
607
|
+
const files = skill.files.length === 0 ? "" : `
|
|
608
|
+
|
|
609
|
+
<skill-files>
|
|
610
|
+
${skill.files.map(
|
|
611
|
+
(file) => `<skill-file path=${JSON.stringify(file.path)}>
|
|
612
|
+
${file.content}
|
|
613
|
+
</skill-file>`
|
|
614
|
+
).join("\n")}
|
|
615
|
+
</skill-files>`;
|
|
616
|
+
return `<command-name>${skill.name}</command-name>${argsTag}
|
|
617
|
+
<command-instructions>
|
|
618
|
+
${description}${skill.content}${files}
|
|
619
|
+
</command-instructions>`;
|
|
546
620
|
}
|
|
547
621
|
|
|
548
622
|
// src/cline-tools.ts
|
|
@@ -657,7 +731,8 @@ var CLINE_NATIVE_BUILTIN_NAMES = [
|
|
|
657
731
|
"bash",
|
|
658
732
|
"grep",
|
|
659
733
|
"glob",
|
|
660
|
-
"ls"
|
|
734
|
+
"ls",
|
|
735
|
+
"skills"
|
|
661
736
|
];
|
|
662
737
|
var CLINE_NATIVE_TOOL_KINDS = {
|
|
663
738
|
read: "readonly",
|
|
@@ -666,7 +741,8 @@ var CLINE_NATIVE_TOOL_KINDS = {
|
|
|
666
741
|
bash: "bash",
|
|
667
742
|
grep: "readonly",
|
|
668
743
|
glob: "readonly",
|
|
669
|
-
ls: "readonly"
|
|
744
|
+
ls: "readonly",
|
|
745
|
+
skills: "readonly"
|
|
670
746
|
};
|
|
671
747
|
function isClineBuiltinToolName(name) {
|
|
672
748
|
return CLINE_NATIVE_BUILTIN_NAMES.includes(name);
|
|
@@ -1110,7 +1186,7 @@ function clineBuiltinToolRequiresApproval(input) {
|
|
|
1110
1186
|
return input.kind === "edit" || input.kind === "bash";
|
|
1111
1187
|
}
|
|
1112
1188
|
function buildSystemPrompt(input) {
|
|
1113
|
-
|
|
1189
|
+
return [
|
|
1114
1190
|
"You are Cline, an autonomous coding agent operating inside a sandboxed workspace.",
|
|
1115
1191
|
`## Workspace
|
|
1116
1192
|
|
|
@@ -1118,11 +1194,7 @@ The workspace root is \`${input.sessionWorkDir}\`. All relative file paths and s
|
|
|
1118
1194
|
`## Sandbox
|
|
1119
1195
|
|
|
1120
1196
|
${input.sandboxDescription}`
|
|
1121
|
-
];
|
|
1122
|
-
if (input.skillsSection) {
|
|
1123
|
-
sections.push(input.skillsSection);
|
|
1124
|
-
}
|
|
1125
|
-
return sections.join("\n\n");
|
|
1197
|
+
].join("\n\n");
|
|
1126
1198
|
}
|
|
1127
1199
|
function toClineBackendProviderBaseUrl(baseUrl) {
|
|
1128
1200
|
return `${baseUrl.replace(/\/+$/, "")}/api/v1`;
|
|
@@ -1133,7 +1205,8 @@ function toAiGatewayProviderBaseUrl(baseUrl) {
|
|
|
1133
1205
|
}
|
|
1134
1206
|
function createClineAgentModel({
|
|
1135
1207
|
settings,
|
|
1136
|
-
clientApp
|
|
1208
|
+
clientApp,
|
|
1209
|
+
modelId
|
|
1137
1210
|
}) {
|
|
1138
1211
|
const gatewayBaseUrl = settings.authEnv.AI_GATEWAY_BASE_URL;
|
|
1139
1212
|
const isAiGateway = gatewayBaseUrl != null;
|
|
@@ -1158,7 +1231,7 @@ function createClineAgentModel({
|
|
|
1158
1231
|
});
|
|
1159
1232
|
const modelSelection = {
|
|
1160
1233
|
providerId,
|
|
1161
|
-
...
|
|
1234
|
+
...modelId ? { modelId } : {}
|
|
1162
1235
|
};
|
|
1163
1236
|
const modelOptions = settings.reasoningEffort === "none" ? { reasoning: { enabled: false } } : {
|
|
1164
1237
|
reasoning: {
|
|
@@ -1199,28 +1272,9 @@ async function createClineSession(input) {
|
|
|
1199
1272
|
const activeBuiltinNames = resolveActiveClineBuiltinNames(
|
|
1200
1273
|
input.builtinToolFiltering
|
|
1201
1274
|
);
|
|
1202
|
-
let skillsSection;
|
|
1203
|
-
let skillRootDir;
|
|
1204
|
-
if (input.skills.length > 0) {
|
|
1205
|
-
skillRootDir = await writeClineSkills({
|
|
1206
|
-
sandbox: toolSafeSandboxSession,
|
|
1207
|
-
sandboxHomeDir,
|
|
1208
|
-
skills: input.skills,
|
|
1209
|
-
...input.abortSignal ? { abortSignal: input.abortSignal } : {}
|
|
1210
|
-
});
|
|
1211
|
-
if (skillRootDir) {
|
|
1212
|
-
skillsSection = renderSkillsPromptSection(input.skills, skillRootDir);
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
1275
|
const ops = createClineRemoteOps({
|
|
1216
1276
|
sandbox: toolSafeSandboxSession,
|
|
1217
|
-
workDir: input.sessionWorkDir
|
|
1218
|
-
...skillRootDir ? { readableRoots: [{ sandboxDir: skillRootDir }] } : {}
|
|
1219
|
-
});
|
|
1220
|
-
const baseSystemPrompt = buildSystemPrompt({
|
|
1221
|
-
sessionWorkDir: input.sessionWorkDir,
|
|
1222
|
-
sandboxDescription: toolSafeSandboxSession.description,
|
|
1223
|
-
...skillsSection ? { skillsSection } : {}
|
|
1277
|
+
workDir: input.sessionWorkDir
|
|
1224
1278
|
});
|
|
1225
1279
|
let currentMessages = [];
|
|
1226
1280
|
if (input.isResume && input.resumeHistoryFileName) {
|
|
@@ -1237,13 +1291,15 @@ async function createClineSession(input) {
|
|
|
1237
1291
|
const mcpRuntime = await createClineMcpRuntime({
|
|
1238
1292
|
mcpServers: input.settings.mcpServers
|
|
1239
1293
|
});
|
|
1240
|
-
|
|
1294
|
+
let activeModelId = input.settings.modelId;
|
|
1295
|
+
let agentModel = createClineAgentModel({
|
|
1241
1296
|
settings: input.settings,
|
|
1242
|
-
clientApp: input.clientApp
|
|
1297
|
+
clientApp: input.clientApp,
|
|
1298
|
+
modelId: activeModelId
|
|
1243
1299
|
});
|
|
1244
1300
|
let agent;
|
|
1245
1301
|
let unsubscribe;
|
|
1246
|
-
let
|
|
1302
|
+
let lastAgentConfigurationSignature;
|
|
1247
1303
|
let agentHasRun = false;
|
|
1248
1304
|
let stopped = false;
|
|
1249
1305
|
let suspending = false;
|
|
@@ -1306,22 +1362,29 @@ async function createClineSession(input) {
|
|
|
1306
1362
|
unsubscribe?.();
|
|
1307
1363
|
unsubscribe = void 0;
|
|
1308
1364
|
agent = new Agent({
|
|
1309
|
-
model,
|
|
1310
|
-
...
|
|
1365
|
+
model: agentModel.model,
|
|
1366
|
+
...activeModelId ? {
|
|
1311
1367
|
messageModelInfo: {
|
|
1312
|
-
id:
|
|
1313
|
-
provider: providerId
|
|
1368
|
+
id: activeModelId,
|
|
1369
|
+
provider: agentModel.providerId
|
|
1314
1370
|
}
|
|
1315
1371
|
} : {},
|
|
1316
1372
|
sessionId: input.sessionId,
|
|
1317
|
-
systemPrompt:
|
|
1373
|
+
systemPrompt: (() => {
|
|
1374
|
+
const baseSystemPrompt = buildSystemPrompt({
|
|
1375
|
+
sessionWorkDir: input.sessionWorkDir,
|
|
1376
|
+
sandboxDescription: toolSafeSandboxSession.description
|
|
1377
|
+
});
|
|
1378
|
+
return rebuildInput.instructions ? `${baseSystemPrompt}
|
|
1318
1379
|
|
|
1319
|
-
${rebuildInput.instructions}` : baseSystemPrompt
|
|
1380
|
+
${rebuildInput.instructions}` : baseSystemPrompt;
|
|
1381
|
+
})(),
|
|
1320
1382
|
initialMessages: currentMessages,
|
|
1321
1383
|
toolExecution: "parallel",
|
|
1322
1384
|
...input.settings.maxIterations !== void 0 ? { maxIterations: input.settings.maxIterations } : {},
|
|
1323
1385
|
tools: [
|
|
1324
1386
|
...buildBuiltinAgentTools({ ops, activeNames: activeBuiltinNames }),
|
|
1387
|
+
...rebuildInput.skillsRuntime.tool && activeBuiltinNames.includes("skills") ? [rebuildInput.skillsRuntime.tool] : [],
|
|
1325
1388
|
...mcpRuntime.tools,
|
|
1326
1389
|
...buildUserAgentTools({
|
|
1327
1390
|
specs: rebuildInput.userTools,
|
|
@@ -1438,46 +1501,64 @@ ${rebuildInput.instructions}` : baseSystemPrompt,
|
|
|
1438
1501
|
done: controlInput.done
|
|
1439
1502
|
};
|
|
1440
1503
|
}
|
|
1441
|
-
function runTurn(turnOpts) {
|
|
1504
|
+
async function runTurn(turnOpts) {
|
|
1442
1505
|
if (stopped) {
|
|
1443
1506
|
throw new Error("Cline session has been stopped.");
|
|
1444
1507
|
}
|
|
1445
1508
|
const userTools = turnOpts.tools;
|
|
1509
|
+
const skillsRuntime = createClineSkillsRuntime({
|
|
1510
|
+
skills: turnOpts.skills
|
|
1511
|
+
});
|
|
1446
1512
|
if (turnOpts.responseFormat?.type === "json" && turnOpts.responseFormat.schema == null) {
|
|
1447
1513
|
throw new HarnessCapabilityUnsupportedError2({
|
|
1448
1514
|
message: "Harness 'cline' requires a JSON schema for structured output.",
|
|
1449
1515
|
harnessId: HARNESS_ID2
|
|
1450
1516
|
});
|
|
1451
1517
|
}
|
|
1452
|
-
if (turnOpts.responseFormat?.type === "json" && providerId === "openai-codex-cli") {
|
|
1518
|
+
if (turnOpts.responseFormat?.type === "json" && agentModel.providerId === "openai-codex-cli") {
|
|
1453
1519
|
throw new HarnessCapabilityUnsupportedError2({
|
|
1454
1520
|
message: "Harness 'cline' cannot require structured output with the openai-codex-cli provider because that provider does not expose external tools.",
|
|
1455
1521
|
harnessId: HARNESS_ID2
|
|
1456
1522
|
});
|
|
1457
1523
|
}
|
|
1524
|
+
if (turnOpts.model != null && turnOpts.model !== activeModelId) {
|
|
1525
|
+
activeModelId = turnOpts.model;
|
|
1526
|
+
agentModel = createClineAgentModel({
|
|
1527
|
+
settings: input.settings,
|
|
1528
|
+
clientApp: input.clientApp,
|
|
1529
|
+
modelId: activeModelId
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1458
1532
|
const signature = JSON.stringify({
|
|
1459
|
-
|
|
1460
|
-
|
|
1533
|
+
modelId: activeModelId,
|
|
1534
|
+
tools: userTools,
|
|
1535
|
+
responseFormat: turnOpts.responseFormat,
|
|
1536
|
+
instructions: turnOpts.instructions,
|
|
1537
|
+
skills: skillsRuntime.signature
|
|
1461
1538
|
});
|
|
1462
|
-
if (agent == null || signature !==
|
|
1539
|
+
if (agent == null || signature !== lastAgentConfigurationSignature) {
|
|
1463
1540
|
currentMessages = agent?.snapshot().messages ?? currentMessages;
|
|
1464
1541
|
rebuildAgent({
|
|
1465
1542
|
userTools,
|
|
1543
|
+
skillsRuntime,
|
|
1466
1544
|
responseFormat: turnOpts.responseFormat,
|
|
1467
1545
|
...turnOpts.instructions ? { instructions: turnOpts.instructions } : {}
|
|
1468
1546
|
});
|
|
1469
|
-
|
|
1547
|
+
lastAgentConfigurationSignature = signature;
|
|
1470
1548
|
}
|
|
1471
1549
|
currentEmit = turnOpts.emit;
|
|
1550
|
+
const userToolNames = new Set(userTools.map((tool2) => tool2.name));
|
|
1472
1551
|
translatorState = createClineTranslatorState({
|
|
1473
|
-
builtinToolNames: activeBuiltinNames
|
|
1474
|
-
|
|
1552
|
+
builtinToolNames: activeBuiltinNames.filter(
|
|
1553
|
+
(name) => !userToolNames.has(name)
|
|
1554
|
+
),
|
|
1555
|
+
hostToolNames: userToolNames,
|
|
1475
1556
|
ignoredToolNames: turnOpts.responseFormat?.type === "json" ? ["structured_output"] : [],
|
|
1476
1557
|
mcpToolNames: mcpRuntime.toolNames
|
|
1477
1558
|
});
|
|
1478
1559
|
turnOpts.emit({
|
|
1479
1560
|
type: "stream-start",
|
|
1480
|
-
...
|
|
1561
|
+
...activeModelId ? { modelId: activeModelId } : {}
|
|
1481
1562
|
});
|
|
1482
1563
|
acceptingUserMessages = true;
|
|
1483
1564
|
const turnPromise = (async () => {
|
|
@@ -1603,13 +1684,14 @@ ${rebuildInput.instructions}` : baseSystemPrompt,
|
|
|
1603
1684
|
const sessionImpl = {
|
|
1604
1685
|
sessionId: input.sessionId,
|
|
1605
1686
|
isResume: input.isResume,
|
|
1606
|
-
...input.settings.modelId ? { modelId: input.settings.modelId } : {},
|
|
1607
1687
|
// The Cline runtime has no bridge to attach to and no in-sandbox event
|
|
1608
1688
|
// log to replay; its only cross-process resume path is restoring the
|
|
1609
1689
|
// persisted history on a fresh runtime, i.e. `rerun`.
|
|
1610
1690
|
doPromptTurn: async (promptOpts) => {
|
|
1611
1691
|
return runTurn({
|
|
1612
1692
|
text: extractUserText(promptOpts.prompt),
|
|
1693
|
+
...promptOpts.model ? { model: promptOpts.model } : {},
|
|
1694
|
+
skills: promptOpts.skills,
|
|
1613
1695
|
tools: promptOpts.tools ?? [],
|
|
1614
1696
|
...promptOpts.instructions ? { instructions: promptOpts.instructions } : {},
|
|
1615
1697
|
emit: promptOpts.emit,
|
|
@@ -1627,6 +1709,8 @@ ${rebuildInput.instructions}` : baseSystemPrompt,
|
|
|
1627
1709
|
}
|
|
1628
1710
|
return runTurn({
|
|
1629
1711
|
text: void 0,
|
|
1712
|
+
...continueOpts.model ? { model: continueOpts.model } : {},
|
|
1713
|
+
skills: continueOpts.skills,
|
|
1630
1714
|
tools: continueOpts.tools ?? [],
|
|
1631
1715
|
...continueOpts.instructions ? { instructions: continueOpts.instructions } : {},
|
|
1632
1716
|
emit: continueOpts.emit,
|
|
@@ -1710,7 +1794,7 @@ ${rebuildInput.instructions}` : baseSystemPrompt,
|
|
|
1710
1794
|
}
|
|
1711
1795
|
|
|
1712
1796
|
// src/version.ts
|
|
1713
|
-
var VERSION = true ? "1.0.
|
|
1797
|
+
var VERSION = true ? "1.0.21" : "0.0.0-test";
|
|
1714
1798
|
|
|
1715
1799
|
// src/cline-harness.ts
|
|
1716
1800
|
var CLINE_CLIENT_APP = `ai-sdk/harness-cline/${VERSION}`;
|
|
@@ -1786,6 +1870,18 @@ var CLINE_BUILTIN_TOOLS = {
|
|
|
1786
1870
|
}),
|
|
1787
1871
|
nativeName: "ls",
|
|
1788
1872
|
toolUseKind: "readonly"
|
|
1873
|
+
},
|
|
1874
|
+
skills: {
|
|
1875
|
+
...tool({
|
|
1876
|
+
description: "Execute a configured skill by name.",
|
|
1877
|
+
inputSchema: z2.object({
|
|
1878
|
+
skill: z2.string(),
|
|
1879
|
+
args: z2.string().optional()
|
|
1880
|
+
}),
|
|
1881
|
+
outputSchema: z2.string()
|
|
1882
|
+
}),
|
|
1883
|
+
nativeName: "skills",
|
|
1884
|
+
toolUseKind: "readonly"
|
|
1789
1885
|
}
|
|
1790
1886
|
};
|
|
1791
1887
|
function createCline(settings = {}) {
|
|
@@ -1804,13 +1900,12 @@ function createCline(settings = {}) {
|
|
|
1804
1900
|
sessionId: startOpts.sessionId,
|
|
1805
1901
|
sandboxSession: startOpts.sandboxSession,
|
|
1806
1902
|
sessionWorkDir: startOpts.sessionWorkDir,
|
|
1807
|
-
skills: startOpts.skills ?? [],
|
|
1808
1903
|
settings: {
|
|
1809
1904
|
authEnv,
|
|
1810
1905
|
isAuthenticationEnvironmentOverride: isHarnessAuthenticationEnvironment2(settings.auth),
|
|
1811
1906
|
...settings.mcpServers ? { mcpServers: settings.mcpServers } : {},
|
|
1812
1907
|
...settings.providerId ? { providerId: settings.providerId } : {},
|
|
1813
|
-
...settings.modelId ? { modelId: settings.modelId }
|
|
1908
|
+
...settings.modelId == null ? {} : { modelId: settings.modelId },
|
|
1814
1909
|
...settings.apiKey ? { apiKey: settings.apiKey } : {},
|
|
1815
1910
|
...settings.baseUrl ? { baseUrl: settings.baseUrl } : {},
|
|
1816
1911
|
...settings.headers ? { headers: settings.headers } : {},
|