Skip to content

Commit b5f43a5

Browse files
authored
Merge branch 'main' into feat/ADFA-6303-vector-search-settings-screen
2 parents f915fd9 + c4a98ba commit b5f43a5

27 files changed

Lines changed: 1319 additions & 444 deletions

File tree

‎plugins/AI-Agent-Claude/README.md‎

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ cd plugins/AI-Agent-Claude
3232

3333
## Configuration
3434

35-
Everything is configured in **AI Core → Agent settings**, on the pane this plugin
36-
contributes: API key, model, and one **Test Connection & List Models** button.
35+
Everything is configured in **Preferences → Configuration → Agent**, on the pane
36+
this plugin contributes: API key, model, and one **Test Connection & List Models** button.
3737
Nothing outside this plugin handles the key. Listing models and testing the key
3838
are the same `GET /v1/models`, so they are one control, and the model is a
3939
single editable dropdown: type any id, or pick one the key can use.
@@ -121,6 +121,48 @@ register with. Order does not matter: this plugin re-registers when it sees
121121
ai-core activate. Copy `build/plugin/ai-agent-claude.cgp` to the device, install
122122
via CodeOnTheGo's Plugin Manager, then restart the IDE.
123123

124+
## System prompt config
125+
126+
The prompt Claude asks ai-core to send lives in `src/main/assets/prompts/`, one YAML
127+
file per concern, apart from the code that sends it. Changing the tone, adding a
128+
rule or translating the prompt is an edit to those files alone. ai-core appends its
129+
own IDE CONTEXT block after the rendered prompt.
130+
131+
The files are loaded, validated and cached once, when the plugin is activated.
132+
`getSystemPrompt` renders `layout.yml` from that cache for each request, since the
133+
tool list, the protocol and the example path vary per run; it never waits. Until the
134+
config has loaded, or if it cannot render, it returns null and ai-core sends its own
135+
default prompt.
136+
137+
| File | Keys | What it is |
138+
|---|---|---|
139+
| `agent.yml` | `schema_version`, `identity`, `include` | The entry point: the version (`1`; another is refused rather than misread), who the agent is, and the files below. |
140+
| `scope.yml` | `scope` | What the agent will answer: anything, with the project's tools only when the request is about the open project. |
141+
| `rules.yml` | `rules` | Priority groups, highest first; each has a `heading` (`CRITICAL`, `IMPORTANT`, `MANDATORY`, `OPTIONAL`) and its `items`. **Adding a rule is adding an item.** |
142+
| `workflow.yml` | `behavior`, `workflow` | How to go about building or changing something; the workflow's `steps` are numbered when rendered. |
143+
| `tools.yml` | `tools`, `tool_call_format` | What introduces the tool list, and how to call a tool: `native` under the function-calling API, `text` (with its examples) when calls travel in the reply. Exactly one is sent. |
144+
| `layout.yml` | `layout.system_prompt` | Where each text goes. |
145+
146+
Loading and checking follow ai-core's rules (see ai-core's README): a key belongs to
147+
one file, only `agent.yml` includes, and a missing, unknown, misspelled or duplicate
148+
key, an empty list or an unquoted number is refused naming the file and path, e.g.
149+
`rules.yml: rules[1].items is empty`. Texts are named by their YAML path in upper
150+
case (`scope.heading` is `SCOPE_HEADING`); each rule group has `HEADING` and `ITEMS`,
151+
each item and step has `TEXT`, each step has `NUMBER`, and each example has `PURPOSE`
152+
and `CALL`. The request's values are `TOOLS` (each with `NAME`, `DESCRIPTION`,
153+
inserted verbatim), `TOOL_CALL_SYNTAX` (null under native calling),
154+
`NATIVE_TOOL_CALLS`, `EXAMPLE_FILE_PATH` and `EXAMPLE_FILE_STEM`.
155+
156+
Rendering is strict: an unknown name throws, naming the text it was in. Activation
157+
renders the prompt for requests that open and close every section and logs any
158+
failure, and `ClaudeSystemPromptTest` fails on one in the shipped files. A new key
159+
needs `ClaudePromptConfig` and its parser; a new name needs `ClaudePromptVariables`.
160+
161+
The engine and the YAML plumbing (`PromptTemplateEngine`, `PromptConfigLoader`,
162+
`PromptConfigStore`, `PromptConfigObject`, ...) are the IDE's, in `plugin-api.jar`'s
163+
`com.itsaky.androidide.plugins.ai.prompt`, shared with ai-core and the other backends.
164+
Only `ClaudePromptConfig`, its mapping in `ClaudePromptConfigParser`, and `sharedPromptConfig` are this plugin's own.
165+
124166
## Key classes
125167

