Skip to content

Commit 1ec4c80

Browse files
committed
release 1.2.0
1 parent cc424e0 commit 1ec4c80

21 files changed

Lines changed: 514 additions & 77 deletions

docs/commands.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Options:
3333
- `--review-temperature`: Override review temperature.
3434
- `--max-tokens`: Override max tokens.
3535
- `--system-prompt`: Extra system prompt guidance.
36+
- `--show-reasoning`, `--with-thinking`: Show the LLM's reasoning process (if supported by the model).
3637

3738
## config (/config)
3839
View or update shell settings.
@@ -82,6 +83,7 @@ Options:
8283
- `--review-temperature`: Override review temperature.
8384
- `--max-tokens`: Override max tokens.
8485
- `--system-prompt`: Extra system prompt guidance.
86+
- `--show-reasoning`, `--with-thinking`: Show the LLM's reasoning process (if supported by the model).
8587

8688
## route (/route)
8789
Preview how the intent router would map text to commands.
@@ -119,6 +121,7 @@ Options:
119121
- `--log-review`: Persist review summary to log.
120122
- `--security`: Focus on security risks in the review.
121123
- `--sast`: Run optional static analysis (requires `assistant.sast.command`).
124+
- `--with-thinking`, `--reasoning`: Show the LLM's reasoning process (if supported by the model).
122125
- `--session`, `--model`, `--review-temperature`, `--max-tokens`, `--system-prompt`.
123126

124127
## reviewlog (/reviewlog)

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</parent>
1212
<groupId>se.alipsa.lca</groupId>
1313
<artifactId>local-coding-assistant</artifactId>
14-
<version>1.1.1-SNAPSHOT</version>
14+
<version>1.2.0</version>
1515
<packaging>jar</packaging>
1616
<name>Local Coding Assistant</name>
1717
<description>The Local Coding assistant is an AI LLM interface based on Ollama and Embabel</description>

release.md

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,66 @@
1-
# Release Notes for the local-coding-assistant
1+
# Release Notes for the local-coding-assistant
2+
3+
## Version 1.2.0, 2026-01-16
4+
**Highlights**
5+
- Migrated from Spring Shell to custom JLine REPL for better control and natural language interaction.
6+
- Added Embabel 0.3.2 thinking/reasoning capabilities to chat and review commands.
7+
- Implemented tool call parsing for LLM-agnostic function calling (writeFile, replace, deleteFile, runCommand).
8+
- Enhanced /implement command with shell command execution and concise output format.
9+
- Added user input coloring (light green) for improved readability.
10+
11+
**REPL & UX**
12+
- Replaced Spring Shell with custom JLine-based REPL for tighter control over input handling and natural language processing.
13+
- Added syntax highlighting for user input (light green) to distinguish from assistant output.
14+
- Fixed /clear command to work with both slash and non-slash variants (/clear, /cls, clear, cls).
15+
- Improved multi-line input handling in command parser to support quoted strings with newlines.
16+
- Enhanced intent routing with smart multi-line handling and conversational context tracking for file references.
17+
- Improved conversational language handling for more natural interactions.
18+
19+
**AI & Agent Improvements**
20+
- Upgraded to Embabel 0.3.2 with thinking/reasoning support:
21+
- ChatAgent now supports --show-reasoning and --with-thinking flags to expose LLM reasoning chains.
22+
- ReviewAgent displays thinking output when using models with extended thinking capabilities.
23+
- Added ChatResponse wrapper to return both message and reasoning content.
24+
- Added tool call parser for LLM-agnostic function calling:
25+
- writeFile(path, content) - create or overwrite files.
26+
- replace(path, old, new) - modify existing files.
27+
- deleteFile(path) - delete files.
28+
- runCommand(command) - execute shell commands (chmod, mkdir, mv, cp, etc.).
29+
- Enhanced /implement command:
30+
- Made output more concise (removed verbose Plan/Implementation/Notes format).
31+
- Added shell command execution support via runCommand() tool.
32+
- Now responds with brief confirmations and tool execution results only.
33+
- Added auto-save feature for code blocks in /chat command.
34+
- Improved code search with case-insensitive option (-i flag) and better feedback.
35+
36+
**Web Search Standardization**
37+
- Added Embabel InternetResource and InternetResources domain object support.
38+
- WebSearchTool now provides:
39+
- searchAsInternetResources() - returns List<InternetResource>.
40+
- searchAsWebSearchResults() - returns WebSearchResults wrapper.
41+
- Backward compatibility maintained with existing search() methods.
42+
43+
**Bug Fixes**
44+
- Fixed integration test failures caused by ChatResponse type mismatch in agent process execution.
45+
- Fixed /implement command to properly handle ChatResponse return type.
46+
- Fixed multi-line input breaking command parser when pasting error messages or prompts with newlines.
47+
- Fixed batch mode integration tests by implementing BatchModeRunner.
48+
- Fixed NPE in integration tests related to agent result type resolution.
49+
50+
**Documentation & Tooling**
51+
- Added comprehensive documentation for Embabel 0.3.2 features and implementation opportunities.
52+
- Updated AGENTS.md to be language-agnostic (supports any programming language).
53+
- Enhanced shell scripts (lca launcher) with better error handling and compatibility.
54+
- Improved test output formatting and readability.
55+
- Added presentation materials and expanded docs.
56+
57+
**Dependencies**
58+
- Upgraded to Embabel 0.3.2 (from 0.3.1).
59+
- Various dependency updates for improved stability and performance.
60+
61+
**Breaking Changes**
62+
- Removed @Action annotation from ChatAgent.respond() method - now only respondWithThinking() is the agent action.
63+
- /implement command output format changed from verbose Plan/Implementation/Notes to concise confirmation + results.
264

