Skip to content

Commit 7c6ff8e

Browse files
committed
Merge remote-tracking branch 'upstream/ai-agent' into ai-agent
2 parents 4c49a8f + 672fbbd commit 7c6ff8e

File tree

11 files changed

+225
-11
lines changed

11 files changed

+225
-11
lines changed

.github/workflows/close-inactive-issues.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
2525
days-before-pr-stale: -1
2626
days-before-pr-close: -1
27-
any-of-issue-labels: "bug, todo, new plugin idea"
27+
exempt-issue-labels: "new plugin idea, todo"
2828
operations-per-run: 100
2929
repo-token: ${{ secrets.GITHUB_TOKEN }}
3030

package-lock.json

Lines changed: 26 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
"cordova-plugin-advanced-http": {
3737
"ANDROIDBLACKLISTSECURESOCKETPROTOCOLS": "SSLv3,TLSv1"
3838
},
39-
"cordova-sqlite-storage": {}
39+
"cordova-sqlite-storage": {},
40+
"com.foxdebug.acode.exec": {}
4041
},
4142
"platforms": [
4243
"android"
@@ -62,6 +63,7 @@
6263
"@types/url-parse": "^1.4.11",
6364
"autoprefixer": "^10.4.19",
6465
"babel-loader": "^9.1.3",
66+
"com.foxdebug.acode.exec": "file:src/plugins/Executor",
6567
"cordova-android": "^13.0.0",
6668
"cordova-clipboard": "^1.3.0",
6769
"cordova-plugin-advanced-http": "^3.3.1",
@@ -118,7 +120,8 @@
118120
"mustache": "^4.2.0",
119121
"url-parse": "^1.5.10",
120122
"vanilla-picker": "^2.12.3",
121-
"yargs": "^17.7.2"
123+
"yargs": "^17.7.2",
124+
"zod": "^3.25.47"
122125
},
123126
"browserslist": "cover 100%,not android < 5"
124-
}
127+
}

src/ace/touchHandler.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,9 +684,17 @@ export default function addTouchListeners(editor, minimal, onclick) {
684684
const range = editor.getSelectionRange();
685685
const { pageX, pageY } = renderer.textToScreenCoordinates(range.start);
686686
const { lineHeight } = renderer;
687-
const [x, y] = relativePosition(pageX - teardropSize, pageY + lineHeight);
688687

689-
$start.style.left = `${x}px`;
688+
// Calculate desired position but ensure it stays within viewport
689+
let targetX = pageX - teardropSize;
690+
const [relativeX, y] = relativePosition(targetX, pageY + lineHeight);
691+
692+
// Ensure the teardrop doesn't go outside the left edge
693+
// Leave some padding (e.g., 4px) so it's not flush against the edge
694+
const minX = 4;
695+
const constrainedX = Math.max(relativeX, minX);
696+
697+
$start.style.left = `${constrainedX}px`;
690698
$start.style.top = `${y}px`;
691699

692700
if (!$start.isConnected) $el.append($start);

src/pages/aiAssistant/assistant.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
} from "./db";
2020
import { CordovaSqliteSaver } from "./memory";
2121
import { SYSTEM_PROMPT } from "./system_prompt";
22+
import { allTools } from "./tools";
2223

