Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .aiignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ GEMINI.md
.gitignore
.aiignore
_example
.intellijPlatform
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,4 @@ yarn-error.log*
/docs/tasks/
/.gradle-user-home-fix/
/.intellijPlatform/
/run-ai.bat
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

---

## [0.0.1.8] - 2026-04-26

### Added

- **Native function calling** — agents can now use providers' structured `tools` API instead of the JSON-in-text envelope. Opt-in per model via `tools.native_tools: auto | always | never` in `config.yaml`; default is `auto` (enabled for models with `supportsFunctionCalling=true`).
- OpenAI (Chat Completions + Responses API) — strict-mode schema sanitization, `tool_choice: auto`.
- Anthropic — `tools` array + `content[].tool_use` response parsing; schema sanitized (composition keywords stripped).
- Gemini — `functionDeclarations` array + `functionCall` response parsing; Gemini-specific type normalization.
- `ToolSchemaSanitizer` — provider-aware JSON Schema normalization (OpenAI strict compatibility check, Anthropic forbidden-keyword stripping, Gemini single-type coercion and nullable fields).
- `NativeToolsFallbackTracker` — session-scoped in-memory registry; if a provider returns 400 "tools not supported", the model is marked and all subsequent requests in the same process skip native tools automatically.
- `NativeToolsResolver` (`NativeToolsMode` enum: `AUTO / ALWAYS / NEVER`) — central decision logic with precedence: fallback cache → NEVER → ALWAYS → `ModelDefinition.supportsFunctionCalling`.
- XML tag fallback in `ToolCallParser` — recovers tool calls from `<tool_name><arg>…</arg></tool_name>` pseudo-tags emitted by weak local models (qwen<70B, some Gemma builds) that bypass the native API entirely. Warns on use.
- New models: **GPT-5.5**, **GPT-5.4 Nano**, **Qwen 3.6 35B/27B** (Ollama), **Qwen 3-next 80B**, **gpt-oss-safeguard 20B/120B**, OpenRouter `qwen/*` patterns.
- `claude-sonnet-4-6` added to `SupportedModels`.
- Per-iteration token and cost metrics persisted directly to the task row so the History panel and live stats bar show running totals without aggregating from message metadata.

### Changed

- `AgentTurnLoop` auto-falls back to the JSON-in-text path when a provider throws `ToolsNotSupportedException` — prompt is rebuilt without `<available_tools>` and the JSON envelope contract; no user action needed.
- When native tools are active the `response_format` / `json_object` override is suppressed (incompatible with function-calling mode on most providers).
- `TurnLLMCaller` accepts `nativeToolSchemas` and forwards them as `native_tools` in `kwargs`; retry handler also propagates `thinking`, `reasoningEffort`, and `noEgressEnabled`.
- Subagent profiles filter the native `tools` array to match their `<available_tools>` list — prevents the model calling tools the harness would reject.
- `ToolCallParser.extractToolCalls` pre-guard (`startsWith("{")`) removed — some models (e.g. glm-4.7-flash) emit prose before the JSON envelope, which the brace-matching strategy handles correctly. All-strategies-failed log downgraded from `WARN` to `DEBUG`.

### Fixed

- Anthropic tool results were mapped to `role: "assistant"` — now correctly mapped to `role: "user"`, fixing HTTP 400 rejections from claude-opus-4-6 and newer models that treat assistant-role tool results as prefill.
- `temperature` parameter no longer sent to models that deprecated it (`claude-opus-4-7`, `claude-opus-4-6`, `gpt-5.5`, `gpt-5.4-nano`) — removes spurious provider warnings.
- Anthropic streaming: `content_block_start` for `tool_use` blocks now captures the call `id` alongside the name.

---

## [0.0.1.7] - 2025-04-17