365
## Version 1.1.0, 2025-12-28
466
**Highlights**

src/main/groovy/se/alipsa/lca/agent/ChatAgent.groovy

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.embabel.chat.AssistantMessage
1010
import com.embabel.chat.Conversation
1111
import com.embabel.chat.UserMessage
1212
import com.embabel.common.ai.model.LlmOptions
13+
import com.embabel.common.core.thinking.ThinkingResponse
1314
import groovy.transform.Canonical
1415
import groovy.transform.CompileStatic
1516
import org.springframework.beans.factory.annotation.Value
@@ -45,9 +46,18 @@ Notes:
4546
this.codingAssistantAgent = codingAssistantAgent
4647
}
4748

48-
@AchievesGoal(description = "Respond to a user message in an ongoing coding conversation")
49-
@Action(canRerun = true, trigger = UserMessage)
49+
/**
50+
* Convenience method that returns just the message without thinking/reasoning.
51+
* This is not an @Action - the agent process executes respondWithThinking() instead.
52+
*/
5053
AssistantMessage respond(Conversation conversation, UserMessage userMessage, ChatRequest request, Ai ai) {
54+
ChatResponse response = respondWithThinking(conversation, userMessage, request, ai)
55+
response.message
56+
}
57+
58+
@AchievesGoal(description = "Respond to a user message with optional thinking/reasoning support")
59+
@Action(canRerun = true, trigger = UserMessage)
60+
ChatResponse respondWithThinking(Conversation conversation, UserMessage userMessage, ChatRequest request, Ai ai) {
5161
Objects.requireNonNull(conversation, "conversation must not be null")
5262
Objects.requireNonNull(userMessage, "userMessage must not be null")
5363
Objects.requireNonNull(request, "request must not be null")
@@ -58,14 +68,39 @@ Notes:
5868
PersonaTemplate template = personaTemplate(request.persona)
5969
String systemPrompt = buildSystemPrompt(template, request)
6070
LlmOptions options = request.options ?: LlmOptions.withDefaultLlm()
61-
AssistantMessage reply = ai
62-
.withLlm(options)
63-
.withPromptContributor(template.persona)
64-
.withSystemPrompt(systemPrompt)
65-
.withToolObject(codingAssistantAgent)
66-
.respond(conversation.messages)
71+
72+
AssistantMessage reply
73+
String reasoning = null
74+
75+
if (request.withThinking) {
76+
def promptRunner = ai
77+
.withLlm(options)
78+
.withPromptContributor(template.persona)
79+
.withSystemPrompt(systemPrompt)
80+
.withToolObject(codingAssistantAgent)
81+
82+
if (promptRunner.supportsThinking()) {
83+
ThinkingResponse<AssistantMessage> thinkingResponse = promptRunner
84+
.withThinking()
85+
.respond(conversation.messages)
86+
reply = thinkingResponse.getResult()
87+
if (thinkingResponse.hasThinking()) {
88+
reasoning = thinkingResponse.getThinkingContent()
89+
}
90+
} else {
91+
reply = promptRunner.respond(conversation.messages)
92+
}
93+
} else {
94+
reply = ai
95+
.withLlm(options)
96+
.withPromptContributor(template.persona)
97+
.withSystemPrompt(systemPrompt)
98+
.withToolObject(codingAssistantAgent)
99+
.respond(conversation.messages)
100+
}
101+
67102
conversation.addMessage(reply)
68-
reply
103+
new ChatResponse(reply, reasoning)
69104
}
70105