2324
export default function openAIAssistantPage() {
2425
// References
@@ -46,9 +47,13 @@ export default function openAIAssistantPage() {
4647
model: "gemini-2.0-flash",
4748
apiKey: GEMINI_API_KEY,
4849
});
50+
51+
// Get all tools as an array for the agent including search
52+
const toolsArray = Object.values(allTools);
53+
4954
const agent = createReactAgent({
5055
llm: model,
51-
tools: [searchTool],
56+
tools: toolsArray,
5257
checkpointSaver: agentCheckpointer,
5358
stateModifier: SYSTEM_PROMPT,
5459
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { readFile } from "./readFile";
2+
3+
// Export all tools as a single object
4+
export const allTools = {
5+
readFile,
6+
};
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { StructuredTool } from "@langchain/core/tools";
2+
import fsOperation from "fileSystem";
3+
import { addedFolder } from "lib/openFolder";
4+
import { z } from "zod";
5+
6+
/**
7+
* Tool for reading file contents in Acode
8+
*/
9+
class ReadFileTool extends StructuredTool {
10+
name = "readFile";
11+
description = "Reads the content of the given file in the project.";
12+
schema = z.object({
13+
path: z
14+
.string()
15+
.describe(
16+
"The relative path of the file to read. This path should never be absolute, and the first component of the path should always be a root directory in a project (opened in sidebar). For example, if root directories are 'directory1' and 'directory2', to access 'file.txt' in 'directory1', use 'directory1/file.txt'. To access 'file.txt' in 'directory2', use 'directory2/file.txt'.",
17+
),
18+
startLine: z
19+
.number()
20+
.min(1)
21+
.optional()
22+
.describe("line number to start reading on (1-based index)"),
23+
endLine: z
24+
.number()
25+
.min(1)
26+
.optional()
27+
.describe("line number to end reading on (1-based index, inclusive)"),
28+
});
29+
30+
async _call({ path, startLine, endLine }) {
31+
try {
32+
// Split the path to get project name and file path
33+
const pathParts = path.split("/");
34+
const projectName = pathParts[0];
35+
const filePath = pathParts.slice(1).join("/");
36+
37+
// Find the project in addedFolder array
38+
const project = addedFolder.find(
39+
(folder) => folder.title === projectName,
40+
);
41+
if (!project) {
42+
return `Error: Project '${projectName}' not found in opened projects`;
43+
}
44+
45+
// Construct the full file URL
46+
const fileUrl = project.url + "/" + filePath;
47+
48+
// Read the file content
49+
const content = await fsOperation(fileUrl).readFile("utf8");
50+
51+
// If startLine or endLine are specified, filter the content
52+
if (startLine !== undefined || endLine !== undefined) {
53+
const lines = content.split("\n");
54+
const start = startLine ? startLine - 1 : 0;
55+
const end = endLine ? endLine : lines.length;
56+
return lines.slice(start, end).join("\n");
57+
}
58+
59+
return content;
60+
} catch (error) {
61+
return `Error reading file: ${error.message}`;
62+
}
63+
}
64+
}
65+
66+
export const readFile = new ReadFileTool();

src/plugins/Executor/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function exec(cmd,success,failure) {
2+
const ACTION = 'exec';
3+
cordova.exec(success, failure, 'Executor', ACTION, [cmd]);
4+
}
5+
6+
export default {
7+
exec,
8+
};

src/plugins/Executor/package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "com.foxdebug.acode.exec",
3+
"version": "1.0.0",
4+
"description": "Execute linux commands",
5+
"cordova": {
6+
"id": "com.foxdebug.acode.exec",
7+
"platforms": [
8+
"android"
9+
]
10+
},
11+
"keywords": [
12+
"ecosystem:cordova",
13+
"cordova-android"
14+
],
15+
"author": "",
16+
"license": "ISC"
17+
}

src/plugins/Executor/plugin.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?xml version='1.0' encoding='utf-8'?>
2+
<plugin id="com.foxdebug.acode.exec" version="1.0.0" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android"><name>Executor</name><js-module name="Executor" src="index.js"><clobbers target="cordova.plugins.Executor" /></js-module><platform name="android"><config-file parent="/*" target="res/xml/config.xml"><feature name="Executor"><param name="android-package" value="com.foxdebug.acode.exec.Executor" /></feature></config-file><config-file parent="/*" target="AndroidManifest.xml"></config-file><source-file src="src/android/Executor.java" target-dir="src/com/foxdebug/acode/exec/Executor" /></platform></plugin>

0 commit comments

Comments
 (0)