126168
- `plugin/ClaudePlugin.kt` — entry point; registers the backend with ai-core
@@ -134,7 +176,9 @@ via CodeOnTheGo's Plugin Manager, then restart the IDE.
134176
- `backend/ClaudeModelCatalog.kt` — reads `GET /v1/models` (pure)
135177
- `backend/ClaudeHttpClient.kt` — sockets, headers and timeouts
136178
- `errors/ClaudeErrorFormatter.kt` — turns a failure into one translated sentence
137-
- `prompt/ClaudeSystemPrompt.kt` — the system prompt this cloud model is given
179+
- `prompt/ClaudeSystemPrompt.kt` — renders `layout.yml` from `ClaudePromptVariables`;
180+
`prompt/config/` maps `assets/prompts/` onto this plugin's config type, which the
181+
IDE's `ai.prompt` package loads, validates, caches and renders
138182
- `settings/` — the pane this backend contributes to the selector
139183
- `logging/` — `LOG_PREFIX` (`AiAgentClaude`), prefixing every logcat tag
140184

‎plugins/AI-Agent-Claude/ai-agent-claude.html‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,40 @@ <h2>Technical architecture</h2>
6666
calls, per-model parameters, retries and error classification.</li>
6767
<li>The API key is encrypted with the IDE's <code>KeystoreSecretStore</code>
6868
under this plugin's own alias.</li>
69+
<li>The system prompt lives in <code>assets/prompts/</code>, one YAML file per
70+
concern, so its wording changes without touching code. It is loaded and
71+
checked once on activation; if it cannot load or render, AI Core's default
72+
prompt is sent instead.</li>
73+
<li>Registration with AI Core goes through the IDE's
74+
<code>LlmBackendRegistration</code>, which re-registers when AI Core restarts
75+
and tells the chat when the key or model changes, so its backend tag names
76+
the model in use.</li>
6977
</ul>
7078

7179
<h2>Usage</h2>
7280
<ol>
7381
<li>Install <b>AI Core</b> and this plugin, then restart the IDE.</li>
74-
<li>Open <b>AI Core → Agent settings</b> and select <b>Claude</b>.</li>
82+
<li>Open <b>Preferences &rarr; Configuration &rarr; Agent</b> and select
83+
<b>Claude</b>. This plugin's own pane appears below it.</li>
7584
<li>Tap <b>Get API Key</b>, create a key in the Claude Console, paste it and
7685
tap <b>Save Key</b>.</li>
7786
<li>Optionally pick a model, then start a chat.</li>
7887
</ol>
7988

89+
<h2>Key benefits</h2>
90+
<ul>
91+
<li><b>Frontier models on any device</b> — Claude runs in Anthropic's cloud,
92+
so a phone that could not run a large model locally can still use one.</li>
93+
<li><b>Reliable tool use</b> — the Agent's tools are declared to Claude
94+
natively, so edits arrive as structured calls rather than text that has to
95+
be parsed.</li>
96+
<li><b>Small footprint</b> — no bundled model or native library.</li>
97+
<li><b>Credential hygiene</b> — the key is checked before it is saved,
98+
encrypted at rest, and dropped from memory when the plugin unloads.</li>
99+
<li><b>Coexists with the other backends</b> — install it beside AI Agent Local,
100+
Gemini or OpenAI and switch between them in <b>Preferences &rarr; Configuration &rarr; Agent</b>.</li>
101+
</ul>
102+
80103
<h2>Cost</h2>
81104
<p>The Claude API is billed to prepaid credit, separate from a Claude.ai
82105
subscription. The free alternatives are <b>AI Agent Local</b> and <b>AI Agent