71106
private String buildSystemPrompt(PersonaTemplate template, ChatRequest request) {

src/main/groovy/se/alipsa/lca/agent/ChatRequest.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ class ChatRequest {
1111
LlmOptions options
1212
String systemPrompt
1313
String responseFormat
14+
boolean withThinking = false
1415
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package se.alipsa.lca.agent
2+
3+
import com.embabel.chat.AssistantMessage
4+
import groovy.transform.Canonical
5+
import groovy.transform.CompileStatic
6+
7+
@Canonical
8+
@CompileStatic
9+
class ChatResponse {
10+
AssistantMessage message
11+
String reasoning
12+
}

src/main/groovy/se/alipsa/lca/agent/CodingAssistantAgent.groovy

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.embabel.agent.domain.library.HasContent
1010
import com.embabel.agent.prompt.persona.RoleGoalBackstory
1111
import com.embabel.agent.prompt.persona.RoleGoalBackstorySpec
1212
import com.embabel.common.ai.model.LlmOptions
13+
import com.embabel.common.core.thinking.ThinkingResponse
1314
import com.embabel.common.core.types.Timestamped
1415
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
1516
import groovy.transform.Canonical
@@ -92,6 +93,7 @@ class CodingAssistantAgent {
9293
CodeSnippet codeSnippet
9394
String review
9495
RoleGoalBackstorySpec reviewer
96+
String reasoning
9597

9698
@Override
9799
@NonNull
@@ -186,18 +188,44 @@ ${reviewer.getRole()}, ${getTimestamp().atZone(ZoneId.systemDefault())
186188
LlmOptions llmOverride,
187189
String systemPromptOverride,
188190
RoleGoalBackstorySpec reviewerPersona
191+
) {
192+
reviewCode(userInput, codeSnippet, ai, llmOverride, systemPromptOverride, reviewerPersona, false)
193+
}
194+
195+
@Action
196+
ReviewedCodeSnippet reviewCode(
197+
UserInput userInput,
198+
CodeSnippet codeSnippet,
199+
Ai ai,
200+
LlmOptions llmOverride,
201+
String systemPromptOverride,
202+
RoleGoalBackstorySpec reviewerPersona,
203+
boolean withThinking
189204
) {
190205
Objects.requireNonNull(ai, "Ai must not be null")
191206
LlmOptions options = llmOverride ?: reviewLlmOptions
192207
RoleGoalBackstorySpec reviewer = reviewerPersona ?: Personas.REVIEWER
193208
String reviewPrompt = buildReviewPrompt(userInput, codeSnippet, systemPromptOverride, reviewer)
194-
String review = ai
195-
.withLlm(options)
196-
.withPromptContributor(reviewer)
197-
.generateText(reviewPrompt)
198-
String formattedReview = enforceReviewFormat(review)
199209

200-
new ReviewedCodeSnippet(codeSnippet, formattedReview, reviewer)
210+
String review
211+
String reasoning = null
212+
213+
def promptRunner = ai.withLlm(options).withPromptContributor(reviewer)
214+
215+
if (withThinking && promptRunner.supportsThinking()) {
216+
ThinkingResponse<String> response = promptRunner
217+
.withThinking()
218+
.generateText(reviewPrompt)
219+
review = response.getResult()
220+
if (response.hasThinking()) {
221+
reasoning = response.getThinkingContent()
222+
}
223+
} else {
224+
review = promptRunner.generateText(reviewPrompt)
225+
}
226+
227+
String formattedReview = enforceReviewFormat(review)
228+
new ReviewedCodeSnippet(codeSnippet, formattedReview, reviewer, reasoning)
201229
}
202230

203231
@Action

src/main/groovy/se/alipsa/lca/agent/ReviewAgent.groovy

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ class ReviewAgent {
3535
ai,
3636
request.options,
3737
request.systemPrompt,
38-
persona
38+
persona,
39+
request.withThinking
3940
)
40-
new ReviewResponse(reviewed.review)
41+
new ReviewResponse(reviewed.review, reviewed.reasoning)
4142
}
4243
}

src/main/groovy/se/alipsa/lca/agent/ReviewRequest.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ class ReviewRequest {
1212
LlmOptions options
1313
String systemPrompt
1414
boolean security
15+
boolean withThinking = false
1516
}

src/main/groovy/se/alipsa/lca/agent/ReviewResponse.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ import groovy.transform.CompileStatic
77
@CompileStatic
88
class ReviewResponse {
99
String review
10+
String reasoning
1011
}

0 commit comments

Comments
 (0)