Skip to content

Commit 6685791

Browse files
committed
docs: synced via GitHub Actions
1 parent 4601432 commit 6685791

File tree

4 files changed

+1168
-2
lines changed

4 files changed

+1168
-2
lines changed

src/gpt/cline/responses.ts

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import { Anthropic } from "@anthropic-ai/sdk"
2+
import * as diff from "diff"
3+
import * as path from "path"
4+
import { ClineIgnoreController, LOCK_TEXT_SYMBOL } from "../ignore/ClineIgnoreController"
5+
6+
export const formatResponse = {
7+
toolDenied: () => `The user denied this operation.`,
8+
9+
toolError: (error?: string) => `The tool execution failed with the following error:\n<error>\n${error}\n</error>`,
10+
11+
clineIgnoreError: (path: string) =>
12+
`Access to ${path} is blocked by the .clineignore file settings. You must try to continue in the task without using this file, or ask the user to update the .clineignore file.`,
13+
14+
noToolsUsed: () =>
15+
`[ERROR] You did not use a tool in your previous response! Please retry with a tool use.
16+
17+
${toolUseInstructionsReminder}
18+
19+
# Next Steps
20+
21+
If you have completed the user's task, use the attempt_completion tool.
22+
If you require additional information from the user, use the ask_followup_question tool.
23+
Otherwise, if you have not completed the task and do not need additional information, then proceed with the next step of the task.
24+
(This is an automated message, so do not respond to it conversationally.)`,
25+
26+
tooManyMistakes: (feedback?: string) =>
27+
`You seem to be having trouble proceeding. The user has provided the following feedback to help guide you:\n<feedback>\n${feedback}\n</feedback>`,
28+
29+
missingToolParameterError: (paramName: string) =>
30+
`Missing value for required parameter '${paramName}'. Please retry with complete response.\n\n${toolUseInstructionsReminder}`,
31+
32+
invalidMcpToolArgumentError: (serverName: string, toolName: string) =>
33+
`Invalid JSON argument used with ${serverName} for ${toolName}. Please retry with a properly formatted JSON argument.`,
34+
35+
toolResult: (text: string, images?: string[]): string | Array<Anthropic.TextBlockParam | Anthropic.ImageBlockParam> => {
36+
if (images && images.length > 0) {
37+
const textBlock: Anthropic.TextBlockParam = { type: "text", text }
38+
const imageBlocks: Anthropic.ImageBlockParam[] = formatImagesIntoBlocks(images)
39+
// Placing images after text leads to better results
40+
return [textBlock, ...imageBlocks]
41+
} else {
42+
return text
43+
}
44+
},
45+
46+
imageBlocks: (images?: string[]): Anthropic.ImageBlockParam[] => {
47+
return formatImagesIntoBlocks(images)
48+
},
49+
50+
formatFilesList: (
51+
absolutePath: string,
52+
files: string[],
53+
didHitLimit: boolean,
54+
clineIgnoreController?: ClineIgnoreController,
55+
): string => {
56+
const sorted = files
57+
.map((file) => {
58+
// convert absolute path to relative path
59+
const relativePath = path.relative(absolutePath, file).toPosix()
60+
return file.endsWith("/") ? relativePath + "/" : relativePath
61+
})
62+
// Sort so files are listed under their respective directories to make it clear what files are children of what directories. Since we build file list top down, even if file list is truncated it will show directories that cline can then explore further.
63+
.sort((a, b) => {
64+
const aParts = a.split("/") // only works if we use toPosix first
65+
const bParts = b.split("/")
66+
for (let i = 0; i < Math.min(aParts.length, bParts.length); i++) {
67+
if (aParts[i] !== bParts[i]) {
68+
// If one is a directory and the other isn't at this level, sort the directory first
69+
if (i + 1 === aParts.length && i + 1 < bParts.length) {
70+
return -1
71+
}
72+
if (i + 1 === bParts.length && i + 1 < aParts.length) {
73+
return 1
74+
}
75+
// Otherwise, sort alphabetically
76+
return aParts[i].localeCompare(bParts[i], undefined, {
77+
numeric: true,
78+
sensitivity: "base",
79+
})
80+
}
81+
}
82+
// If all parts are the same up to the length of the shorter path,
83+
// the shorter one comes first
84+
return aParts.length - bParts.length
85+
})
86+
87+
const clineIgnoreParsed = clineIgnoreController
88+
? sorted.map((filePath) => {
89+
// path is relative to absolute path, not cwd
90+
// validateAccess expects either path relative to cwd or absolute path
91+
// otherwise, for validating against ignore patterns like "assets/icons", we would end up with just "icons", which would result in the path not being ignored.
92+
const absoluteFilePath = path.resolve(absolutePath, filePath)
93+
const isIgnored = !clineIgnoreController.validateAccess(absoluteFilePath)
94+
if (isIgnored) {
95+
return LOCK_TEXT_SYMBOL + " " + filePath
96+
}
97+
98+
return filePath
99+
})
100+
: sorted
101+
102+
if (didHitLimit) {
103+
return `${clineIgnoreParsed.join(
104+
"\n",
105+
)}\n\n(File list truncated. Use list_files on specific subdirectories if you need to explore further.)`
106+
} else if (clineIgnoreParsed.length === 0 || (clineIgnoreParsed.length === 1 && clineIgnoreParsed[0] === "")) {
107+
return "No files found."
108+
} else {
109+
return clineIgnoreParsed.join("\n")
110+
}
111+
},
112+
113+
createPrettyPatch: (filename = "file", oldStr?: string, newStr?: string) => {
114+
// strings cannot be undefined or diff throws exception
115+
const patch = diff.createPatch(filename.toPosix(), oldStr || "", newStr || "")
116+
const lines = patch.split("\n")
117+
const prettyPatchLines = lines.slice(4)
118+
return prettyPatchLines.join("\n")
119+
},
120+
}
121+
122+
// to avoid circular dependency
123+
const formatImagesIntoBlocks = (images?: string[]): Anthropic.ImageBlockParam[] => {
124+
return images
125+
? images.map((dataUrl) => {
126+
// data:image/png;base64,base64string
127+
const [rest, base64] = dataUrl.split(",")
128+
const mimeType = rest.split(":")[1].split(";")[0]
129+
return {
130+
type: "image",
131+
source: {
132+
type: "base64",
133+
media_type: mimeType,
134+
data: base64,
135+
},
136+
} as Anthropic.ImageBlockParam
137+
})
138+
: []
139+
}
140+
141+
const toolUseInstructionsReminder = `# Reminder: Instructions for Tool Use
142+
143+
Tool uses are formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
144+
145+
<tool_name>
146+
<parameter1_name>value1</parameter1_name>
147+
<parameter2_name>value2</parameter2_name>
148+
...
149+
</tool_name>
150+
151+
For example:
152+
153+
<attempt_completion>
154+
<result>
155+
I have completed the task...
156+
</result>
157+
</attempt_completion>
158+
159+
Always adhere to this format for all tool uses to ensure proper parsing and execution.`

0 commit comments

Comments
 (0)