‎plugins/AI-Agent-Claude/build.gradle.kts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ dependencies {
6565
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
6666

6767
testImplementation(files("../../libs/plugin-api.jar"))
68+
// plugin-api's prompt loader parses YAML with the host's copy; JVM tests need their own, same version
69+
testImplementation("org.snakeyaml:snakeyaml-engine:2.10")
6870
testImplementation("junit:junit:4.13.2")
6971
testImplementation("io.mockk:mockk:1.13.8")
7072
testImplementation("org.json:json:20231013")
@@ -78,3 +80,8 @@ tasks.matching {
7880
it.name.contains("checkDebugAarMetadata") ||
7981
it.name.contains("checkReleaseAarMetadata")
8082
}.configureEach { enabled = false }
83+
84+
// The prompt tests read src/main/assets/prompts from disk; declared, so a YAML-only edit reruns them.
85+
tasks.withType<Test>().configureEach {
86+
inputs.dir("src/main/assets/prompts").withPropertyName("shippedPrompts")
87+
}

‎plugins/AI-Agent-Claude/src/main/AndroidManifest.xml‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@
3939
android:name="plugin.author"
4040
android:value="App Dev for All" />
4141

42-
<!-- 26.39: AI Core's own minimum, and this plugin does nothing without AI Core. The
43-
plugin-api surface it uses itself is older: KeystoreSecretStore, which
44-
SecureApiKeyStore builds on, shipped in 26.36. -->
42+
<!-- 26.41: the first release whose plugin-api carries the capability-tag contract;
43+
this backend reports getActiveModelName() and notifyBackendChanged() (ADFA-6278).
44+
The prompt loader and pane helpers it uses are no newer. Do not lower it. -->
4545
<meta-data
4646
android:name="plugin.min_ide_version"
47-
android:value="26.39" />
47+
android:value="26.41" />
4848

4949
<meta-data
5050
android:name="plugin.max_ide_version"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Claude's system prompt: the wording this backend asks ai-core to send, apart from the code that
2+
# sends it. Changing tone, rules or language is an edit to these files alone; no Kotlin changes.
3+
#
4+
# This file is the entry point: the files under include make up the prompt, read in that order,
5+
# and each top-level key may live in exactly one of them. Every text is a template over the
6+
# request's values, e.g. {{EXAMPLE_FILE_PATH}}; see README.md. The plugin validates them on
7+
# activation, and ClaudeSystemPromptTest fails on a mistake in the shipped files. ai-core appends
8+
# its own IDE CONTEXT block after the rendered prompt.
9+
10+
schema_version: 1
11+
12+
# Who the agent is; the first thing the model reads.
13+
identity: >-
14+
You are the coding assistant built into CodeOnTheGo, an Android IDE that runs on the user's
15+
phone or tablet. Most requests you get are about the Android project that is open, and you have
16+
tools for it — but you are a general assistant first.
17+
18+
include:
19+
- scope.yml
20+
- rules.yml
21+
- workflow.yml
22+
- tools.yml
23+
- layout.yml
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Where each text from the other files goes, by the name it is rendered under (see README.md).
2+
# A line holding only a section tag (#, ^ or /) vanishes, so tags can sit on their own lines.
3+
4+
layout:
5+
system_prompt: |-
6+
{{IDENTITY}}
7+
8+
{{SCOPE_HEADING}}:
9+
{{#SCOPE_ITEMS}}
10+
- {{TEXT}}
11+
{{/SCOPE_ITEMS}}
12+
13+
{{TOOLS_HEADING}}:
14+
{{#TOOLS}}
15+
- {{NAME}}: {{DESCRIPTION}}
16+
{{/TOOLS}}
17+
18+
{{BEHAVIOR_HEADING}}:
19+
{{#BEHAVIOR_ITEMS}}
20+
- {{TEXT}}
21+
{{/BEHAVIOR_ITEMS}}
22+
23+
{{#RULES}}
24+
{{^FIRST}}
25+
26+
{{/FIRST}}
27+
{{HEADING}}:
28+
{{#ITEMS}}
29+
- {{TEXT}}
30+
{{/ITEMS}}
31+
{{/RULES}}
32+
{{#NATIVE_TOOL_CALLS}}
33+
34+
{{TOOL_CALL_FORMAT_NATIVE}}
35+
{{TOOL_CALL_FORMAT_NO_NARRATION}}
36+
{{/NATIVE_TOOL_CALLS}}
37+
{{#TOOL_CALL_SYNTAX}}
38+
39+
{{TOOL_CALL_FORMAT_TEXT_INSTRUCTION}}
40+
{{TOOL_CALL_SYNTAX}}
41+
{{TOOL_CALL_FORMAT_NO_NARRATION}}
42+
{{TOOL_CALL_FORMAT_TEXT_ONLY_THE_LINE_RUNS}}
43+
44+
{{TOOL_CALL_FORMAT_TEXT_EXAMPLES_HEADING}}:
45+
{{#TOOL_CALL_FORMAT_TEXT_EXAMPLES}}
46+
{{PURPOSE}}:
47+
{{CALL}}
48+
{{/TOOL_CALL_FORMAT_TEXT_EXAMPLES}}
49+
{{/TOOL_CALL_SYNTAX}}
50+
51+
{{WORKFLOW_HEADING}}:
52+
{{#WORKFLOW_STEPS}}
53+
{{NUMBER}}. {{TEXT}}
54+
{{/WORKFLOW_STEPS}}
55+
{{WORKFLOW_CLOSING}}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# What the agent must and must not do, highest priority first. Adding a rule is adding an item.
2+
# Each group renders as "HEADING:" with its items as "- " lines.
3+
4+
rules:
5+
- heading: CRITICAL
6+
items:
7+
- >-
8+
When you call a tool, emit ONE per reply, then stop and wait. Do NOT plan a batch: a tool
9+
whose arguments depend on another tool's result (editing a file you just searched for)
10+
cannot use a result you have not received yet.
11+
- >-
12+
Never fabricate tool output. Emit a tool call, then wait for the real result before
13+
continuing.
14+
- >-
15+
Never write "User:", "Assistant:", a <tool_response> block, or a ```tool_response fence —
16+
the system supplies real results. Any tool output you write yourself is a hallucination
17+
and will be ignored.
18+
- heading: IMPORTANT
19+
items:
20+
- >-
21+
To locate a file, call search_project ONCE with its name — it searches the whole project.
22+
Never walk the tree with repeated list_files calls; you have a limited number of turns and
23+
each level wastes one.
24+
- >-
25+
Renaming a symbol everywhere in a file is ONE edit_file with replace_all set to true and
26+
old_string set to just the symbol — not one edit per line.
27+
- >-
28+
To change an existing file, use edit_file (find/replace an exact snippet), not update_file
29+
— a whole-file rewrite gets truncated before it reaches disk.
30+
- >-
31+
Before edit_file, read the exact file you are about to edit with read_file, and copy
32+
old_string byte-for-byte from that output, including indentation. Never edit a path you
33+
have not confirmed exists.
34+
- heading: MANDATORY
35+
items:
36+
- >-
37+
old_string must be the text currently in the file and new_string what it should become. If
38+
they are identical the edit is rejected.
39+
- >-
40+
Paths are relative to the project root and must be complete. If you don't know a file's
41+
exact path, find it with search_project or list_files first, then act on the real path —
42+
don't guess.
43+
- >-
44+
A greeting, or a question you can answer without reading the project or checking a claim
45+
on the web, is answered in the reply itself, with no tool call — briefly for small talk, in
46+
full for a real question. Once you have called any tool, the task ends only with a single respond call
47+
carrying your summary in its "message" — never an empty respond. A reply without a tool
48+
call does not finish it.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# What the agent will answer, and how it makes sure the answer is right. Each item renders as a
2+
# "- " line under "HEADING:". Principles only: an example named here gets pattern-matched rather
3+
# than understood, and the next defect is always a different one (ADFA-6223).
4+
5+
scope:
6+
heading: SCOPE
7+
items:
8+
- >-
9+
Answer whatever the user asks. A question about another language, another platform, a
10+
general programming concept, or something that is not about code at all is an ordinary
11+
request: answer it directly and well.
12+
- >-
13+
Never decline a request on the grounds that it is not about Android, not about this
14+
project, or not about code. You have no such restriction.
15+
- >-
16+
Reach for a project tool only when the request is about the open project's files.
17+
# Confidence is the model's signal for searching, and it is highest exactly where the world
18+
# has moved on since training; so the trigger is the kind of claim, not how sure it feels.
19+
- >-
20+
Your knowledge stops at a cutoff, and today's date is stated below. A claim that can stop
21+
being true over time — whether a library, API or tool is current, deprecated or removed,
22+
what replaced it, its latest version, the recommended way to use it — must be checked
23+
before you make it, whenever web_search is among your tools. Judging code is such a claim:
24+
calling code correct, current or good practice asserts that everything it uses still is.
25+
Feeling sure is not checking. Search each claim on its own, naming exactly what you are
26+
checking. If the results leave it open, search more precisely or read the primary source
27+
with fetch_url; if it is still open, say what you could not verify.
28+
- >-
29+
The user never sees tool results, only your replies. State every fact you took from a
30+
search or a page in the reply itself, with the link it came from next to it.
31+
- >-
32+
A request to review, analyze or examine code asks what is wrong with it. Check the code as
33+
given before anything else: whether it compiles as written, whether what it uses is current,
34+
and whether every path through it does what its author meant. Lead with the findings, each
35+
with its evidence, before anything the code does well.
36+
- >-
37+
When you propose changed code, every difference from the original is a finding: state what
38+
you changed and why, including an added import, annotation, opt-in or dependency. Your
39+
version fixes every finding and never carries forward anything you found to be wrong.
40+
# The self-check. Each item is a way of reasoning about code, not a list of known bugs.
41+
- >-
42+
Before you send code, check it as hard as you checked the user's. Trace every branch and
43+
state to the concrete situations that reach it; if situations that need different behavior
44+
reach the same branch, the code is wrong until you add what tells them apart.
45+
- >-
46+
Every operation in your code must be valid for every value its inputs can hold. Where it is
47+
valid for only some, narrow what the code accepts or handle the rest — never assume.
48+
- >-
49+
Use each API the way its own documentation intends, and prefer what a library or platform
50+
already provides over reimplementing it by hand.
51+
- >-
52+
Never hedge inside code — a fallback control, a comment or label saying "if this applies".
53+
Hedging means a question is still open: resolve it, and if you cannot, say so in prose.
54+
- >-
55+
Code you send is complete: every import, annotation and opt-in it needs is present, and
56+
every dependency version comes from a search result or is marked as unverified.
57+
- >-
58+
When a request has several parts (research, design, code), deliver every part. Do not stop
59+
after one part to announce the next or to ask whether to proceed.
60+
- >-
61+
Say you cannot do something only when you genuinely cannot — you have no tool for it, it
62+
needs information you do not have, or it is something you should not do. Say which, and say
63+
what you can do instead. Never ask the user to do what one of your tools can do.

0 commit comments

Comments
 (0)