@@ -116,13 +116,30 @@ via CodeOnTheGo's Plugin Manager, then restart the IDE.
116116
117117## Native function calling
118118
119- Not implemented, deliberately. This backend declares ` HistoryCapableBackend ` but
120- not ` ToolCallingBackend ` , so ai-core streams it the whole conversation and the
121- agent loop drives tools through a text envelope in the system prompt, which is
122- provider-agnostic. Declaring ` ToolCallingBackend ` without native function calling
123- would leave the caller waiting on a call this backend never makes. The system
124- prompt also tells the model not to use its own function-calling channel, since
125- nothing reads it.
119+ This backend declares ` ToolCallingBackend ` , so ai-core calls
120+ ` generateStreamingWithTools ` and the agent's tools travel through the
121+ Chat Completions function-calling API rather than a text envelope in the reply
122+ (ADFA-5410). Declared tools arrive already structured, so a file whose contents
123+ carry quotes or newlines cannot break the call.
124+
125+ - ** Request.** Each tool is sent in ` tools[] ` as ` {"type":"function","function":{name, description, parameters}} `
126+ (` OpenAiToolProtocol ` ). ` tool_choice ` is sent only when ai-core names a required
127+ tool (` EXTRA_PARAM_REQUIRED_TOOL ` ); a server that refuses it is retried once
128+ without it, under the same rule as the other 400 retries (` RequestTuning ` ).
129+ - ** Stream.** ` tool_calls ` deltas are joined by index (` SseChunk ` ,
130+ ` OpenAiToolProtocol.CallAccumulator ` ) and reported through ` onToolCall ` once the
131+ stream ends, so a call a retry replaced never reaches the caller. A call with no
132+ name or unparseable arguments is dropped.
133+ - ** Results.** ` ChatMessage ` gives an assistant turn no way to carry ` tool_calls ` ,
134+ and a ` tool ` role is only legal after one, so tool results go back as ` user ` turns.
135+ - ** Prompt.** ai-core sees the backend calls tools natively and passes no text call
136+ syntax, so ` tools.yml ` 's ` native ` format is sent. The text protocol, and its
137+ ` no_native_channel ` line, is not used by this backend.
138+ - ** Servers without function calling.** If a server refuses the ` tools ` declaration
139+ (400, 404 or 422 naming a tool field as unsupported), the turn is retried with no
140+ tools and a Toast says the agent cannot call tools on that server. The refusal is
141+ remembered per base URL, so only the first turn pays for it. The prompt for that
142+ run was built for native calling, so the model answers in prose.
126143
127144## System prompt config
128145
@@ -169,10 +186,12 @@ Every source file sits in a package named for its layer; nothing is loose at the
169186root of ` com/itsaky/androidide/plugins/aiagentopenai/ ` .
170187
171188- ` plugin/OpenAiPlugin.kt ` — plugin entry point; registers the backend with ai-core
172- - ` backend/OpenAiBackend.kt ` — the HTTP transport, SSE streaming and model catalog
173- - ` backend/OpenAiRequestBuilder.kt ` — ` messages[] ` mapping and request JSON (pure)
174- - ` backend/RequestTuning.kt ` — reasoning-model parameters and the 400-retry rule (pure)
175- - ` backend/SseChunk.kt ` — one line of the token stream (pure)
189+ - ` backend/OpenAiBackend.kt ` — SSE streaming, native tool calling and the model catalog
190+ - ` backend/OpenAiHttpClient.kt ` — the HTTP transport
191+ - ` backend/OpenAiRequestBuilder.kt ` — ` messages[] ` mapping and request JSON, including ` tools ` (pure)
192+ - ` backend/OpenAiToolProtocol.kt ` — ` tools[] ` , ` tool_choice ` and the streamed ` tool_calls ` accumulator (pure)
193+ - ` backend/RequestTuning.kt ` — reasoning-model parameters, the 400-retry rule and tool-refusal detection (pure)
194+ - ` backend/SseChunk.kt ` — one line of the token stream, text or ` tool_calls ` deltas (pure)
176195- ` backend/ModelCatalogFilter.kt ` — splits one catalog into the chat and embedding pickers (pure)
177196- ` backend/OpenAiEmbeddingProtocol.kt ` — the ` /v1/embeddings ` body, batching and index-ordered reply (pure)
178197- ` errors/OpenAiErrorFormatter.kt ` — turns a failure into one translated sentence
@@ -188,7 +207,7 @@ root of `com/itsaky/androidide/plugins/aiagentopenai/`.
188207- ` logging/ ` — ` LOG_PREFIX ` (` AiAgentOpenAi ` ), prefixing every logcat tag
189208
190209The pure units carry the logic that would otherwise only fail on a device; they
191- are covered by 177 JVM tests.
210+ are covered by 245 JVM tests.
192211
193212## License
194213
0 commit comments