### Added
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![IntelliJ](https://img.shields.io/badge/IntelliJ-2024.1+-orange.svg)](https://www.jetbrains.com/idea/)
[![Version](https://img.shields.io/badge/version-0.0.1.5-green.svg)](CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-0.0.1.8-green.svg)](CHANGELOG.md)
[![Stage](https://img.shields.io/badge/stage-early--active-yellow.svg)](docs/ROADMAP.md)

**Open-source AI coding plugin for IntelliJ IDEA, built in Kotlin.**
Expand Down Expand Up @@ -216,12 +216,12 @@ See [docs/config.md](docs/config.md) for full configuration reference.

## Project status

| | |
|---|---|
| **Version** | 0.0.1.5 |
| **Stage** | Early-stage — active development |
| **License** | MIT |
| **Community** | Small, growing — PRs and issues welcome |
| | |
|---|------------------------------------------|
| **Version** | 0.0.1.8 |
| **Stage** | Early-stage — active development |
| **License** | MIT |
| **Community** | Small, growing — PRs and issues welcome |
| **Change cadence** | Fast. Breaking changes possible pre-1.0. |

---
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/kotlin/pl/jclab/refio/core/api/ApiModels.kt
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,9 @@ data class ProjectContextResponse(
// Active LLM request preview (exact runtime shape for next call)
val activeLlmRequestPrompt: String? = null,
// Auxiliary prompt preview (tool/system/user templates not in active request)
val auxiliaryPromptsPreview: String? = null
val auxiliaryPromptsPreview: String? = null,
// Raw context prompt as produced by ContextService.buildLLMContextPrompt (no system prompt, no messages)
val rawContextPrompt: String? = null
)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class CoreApiRouter(
configService = configService,
ragRepository = persistence.ragRepository,
snapshotRepository = persistence.snapshotRepository,
snapshotGroupRepository = persistence.snapshotGroupRepository,
analysisReportRepository = persistence.projectAnalysisReportRepository,
taskRepository = taskRepository,
chatMessageRepository = persistence.chatMessageRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ internal class AgentTurnLoopFactory(
llmRetryHandler = null,
workingMemoryIntegration = workingMemoryIntegration,
agentEventBus = agentEventBus,
hookService = hookService
hookService = hookService,
toolPermissionsService = toolPermissionsService
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import pl.jclab.refio.core.config.ConfigKeys
import pl.jclab.refio.core.db.repositories.ChatMessageRepository
import pl.jclab.refio.core.db.repositories.ProjectAnalysisReportRepository
import pl.jclab.refio.core.db.repositories.RagRepository
import pl.jclab.refio.core.db.repositories.SnapshotGroupRepository
import pl.jclab.refio.core.db.repositories.SnapshotRepository
import pl.jclab.refio.core.db.repositories.SubtaskRepository
import pl.jclab.refio.core.db.repositories.TaskRepository
Expand All @@ -26,6 +27,7 @@ internal class AnalysisStack(
private val configService: ConfigService,
private val ragRepository: RagRepository,
snapshotRepository: SnapshotRepository,
snapshotGroupRepository: SnapshotGroupRepository,
analysisReportRepository: ProjectAnalysisReportRepository,
taskRepository: TaskRepository,
chatMessageRepository: ChatMessageRepository,
Expand Down Expand Up @@ -104,7 +106,7 @@ internal class AnalysisStack(
} else null

val snapshotService: SnapshotService? = if (projectRoot != null) {
SnapshotService(snapshotRepository, projectRoot)
SnapshotService(snapshotRepository, snapshotGroupRepository, projectRoot)
} else null

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ internal class DomainRouters(
projectAnalyzer = projectAnalyzer,
richProjectAnalysisEngine = richProjectAnalysisEngine,
promptSectionProviders = promptSectionProviders,
configService = configService,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import pl.jclab.refio.core.db.repositories.DocumentationRepository
import pl.jclab.refio.core.db.repositories.ProjectAnalysisReportRepository
import pl.jclab.refio.core.db.repositories.PromptsRepository
import pl.jclab.refio.core.db.repositories.RagRepository
import pl.jclab.refio.core.db.repositories.SnapshotGroupRepository
import pl.jclab.refio.core.db.repositories.SnapshotRepository
import pl.jclab.refio.core.db.repositories.SubtaskRepository
import pl.jclab.refio.core.db.repositories.TaskRepository
Expand All @@ -29,6 +30,7 @@ class PersistenceModule {
val ragRepository = RagRepository()
val documentationRepository = DocumentationRepository()
val snapshotRepository = SnapshotRepository()
val snapshotGroupRepository = SnapshotGroupRepository()
val projectAnalysisReportRepository = ProjectAnalysisReportRepository()
val agentSessionRepository = AgentSessionRepository()
val agentInstanceRepository = AgentInstanceRepository()
Expand Down
Loading
Loading